Adjustments based on comments

make-only-subtitle-default
HaveAGitGat 2 years ago
parent 3204bce8bb
commit abfa9af5aa

@ -9,29 +9,56 @@ const details = () => ({
Version: '3.1', Version: '3.1',
Tags: 'pre-processing,ffmpeg,video only,nvenc h265,configurable', Tags: 'pre-processing,ffmpeg,video only,nvenc h265,configurable',
Inputs: [ Inputs: [
{
name: 'encoder',
type: 'string',
defaultValue: 'hevc',
inputUI: {
type: 'dropdown',
options: [
'hevc',
'vp9',
'h264',
'vp8',
],
},
tooltip: 'Specify the codec to use',
},
{
name: 'use_gpu',
type: 'boolean',
defaultValue: true,
inputUI: {
type: 'dropdown',
options: [
'false',
'true',
],
},
tooltip: 'If enabled then will use GPU if possible.',
},
{ {
name: 'container', name: 'container',
type: 'string', type: 'string',
defaultValue: 'mkv', defaultValue: 'mkv',
inputUI: { inputUI: {
type: 'text', type: 'dropdown',
options: [
'mkv',
'mp4',
'avi',
'ts',
'original',
],
}, },
tooltip: `Specify output container of file. Use 'original' wihout quotes to keep original container. tooltip: `Specify output container of file. Use 'original' wihout quotes to keep original container.
\\n Ensure that all stream types you may have are supported by your chosen container. \\n Ensure that all stream types you may have are supported by your chosen container.
\\n mkv is recommended. \\n mkv is recommended`,
\\nExample:\\n
mkv
\\nExample:\\n
mp4
\\nExample:\\n
original`,
}, },
{ {
name: 'bitrate_cutoff', name: 'bitrate_cutoff',
type: 'string', type: 'number',
defaultValue: '', defaultValue: 0,
inputUI: { inputUI: {
type: 'text', type: 'text',
}, },
@ -103,35 +130,6 @@ const details = () => ({
\\nExample:\\n \\nExample:\\n
false`, false`,
}, },
{
name: 'encoder',
type: 'string',
defaultValue: 'hevc',
inputUI: {
type: 'dropdown',
options: [
'hevc',
'vp9',
'h264',
'vp8',
],
},
tooltip: 'Specify the codec to use',
},
{
name: 'use_gpu',
type: 'boolean',
defaultValue: true,
inputUI: {
type: 'dropdown',
options: [
'false',
'true',
],
},
tooltip: 'If enabled then will use GPU if possible.',
},
], ],
}); });
@ -140,9 +138,9 @@ const hasEncoder = async ({
encoder, encoder,
}) => { }) => {
const { exec } = require('child_process'); const { exec } = require('child_process');
let res = false; let isEnabled = false;
try { try {
res = await new Promise((resolve) => { isEnabled = await new Promise((resolve) => {
exec(`${ffmpegPath} -f lavfi -i color=c=black:s=256x256:d=1:r=30 -c:v ${encoder} -f null /dev/null`, ( exec(`${ffmpegPath} -f lavfi -i color=c=black:s=256x256:d=1:r=30 -c:v ${encoder} -f null /dev/null`, (
error, error,
// stdout, // stdout,
@ -160,7 +158,7 @@ const hasEncoder = async ({
console.log(err); console.log(err);
} }
return res; return isEnabled;
}; };
const getEncoder = async ({ const getEncoder = async ({
@ -168,8 +166,7 @@ const getEncoder = async ({
otherArguments, otherArguments,
}) => { }) => {
let { encoder } = inputs; let { encoder } = inputs;
if (inputs.use_gpu if (inputs.use_gpu && (inputs.encoder === 'hevc' || inputs.encoder === 'h264')) {
&& (inputs.encoder === 'hevc' || inputs.encoder === 'h264')) {
const gpuEncoders = [ const gpuEncoders = [
{ {
encoder: 'hevc_nvenc', encoder: 'hevc_nvenc',
@ -209,11 +206,11 @@ const getEncoder = async ({
const filteredGpuEncoders = gpuEncoders.filter((device) => device.encoder.includes(inputs.encoder)); const filteredGpuEncoders = gpuEncoders.filter((device) => device.encoder.includes(inputs.encoder));
// eslint-disable-next-line no-restricted-syntax // eslint-disable-next-line no-restricted-syntax
for (const device of filteredGpuEncoders) { for (const gpuEncoder of filteredGpuEncoders) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
device.enabled = await hasEncoder({ gpuEncoder.enabled = await hasEncoder({
ffmpegPath: otherArguments.ffmpegPath, ffmpegPath: otherArguments.ffmpegPath,
encoder: device.encoder, encoder: gpuEncoder.encoder,
}); });
} }
@ -246,18 +243,7 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
otherArguments, otherArguments,
}); });
let duration = '';
// Check if inputs.container has been configured. If it hasn't then exit plugin.
if (inputs.container === '') {
response.infoLog += 'Plugin has not been configured, please configure required options. Skipping this plugin. \n';
response.processFile = false;
return response;
}
if (inputs.container === 'original') { if (inputs.container === 'original') {
// eslint-disable-next-line no-param-reassign
inputs.container = `${file.container}`;
response.container = `.${file.container}`; response.container = `.${file.container}`;
} else { } else {
response.container = `.${inputs.container}`; response.container = `.${inputs.container}`;
@ -265,19 +251,19 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
// Check if file is a video. If it isn't then exit plugin. // 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.infoLog += 'File is not a video. \n'; response.infoLog += 'File is not a video. \n';
return response; return response;
} }
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. let duration = 0;
// If not filled then get duration of stream 0 and do the same.
// Get duration in seconds
if (parseFloat(file.ffProbeData?.format?.duration) > 0) { if (parseFloat(file.ffProbeData?.format?.duration) > 0) {
duration = parseFloat(file.ffProbeData?.format?.duration) * 0.0166667; duration = parseFloat(file.ffProbeData?.format?.duration);
} else if (typeof file.meta.Duration !== 'undefined') { } else if (typeof file.meta.Duration !== 'undefined') {
duration = file.meta.Duration * 0.0166667; duration = file.meta.Duration;
} else { } else {
duration = file.ffProbeData.streams[0].duration * 0.0166667; duration = file.ffProbeData.streams[0].duration;
} }
// Set up required variables. // Set up required variables.
@ -286,49 +272,45 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
let extraArguments = ''; let extraArguments = '';
let genpts = ''; let genpts = '';
let bitrateSettings = ''; let bitrateSettings = '';
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)"
// Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/ // Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
// eslint-disable-next-line no-bitwise
const currentBitrate = ~~(file.file_size / (duration * 0.0075)); const currentBitrate = (file.file_size * 1024 * 1024 * 8) / duration;
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. // Use the same calculation used for currentBitrate but divide it in half to get targetBitrate.
// Logic of h265 can be half the bitrate as h264 without losing quality. // Logic of h265 can be half the bitrate as h264 without losing quality.
// eslint-disable-next-line no-bitwise
const targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2); const targetBitrate = currentBitrate / 2;
// Allow some leeway under and over the targetBitrate. // Allow some leeway under and over the targetBitrate.
// eslint-disable-next-line no-bitwise
const minimumBitrate = ~~(targetBitrate * 0.7); const minimumBitrate = (targetBitrate * 0.7);
// eslint-disable-next-line no-bitwise
const maximumBitrate = ~~(targetBitrate * 1.3); const maximumBitrate = (targetBitrate * 1.3);
// If Container .ts or .avi set genpts to fix unknown timestamp // If Container .ts or .avi set genpts to fix unknown timestamp
if (inputs.container.toLowerCase() === 'ts' || inputs.container.toLowerCase() === 'avi') { if (inputs.container === 'ts' || inputs.container === 'avi') {
genpts = '-fflags +genpts'; genpts = '-fflags +genpts';
} }
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculated. // If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculated.
// Cancel plugin completely. // Cancel plugin completely.
if (targetBitrate === 0) { if (targetBitrate === 0) {
response.processFile = false;
response.infoLog += 'Target bitrate could not be calculated. Skipping this plugin. \n'; response.infoLog += 'Target bitrate could not be calculated. Skipping this plugin. \n';
return response; return response;
} }
// Check if inputs.bitrate cutoff has something entered. // Check if inputs.bitrate cutoff has something entered.
// (Entered means user actually wants something to happen, empty would disable this). // (Entered means user actually wants something to happen, empty would disable this).
if (inputs.bitrate_cutoff !== '') { // 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}. Cancelling plugin. \n`;
response.processFile = false; return response;
response.infoLog += `Current bitrate is below set cutoff of ${inputs.bitrate_cutoff}. Cancelling plugin. \n`;
return response;
}
} }
// Check if force_conform option is checked. // Check if force_conform option is checked.
// If so then check streams and add any extra parameters required to make file conform with output format. // If so then check streams and add any extra parameters required to make file conform with output format.
if (inputs.force_conform === true) { if (inputs.force_conform === true) {
if (inputs.container.toLowerCase() === 'mkv') { if (inputs.container === 'mkv') {
extraArguments += '-map -0:d '; extraArguments += '-map -0:d ';
for (let i = 0; i < file.ffProbeData.streams.length; i++) { for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
@ -347,7 +329,7 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
} }
} }
} }
if (inputs.container.toLowerCase() === 'mp4') { if (inputs.container === 'mp4') {
for (let i = 0; i < file.ffProbeData.streams.length; i++) { for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if ( if (
@ -399,12 +381,9 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
// Check if codec of stream is hevc or vp9 AND check if file.container matches inputs.container. // Check if codec of stream is hevc or vp9 AND check if file.container matches inputs.container.
// If so nothing for plugin to do. // If so nothing for plugin to do.
if ( if (
( inputs.encoder === file.ffProbeData.streams[i].codec_name
inputs.encoder === file.ffProbeData.streams[i].codec_name
)
&& file.container === inputs.container && file.container === inputs.container
) { ) {
response.processFile = false;
response.infoLog += `File is already ${inputs.encoder} & in ${inputs.container}. \n`; response.infoLog += `File is already ${inputs.encoder} & in ${inputs.container}. \n`;
return response; return response;
} }
@ -412,13 +391,13 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
// AND check if file.container does NOT match inputs.container. // AND check if file.container does NOT match inputs.container.
// If so remux file. // If so remux file.
if ( if (
(
inputs.encoder === file.ffProbeData.streams[i].codec_name inputs.encoder === file.ffProbeData.streams[i].codec_name
)
&& file.container !== inputs.container && file.container !== inputs.container
) { ) {
response.infoLog += `File is hevc or vp9 but is not in ${inputs.container} container. Remuxing. \n`; response.infoLog += `File is hevc or vp9 but is not in ${inputs.container} container. Remuxing. \n`;
response.preset = `, -map 0 -c copy ${extraArguments}`; response.preset = `<io> -map 0 -c copy ${extraArguments}`;
response.processFile = true; response.processFile = true;
return response; return response;
} }
@ -427,7 +406,7 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
if ( if (
inputs.encoder === 'hevc' inputs.encoder === 'hevc'
&& (file.ffProbeData.streams[i].profile === 'High 10' && (file.ffProbeData.streams[i].profile === 'High 10'
|| file.ffProbeData.streams[i].bits_per_raw_sample === '10') || file.ffProbeData.streams[i].bits_per_raw_sample === '10')
) { ) {
CPU10 = true; CPU10 = true;
} }
@ -438,8 +417,8 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
} }
// Set bitrateSettings variable using bitrate information calulcated earlier. // Set bitrateSettings variable using bitrate information calulcated earlier.
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k ` bitrateSettings = `-b:v ${targetBitrate} -minrate ${minimumBitrate} `
+ `-maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`; + `-maxrate ${maximumBitrate} -bufsize ${currentBitrate}`;
// Print to infoLog information around file & bitrate settings. // Print to infoLog information around file & bitrate settings.
response.infoLog += `Container for output selected as ${inputs.container}. \n`; response.infoLog += `Container for output selected as ${inputs.container}. \n`;
response.infoLog += `Current bitrate = ${currentBitrate} \n`; response.infoLog += `Current bitrate = ${currentBitrate} \n`;
@ -448,14 +427,11 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
response.infoLog += `Minimum = ${minimumBitrate} \n`; response.infoLog += `Minimum = ${minimumBitrate} \n`;
response.infoLog += `Maximum = ${maximumBitrate} \n`; response.infoLog += `Maximum = ${maximumBitrate} \n`;
if (encoder === 'hevc_nvenc' || encoder === 'h264_nvenc') { if (encoder.contains('nvenc')) {
// Codec will be checked so it can be transcoded correctly
if (file.video_codec_name === 'h263') { if (file.video_codec_name === 'h263') {
response.preset = '-c:v h263_cuvid'; response.preset = '-c:v h263_cuvid';
} else if (file.video_codec_name === 'h264') { } else if (file.video_codec_name === 'h264' && CPU10 === false) {
if (CPU10 === false) { response.preset = '-c:v h264_cuvid';
response.preset = '-c:v h264_cuvid';
}
} else if (file.video_codec_name === 'mjpeg') { } else if (file.video_codec_name === 'mjpeg') {
response.preset = '-c:v mjpeg_cuvid'; response.preset = '-c:v mjpeg_cuvid';
} else if (file.video_codec_name === 'mpeg1') { } else if (file.video_codec_name === 'mpeg1') {
@ -471,8 +447,8 @@ const plugin = async (file, librarySettings, inputs, otherArguments) => {
} }
} }
response.preset += `${genpts}, -map 0 -c:v ${encoder} -cq:v 19 ${bitrateSettings} ` response.preset += `${genpts}<io> -map 0 -c copy -c:v ${encoder} -cq:v 19 ${bitrateSettings} `
+ `-spatial_aq:v 1 -rc-lookahead:v 32 -c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments}`; + `-spatial_aq:v 1 -rc-lookahead:v 32 -max_muxing_queue_size 9999 ${extraArguments}`;
response.processFile = true; response.processFile = true;
response.infoLog += 'File is not hevc or vp9. Transcoding. \n'; response.infoLog += 'File is not hevc or vp9. Transcoding. \n';
return response; return response;

Loading…
Cancel
Save