diff --git a/app/static/public/js/video.js b/app/static/public/js/video.js
index 71748fa..c9987ca 100644
--- a/app/static/public/js/video.js
+++ b/app/static/public/js/video.js
@@ -1501,43 +1501,54 @@
const segBSource = `${prefix}_b_source.mp4`;
const segA = `${prefix}_a.mp4`;
const segB = `${prefix}_b.mp4`;
+ const segANorm = `${prefix}_a_norm.mp4`;
+ const segBNorm = `${prefix}_b_norm.mp4`;
const listFile = `${prefix}_list.txt`;
const mergedFile = `${prefix}_merged.mp4`;
try {
- await ffmpegWriteFile(ff, segASource, sourceStable);
- await ffmpegWriteFile(ff, segBSource, generatedBuffer);
- const trimSeconds = (Math.max(0, lockedTimestampMs) / 1000).toFixed(3);
- if (Number(trimSeconds) > 0) {
- await ffmpegExec(
- ff,
- ['-y', '-i', segASource, '-t', trimSeconds, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', segA]
- );
- await ffmpegExec(
- ff,
- ['-y', '-i', segBSource, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', segB]
- );
+ const trimSeconds = (Math.max(0, lockedTimestampMs) / 1000).toFixed(3);
+ if (Number(trimSeconds) <= 0) {
+ return new Blob([toStableUint8(generatedBuffer)], { type: 'video/mp4' });
+ }
+ await ffmpegWriteFile(ff, segASource, sourceStable);
+ await ffmpegWriteFile(ff, segBSource, generatedBuffer);
+
+ await ffmpegExec(ff, ['-y', '-i', segASource, '-t', trimSeconds, '-c', 'copy', segA]);
await ffmpegWriteFile(
ff,
listFile,
- new TextEncoder().encode(`file '${segA}'\nfile '${segB}'\n`)
+ new TextEncoder().encode(`file '${segA}'\nfile '${segBSource}'\n`)
);
- await ffmpegExec(
- ff,
- ['-y', '-f', 'concat', '-safe', '0', '-i', listFile, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', mergedFile]
- );
- } else {
- await ffmpegExec(
- ff,
- ['-y', '-i', segBSource, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', mergedFile]
- );
- }
- const merged = await ffmpegReadFile(ff, mergedFile);
- return new Blob([toStableUint8(merged)], { type: 'video/mp4' });
+ try {
+ await ffmpegExec(ff, ['-y', '-f', 'concat', '-safe', '0', '-i', listFile, '-c', 'copy', mergedFile]);
+ } catch (copyErr) {
+ await ffmpegExec(
+ ff,
+ ['-y', '-i', segASource, '-t', trimSeconds, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', segANorm]
+ );
+ await ffmpegExec(
+ ff,
+ ['-y', '-i', segBSource, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', segBNorm]
+ );
+ await ffmpegWriteFile(
+ ff,
+ listFile,
+ new TextEncoder().encode(`file '${segANorm}'\nfile '${segBNorm}'\n`)
+ );
+ await ffmpegExec(
+ ff,
+ ['-y', '-f', 'concat', '-safe', '0', '-i', listFile, '-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-ar', '48000', '-ac', '2', mergedFile]
+ );
+ }
+ const merged = await ffmpegReadFile(ff, mergedFile);
+ return new Blob([toStableUint8(merged)], { type: 'video/mp4' });
} finally {
await ffmpegDeleteFileSafe(ff, segASource);
await ffmpegDeleteFileSafe(ff, segBSource);
await ffmpegDeleteFileSafe(ff, segA);
await ffmpegDeleteFileSafe(ff, segB);
+ await ffmpegDeleteFileSafe(ff, segANorm);
+ await ffmpegDeleteFileSafe(ff, segBNorm);
await ffmpegDeleteFileSafe(ff, listFile);
await ffmpegDeleteFileSafe(ff, mergedFile);
}
diff --git a/app/static/public/pages/video.html b/app/static/public/pages/video.html
index 53ddeec..41a555c 100644
--- a/app/static/public/pages/video.html
+++ b/app/static/public/pages/video.html
@@ -274,7 +274,7 @@
-
+