Spaces:
Running
Running
Commit ·
ad6b549
1
Parent(s): 7ad7585
Change caption render logic
Browse files- utils/CaptionRender.js +36 -31
utils/CaptionRender.js
CHANGED
|
@@ -23,19 +23,17 @@ export class CaptionRenderer {
|
|
| 23 |
const outDir = path.join(process.cwd(), 'out');
|
| 24 |
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
| 25 |
|
| 26 |
-
const
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
|
|
|
| 33 |
|
| 34 |
-
originalManuscript.transcript.forEach((section, i) => {
|
| 35 |
const media = section.mediaAbsPaths || [];
|
| 36 |
-
if (!media.length)
|
| 37 |
-
|
| 38 |
-
const audioIndex = inputIndex + media.length;
|
| 39 |
|
| 40 |
media.forEach(m => {
|
| 41 |
inputs.push('-i', m.path);
|
|
@@ -70,32 +68,39 @@ export class CaptionRenderer {
|
|
| 70 |
const aout = `aout${i}`;
|
| 71 |
|
| 72 |
filter.push(`[${sub}]null[${vout}]`);
|
| 73 |
-
filter.push(`[${
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
-
|
| 80 |
-
|
|
|
|
| 81 |
|
| 82 |
-
|
| 83 |
-
inputs.push('-i', originalManuscript.bgMusic);
|
| 84 |
-
filter.push(`[${inputIndex}:a]volume=${originalManuscript.bgMusicVolume || 0.25}[bgm]`);
|
| 85 |
-
filter.push(`[finala][bgm]amix=inputs=2:duration=first:dropout_transition=2[mixeda]`);
|
| 86 |
-
}
|
| 87 |
|
| 88 |
-
const
|
| 89 |
-
|
| 90 |
-
'-
|
| 91 |
-
'-
|
| 92 |
-
'-
|
| 93 |
-
'-
|
| 94 |
-
'-c:a', 'aac',
|
| 95 |
-
'-y', outFile
|
| 96 |
];
|
| 97 |
|
| 98 |
-
|
|
|
|
|
|
|
| 99 |
}
|
| 100 |
|
| 101 |
runFFmpeg(args, controller, onLog) {
|
|
|
|
| 23 |
const outDir = path.join(process.cwd(), 'out');
|
| 24 |
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
| 25 |
|
| 26 |
+
const segmentFiles = [];
|
| 27 |
|
| 28 |
+
// Render each transcript section separately
|
| 29 |
+
for (const [i, section] of originalManuscript.transcript.entries()) {
|
| 30 |
+
const segmentFile = path.join(outDir, `${jobId}_segment_${i}.mp4`);
|
| 31 |
+
const inputs = [];
|
| 32 |
+
const filter = [];
|
| 33 |
+
let inputIndex = 0;
|
| 34 |
|
|
|
|
| 35 |
const media = section.mediaAbsPaths || [];
|
| 36 |
+
if (!media.length) continue;
|
|
|
|
|
|
|
| 37 |
|
| 38 |
media.forEach(m => {
|
| 39 |
inputs.push('-i', m.path);
|
|
|
|
| 68 |
const aout = `aout${i}`;
|
| 69 |
|
| 70 |
filter.push(`[${sub}]null[${vout}]`);
|
| 71 |
+
filter.push(`[${inputIndex - 1}:a]anull[${aout}]`);
|
| 72 |
+
|
| 73 |
+
const args = [
|
| 74 |
+
...inputs,
|
| 75 |
+
'-filter_complex', filter.join(';'),
|
| 76 |
+
'-map', `[${vout}]`,
|
| 77 |
+
'-map', `[${aout}]`,
|
| 78 |
+
'-c:v', 'libx264',
|
| 79 |
+
'-c:a', 'aac',
|
| 80 |
+
'-y', segmentFile
|
| 81 |
+
];
|
| 82 |
+
|
| 83 |
+
await this.runFFmpeg(args, controller, onLog);
|
| 84 |
+
segmentFiles.push(segmentFile);
|
| 85 |
+
}
|
| 86 |
|
| 87 |
+
// Concatenate all segments together
|
| 88 |
+
const concatFile = path.join(outDir, `${jobId}_final.mp4`);
|
| 89 |
+
const concatList = path.join(outDir, `${jobId}_concat_list.txt`);
|
| 90 |
|
| 91 |
+
fs.writeFileSync(concatList, segmentFiles.map(f => `file '${f}'`).join('\n'));
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
+
const concatArgs = [
|
| 94 |
+
'-f', 'concat',
|
| 95 |
+
'-safe', '0',
|
| 96 |
+
'-i', concatList,
|
| 97 |
+
'-c', 'copy',
|
| 98 |
+
'-y', concatFile
|
|
|
|
|
|
|
| 99 |
];
|
| 100 |
|
| 101 |
+
await this.runFFmpeg(concatArgs, controller, onLog);
|
| 102 |
+
|
| 103 |
+
return concatFile;
|
| 104 |
}
|
| 105 |
|
| 106 |
runFFmpeg(args, controller, onLog) {
|