From 3b0cdeaaacf95c5d403292d2a8072a01cee6ce8c Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sun, 25 Oct 2020 18:32:07 +0100 Subject: [PATCH] Various changes: * Reformatted source code automatically. * Possible fix for x264 refusing to build lossless videos. * Allow encoders to add extra options to the command line, such as gpu selection. --- config.json | 19 ++++++---- encoder.js | 4 +++ encoder_h264_nvenc.js | 12 ++----- ves.js | 80 ++++++++++++++++++++++++++++--------------- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/config.json b/config.json index a2186c6..38ddabd 100644 --- a/config.json +++ b/config.json @@ -31,6 +31,7 @@ "enabled": true, "pool": "nvenc", "parallel": 2, + "gpu": -1, "presets": [ "p5", "p6", @@ -55,32 +56,38 @@ "hevc_nvenc": { "enabled": false, "pool": "nvenc", - "parallel": 3 + "parallel": 2, + "gpu": -1 }, "h264_amf": { "enabled": false, "pool": "amf", - "parallel": 3 + "parallel": 2, + "gpu": -1 }, "hevc_amf": { "enabled": false, "pool": "amf", - "parallel": 3 + "parallel": 2, + "gpu": -1 }, "h264_qsv": { "enabled": false, "pool": "qsv", - "parallel": 3 + "parallel": 2, + "gpu": -1 }, "hevc_qsv": { "enabled": false, "pool": "qsv", - "parallel": 3 + "parallel": 2, + "gpu": -1 }, "vp9_qsv": { "enabled": false, "pool": "qsv", - "parallel": 3 + "parallel": 2, + "gpu": -1 }, "libvpx-vp9": { "enabled": false, diff --git a/encoder.js b/encoder.js index 39c41ed..101b78c 100644 --- a/encoder.js +++ b/encoder.js @@ -35,6 +35,10 @@ class encoder { get(index, width, height, framerate) { throw new Error("Not Implemented"); } + + extra() { + return []; + } } module.exports = encoder; diff --git a/encoder_h264_nvenc.js b/encoder_h264_nvenc.js index df9dac8..02ca76c 100644 --- a/encoder_h264_nvenc.js +++ b/encoder_h264_nvenc.js @@ -139,15 +139,9 @@ class h264_nvenc extends encoder { return this.combinations[index]; } -/* -for (let br of _config.bitrates) - "-b:v", `${br.toFixed(0)}k`, - "-bufsize", `${(br * 2).toFixed(0)}k`, - "-minrate", "0", - "-maxrate", `${br.toFixed(0)}k`, -for (let kfm of _config.keyframe_multiplier) - "-g", (_cache.fps * kfm).toFixed(0), -*/ + extra() { + return ["-gpu", settings.gpu]; + } } module.exports = h264_nvenc; diff --git a/ves.js b/ves.js index cd16dd7..def577b 100644 --- a/ves.js +++ b/ves.js @@ -29,7 +29,7 @@ function float_lt(a, b, edge) { return ((a + edge) < b); } function float_le(a, b, edge) { return float_lt(a, b, edge) || float_eq(a, b, edge); } function float_gt(a, b, edge) { return ((a - edge) > b); } function float_ge(a, b, edge) { return float_gt(a, b, edge) || float_eq(a, b, edge); } -Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) { size++; } } return size; }; +Object.size = function (obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) { size++; } } return size; }; // Actual Code async function load_config() { // Load Configuration @@ -103,7 +103,7 @@ async function load_videos(config, ff) { // Load Videos if (global.debug) console.debug(`${name} is disabled or invalid.`); continue; } - + // Does the video exist? if (!fs.existsSync(path.join(config.paths.videos, `${name}.mkv`))) { console.error(`${name} does not exist.`); @@ -119,27 +119,27 @@ async function load_videos(config, ff) { // Load Videos probeprom.then((json) => { let data = new Object(); - data.name = name; - data.info = json; - data.caches = new Map(); + data.name = name; + data.info = json; + data.caches = new Map(); // File Information - data.file_name = `${name}.mkv`; - data.file_ext = path.extname(data.file_name); - data.file_base = path.basename(data.file_name, data.file_ext); - data.file = path.join(config.paths.videos, data.file_name); + data.file_name = `${name}.mkv`; + data.file_ext = path.extname(data.file_name); + data.file_base = path.basename(data.file_name, data.file_ext); + data.file = path.join(config.paths.videos, data.file_name); // Video Information - data.resolution = { width: data.info.streams[0].width, height: data.info.streams[0].height }; - data.framerate = eval(data.info.streams[0].r_frame_rate); - data.duration = data.info.streams[0].duration; - + data.resolution = { width: data.info.streams[0].width, height: data.info.streams[0].height }; + data.framerate = eval(data.info.streams[0].r_frame_rate); + data.duration = data.info.streams[0].duration; + // Color Information data.color = {}; - data.color.range = data.info.streams[0].color_range ? data.info.streams[0].color_range : 'tv'; - data.color.trc = data.info.streams[0].color_transfer ? data.info.streams[0].color_transfer : 'bt709'; - data.color.primaries = data.info.streams[0].color_primaries ? data.info.streams[0].color_primaries : 'bt709'; - data.color.matrix = data.info.streams[0].color_space ? data.info.streams[0].color_space : 'bt709'; + data.color.range = data.info.streams[0].color_range ? data.info.streams[0].color_range : 'tv'; + data.color.trc = data.info.streams[0].color_transfer ? data.info.streams[0].color_transfer : 'bt709'; + data.color.primaries = data.info.streams[0].color_primaries ? data.info.streams[0].color_primaries : 'bt709'; + data.color.matrix = data.info.streams[0].color_space ? data.info.streams[0].color_space : 'bt709'; videos.set(data.name, data); console.timeEnd(name); @@ -202,11 +202,11 @@ async function create_caches(config, ff, videos, encoders) { // Create Caches if (fs.existsSync(cache.file)) { let info = ff.probeSync(cache.file); if ((info.streams) - && (info.streams.length > 0) - && (info.streams[0].width == cache.width) - && (info.streams[0].height == cache.height) - && float_eq(eval(info.streams[0].r_frame_rate), cache.framerate, 0.01) - && float_eq(info.streams[0].duration, video.duration, 0.1)) { + && (info.streams.length > 0) + && (info.streams[0].width == cache.width) + && (info.streams[0].height == cache.height) + && float_eq(eval(info.streams[0].r_frame_rate), cache.framerate, 0.01) + && float_eq(info.streams[0].duration, video.duration, 0.1)) { if (global.debug) console.debug(`${key} already exists.`); continue; } @@ -224,7 +224,7 @@ async function create_caches(config, ff, videos, encoders) { // Create Caches if (encoders.has("h264_nvenc")) { command.push( "-c:v", "h264_nvenc", - "-profile:v", "high", + "-profile:v", "high", "-preset", "p1", "-tune", "lossless", "-rc", "constqp", @@ -244,7 +244,6 @@ async function create_caches(config, ff, videos, encoders) { // Create Caches } else { command.push( "-c:v", "libx264", - "-profile:v", "high", "-preset", "veryfast", "-crf", "0", "-b:v", "0", @@ -254,7 +253,7 @@ async function create_caches(config, ff, videos, encoders) { // Create Caches "-g", `15`, ); } - command.push(cache.file); + command.push(cache.file); let res = ff.ffmpegSync(command); if (res.status != 0) { console.log(res.stderr.toString()); @@ -302,7 +301,7 @@ async function transcode(config, ff, videos, encoders) { let queue_files = new poolqueue(); for (let idx = 0; idx < encoder.count(); idx++) { let command_promises = []; - let command = encoder.get(idx, cache.width, cache.height, cache.framerate); + let command = encoder.get(idx, cache.width, cache.height, cache.framerate); for (let bitrate of config.options.bitrates) { for (let kfinterval of config.options.keyframeinterval) { command_promises.push(new Promise((resolve, reject) => { @@ -342,7 +341,7 @@ async function transcode(config, ff, videos, encoders) { "-minrate", "0", "-maxrate", "0", "-bufsize", `${2 * bitrate}k`, - ].concat(command.options).concat([file]); + ].concat(command.options).concat(encoder.extra()).concat([file]); queue_commands.push( encoder.pool(), @@ -359,7 +358,7 @@ async function transcode(config, ff, videos, encoders) { })); } } - queue_promises.push(async function() { + queue_promises.push(async function () { await Promise.allSettled(command_promises); }); } @@ -379,8 +378,33 @@ async function transcode(config, ff, videos, encoders) { console.timeEnd("Subtotal"); console.groupEnd(); + // Process from here on out. + // LOOP + // 1. Pull out front of the command and file queue. + // 2. Encode using the given command(s). + // 3. Compare resulting files with real input (libvmaf). + // 4. Delete encoded files. + // 5. Repeat until queues empty, no more caches for video, and no more videos. +/* + console.group("Queueing...") + console.time("Subtotal"); + for (let video_key of videos.keys()) { + console.group(video_key); + console.time(video_key); + let video = videos.get(video_key); + for (let cache_key of video.caches.keys()) { + let cache = video.caches.get(cache_key); + console.time(cache_key); + console.timeEnd(cache_key); + } + console.timeEnd(video_key); + console.groupEnd(); + } + console.timeEnd("Subtotal"); + console.groupEnd(); +*/ /* for (let video_name in videos) { console.time(video_name);