Add boosh changes

make-only-subtitle-default
HaveAGitGat 3 years ago
parent d6922ec703
commit a09237aae7

@ -3,8 +3,10 @@
// Extra logic is mainly to control encoder quality/speed & to allow HEVC files to be reprocessed to reduce file size // Extra logic is mainly to control encoder quality/speed & to allow HEVC files to be reprocessed to reduce file size
// NOTE - This does not use VAAPI, it is QSV only. So newer intel iGPUs only. 8th+ gen should work. // NOTE - This does not use VAAPI, it is QSV only. So newer intel iGPUs only. 8th+ gen should work.
// Additionally this was designed and tested on UNRAID via docker though there is logic to support use on // Additionally this was designed and tested on UNRAID via docker, though there is logic to support use on
// Windows, Linux & Mac // Windows & Linux - Both platforms have now been confirmed working, however there is no way to test all use cases
// Mac is supported, however it does not use QSV. This is because ffmpeg on Mac does not actually leverage QSV and
// instead uses "VideoToolbox" which is more a general video encode accelerator.
// White paper from intel regarding QSV performance on linux using FFMPEG here: // White paper from intel regarding QSV performance on linux using FFMPEG here:
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
@ -16,16 +18,22 @@ const details = () => ({
Name: 'Boosh-Transcode using QSV GPU & FFMPEG', Name: 'Boosh-Transcode using QSV GPU & FFMPEG',
Type: 'Video', Type: 'Video',
Operation: 'Transcode', Operation: 'Transcode',
Description: `This is a QSV specific plugin. 8th+ gen INTEL QSV enabled CPUs are required. VAAPI is NOT used. Description: `==DETAILS== This is a QSV plugin. 8th+ gen INTEL QSV enabled CPUs are recommended. VAAPI is NOT used.
Files not in H265/HEVC will be transcoded into H265/HEVC using Quick Sync Video (QSV) \n\n==OS SUPPORT== This plugin supports Linux & Windows using QSV. Mac is supported though cannot use QSV and
via Intel GPU using FFmpeg. Settings are dependant on file bitrate working by the logic that H265 can support relies on 'VideoToolBox' - Expect to see different encode speed & quality on Mac compared to other platforms.
the same amount of data at half the bitrate of H264. This plugin will skip files already in HEVC, AV1 & VP9 Ensure you set your node settings accordingly!
unless "reconvert_hevc" is marked as true. If it is then these will be reconverted again into HEVC if they \n\n==LOGIC== Files will be transcoded into H265/HEVC using Quick Sync Video (QSV) via Intel GPU using ffmpeg.
exceed the bitrate specified in "hevc_max_bitrate". Reminder! An INTEL QSV enabled CPU is required. Settings are dependant on file bitrate working by the logic that H265 can support the same amount of data at half
NOTE - Created for use with UNRAID Docker and while it should support Windows/Mac etc, it may require the bitrate of H264. This plugin will skip files already in HEVC, AV1 & VP9 unless "reconvert_hevc" is marked as
a custom version of FFmpeg to work properly.`, true. If it is then these will be reconverted again if they exceed the bitrate specified in "hevc_max_bitrate".
Version: '1.0', This plugin will also attempt to use mkvpropedit to generate accurate bitrate metadata in MKV files.
Tags: 'pre-processing,ffmpeg,video only,qsv,h265,hevc,configurable', It's not required to enable mkvpropedit but highly recommended to ensure accurate bitrates are used when
encoding your media.
\n\n==NOTE== Intel ARC cards are reportedly working successfully with this plugin, however please bare in mind that
I've not officially tested with them yet and your results might vary. Don't just assume it will work and if it does
ensure you properly test your files & workflow!`,
Version: '1.2',
Tags: 'pre-processing,ffmpeg,video only,qsv,h265,hevc,mkvpropedit,configurable',
Inputs: [ Inputs: [
{ {
name: 'container', name: 'container',
@ -40,11 +48,11 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Specifies the output container of the file. \\nSpecifies the output container of the file.
\\n Ensure that all stream types you may have are supported by your chosen container. \\nEnsure that all stream types you may have are supported by your chosen container.
\\n \\n
==INFO== ==INFO==
\\n Only MP4 & MKV are supported and MKV is recommended. \\nOnly MP4 & MKV are supported and MKV is recommended.
\\nExample:\\n \\nExample:\\n
mkv mkv
\\nExample:\\n \\nExample:\\n
@ -63,16 +71,42 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Make the file conform to output containers requirements. \\nMake the file conform to output containers requirements.
Use if you need to ensure the encode works from mp4>mkv or mkv>mp4. \\n Use if you need to ensure the encode works from mp4>mkv or mkv>mp4. \\n
==WARNING== \\n ==WARNING== \\n
This will remove data of certain types so ensure you are happy with that, This will remove data of certain types so ensure you are happy with that,
or use another plugin to convert these data types first! or use another plugin to convert these data types first!
\\n \\n
==INFO== ==INFO==
\\n Drop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4. \\nDrop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4.
\\n Drop data streams/mov_text/eia_608/timed_id3 for MKV. \\nDrop data streams/mov_text/eia_608/timed_id3 for MKV.
\\n Default is false. \\nDefault is false.
\\nExample:\\n
true
\\nExample:\\n
false`,
},
{
name: 'enable_10bit',
type: 'boolean',
defaultValue: false,
inputUI: {
type: 'dropdown',
options: [
'false',
'true',
],
},
tooltip: `\\n
==DESCRIPTION==
\\nSpecify if we want to enable 10bit encoding.
\\nIf this is enabled files will be processed and converted into 10bit
HEVC using main10 profile and with p010le pixel format. \n
If you just want to retain files that are already 10 bit then this can be left as false, as
10bit to 10bit in ffmpeg should be automatic.
\\n
==INFO==
\\nDefault is "false".
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
@ -96,15 +130,15 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Specify the encoder speed/preset to use. \\nSpecify the encoder speed/preset to use.
Slower options mean a slower encode but better quality and faster options mean faster encodes but Slower options mean a slower encode but better quality and faster options mean faster encodes but
worse quality. worse quality.
\\n For more information see intel white paper on FFmpeg results using QSV: \\n` \\nFor more information see intel white paper on ffmpeg results using QSV: \\n`
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
+ `https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/cloud-computing-quicksync-video-ffmpeg-white-paper.pdf + `https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/cloud-computing-quicksync-video-ffmpeg-white-paper.pdf
\\n \\n
==INFO== ==INFO==
\\n Default is "slow". \\nDefault is "slow".
\\nExample:\\n \\nExample:\\n
medium medium
\\nExample:\\n \\nExample:\\n
@ -119,50 +153,32 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Here you can add extra options to the FFmpeg QSV ENCODE cmd. \\nHere you can add extra options to the ffmpeg QSV ENCODE cmd.
This does not override the FFmpeg cmd, it just allows additions to it. This does not override the ffmpeg cmd, it just allows additions to it.
\\n \\n
There are extra QSV options that can be There are extra QSV options that can be
forced on/off as desired. See here for some possible cmds - forced on/off as desired. See here for some possible cmds -
https://ffmpeg.org/ffmpeg-codecs.html#toc-HEVC-Options-1 https://ffmpeg.org/ffmpeg-codecs.html#toc-HEVC-Options-1
\\n \\n
==WARNING== \\n ==WARNING== \\n
Just because a cmd is mentioned doesn't mean your installed version of FFmpeg supports it... Just because a cmd is mentioned doesn't mean your installed version of ffmpeg supports it...
Be certain to verify the cmds work before adding to your workflow. \\n Be certain to verify the cmds work before adding to your workflow. \\n
Check Tdarr Help Tab. Enter FFmpeg cmd - "-h encoder=hevc_qsv". This will give a list of supported commands. Check Tdarr Help Tab. Enter ffmpeg cmd - "-h encoder=hevc_qsv". This will give a list of supported commands. \\n
MAC SPECIFIC - This option is ignored on Mac because videotoolbox is used rather than qsv.
\\n \\n
==INFO== ==INFO==
\\n Default is empty but a suggested value is below. If unsure just leave empty. \\nDefault is empty but the first example below has a suggested value. If unsure just leave empty.
\\n Ensure to only use cmds valid to encoding QSV as the script handles other FFmpeg cmds relating to \\nEnsure to only use cmds valid to encoding QSV as the script handles other ffmpeg cmds relating to
bitrate etc. Anything else entered here might be supported but could cause undesired results. bitrate etc. Anything else entered here might be supported but could cause undesired results.
\\nExample:\\n \\nExample:\\n
-extbrc 1 -rdo 1 -mbbrc 1 -b_strategy 1 -adaptive_i 1 -adaptive_b 1`, -look_ahead 1 -look_ahead_depth 100 -extbrc 1 -rdo 1 -mbbrc 1 -b_strategy 1 -adaptive_i 1 -adaptive_b 1
}, \\n Above enables look ahead, extended bitrate control, b-frames, etc.\\n
{
name: 'enable_10bit',
type: 'boolean',
defaultValue: false,
inputUI: {
type: 'dropdown',
options: [
'false',
'true',
],
},
tooltip: `\\n
==DESCRIPTION==
\\n Specify if we want to enable 10bit encoding.
\\n If this is enabled files will be processed and converted into 10bit
HEVC using main10 profile and with p010le pixel format. \n
If you just want to retain files that are already 10 bit then this can be left as false, as
10bit to 10bit in FFmpeg should be automatic.
\\n
==INFO==
\\n Default is "false".
\\nExample:\\n \\nExample:\\n
true -vf scale_qsv=w=1280:h=720
\\nScale video resolution Method 1\\n
\\nExample:\\n \\nExample:\\n
false`, -vf scale_qsv=1280:-1
\\nScale video resolution Method 2\\n`,
}, },
{ {
name: 'bitrate_cutoff', name: 'bitrate_cutoff',
@ -173,14 +189,12 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Specify bitrate cutoff, files with a total bitrate lower then this will not be processed. \n \\nSpecify bitrate cutoff, files with a video bitrate lower then this will not be processed. \n
Since getting the bitrate of the video from files is unreliable, bitrate here refers to the total
bitrate of the file and not just the video steam.
\\n \\n
==INFO== ==INFO==
\\n Rate is in kbps. \\nRate is in kbps.
\\n Defaults to 0 which means this is disabled. \\nDefaults to 0 which means this is disabled.
\\n Enter a valid number to enable. \\nEnter a valid number to enable.
\\nExample:\\n \\nExample:\\n
2500 2500
\\nExample:\\n \\nExample:\\n
@ -195,16 +209,16 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Specify a maximum average video bitrate. When encoding we take the current total bitrate and halve it \\nSpecify a maximum average video bitrate. When encoding we take the current video bitrate and halve it
to get an average target. This option sets a upper limit to that average to get an average target. This option sets a upper limit to that average
(i.e if you have a video bitrate of 10000, half is 5000, if your maximum desired average bitrate is 4000 (i.e if you have a video bitrate of 10000, half is 5000, if your maximum desired average bitrate is 4000
then we use that as the target instead of 5000). then we use that as the target instead of 5000).
\\n \\n
==INFO== ==INFO==
\\n Bitrate here is referring to video bitrate as we want to set the video bitrate on encode. \\nBitrate here is referring to video bitrate as we want to set the video bitrate on encode.
\\n Rate is in kbps. \\nRate is in kbps.
\\n Defaults to 0 which means this is disabled. \\nDefaults to 0 which means this is disabled.
\\n Enter a valid number to enable. \\nEnter a valid number to enable.
\\nExample:\\n \\nExample:\\n
4000 4000
\\nExample:\\n \\nExample:\\n
@ -219,16 +233,16 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Specify a minimum average video bitrate. When encoding we take the current total bitrate and halve \\nSpecify a minimum average video bitrate. When encoding we take the current video bitrate and halve
it to get an average target. This option sets a lower limit to that average (i.e if you have a video bitrate it to get an average target. This option sets a lower limit to that average (i.e if you have a video bitrate
of 3000, half is 1500, if your minimum desired average bitrate is 2000 then we use that as the target instead of 3000, half is 1500, if your minimum desired average bitrate is 2000 then we use that as the target instead
of 1500). of 1500).
\\n \\n
==INFO== ==INFO==
\\n Bitrate here is referring to video bitrate as we want to set the video bitrate on encode. \\nBitrate here is referring to video bitrate as we want to set the video bitrate on encode.
\\n Rate is in kbps. \\nRate is in kbps.
\\n Defaults to 0 which means this is disabled. \\nDefaults to 0 which means this is disabled.
\\n Enter a valid number to enable. \\nEnter a valid number to enable.
\\nExample:\\n \\nExample:\\n
2000 2000
\\nExample:\\n \\nExample:\\n
@ -247,21 +261,22 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Specify if we want to reprocess HEVC, VP9 or AV1 files \\nSet to reprocess HEVC, VP9 or AV1 files (i.e reduce bitrate of files already in those codecs).
(i.e reduce bitrate of files already in those codecs). \\nSince this uses the same logic as normal, halving the current bitrate, this is NOT recommended
\\n Since this uses the same logic as normal, halving the current bitrate, this is NOT recommended unless you know what you are doing, so please leave FALSE if unsure!
unless you know what you are doing, so leave false if unsure. \\nNEEDS to be used in conjunction with "bitrate_cutoff" or "hevc_max_bitrate" otherwise is ignored.
NEEDS to be used in conjunction with "bitrate_cutoff" or "hevc_max_bitrate" otherwise is ignored. \\nThis is useful in certain situations, perhaps you have a file which is HEVC but has an extremely high
This is useful in certain situations, perhaps you have a file which is HEVC but has an extremely high
bitrate and you'd like to reduce it. bitrate and you'd like to reduce it.
\\n Bare in mind that you can convert a file to HEVC and still be above your cutoff meaning it would
be converted again if this is set to true (since it's now HEVC). So if you use this be sure to set
"hevc_max_bitrate" & "max_average_bitrate" to prevent the plugin looping. Also it is highly suggested
that you have your "hevc_max_bitrate" higher than "max_average_bitrate".
\\n Again if you are unsure, please leave this as false!
\\n \\n
==WARNING== \\n ==WARNING== \\n
IF YOU HAVE VP9 OR AV1 FILES YOU WANT TO KEEP IN THOSE FORMATS THEN DO NOT USE THIS OPTION. IF YOU HAVE VP9 OR AV1 FILES YOU WANT TO KEEP IN THOSE FORMATS THEN DO NOT USE THIS OPTION. \\n
\\nThis option has the potential to LOOP your encodes! You can encode a file to HEVC and still
be above your cutoff and it would be converted again & again if this is set to true (since it's now HEVC).
So if you use this be sure to set "hevc_max_bitrate" & "max_average_bitrate" to help prevent the plugin looping.
Also it is highly suggested that you have your "hevc_max_bitrate" higher than "max_average_bitrate".
\\nPlease be certain you want this enabled before setting it otherwise leave this as FALSE!
While the plugin will attempt to generate accurate video bitrate metadata, it can not always reliably do so
and will be forced to fall back onto estimates. Please bare this in mind when using the HEVC reprocess option.
\\n \\n
\\nExample:\\n \\nExample:\\n
true true
@ -277,21 +292,23 @@ const details = () => ({
}, },
tooltip: `\\n tooltip: `\\n
==DESCRIPTION== ==DESCRIPTION==
\\n Has no effect unless "reconvert_hevc" is set to true. This allows you to specify a maximum \\nHas no effect unless "reconvert_hevc" is set to true. This allows you to specify a maximum
allowed average bitrate for HEVC or similar files. Much like the "bitrate_cutoff" option, but allowed average OVERALL bitrate for HEVC or similar files. Much like the "bitrate_cutoff" option, but
specifically for HEVC files. It should be set HIGHER then your standard cutoff for safety. specifically for HEVC files. It should be set HIGHER then your standard cutoff for safety.
\\n Also, it's highly suggested you use the min & max average bitrate options in combination with this. You \\nAlso, it's highly suggested you use the min & max average bitrate options in combination with this. You
will want those to control the bitrate otherwise you may end up repeatedly reprocessing HEVC files. will want those to control the encoded video bitrate, otherwise you may end up repeatedly reprocessing HEVC files.
i.e your file might have a bitrate of 20000, if your hevc cutoff is 5000 then it's going to reconvert i.e your file might have a overall bitrate of 20000, if your hevc cutoff is 5000 then it's going to reconvert
multiple times before it'll fall below that cutoff. While HEVC reprocessing can be useful multiple times before it'll fall below that cutoff. While HEVC reprocessing can be useful this is why it is NOT
this is why it is NOT recommended! recommended!
\\n As with the cutoff, getting the bitrate of the video from files is unreliable, so bitrate \\n
here refers to the total bitrate of the file and not just the video steam. ==WARNING== \\n
While the plugin will attempt to generate accurate video bitrate metadata, it can not always reliably do so
and will be forced to fall back onto estimates. Please bare this in mind when using the HEVC reprocess option.
\\n \\n
==INFO== ==INFO==
\\n Rate is in kbps. \\nRate is in kbps.
\\n Defaults to 0 which means this is disabled. \\nDefaults to 0 which means this is disabled.
\\n Enter a valid number to enable, otherwise we use "bitrate_cutoff" and multiply x2 for a safe limit. \\nEnter a valid number to enable, otherwise we use "bitrate_cutoff" and multiply x2 for a safe limit.
\\nExample:\\n \\nExample:\\n
4000 4000
\\nExample:\\n \\nExample:\\n
@ -300,9 +317,27 @@ const details = () => ({
], ],
}); });
// Set up required variables.
let currentBitrate = 0;
let overallBitRate = 0;
let targetBitrate = 0;
let minimumBitrate = 0;
let maximumBitrate = 0;
let duration = '';
let videoIdx = 0;
let extraArguments = '';
let bitrateSettings = '';
let inflatedCutoff = 0;
let main10 = false;
let videoBR = 0;
// Finds the first video stream and get video bitrate
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const plugin = (file, librarySettings, inputs, otherArguments) => { const plugin = (file, librarySettings, inputs, otherArguments) => {
const lib = require('../methods/lib')(); const os = require('os'); const lib = require('../methods/lib')();
const os = require('os');
const proc = require('child_process');
// eslint-disable-next-line no-unused-vars,no-param-reassign // eslint-disable-next-line no-unused-vars,no-param-reassign
inputs = lib.loadDefaultValues(inputs, details); inputs = lib.loadDefaultValues(inputs, details);
const response = { const response = {
@ -315,41 +350,137 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
container: `.${inputs.container}`, container: `.${inputs.container}`,
}; };
// Set up required variables.
let duration = 0;
let videoIdx = 0;
let extraArguments = '';
let bitrateSettings = '';
let inflatedCutoff = 0;
let main10 = false;
// Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== 'video') { if (file.fileMedium !== 'video') {
response.infoLog += 'File is not a video. \n'; response.processFile = false;
response.infoLog += `☒ File seems to be ${file.fileMedium} & not video. Exiting \n`;
return response; return response;
} }
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. // MKVPROPEDIT - Refresh video stats
// If not filled then get duration of stream 0 and do the same. const intStatsDays = 7; // Use 1 week threshold for new stats
if (parseFloat(file.ffProbeData?.format?.duration) > 0) { let statsUptoDate = false;
duration = parseFloat(file.ffProbeData?.format?.duration) * 0.0166667; const currentFileName = file._id;
} else if (typeof file.meta.Duration !== 'undefined') { let statsError = false;
duration = file.meta.Duration * 0.0166667; let metadataEncode = '';
// Only process MKV files
if (file.container === 'mkv') {
let datStats = Date.parse(new Date(70, 1).toISOString()); // Placeholder date
metadataEncode = `-map_metadata:g -1 -metadata JBDONEDATE=${datStats}`;
if (file.mediaInfo.track[0].extra !== undefined && file.mediaInfo.track[0].extra.JBDONEDATE !== undefined) {
datStats = Date.parse(file.mediaInfo.track[0].extra.JBDONEDATE);
} else {
try {
if (
file.mediaInfo.track[0].extra !== undefined
&& file.ffProbeData.streams[0].tags['_STATISTICS_WRITING_DATE_UTC-eng'] !== undefined
) {
// Set stats date to match info inside file
datStats = Date.parse(`${file.ffProbeData.streams[0].tags['_STATISTICS_WRITING_DATE_UTC-eng']} GMT`);
}
} catch (err) {
// Catch error - Ignore & carry on - If check can bomb out if the tag doesn't exist...
}
}
// Threshold for stats date
const statsThres = Date.parse(new Date(new Date().setDate(new Date().getDate() - intStatsDays)).toISOString());
// Strings for easy to read dates in info log
let statsThresString = new Date(statsThres);
statsThresString = statsThresString.toUTCString();
let datStatsString = new Date(datStats);
datStatsString = datStatsString.toUTCString();
response.infoLog += `Checking file stats - If stats are older than ${intStatsDays} days we'll grab new stats.\n
Stats threshold: ${statsThresString}\n
Current stats date: ${datStatsString}\n`;
// Are the stats out of date?
if (datStats >= statsThres) {
statsUptoDate = true;
response.infoLog += '☑ File stats are upto date! - Continuing...\n';
} else {
response.infoLog += '☒ File stats are out of date! - Will attempt to use mkvpropedit to refresh stats\n';
try {
if (otherArguments.mkvpropeditPath !== '') { // Try to use mkvpropedit path if it is set
proc.execSync(`"${otherArguments.mkvpropeditPath}" --add-track-statistics-tags "${currentFileName}"`);
} else { // Otherwise just use standard mkvpropedit cmd
proc.execSync(`mkvpropedit --add-track-statistics-tags "${currentFileName}"`);
}
} catch (err) {
response.infoLog += '☒ Error updating file stats - Possible mkvpropedit failure or file issue - '
+ ' Ensure mkvpropedit is set correctly in the node settings & check the filename for unusual characters.\n'
+ ' Continuing but file stats will likely be inaccurate...\n';
statsError = true;
}
if (statsError !== true) {
// File now updated with new stats
response.infoLog += 'Remuxing file to write in updated file stats! \n';
response.preset += `-fflags +genpts <io> -map 0 -c copy -max_muxing_queue_size 9999 -map_metadata:g -1
-metadata JBDONEDATE=${new Date().toISOString()}`;
response.processFile = true;
return response;
}
}
} else { } else {
duration = file.ffProbeData.streams[0].duration * 0.0166667; response.infoLog += 'Input file is not MKV so cannot use mkvpropedit to get new file stats. '
+ 'Continuing but file stats will likely be inaccurate...\n';
} }
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" for (let i = 0; i < file.ffProbeData.streams.length; i += 1) {
// Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/ const strstreamType = file.ffProbeData.streams[i].codec_type.toLowerCase();
const currentBitrate = Math.round(file.file_size / (duration * 0.0075)); videoIdx = -1;
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. // Check if stream is a video.
// Logic of h265 can be half the bitrate as h264 without losing quality. if (videoIdx === -1 && strstreamType === 'video') {
let targetBitrate = Math.round((file.file_size / (duration * 0.0075)) / 2); videoIdx = i;
// Allow some leeway under and over the targetBitrate. videoBR = Number(file.mediaInfo.track[i + 1].BitRate) / 1000;
let minimumBitrate = Math.round(targetBitrate * 0.75);
let maximumBitrate = Math.round(targetBitrate * 1.25); // If MediaInfo fails somehow fallback to ffprobe - Try two types of tags that might exist
if (videoBR <= 0) {
if (Number(file.ffProbeData.streams[i].tags.BPS) > 0) {
videoBR = file.ffProbeData.streams[i].tags.BPS / 1000;
} else {
try {
if (Number(file.ffProbeData.streams[i].tags.BPS['-eng']) > 0) {
videoBR = file.ffProbeData.streams[i].tags.BPS['-eng'] / 1000;
}
} catch (err) {
// Catch error - Ignore & carry on - If check can bomb out if tags don't exist...
}
}
}
}
}
response.infoLog += `☑ It looks like the current bitrate is ${currentBitrate}k. \n`; // Check if duration info is filled, if so convert time format to minutes.
// If not filled then get duration of video stream and do the same.
if (typeof file.meta.Duration !== 'undefined') {
duration = file.meta.Duration;
// Get seconds by using a Date & then convert to minutes
duration = (new Date(`1970-01-01T${duration}Z`).getTime() / 1000) / 60;
} else {
duration = file.ffProbeData.streams[videoIdx].tags.DURATION;
duration = (new Date(`1970-01-01T${duration}Z`).getTime() / 1000) / 60;
}
if (Number.isNaN(videoBR) || videoBR <= 0) {
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)"
currentBitrate = Math.round(file.file_size / (duration * 0.0075));
response.infoLog += '==WARNING== Failed to get an accurate video bitrate, ';
response.infoLog += `falling back to old method to get OVERALL file bitrate of ${currentBitrate}kbps. `;
response.infoLog += 'Bitrate calculations for video encode will likely be inaccurate... \n';
} else {
currentBitrate = Math.round(videoBR);
response.infoLog += `☑ It looks like the current video bitrate is ${currentBitrate}kbps. \n`;
}
// Get overall bitrate for use with HEVC reprocessing
overallBitRate = Math.round(file.file_size / (duration * 0.0075));
// Halve current bitrate for Target bitrate, in theory h265 can be half the bitrate as h264 without losing quality.
targetBitrate = Math.round(currentBitrate / 2);
// Allow some leeway under and over the targetBitrate.
minimumBitrate = Math.round(targetBitrate * 0.75);
maximumBitrate = Math.round(targetBitrate * 1.25);
// If targetBitrate or currentBitrate comes out as 0 then something // If targetBitrate or currentBitrate comes out as 0 then something
// has gone wrong and bitrates could not be calculated. // has gone wrong and bitrates could not be calculated.
@ -363,18 +494,19 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// has gone wrong as that is not what we want. // has gone wrong as that is not what we want.
// Cancel plugin completely. // Cancel plugin completely.
if (targetBitrate >= currentBitrate) { if (targetBitrate >= currentBitrate) {
response.infoLog += `☒ Target bitrate has been calculated as ${targetBitrate}k. This is equal or greater response.infoLog += `☒ Target bitrate has been calculated as ${targetBitrate}kbps. This is equal or greater `;
than the current bitrate... Something has gone wrong and this shouldn't happen! Skipping this plugin. \n`; response.infoLog += "than the current bitrate... Something has gone wrong and this shouldn't happen! "
+ 'Skipping this plugin. \n';
return response; return response;
} }
// Ensure that bitrate_cutoff is set if reconvert_hevc is true since we need some protection against a loop // Ensure that bitrate_cutoff is set if reconvert_hevc is true since we need some protection against a loop
// Cancel the plugin // Cancel the plugin
if (inputs.reconvert_hevc === true && inputs.bitrate_cutoff <= 0 && inputs.hevc_max_bitrate <= 0) { if (inputs.reconvert_hevc === true && inputs.bitrate_cutoff <= 0 && inputs.hevc_max_bitrate <= 0) {
response.infoLog += `Reconvert HEVC is ${inputs.reconvert_hevc}, however there is no bitrate cutoff response.infoLog += `Reconvert HEVC is ${inputs.reconvert_hevc}, however there is no bitrate cutoff `;
or HEVC specific cutoff set so we have no way to know when to stop processing this file. response.infoLog += 'or HEVC specific cutoff set so we have no way to know when to stop processing this file. \n'
Either set reconvert_HEVC to false or set a bitrate cutoff and set a hevc_max_bitrate cutoff. + 'Either set reconvert_HEVC to false or set a bitrate cutoff and set a hevc_max_bitrate cutoff. \n'
Skipping this plugin. \n`; + '☒ Skipping this plugin. \n';
return response; return response;
} }
@ -384,7 +516,8 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// Checks if currentBitrate is below inputs.bitrate_cutoff. // Checks if currentBitrate is below inputs.bitrate_cutoff.
// If so then cancel plugin without touching original files. // If so then cancel plugin without touching original files.
if (currentBitrate <= inputs.bitrate_cutoff) { if (currentBitrate <= inputs.bitrate_cutoff) {
response.infoLog += `☑ Current bitrate is below set cutoff of ${inputs.bitrate_cutoff}k. Cancelling plugin. \n`; response.infoLog += `☑ Current bitrate is below set cutoff of ${inputs.bitrate_cutoff}kbps. \n`
+ 'Cancelling plugin. \n';
return response; return response;
} }
// If above cutoff then carry on // If above cutoff then carry on
@ -397,8 +530,8 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// Checks if targetBitrate is above inputs.max_average_bitrate. // Checks if targetBitrate is above inputs.max_average_bitrate.
// If so then clamp target bitrate // If so then clamp target bitrate
if (targetBitrate > inputs.max_average_bitrate) { if (targetBitrate > inputs.max_average_bitrate) {
response.infoLog += `Our target bitrate is above the max_average_bitrate so response.infoLog += 'Our target bitrate is above the max_average_bitrate ';
target average bitrate clamped at max of ${inputs.max_average_bitrate}k. \n`; response.infoLog += `so clamping at max of ${inputs.max_average_bitrate}kbps. \n`;
targetBitrate = Math.round(inputs.max_average_bitrate); targetBitrate = Math.round(inputs.max_average_bitrate);
minimumBitrate = Math.round(targetBitrate * 0.75); minimumBitrate = Math.round(targetBitrate * 0.75);
maximumBitrate = Math.round(targetBitrate * 1.25); maximumBitrate = Math.round(targetBitrate * 1.25);
@ -411,13 +544,13 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// Exit the plugin is the cutoff is less than the min average bitrate. Most likely user error // Exit the plugin is the cutoff is less than the min average bitrate. Most likely user error
if (inputs.bitrate_cutoff < inputs.min_average_bitrate) { if (inputs.bitrate_cutoff < inputs.min_average_bitrate) {
response.infoLog += `☒ Bitrate cutoff ${inputs.bitrate_cutoff}k is less than the set minimum response.infoLog += `☒ Bitrate cutoff ${inputs.bitrate_cutoff}k is less than the set minimum
average bitrate set of ${inputs.min_average_bitrate}k. We don't want this. Cancelling plugin. \n`; average bitrate set of ${inputs.min_average_bitrate}kbps. We don't want this. Cancelling plugin. \n`;
return response; return response;
} }
// Checks if inputs.bitrate_cutoff is below inputs.min_average_bitrate. // Checks if inputs.bitrate_cutoff is below inputs.min_average_bitrate.
// If so then set currentBitrate to the minimum allowed.) // If so then set currentBitrate to the minimum allowed.)
if (targetBitrate < inputs.min_average_bitrate) { if (targetBitrate < inputs.min_average_bitrate) {
response.infoLog += `Target average bitrate clamped at min of ${inputs.min_average_bitrate}k. \n`; response.infoLog += `Target average bitrate clamped at min of ${inputs.min_average_bitrate}kbps. \n`;
targetBitrate = Math.round(inputs.min_average_bitrate); targetBitrate = Math.round(inputs.min_average_bitrate);
minimumBitrate = Math.round(targetBitrate * 0.75); minimumBitrate = Math.round(targetBitrate * 0.75);
maximumBitrate = Math.round(targetBitrate * 1.25); maximumBitrate = Math.round(targetBitrate * 1.25);
@ -488,12 +621,12 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
} }
// Check for HDR in files. If so exit plugin. We assume HDR files have bt2020 color spaces. HDR can be complicated // Check for HDR in files. If so exit plugin. We assume HDR files have bt2020 color spaces. HDR can be complicated
// and some aspects are still unsupported in FFmpeg I believe. Likely we don't want to re-encode anything HDR. // and some aspects are still unsupported in ffmpeg I believe. Likely we don't want to re-encode anything HDR.
if (file.ffProbeData.streams[i].color_space === 'bt2020nc' if (file.ffProbeData.streams[i].color_space === 'bt2020nc'
&& file.ffProbeData.streams[i].color_transfer === 'smpte2084' && file.ffProbeData.streams[i].color_transfer === 'smpte2084'
&& file.ffProbeData.streams[i].color_primaries === 'bt2020') { && file.ffProbeData.streams[i].color_primaries === 'bt2020') {
response.infoLog += `☒ This looks to be a HDR file. HDR files are unfortunately response.infoLog += '☒ This looks to be a HDR file. HDR files are unfortunately '
not supported by this plugin. Exiting plugin. \n\n`; + 'not supported by this plugin. Exiting plugin. \n\n';
return response; return response;
} }
@ -519,24 +652,28 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
return response; return response;
} }
// New logic for reprocessing HEVC. Mainly done for my own use. Since we're reprocessing we're checking // New logic for reprocessing HEVC. Mainly done for my own use.
// bitrate again and since this can be inaccurate (It calculates overall bitrate not video specific) // We attempt to get accurate stats earlier - If we can't we fall back onto overall bitrate
// we have to inflate the current bitrate so we don't keep looping this logic. // which can be inaccurate. We may inflate the current bitrate check so we don't keep looping this logic.
} else if (inputs.reconvert_hevc === true && (file.ffProbeData.streams[i].codec_name === 'hevc' } else if (inputs.reconvert_hevc === true && (file.ffProbeData.streams[i].codec_name === 'hevc'
|| file.ffProbeData.streams[i].codec_name === 'vp9' || file.ffProbeData.streams[i].codec_name === 'av1')) { || file.ffProbeData.streams[i].codec_name === 'vp9' || file.ffProbeData.streams[i].codec_name === 'av1')) {
// If we're using the hevc max bitrate then update the cutoff to use it if (statsUptoDate !== true) {
currentBitrate = overallBitRate; // User overall bitrate if we don't have upto date stats
response.infoLog += `☒ Unable to get accurate stats for HEVC so falling back to Overall file Bitrate.
Remux to MKV to allow generation of accurate video bitrate statistics.
File overall bitrate is ${overallBitRate}kbps.\n`;
}
if (inputs.hevc_max_bitrate > 0) { if (inputs.hevc_max_bitrate > 0) {
if (currentBitrate > inputs.hevc_max_bitrate) { if (currentBitrate > inputs.hevc_max_bitrate) {
// If bitrate is higher then hevc_max_bitrate then need to re-encode // If bitrate is higher then hevc_max_bitrate then need to re-encode
response.infoLog += `☒ Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, VP9 or AV1. response.infoLog += `Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, `
Using HEVC specific cutoff of ${inputs.hevc_max_bitrate}k. \n + `VP9 or AV1. Using HEVC specific cutoff of ${inputs.hevc_max_bitrate}kbps. \n`;
The file is still above this new cutoff! Reconverting. \n\n`; response.infoLog += '☒ The file is still above this new cutoff! Reconverting. \n';
} else { } else {
// Otherwise we're now below the hevc cutoff and we can exit // Otherwise we're now below the hevc cutoff and we can exit
response.infoLog += `Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, VP9 or AV1. response.infoLog += `Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, `
Using HEVC specific cutoff of ${inputs.hevc_max_bitrate}k. \n + `VP9 or AV1. Using HEVC specific cutoff of ${inputs.hevc_max_bitrate}kbps. \n`;
The file is NOT above this new cutoff. Exiting plugin. \n\n`; response.infoLog += '☑ The file is NOT above this new cutoff. Exiting plugin. \n';
return response; return response;
} }
@ -544,15 +681,21 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
// looping this plugin. For maximum safety we simply multiply the cutoff by 2. // looping this plugin. For maximum safety we simply multiply the cutoff by 2.
} else if (currentBitrate > (inputs.bitrate_cutoff * 2)) { } else if (currentBitrate > (inputs.bitrate_cutoff * 2)) {
inflatedCutoff = Math.round(inputs.bitrate_cutoff * 2); inflatedCutoff = Math.round(inputs.bitrate_cutoff * 2);
response.infoLog += `☒ Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, VP9 or AV1. response.infoLog += `Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, `;
HEVC specific cutoff not set so bitrate_cutoff is multiplied by 2 for safety! response.infoLog += 'VP9 or AV1. Will use Overall file Bitrate for HEVC files as safety, ';
Cutoff now temporarily ${inflatedCutoff}k. \n The file is still above this new cutoff! Reconverting. \n\n`; response.infoLog += `bitrate is ${overallBitRate}kbps. \n`;
response.infoLog += 'HEVC specific cutoff not set so bitrate_cutoff is multiplied by 2 for safety! \n';
response.infoLog += `Cutoff now temporarily ${inflatedCutoff}kbps. \n`;
response.infoLog += '☒ The file is still above this new cutoff! Reconverting. \n';
} else { } else {
// File is below cutoff so we can exit // File is below cutoff so we can exit
inflatedCutoff = Math.round(inputs.bitrate_cutoff * 2); inflatedCutoff = Math.round(inputs.bitrate_cutoff * 2);
response.infoLog += `☑ Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, VP9 or AV1 response.infoLog += `Reconvert_hevc is ${inputs.reconvert_hevc} & the file is already HEVC, `;
so bitrate_cutoff is multiplied by 2! Cutoff now temporarily ${inflatedCutoff}k. \n response.infoLog += 'VP9 or AV1. Will use Overall file Bitrate for HEVC files as safety, ';
The file is NOT above this new cutoff. Exiting plugin. \n\n`; response.infoLog += `bitrate is ${overallBitRate}kbps. \n`;
response.infoLog += 'HEVC specific cutoff not set so bitrate_cutoff is multiplied by 2 for safety! \n';
response.infoLog += `Cutoff now temporarily ${inflatedCutoff}kbps. \n`;
response.infoLog += '☑The file is NOT above this new cutoff. Exiting plugin. \n';
return response; return response;
} }
} }
@ -563,7 +706,7 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
|| file.ffProbeData.streams[i].profile === 'Main 10' || file.ffProbeData.streams[i].profile === 'Main 10'
|| file.ffProbeData.streams[i].bits_per_raw_sample === '10') { || file.ffProbeData.streams[i].bits_per_raw_sample === '10') {
main10 = true; main10 = true;
response.infoLog += 'Input file is 10bit. Disabling hardware decoding to avoid problems. \n\n'; response.infoLog += 'Input file is 10bit. Disabling hardware decoding to avoid problems. \n';
} }
// Increment video index. Needed to keep track of video id in case there is more than one video track. // Increment video index. Needed to keep track of video id in case there is more than one video track.
@ -576,77 +719,100 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k ` bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k `
+ `-maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`; + `-maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`;
// Print to infoLog information around file & bitrate settings. // Print to infoLog information around file & bitrate settings.
response.infoLog += `\nContainer for output selected as ${inputs.container}. \n`; response.infoLog += `Container for output selected as ${inputs.container}. \n`;
response.infoLog += 'Encode variable bitrate settings: \n'; response.infoLog += 'Encode variable bitrate settings: \n';
response.infoLog += `Target = ${targetBitrate}k \n`; response.infoLog += `Target = ${targetBitrate}k \n`;
response.infoLog += `Minimum = ${minimumBitrate}k \n`; response.infoLog += `Minimum = ${minimumBitrate}k \n`;
response.infoLog += `Maximum = ${maximumBitrate}k \n`; response.infoLog += `Maximum = ${maximumBitrate}k \n`;
// START PRESET // START PRESET
// DECODE FLAGS
// -fflags +genpts should regenerate timestamps if they end up missing... // -fflags +genpts should regenerate timestamps if they end up missing...
response.preset = '-fflags +genpts '; response.preset = '-fflags +genpts ';
// Attempt to enable HW Decoding... // HW ACCEL FLAGS
// If source file is 10 bit then bail as this can cause issues. Think it's the -c:v option that can break during 10bit // Account for different OS
if (main10 === false) { switch (os.platform()) {
// Currently supported HW decode types case 'darwin': // Mac OS - Enable videotoolbox instead of QSV
switch (file.video_codec_name) { response.preset += '-hwaccel videotoolbox';
case 'mpeg2': break;
response.preset += '-hwaccel qsv -c:v mpeg2_qsv'; case 'linux': // Linux - Full device, should fix child_device_type warnings
break; response.preset += `-hwaccel qsv -hwaccel_output_format qsv
case 'h264': -init_hw_device qsv:hw_any,child_device_type=vaapi `;
response.preset += '-hwaccel qsv -c:v h264_qsv'; break;
break; case 'win32': // Windows - Full device, should fix child_device_type warnings
case 'vc1': response.preset += `-hwaccel qsv -hwaccel_output_format qsv
response.preset += '-hwaccel qsv -c:v vc1_qsv'; -init_hw_device qsv:hw_any,child_device_type=d3d11va `;
break; break;
case 'mjpeg': default:
response.preset += '-hwaccel qsv -c:v mjpeg_qsv'; response.preset += '-hwaccel qsv -hwaccel_output_format qsv -init_hw_device qsv:hw_any ';
break; }
case 'vp8':
response.preset += '-hwaccel qsv -c:v vp8_qsv'; // DECODE FLAGS
break; if (os.platform() !== 'darwin') {
case 'hevc': if (main10 === false) { // Don't enable if 10bit is on - Seems to cause issues, may need different decode flags
response.preset += '-hwaccel qsv -c:v hevc_qsv'; switch (file.video_codec_name) {
break; case 'mpeg2':
case 'vp9': // Should be supported by 8th Gen + response.preset += '-c:v mpeg2_qsv';
response.preset += '-hwaccel qsv -c:v vp9_qsv'; break;
break; case 'h264':
default: response.preset += '-c:v h264_qsv';
response.preset += '-hwaccel qsv'; break;
case 'vc1':
response.preset += '-c:v vc1_qsv';
break;
case 'mjpeg':
response.preset += '-c:v mjpeg_qsv';
break;
case 'vp8':
response.preset += '-c:v vp8_qsv';
break;
case 'hevc':
response.preset += '-c:v hevc_qsv';
break;
case 'vp9': // Should be supported by 8th Gen +
response.preset += '-c:v vp9_qsv';
break;
default:
response.preset += '';
}
} }
} else {
response.preset += '-hwaccel qsv';
// Enable basic hwaccel regardless. Seems to work...
} }
// ADD ENCODE FLAGS TO PRESET // ENCODE FLAGS
response.preset += '<io> -map 0 -c:v '; response.preset += '<io> -map 0 -c:v ';
// Account for different OS setup for QSV. // Account for different OS setup for QSV HEVC encode.
// FYI Darwin is Mac OS
switch (os.platform()) { switch (os.platform()) {
case 'darwin': case 'darwin':
response.preset += 'hevc_videotoolbox'; response.preset += 'hevc_videotoolbox';
// hevc_videotoolbox is for Mac but that doesn't seem to be included in Tdarr current Jellyfin FFmpeg // Mac OS & uses hevc_videotoolbox not QSV - Only shows up on Mac installs
// Likely needs custom FFmpeg installed
break; break;
case 'linux': case 'linux':
response.preset += 'hevc_qsv'; response.preset += 'hevc_qsv';
break; break;
case 'win32': case 'win32':
response.preset += 'hevc_qsv -load_plugin hevc_hw'; response.preset += 'hevc_qsv -load_plugin hevc_hw';
// Windows needs the additional -load_plugin plugin. Tested working on a Win 10 - i5-10505 // Windows needs the additional -load_plugin. Tested working on a Win 10 - i5-10505
break; break;
default: default:
response.preset += 'hevc_qsv'; response.preset += 'hevc_qsv'; // Default to QSV
} }
// Add the rest of the FFmpeg command // Add the rest of the ffmpeg command
response.preset += ` ${bitrateSettings} ` switch (os.platform()) {
+ `-preset ${inputs.encoder_speedpreset} ${inputs.extra_qsv_options} case 'darwin':
-c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments}`; // Mac OS - Don't use extra_qsv_options - These are intended for QSV cmds so videotoolbox causes issues
response.preset += ` ${bitrateSettings} `
+ `-preset ${inputs.encoder_speedpreset} -c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments}`;
response.infoLog += '==ALERT== OS detected as MAC - This will use VIDEOTOOLBOX to encode which is NOT QSV\n'
+ 'cmds set in extra_qsv_options will be IGNORED!\n';
break;
default:
// Normal behavior
response.preset += ` ${bitrateSettings} `
+ `-preset ${inputs.encoder_speedpreset} ${inputs.extra_qsv_options} `
+ `-c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments} ${metadataEncode}`;
}
response.processFile = true; response.processFile = true;
response.infoLog += 'File Transcoding... \n'; response.infoLog += 'File Transcoding... \n';
@ -654,4 +820,4 @@ const plugin = (file, librarySettings, inputs, otherArguments) => {
return response; return response;
}; };
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -13,52 +13,51 @@ const tests = [
output: { output: {
linux: { linux: {
processFile: true, processFile: true,
preset: '-fflags +genpts -hwaccel qsv -c:v h264_qsv<io> -map 0 -c:v hevc_qsv -b:v 759k -minrate 569k -maxrate 949k -bufsize 1517k -preset slow \n' preset: '-fflags +genpts -hwaccel qsv -hwaccel_output_format qsv -init_hw_device qsv:hw_any,child_device_type=vaapi -c:v h264_qsv<io> -map 0 -c:v hevc_qsv -b:v 603k -minrate 452k -maxrate 754k -bufsize 1206k -preset slow -c:a copy -c:s copy -max_muxing_queue_size 9999 ',
+ ' -c:a copy -c:s copy -max_muxing_queue_size 9999 ',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '\n' + '☑ It looks like the current video bitrate is 1206kbps. \n'
+ 'Container for output selected as mkv. \n' + 'Container for output selected as mkv. \n'
+ 'Encode variable bitrate settings: \n' + 'Encode variable bitrate settings: \n'
+ 'Target = 759k \n' + 'Target = 603k \n'
+ 'Minimum = 569k \n' + 'Minimum = 452k \n'
+ 'Maximum = 949k \n' + 'Maximum = 754k \n'
+ 'File Transcoding... \n', + 'File Transcoding... \n',
container: '.mkv', container: '.mkv',
}, },
win32: { win32: {
processFile: true, processFile: true,
preset: '-fflags +genpts -hwaccel qsv -c:v h264_qsv<io> -map 0 -c:v hevc_qsv -load_plugin hevc_hw -b:v 759k -minrate 569k -maxrate 949k -bufsize 1517k -preset slow \n' preset: '-fflags +genpts -hwaccel qsv -hwaccel_output_format qsv -init_hw_device qsv:hw_any,child_device_type=d3d11va -c:v h264_qsv<io> -map 0 -c:v hevc_qsv -load_plugin hevc_hw -b:v 603k -minrate 452k -maxrate 754k -bufsize 1206k -preset slow -c:a copy -c:s copy -max_muxing_queue_size 9999 ',
+ ' -c:a copy -c:s copy -max_muxing_queue_size 9999 ',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '\n' + '☑ It looks like the current video bitrate is 1206kbps. \n'
+ 'Container for output selected as mkv. \n' + 'Container for output selected as mkv. \n'
+ 'Encode variable bitrate settings: \n' + 'Encode variable bitrate settings: \n'
+ 'Target = 759k \n' + 'Target = 603k \n'
+ 'Minimum = 569k \n' + 'Minimum = 452k \n'
+ 'Maximum = 949k \n' + 'Maximum = 754k \n'
+ 'File Transcoding... \n', + 'File Transcoding... \n',
container: '.mkv', container: '.mkv',
}, },
darwin: { darwin: {
processFile: true, processFile: true,
preset: '-fflags +genpts -hwaccel qsv -c:v h264_qsv<io> -map 0 -c:v hevc_videotoolbox -b:v 759k -minrate 569k -maxrate 949k -bufsize 1517k -preset slow \n' preset: '-fflags +genpts -hwaccel videotoolbox<io> -map 0 -c:v hevc_videotoolbox -b:v 603k -minrate 452k -maxrate 754k -bufsize 1206k -preset slow -c:a copy -c:s copy -max_muxing_queue_size 9999 ',
+ ' -c:a copy -c:s copy -max_muxing_queue_size 9999 ',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '\n' + '☑ It looks like the current video bitrate is 1206kbps. \n'
+ 'Container for output selected as mkv. \n' + 'Container for output selected as mkv. \n'
+ 'Encode variable bitrate settings: \n' + 'Encode variable bitrate settings: \n'
+ 'Target = 759k \n' + 'Target = 603k \n'
+ 'Minimum = 569k \n' + 'Minimum = 452k \n'
+ 'Maximum = 949k \n' + 'Maximum = 754k \n'
+ '==ALERT== OS detected as MAC - This will use VIDEOTOOLBOX to encode which is NOT QSV\n'
+ 'cmds set in extra_qsv_options will be IGNORED!\n'
+ 'File Transcoding... \n', + 'File Transcoding... \n',
container: '.mkv', container: '.mkv',
}, },
@ -78,55 +77,54 @@ const tests = [
output: { output: {
linux: { linux: {
processFile: true, processFile: true,
preset: '-fflags +genpts -hwaccel qsv<io> -map 0 -c:v hevc_qsv -b:v 759k -minrate 569k -maxrate 949k -bufsize 1517k -preset fast \n' preset: '-fflags +genpts -hwaccel qsv -hwaccel_output_format qsv -init_hw_device qsv:hw_any,child_device_type=vaapi <io> -map 0 -c:v hevc_qsv -b:v 603k -minrate 452k -maxrate 754k -bufsize 1206k -preset fast -c:a copy -c:s copy -max_muxing_queue_size 9999 -profile:v main10 -pix_fmt p010le ',
+ ' -c:a copy -c:s copy -max_muxing_queue_size 9999 -profile:v main10 -pix_fmt p010le ',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '☑ It looks like the current video bitrate is 1206kbps. \n'
+ '10 bit encode enabled. Setting Main10 Profile & 10 bit pixel format \n' + '10 bit encode enabled. Setting Main10 Profile & 10 bit pixel format \n'
+ '\n'
+ 'Container for output selected as mp4. \n' + 'Container for output selected as mp4. \n'
+ 'Encode variable bitrate settings: \n' + 'Encode variable bitrate settings: \n'
+ 'Target = 759k \n' + 'Target = 603k \n'
+ 'Minimum = 569k \n' + 'Minimum = 452k \n'
+ 'Maximum = 949k \n' + 'Maximum = 754k \n'
+ 'File Transcoding... \n', + 'File Transcoding... \n',
container: '.mp4', container: '.mp4',
}, },
win32: { win32: {
processFile: true, processFile: true,
preset: '-fflags +genpts -hwaccel qsv<io> -map 0 -c:v hevc_qsv -load_plugin hevc_hw -b:v 759k -minrate 569k -maxrate 949k -bufsize 1517k -preset fast \n' preset: '-fflags +genpts -hwaccel qsv -hwaccel_output_format qsv -init_hw_device qsv:hw_any,child_device_type=d3d11va <io> -map 0 -c:v hevc_qsv -load_plugin hevc_hw -b:v 603k -minrate 452k -maxrate 754k -bufsize 1206k -preset fast -c:a copy -c:s copy -max_muxing_queue_size 9999 -profile:v main10 -pix_fmt p010le ',
+ ' -c:a copy -c:s copy -max_muxing_queue_size 9999 -profile:v main10 -pix_fmt p010le ',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '☑ It looks like the current video bitrate is 1206kbps. \n'
+ '10 bit encode enabled. Setting Main10 Profile & 10 bit pixel format \n' + '10 bit encode enabled. Setting Main10 Profile & 10 bit pixel format \n'
+ '\n'
+ 'Container for output selected as mp4. \n' + 'Container for output selected as mp4. \n'
+ 'Encode variable bitrate settings: \n' + 'Encode variable bitrate settings: \n'
+ 'Target = 759k \n' + 'Target = 603k \n'
+ 'Minimum = 569k \n' + 'Minimum = 452k \n'
+ 'Maximum = 949k \n' + 'Maximum = 754k \n'
+ 'File Transcoding... \n', + 'File Transcoding... \n',
container: '.mp4', container: '.mp4',
}, },
darwin: { darwin: {
processFile: true, processFile: true,
preset: '-fflags +genpts -hwaccel qsv<io> -map 0 -c:v hevc_videotoolbox -b:v 759k -minrate 569k -maxrate 949k -bufsize 1517k -preset fast \n' preset: '-fflags +genpts -hwaccel videotoolbox <io> -map 0 -c:v hevc_videotoolbox -b:v 603k -minrate 452k -maxrate 754k -bufsize 1206k -preset fast -c:a copy -c:s copy -max_muxing_queue_size 9999 -profile:v main10 -pix_fmt p010le ',
+ ' -c:a copy -c:s copy -max_muxing_queue_size 9999 -profile:v main10 -pix_fmt p010le ',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '☑ It looks like the current video bitrate is 1206kbps. \n'
+ '10 bit encode enabled. Setting Main10 Profile & 10 bit pixel format \n' + '10 bit encode enabled. Setting Main10 Profile & 10 bit pixel format \n'
+ '\n'
+ 'Container for output selected as mp4. \n' + 'Container for output selected as mp4. \n'
+ 'Encode variable bitrate settings: \n' + 'Encode variable bitrate settings: \n'
+ 'Target = 759k \n' + 'Target = 603k \n'
+ 'Minimum = 569k \n' + 'Minimum = 452k \n'
+ 'Maximum = 949k \n' + 'Maximum = 754k \n'
+ '==ALERT== OS detected as MAC - This will use VIDEOTOOLBOX to encode which is NOT QSV\n'
+ 'cmds set in extra_qsv_options will be IGNORED!\n'
+ 'File Transcoding... \n', + 'File Transcoding... \n',
container: '.mp4', container: '.mp4',
}, },
@ -150,11 +148,13 @@ const tests = [
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '☑ It looks like the current bitrate is 1517k. \n' infoLog: 'Input file is not MKV so cannot use mkvpropedit to get new file stats. Continuing but file stats will likely be inaccurate...\n'
+ '☑ Current bitrate is below set cutoff of 2000k. Cancelling plugin. \n', + '☑ It looks like the current video bitrate is 1206kbps. \n'
+ '☑ Current bitrate is below set cutoff of 2000kbps. \n'
+ 'Cancelling plugin. \n',
container: '.mp4', container: '.mp4',
}, },
}, },
]; ];
run(tests); run(tests);
Loading…
Cancel
Save