feat(transcode): scale 2-pass progress to 50% per pass for total 100%
This commit is contained in:
1 parent
2daa75df60
commit
70f065a3a2
2 files changed
+87
-7
No files matched your search
@@ -156,6 +156,17 @@ const shouldCopyVideo = (videoStream, copyHevcBelowKbps, streams, format) => {
|
|||||||
&& bitrateKbps > 0 && bitrateKbps < copyHevcBelowKbps;
|
&& bitrateKbps > 0 && bitrateKbps < copyHevcBelowKbps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scalePassPercentage = (pass, percentage) => {
|
||||||
|
const p = Math.min(100, Math.max(0, Number(percentage) || 0));
|
||||||
|
if (pass === 1) {
|
||||||
|
return +(p * 0.5).toFixed(1);
|
||||||
|
}
|
||||||
|
if (pass === 2) {
|
||||||
|
return +(50 + p * 0.5).toFixed(1);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
// ─── Plugin ───────────────────────────────────────────────────────────────────
|
// ─── Plugin ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const plugin = async (args) => {
|
const plugin = async (args) => {
|
||||||
@@ -297,9 +308,62 @@ const plugin = async (args) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { CLI } = require('../../../../FlowHelpers/1.0.0/cliUtils');
|
const { CLI } = require('../../../../FlowHelpers/1.0.0/cliUtils');
|
||||||
|
const { updateProgress } = args;
|
||||||
|
|
||||||
|
// Scale 2-pass progress so Pass 1 counts for 0-50% and Pass 2 counts for 50-100%
|
||||||
|
const pass1UpdateWorker = (progressData) => {
|
||||||
|
if (typeof updateWorker !== 'function') return;
|
||||||
|
if (progressData && typeof progressData.percentage === 'number') {
|
||||||
|
updateWorker({
|
||||||
|
...progressData,
|
||||||
|
percentage: scalePassPercentage(1, progressData.percentage),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateWorker(progressData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pass1UpdateProgress = (progressData) => {
|
||||||
|
if (typeof updateProgress !== 'function') return;
|
||||||
|
if (progressData && typeof progressData.progress === 'number') {
|
||||||
|
updateProgress({
|
||||||
|
...progressData,
|
||||||
|
progress: scalePassPercentage(1, progressData.progress),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateProgress(progressData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pass2UpdateWorker = (progressData) => {
|
||||||
|
if (typeof updateWorker !== 'function') return;
|
||||||
|
if (progressData && typeof progressData.percentage === 'number') {
|
||||||
|
updateWorker({
|
||||||
|
...progressData,
|
||||||
|
percentage: scalePassPercentage(2, progressData.percentage),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateWorker(progressData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pass2UpdateProgress = (progressData) => {
|
||||||
|
if (typeof updateProgress !== 'function') return;
|
||||||
|
if (progressData && typeof progressData.progress === 'number') {
|
||||||
|
updateProgress({
|
||||||
|
...progressData,
|
||||||
|
progress: scalePassPercentage(2, progressData.progress),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateProgress(progressData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// ══ PASS 1 ════════════════════════════════════════════════════════════════
|
// ══ PASS 1 ════════════════════════════════════════════════════════════════
|
||||||
jobLog('[transcode2PassX265] Starting Pass 1...\n');
|
jobLog('[transcode2PassX265] Starting Pass 1...\n');
|
||||||
|
pass1UpdateWorker({ percentage: 0 });
|
||||||
|
pass1UpdateProgress({ progress: 0 });
|
||||||
|
|
||||||
const pass1Cli = new CLI({
|
const pass1Cli = new CLI({
|
||||||
cli: args.ffmpegPath,
|
cli: args.ffmpegPath,
|
||||||
spawnArgs: [
|
spawnArgs: [
|
||||||
@@ -317,16 +381,18 @@ const plugin = async (args) => {
|
|||||||
WorkDir: workDir,
|
WorkDir: workDir,
|
||||||
jobLog,
|
jobLog,
|
||||||
inputFileObj,
|
inputFileObj,
|
||||||
updateWorker,
|
updateWorker: pass1UpdateWorker,
|
||||||
logFullCliOutput: args.logFullCliOutput || false,
|
logFullCliOutput: args.logFullCliOutput || false,
|
||||||
args,
|
args: { ...args, updateWorker: pass1UpdateWorker, updateProgress: pass1UpdateProgress },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { cliExitCode: pass1Exit } = await pass1Cli.runCli();
|
const { cliExitCode: pass1Exit } = await pass1Cli.runCli();
|
||||||
if (pass1Exit !== 0) {
|
if (pass1Exit !== 0) {
|
||||||
throw new Error(`[transcode2PassX265] Pass 1 failed with exit code ${pass1Exit}`);
|
throw new Error(`[transcode2PassX265] Pass 1 failed with exit code ${pass1Exit}`);
|
||||||
}
|
}
|
||||||
jobLog('[transcode2PassX265] Pass 1 complete.\n');
|
pass1UpdateWorker({ percentage: 100 });
|
||||||
|
pass1UpdateProgress({ progress: 100 });
|
||||||
|
jobLog('[transcode2PassX265] Pass 1 complete (50% total progress).\n');
|
||||||
|
|
||||||
// ══ PASS 2 ════════════════════════════════════════════════════════════════
|
// ══ PASS 2 ════════════════════════════════════════════════════════════════
|
||||||
const audioArgs = buildAudioArgs(variables);
|
const audioArgs = buildAudioArgs(variables);
|
||||||
@@ -335,6 +401,9 @@ const plugin = async (args) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jobLog('[transcode2PassX265] Starting Pass 2...\n');
|
jobLog('[transcode2PassX265] Starting Pass 2...\n');
|
||||||
|
pass2UpdateWorker({ percentage: 0 });
|
||||||
|
pass2UpdateProgress({ progress: 0 });
|
||||||
|
|
||||||
const pass2Cli = new CLI({
|
const pass2Cli = new CLI({
|
||||||
cli: args.ffmpegPath,
|
cli: args.ffmpegPath,
|
||||||
spawnArgs: [
|
spawnArgs: [
|
||||||
@@ -355,16 +424,18 @@ const plugin = async (args) => {
|
|||||||
jobLog,
|
jobLog,
|
||||||
outputFilePath: outFile,
|
outputFilePath: outFile,
|
||||||
inputFileObj,
|
inputFileObj,
|
||||||
updateWorker,
|
updateWorker: pass2UpdateWorker,
|
||||||
logFullCliOutput: args.logFullCliOutput || false,
|
logFullCliOutput: args.logFullCliOutput || false,
|
||||||
args,
|
args: { ...args, updateWorker: pass2UpdateWorker, updateProgress: pass2UpdateProgress },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { cliExitCode: pass2Exit } = await pass2Cli.runCli();
|
const { cliExitCode: pass2Exit } = await pass2Cli.runCli();
|
||||||
if (pass2Exit !== 0) {
|
if (pass2Exit !== 0) {
|
||||||
throw new Error(`[transcode2PassX265] Pass 2 failed with exit code ${pass2Exit}`);
|
throw new Error(`[transcode2PassX265] Pass 2 failed with exit code ${pass2Exit}`);
|
||||||
}
|
}
|
||||||
jobLog('[transcode2PassX265] Pass 2 complete.\n');
|
pass2UpdateWorker({ percentage: 100 });
|
||||||
|
pass2UpdateProgress({ progress: 100 });
|
||||||
|
jobLog('[transcode2PassX265] Pass 2 complete (100% total progress).\n');
|
||||||
|
|
||||||
// ── Cleanup 2-pass log files and temporary input copy ────────────────────
|
// ── Cleanup 2-pass log files and temporary input copy ────────────────────
|
||||||
[statsFile, `${statsFile}.mbtree`, `${statsFile}.cutree`].forEach((f) => {
|
[statsFile, `${statsFile}.mbtree`, `${statsFile}.cutree`].forEach((f) => {
|
||||||
@@ -389,3 +460,4 @@ const plugin = async (args) => {
|
|||||||
|
|
||||||
module.exports.details = details;
|
module.exports.details = details;
|
||||||
module.exports.plugin = plugin;
|
module.exports.plugin = plugin;
|
||||||
|
module.exports.scalePassPercentage = scalePassPercentage;
|
||||||
@@ -236,8 +236,16 @@ const AUDIO_INPUTS = {
|
|||||||
ok(transcodeCode.includes("normalizedKey === 'bps' || normalizedKey === 'bps-eng'"), 'HEVC copy check falls back to Matroska BPS metadata');
|
ok(transcodeCode.includes("normalizedKey === 'bps' || normalizedKey === 'bps-eng'"), 'HEVC copy check falls back to Matroska BPS metadata');
|
||||||
ok(transcodeCode.includes('containerBitrate - otherStreamBitrate'), 'HEVC copy check estimates video bitrate from container and companion streams');
|
ok(transcodeCode.includes('containerBitrate - otherStreamBitrate'), 'HEVC copy check estimates video bitrate from container and companion streams');
|
||||||
ok(!transcodeCode.includes("'-map_metadata -1'"), 'pass 1 separates -map_metadata from its value');
|
ok(!transcodeCode.includes("'-map_metadata -1'"), 'pass 1 separates -map_metadata from its value');
|
||||||
ok(!transcodeCode.includes("'-map_chapters -1'"), 'pass 1 separates -map_chapters from its value');
|
|
||||||
ok(transcodeCode.includes('const statsForX265 = path.basename(statsFile)'), 'x265 stats file is relative to workDir on Windows');
|
ok(transcodeCode.includes('const statsForX265 = path.basename(statsFile)'), 'x265 stats file is relative to workDir on Windows');
|
||||||
|
const { scalePassPercentage } = require(path.join(ROOT, 'LocalFlowPlugins/video/transcode2PassX265/1.0.0/index.js'));
|
||||||
|
eq(scalePassPercentage(1, 0), 0, 'pass 1 at 0% maps to 0%');
|
||||||
|
eq(scalePassPercentage(1, 50), 25, 'pass 1 at 50% maps to 25%');
|
||||||
|
eq(scalePassPercentage(1, 100), 50, 'pass 1 at 100% maps to 50%');
|
||||||
|
eq(scalePassPercentage(2, 0), 50, 'pass 2 at 0% maps to 50%');
|
||||||
|
eq(scalePassPercentage(2, 50), 75, 'pass 2 at 50% maps to 75%');
|
||||||
|
eq(scalePassPercentage(2, 100), 100, 'pass 2 at 100% maps to 100%');
|
||||||
|
ok(transcodeCode.includes('scalePassPercentage(1,'), 'pass 1 wraps updateWorker with 50% scale');
|
||||||
|
ok(transcodeCode.includes('scalePassPercentage(2,'), 'pass 2 wraps updateWorker with 50% scale');
|
||||||
|
|
||||||
// ── copyToWorkDir & replaceOriginalFile v1.0.0 checks ─────────────────────
|
// ── copyToWorkDir & replaceOriginalFile v1.0.0 checks ─────────────────────
|
||||||
const copyPluginCode = require('fs').readFileSync(path.join(ROOT, 'LocalFlowPlugins/utility/copyToWorkDir/1.0.0/index.js'), 'utf8');
|
const copyPluginCode = require('fs').readFileSync(path.join(ROOT, 'LocalFlowPlugins/utility/copyToWorkDir/1.0.0/index.js'), 'utf8');
|
||||||
|
|||||||
Reference in new issue
Block a user