@ -7,7 +7,7 @@
/ *
/ *
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
Author : JarBinks , Zachg99 , Jeff47
Author : JarBinks , Zachg99 , Jeff47
Date : 0 1/ 20 / 2022
Date : 0 3/ 22 / 2022
This is my attempt to create an all in one routine that will maintain my library in optimal format
This is my attempt to create an all in one routine that will maintain my library in optimal format
! ! ! ! FOR MY REQUIREMENTS ! ! ! ! Chances are very good you will need to make some changes to this routine
! ! ! ! FOR MY REQUIREMENTS ! ! ! ! Chances are very good you will need to make some changes to this routine
and it ' s partner in order to make it work for you .
and it ' s partner in order to make it work for you .
@ -61,10 +61,6 @@ Audio: (Only one audio stream is used!!)
Transcode the stream to aac using 100 % of the original streams bitrate
Transcode the stream to aac using 100 % of the original streams bitrate
It could probably be less but if the source is of low bitrate but , we don <EFBFBD> t want
It could probably be less but if the source is of low bitrate but , we don <EFBFBD> t want
to compromise too much on the transcode
to compromise too much on the transcode
Subtitles :
All are removed ? ? ( TODO : ensure this is correct and mention the flag to keep them if desired )
All are copied ( They usually take up little space so I keep them )
Any that are in mov _text will be converted to srt
Chapters :
Chapters :
If chapters are found the script keeps them unless ...
If chapters are found the script keeps them unless ...
Any chapter start time is a negative number ( Yes I have seen it )
Any chapter start time is a negative number ( Yes I have seen it )
@ -86,68 +82,7 @@ Subtitles:
Tdarr _Plugin _JB69 _JBHEVCQSV _MinimalFile ( JB - H265 , AAC , MKV , bitrate optimized )
Tdarr _Plugin _JB69 _JBHEVCQSV _MinimalFile ( JB - H265 , AAC , MKV , bitrate optimized )
Tdarr _Plugin _JB69 _JBHEVCQSZ _PostFix ( JB - MKV Stats , Chapters , Audio Language )
Tdarr _Plugin _JB69 _JBHEVCQSZ _PostFix ( JB - MKV Stats , Chapters , Audio Language )
I am running the docker image provided for Tdarr
I am running the docker image provided for Tdarr
* * * * To get the proper video bitrate you need to run this in the docker container :
apt install mkvtoolnix
If those tools are added that no longer needs to be run .
Here is my docker config ( I am running compose so yours might be a little different )
tdarr _server :
container _name : tdarr _server
image : haveagitgat / tdarr : latest
privileged : true
restart : unless - stopped
environment :
- PUID = $ { PUID } # default user id , defined in . env
- PGID = $ { PGID } # default group id , defined in . env
- TZ = $ { TZ } # timezone , defined in . env
- serverIP = tdarr _server # using internal docker networking . This should at least work when the nodes are on
# the same docker compose as the server
- serverPort = 8266
- webUIPort = 8265
volumes :
- $ { ROOT } / tdarr / server : / a p p / s e r v e r / T d a r r # T d a r r s e r v e r f i l e s
- $ { ROOT } / tdarr / configs : / a p p / c o n f i g s # c o n f i g f i l e s - c a n b e s a m e a s N O D E ( u n l e s s s e p a r a t e s e r v e r )
- $ { ROOT } / tdarr / logs : / a p p / l o g s # T d a r r l o g f i l e s
- $ { ROOT } / tdarr / cache : / t e m p # C a c h e f o l d e r , S h o u l d b e s a m e p a t h m a p p e d o n N O D E
- $ { ROOT } / tdarr / testmedia : / h o m e / T d a r r / t e s t m e d i a # S h o u l d b e s a m e p a t h m a p p e d o n N O D E i f u s i n g a t e s t f o l d e r
- $ { ROOT } / tdarr / scripts : / h o m e / T d a r r / s c r i p t s # m y r a n d o m w a y o f s a v i n g s c r i p t f i l e s
- / v o l u m e 1 / v i d e o : / m e d i a # v i d e o l i b r a r y S h o u l d b e s a m e p a t h m a p p e d o n N O D E
ports :
- 8265 : 8265 # Exposed to access webui externally
- 8266 : 8266 # Exposed to allow external nodes to reach the server
logging :
options :
max - size : "2m"
max - file : "3"
tdarr _node :
container _name : tdarr _node
image : haveagitgat / tdarr _node : latest
privileged : true
restart : unless - stopped
devices :
- / d e v / d r i : / d e v / d r i
environment :
- PUID = $ { PUID } # default user id , defined in . env
- PGID = $ { PGID } # default group id , defined in . env
- TZ = $ { TZ } # timezone , defined in . env
- serverIP = 192.168 . x . x # container name of the server , should be modified if server is on another machine
- serverPort = 8266
- nodeID = TDARRNODE _1
- nodeIP = 192.168 . x . x # container name of the node
- nodePort = 9267 # not exposed via a "ports: " setting as the server / node communication is done on the internal
# docker network and can communicate on all ports
volumes :
- $ { ROOT } / tdarr / configs : / a p p / c o n f i g s # c o n f i g f i l e s - c a n b e s a m e a s s e r v e r ( u n l e s s s e p a r a t e s e r v e r )
- $ { ROOT } / tdarr / logs : / a p p / l o g s # c o n f i g f i l e s - c a n b e s a m e a s s e r v e r ( u n l e s s s e p a r a t e s e r v e r )
- $ { ROOT } / tdarr / testmedia : / h o m e / T d a r r / t e s t m e d i a # S h o u l d b e s a m e p a t h m a p p e d o n s e r v e r i f u s i n g a t e s t f o l d e r
- $ { ROOT } / tdarr / scripts : / h o m e / T d a r r / s c r i p t s # m y r a n d o m w a y o f s a v i n g s c r i p t f i l e s
- $ { ROOT } / tdarr / cache : / t e m p # C a c h e f o l d e r , S h o u l d b e s a m e p a t h m a p p e d o n s e r v e r
- / m n t / v i d e o : / m e d i a # v i d e o l i b r a r y S h o u l d b e s a m e p a t h m a p p e d o n s e r v e r
ports :
- 9267 : 9267
logging :
options :
max - size : "2m"
max - file : "3"
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
* /
* /
@ -159,7 +94,7 @@ const details = () => ({
Operation : 'Transcode' ,
Operation : 'Transcode' ,
Description : ` ***You should not use this*** until you read the comments at the top of the code and understand
Description : ` ***You should not use this*** until you read the comments at the top of the code and understand
how it works * * this does a lot * * and is 1 of 2 routines you should to run * * Part 1 * * \ n ` ,
how it works * * this does a lot * * and is 1 of 2 routines you should to run * * Part 1 * * \ n ` ,
Version : '2. 2 ',
Version : '2. 4 ',
Tags : 'pre-processing,ffmpeg,video,audio,qsv,h265,aac' ,
Tags : 'pre-processing,ffmpeg,video,audio,qsv,h265,aac' ,
Inputs : [ {
Inputs : [ {
name : 'Stats_Days' ,
name : 'Stats_Days' ,
@ -348,21 +283,17 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
const targetAudioBitratePerChannel = inputs . Target _Audio _Bitrate _Per _Channel ;
const targetAudioBitratePerChannel = inputs . Target _Audio _Bitrate _Per _Channel ;
const targetAudioChannels = inputs . Target _Audio _Channels ;
const targetAudioChannels = inputs . Target _Audio _Channels ;
// Subtitles
// const bolIncludeSubs = true; //not currently used, it's possible to remove subs but not setup now
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
const proc = require ( 'child_process' ) ;
const proc = require ( 'child_process' ) ;
let bolStatsAreCurrent = false ;
let bolStatsAreCurrent = false ;
// Check if file is a video. If it isn't then exit plugin.
if ( file . fileMedium !== 'video' ) {
if ( file . fileMedium !== 'video' ) {
response . processFile = false ;
response . processFile = false ;
response . infoLog += 'File is not a video. Exiting \n' ;
response . infoLog += 'File is not a video. Exiting \n' ;
return response ;
return response ;
}
}
// If the file has already been processed we dont need to do more
if ( file . container === 'mkv' && (
if ( file . container === 'mkv' && (
file . mediaInfo . track [ 0 ] . extra !== undefined
file . mediaInfo . track [ 0 ] . extra !== undefined
&& file . mediaInfo . track [ 0 ] . extra . JBDONEVERSION !== undefined
&& file . mediaInfo . track [ 0 ] . extra . JBDONEVERSION !== undefined
@ -409,10 +340,6 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
} catch ( err ) {
} catch ( err ) {
response . infoLog += 'Error Updating Status Probably Bad file, A remux will probably fix, will continue\n' ;
response . infoLog += 'Error Updating Status Probably Bad file, A remux will probably fix, will continue\n' ;
}
}
response . infoLog += 'Getting Stats Objects, again!\n' ;
// objMedInfo = JSON.parse(proc.execSync('mediainfo "' + currentFileName + '" --output=JSON').toString());
// objFFProbeInfo = JSON.parse(proc.execSync('ffprobe -v error -print_format json' +
// ' -show_format -show_streams -show_chapters "' + currentFileName + '"').toString());
}
}
}
}
@ -440,7 +367,6 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
const bolDoChapters = true ;
const bolDoChapters = true ;
// Set up required variables
let videoIdx = - 1 ;
let videoIdx = - 1 ;
let videoIdxFirst = - 1 ;
let videoIdxFirst = - 1 ;
let audioIdx = - 1 ;
let audioIdx = - 1 ;
@ -449,14 +375,12 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
let strStreamType = '' ;
let strStreamType = '' ;
let MILoc = - 1 ;
let MILoc = - 1 ;
// Go through each stream in the file.
for ( let i = 0 ; i < file . ffProbeData . streams . length ; i += 1 ) {
for ( let i = 0 ; i < file . ffProbeData . streams . length ; i += 1 ) {
strStreamType = file . ffProbeData . streams [ i ] . codec _type . toLowerCase ( ) ;
strStreamType = file . ffProbeData . streams [ i ] . codec _type . toLowerCase ( ) ;
// Looking For Video
// Looking For Video
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
if ( strStreamType === 'video' ) {
if ( strStreamType === 'video' ) {
// First we need to check if it is included in the MediaInfo struture, it might not be (mjpeg??, others??)
MILoc = findMediaInfoItem ( file , i ) ;
MILoc = findMediaInfoItem ( file , i ) ;
response . infoLog += ` Index ${ i } MediaInfo stream: ${ MILoc } \n ` ;
response . infoLog += ` Index ${ i } MediaInfo stream: ${ MILoc } \n ` ;
@ -484,9 +408,7 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
videoIdx = i ;
videoIdx = i ;
} else {
} else {
const MILocC = findMediaInfoItem ( file , videoIdx ) ;
const MILocC = findMediaInfoItem ( file , videoIdx ) ;
// const curstreamheight = file.ffProbeData.streams[videoIdx].height * 1; //Not needed
const curStreamWidth = file . ffProbeData . streams [ videoIdx ] . width * 1 ;
const curStreamWidth = file . ffProbeData . streams [ videoIdx ] . width * 1 ;
// const curstreamFPS = file.mediaInfo.track[MILocC].FrameRate * 1; //Not needed
let curStreamBR = file . mediaInfo . track [ MILocC ] . BitRate * 1 ;
let curStreamBR = file . mediaInfo . track [ MILocC ] . BitRate * 1 ;
if ( isNaN ( curStreamBR ) ) {
if ( isNaN ( curStreamBR ) ) {
@ -505,12 +427,6 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// Looking For Audio
// Looking For Audio
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
if ( strStreamType === 'audio' ) {
if ( strStreamType === 'audio' ) {
// response.processFile = false;
// response.infoLog += i + ":" + objFFProbeInfo.streams[i].tags.language + " \n";
// audioIdxFirst = i;
// response.infoLog += JSON.stringify(objFFProbeInfo.streams[i]) + " \n";
audioChannels = file . ffProbeData . streams [ i ] . channels * 1 ;
audioChannels = file . ffProbeData . streams [ i ] . channels * 1 ;
audioBitrate = file . mediaInfo . track [ findMediaInfoItem ( file , i ) ] . BitRate * 1 ;
audioBitrate = file . mediaInfo . track [ findMediaInfoItem ( file , i ) ] . BitRate * 1 ;
@ -564,7 +480,7 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
}
}
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
// Looking For Subtitles -- These are causing problems let's just exclude for now
// Looking For Subtitles
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
if ( ! bolForceNoSubs && ! bolDoSubs && ( strStreamType === 'text' || strStreamType === 'subtitle' ) ) {
if ( ! bolForceNoSubs && ! bolDoSubs && ( strStreamType === 'text' || strStreamType === 'subtitle' ) ) {
// A sub has an S_TEXT/WEBVTT codec, ffmpeg will fail with it
// A sub has an S_TEXT/WEBVTT codec, ffmpeg will fail with it
@ -581,33 +497,9 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
bolForceNoSubs = true ;
bolForceNoSubs = true ;
}
}
}
}
// bolDoSubs = true;
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
}
}
// return response;
// Go through chapters in the file looking for badness
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
// Not processing chapters - fileobject doesn't seem to have the chapters section
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
// for (var i = 0; i < objFFProbeInfo.chapters.length; i+=1) {
// Bad start times
// if (objFFProbeInfo.chapters[i].start_time < 0) {
// bolDoChapters = false;
// break; //Dont need to continue because we know they are bad
// }
// Duplicate start times
// for (var x = 0; i < objFFProbeInfo.chapters.length; i+=1) {
// if (i != x && objFFProbeInfo.chapters[i].start_time == objFFProbeInfo.chapters[x].start_time) {
// bolDoChapters = false;
// break; //Dont need to continue because we know they are bad
// }
// }
// }
// Video Decision section
// Video Decision section
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
if ( videoIdx === - 1 ) {
if ( videoIdx === - 1 ) {
@ -638,11 +530,11 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// Source is Variable Frame rate but we will transcode to fixed
// Source is Variable Frame rate but we will transcode to fixed
if ( file . mediaInfo . track [ MILoc ] . FrameRate _Mode === 'VFR' ) videoFPS = 9999 ;
if ( file . mediaInfo . track [ MILoc ] . FrameRate _Mode === 'VFR' ) videoFPS = 9999 ;
if ( videoFPS > targetFrameRate ) {
if ( videoFPS > targetFrameRate && file . container !== 'ts' ) {
bolChangeFrameRateVideo = true ; // Need to fix this it does not work :-(
bolChangeFrameRateVideo = true ; // Need to fix this it does not work :-(
}
}
// Lets see if we need to scal down the video size
// Lets see if we need to scal e down the video size
if ( videoHeight > maxVideoHeight ) {
if ( videoHeight > maxVideoHeight ) {
bolScaleVideo = true ;
bolScaleVideo = true ;
videoNewWidth = Math . floor ( ( maxVideoHeight / videoHeight ) * videoWidth ) ;
videoNewWidth = Math . floor ( ( maxVideoHeight / videoHeight ) * videoWidth ) ;
@ -723,7 +615,6 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
}
}
} else {
} else {
// We already know the existing bitrate has enough meat for a decent transcode
// We already know the existing bitrate has enough meat for a decent transcode
// bolTranscodeVideo = true;
response . infoLog += ` Video existing Bitrate, ${ videoBR } , is higher than target, `
response . infoLog += ` Video existing Bitrate, ${ videoBR } , is higher than target, `
+ ` ${ optimalVideoBitrate } , transcoding \n ` ;
+ ` ${ optimalVideoBitrate } , transcoding \n ` ;
}
}
@ -759,12 +650,12 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
audioNewChannels = file . ffProbeData . streams [ audioIdx ] . channels ;
audioNewChannels = file . ffProbeData . streams [ audioIdx ] . channels ;
}
}
let optimal audiob itrate = audioNewChannels * targetAudioBitratePerChannel ;
let optimal AudioB itrate = audioNewChannels * targetAudioBitratePerChannel ;
// Now what are we going todo with the audio part
// Now what are we going todo with the audio part
if ( audioBR > ( optimal audiob itrate * 1.1 ) ) {
if ( audioBR > ( optimal AudioB itrate * 1.1 ) ) {
bolTranscodeAudio = true ;
bolTranscodeAudio = true ;
response . infoLog += ` Audio existing Bitrate, ${ audioBR } , is higher than target, ${ optimal audiob itrate} \n ` ;
response . infoLog += ` Audio existing Bitrate, ${ audioBR } , is higher than target, ${ optimal AudioB itrate} \n ` ;
}
}
// If the audio codec is not what we want then we should transcode
// If the audio codec is not what we want then we should transcode
@ -776,10 +667,10 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
}
}
// If the source bitrate is less than out target bitrate we should not ever go up
// If the source bitrate is less than out target bitrate we should not ever go up
if ( audioBR < optimal audiob itrate) {
if ( audioBR < optimal AudioB itrate) {
response . infoLog += ` Audio existing Bitrate, ${ audioBR } , is lower than target, `
response . infoLog += ` Audio existing Bitrate, ${ audioBR } , is lower than target, `
+ ` ${ optimal audiob itrate} , using existing ` ;
+ ` ${ optimal AudioB itrate} , using existing ` ;
optimal audiob itrate = audioBR ;
optimal AudioB itrate = audioBR ;
if ( file . ffProbeData . streams [ audioIdx ] . codec _name !== targetAudioCodec ) {
if ( file . ffProbeData . streams [ audioIdx ] . codec _name !== targetAudioCodec ) {
response . infoLog += 'rate' ;
response . infoLog += 'rate' ;
} else {
} else {
@ -791,57 +682,35 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// lets assemble our ffmpeg command
// lets assemble our ffmpeg command
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
const strTranCodeBaseHW = ' -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi ' ;
const strTranCodeBaseSW = ' -vaapi_device /dev/dri/renderD128 ' ;
const strTranscodeVideoMapping = ' <io> -max_muxing_queue_size 8000 -map 0:{0} ' ;
const strTranscodeVideoCopy = ' -c:v:0 copy ' ;
const strTranscodeVideoTranscoding = ' -c:v:0 hevc_vaapi ' ;
// Used to make the output 10bit, I think the quotes need to be this way for ffmpeg
const strTranscodeVideoOptions = ' -vf "{0}" ' ;
const strTranscodeVideoScaling = 'w=-1:h=1080' ; // Used when video is above our target of 1080
const strTransCodeFrameRate = 'fps={0}' ; // Used to change the framerate to the target framerate
const strTranscodeVideoFormatHW = 'scale_vaapi=' ; // Used to make the output 10bit
const strTranscodeVideoFormat = 'format={0}' ; // Used to add filters to the hardware transcode
const strTranscodeVideo10bit = 'p010' ; // Used to make the output 10bit
const strTranscodeVideo8bit = 'p008' ; // Used to make the output 8bit
const strTranscodeVideoSWDecode = 'hwupload' ; // Used to make it use software decode if necessary
// Used to make it sure the software decode is in the proper pixel format
const strTranscodeVideoSWDecode10bit = 'nv12|vaapi' ;
const strTranscodeVideoBitrate = ' -b:v {0} ' ; // Used when video is above our target of 1080
const strTranscodeAudioMapping = ' -map 0:{0} ' ;
const strTranscodeAudioCopy = ' -c:a:0 copy ' ;
const strTranscodeAudioTranscoding = ' -c:a:0 ${targetAudioCodec} -b:a {0} ' ;
const strTranscodeAudioDownMixing = ' -ac {0} ' ;
const strTranscodeSubs = ' -map 0:s -scodec copy ' ;
const strTranscodeSubsConvert = ' -map 0:s -c:s srt ' ;
const strTranscodeSubsNone = ' -map -0:s ' ;
const strTranscodeMetadata = ' -map_metadata:g -1 -metadata JBDONEVERSION=1 -metadata JBDONEDATE={0} ' ;
const strTranscodeChapters = ' -map_chapters {0} ' ;
const strTranscodeFileOptions = ' ' ;
const strTranscodeFileOptions = ' ' ;
let strFFcmd = '' ;
let strFFcmd = '' ;
if ( bolTranscodeVideo ) {
if ( bolTranscodeVideo ) {
if ( bolTranscodeSoftwareDecode ) {
if ( bolTranscodeSoftwareDecode ) {
strFFcmd += strTranCodeBaseSW ;
strFFcmd += ' -vaapi_device /dev/dri/renderD128 ' ;
} else {
} else {
strFFcmd += strTranCodeBaseHW ;
strFFcmd += ' -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi ' ;
}
}
}
}
strFFcmd += strTranscodeVideoMapping . replace ( '{0}' , videoIdx ) ;
strFFcmd += ` <io> -max_muxing_queue_size 8000 -map 0: ${ videoIdx } ` ;
if ( bolTranscodeVideo ) {
if ( bolTranscodeVideo ) {
strFFcmd += strTranscodeVideoTranscoding ;
// Used to make the output 10bit, I think the quotes need to be this way for ffmpeg
strFFcmd += ' -c:v:0 hevc_vaapi ' ;
if ( bolScaleVideo || bolUse10bit || bolTranscodeSoftwareDecode || bolChangeFrameRateVideo ) {
if ( bolScaleVideo || bolUse10bit || bolTranscodeSoftwareDecode || bolChangeFrameRateVideo ) {
let strOptions = '' ;
let strOptions = '' ;
let strFormat = '' ;
let strFormat = '' ;
if ( bolScaleVideo ) {
if ( bolScaleVideo ) {
strOptions += strTranscodeVideoScaling ;
// Used when video is above our target
strOptions += ` w=-1:h= ${ maxVideoHeight } ` ;
}
}
let strChangeVideoRateString = '' ;
let strChangeVideoRateString = '' ;
if ( bolChangeFrameRateVideo ) {
if ( bolChangeFrameRateVideo ) {
strChangeVideoRateString = ` ${ strTransCodeFrameRate . replace ( '{0}' , targetFrameRate ) } , ` ;
// Used to change the framerate to the target framerate
strChangeVideoRateString = ` fps= ${ targetFrameRate } , ` ;
}
}
if ( strFormat . length > 0 ) {
if ( strFormat . length > 0 ) {
@ -849,11 +718,13 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
}
}
if ( bolUse10bit && ! bolSource10bit ) {
if ( bolUse10bit && ! bolSource10bit ) {
strFormat += strTranscodeVideo10bit ;
// Used to make the output 10bit
strFormat += 'p010' ;
}
}
if ( ! bolUse10bit && bolSource10bit ) {
if ( ! bolUse10bit && bolSource10bit ) {
strFormat += strTranscodeVideo8bit ;
// Used to make the output 8bit
strFormat += 'p008' ;
}
}
if ( bolTranscodeSoftwareDecode ) {
if ( bolTranscodeSoftwareDecode ) {
@ -861,66 +732,64 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
if ( strFormat . length > 0 ) {
if ( strFormat . length > 0 ) {
strFormat += ',' ;
strFormat += ',' ;
}
}
strFormat += strTranscodeVideoSWDecode10bit ;
// Used to make it sure the software decode is in the proper pixel format
strFormat += 'nv12|vaapi' ;
}
}
if ( strFormat . length > 0 ) {
if ( strFormat . length > 0 ) {
strFormat += ',' ;
strFormat += ',' ;
}
}
strFormat += strTranscodeVideoSWDecode ;
// Used to make it use software decode if necessary
strFormat += 'hwupload' ;
}
}
if ( strFormat . length > 0 ) {
if ( strFormat . length > 0 ) {
if ( strOptions . length > 0 ) {
if ( strOptions . length > 0 ) {
strOptions += ',' ;
strOptions += ',' ;
}
}
strOptions += strTranscodeVideoFormat . replace ( '{0}' , strFormat ) ;
strOptions += ` format= ${ strFormat } ` ;
}
}
if ( bolTranscodeSoftwareDecode ) {
if ( bolTranscodeSoftwareDecode ) {
strFFcmd += strTranscodeVideoOptions . replace ( '{0}' , strChangeVideoRateString + strOptions ) ;
strFFcmd += ` -vf " ${ strChangeVideoRateString } ${ strOptions } " ` ;
} else {
} else {
strFFcmd += strTranscodeVideoOptions
strFFcmd += ` -vf " ${ strChangeVideoRateString } scale_vaapi= ${ strOptions } " ` ;
. replace ( '{0}' , strChangeVideoRateString + strTranscodeVideoFormatHW + strOptions ) ;
}
}
}
}
strFFcmd += strTranscodeVideoBitrate . replace ( '{0}' , optimalVideoBitrate ) ;
// Used when video is above our target
strFFcmd += ` -b:v ${ optimalVideoBitrate } ` ;
} else {
} else {
strFFcmd += strTranscodeVideoCopy ;
strFFcmd += ' -c:v:0 copy ' ;
}
}
strFFcmd += strTranscodeAudioMapping . replace ( '{0}' , audioIdx ) ;
strFFcmd += ` -map 0: ${ audioIdx } ` ;
if ( bolTranscodeAudio ) {
if ( bolTranscodeAudio ) {
strFFcmd += strTranscodeAudioTranscoding
strFFcmd += ` -c:a:0 ${ targetAudioCodec } -b:a ${ optimalAudioBitrate } ` ;
. replace ( '{0}' , optimalaudiobitrate )
. replace ( '${targetAudioCodec}' , targetAudioCodec ) ;
} else {
} else {
strFFcmd += strTranscodeAudioCopy ;
strFFcmd += ' -c:a:0 copy ' ;
}
}
if ( bolDownMixAudio ) {
if ( bolDownMixAudio ) {
strFFcmd += strTranscodeAudioDownMixing . replace ( '{0}' , audioNewChannels ) ;
strFFcmd += ` -ac ${ audioNewChannels } ` ;
}
}
if ( bolForceNoSubs ) {
if ( bolForceNoSubs ) {
strFFcmd += strTranscodeSubsNone ;
strFFcmd += ' -map -0:s ' ;
} else if ( bolDoSubs ) {
} else if ( bolDoSubs ) {
if ( bolDoSubsConvert ) {
if ( bolDoSubsConvert ) {
strFFcmd += strTranscodeSubsConvert ;
strFFcmd += ' -map 0:s -c:s srt ' ;
} else {
} else {
strFFcmd += strTranscodeSubs ;
strFFcmd += ' -map 0:s -scodec copy ' ;
}
}
}
}
strFFcmd += strTranscodeMetadata . replace ( '{0}' , new Date ( ) . toISOString ( ) ) ;
strFFcmd += ` -map_metadata:g -1 -metadata JBDONEVERSION=1 -metadata JBDONEDATE= ${ new Date ( ) . toISOString ( ) } ` ;
if ( bolDoChapters ) {
if ( bolDoChapters ) {
strFFcmd += strTranscodeChapters . replace ( '{0}' , '0' ) ;
strFFcmd += ' -map_chapters 0 ' ;
} else {
} else {
strFFcmd += strTranscodeChapters . replace ( '{0}' , '-1' ) ;
strFFcmd += ' -map_chapters -1 ' ;
}
}
strFFcmd += strTranscodeFileOptions ;
strFFcmd += strTranscodeFileOptions ;
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////////////////////////////////////
// response.infoLog += strFFcmd + "\n";
response . preset += strFFcmd ;
response . preset += strFFcmd ;
response . processFile = true ;
response . processFile = true ;
response . infoLog += 'File needs work. Transcoding. \n' ;
response . infoLog += 'File needs work. Transcoding. \n' ;