fix(producer): normalize padded audio on sample timeline

This commit is contained in:
Miguel Ángel
2026-07-25 21:14:18 +00:00
parent 63bc525ca9
commit 4b116b9880
8 changed files with 115 additions and 181 deletions
@@ -373,29 +373,6 @@ describe("encodeFramesChunkedConcat ffmpegEncodeTimeout", () => {
});
describe("muxVideoWithAudio audio codec handling", () => {
it("caps copied audio to the encoded video duration", async () => {
const { spawn, calls } = createSpawnSpy();
vi.resetModules();
vi.doMock("child_process", () => ({ spawn }));
const { muxVideoWithAudio } = await import("./chunkEncoder.js");
const muxPromise = muxVideoWithAudio(
"/tmp/video-only.mp4",
"/tmp/audio.duration-normalized.m4a",
"/tmp/output.mp4",
undefined,
{ audioCodec: "aac", durationSeconds: 16.066667 },
{ num: 30, den: 1 },
);
await flushMuxCodecResolution();
expect(calls[0]!.args).toContain("-shortest");
expect(calls[0]!.args).toContain("-t");
expect(calls[0]!.args).toContain("16.066667");
emitClose(calls[0]!.proc, 0);
await expect(muxPromise).resolves.toMatchObject({ success: true });
});
it("copies HyperFrames AAC sidecars into MP4 instead of re-encoding", async () => {
const { spawn, calls } = createSpawnSpy();
vi.resetModules();
@@ -80,7 +80,6 @@ export interface MuxVideoWithAudioOptions extends Partial<
/** Preserve a priming edit list known to have been created by AAC re-encoding. */
preserveAudioPrimingEditList?: boolean;
/** Hard cap copied audio to the already-encoded video's exact duration. */
durationSeconds?: number;
}
async function shouldCopyAacSidecar(
@@ -708,16 +707,6 @@ export async function muxVideoWithAudio(
// output container metadata. `-c:v copy` is retained; no re-encode.
args.push("-r", fpsToFfmpegArg(fps));
}
if (config?.durationSeconds !== undefined) {
// Stream-copying a normalized AAC sidecar can preserve a longer packet
// timeline than its container/edit-list duration. `-t` alone limits the
// output timestamp window but does not prevent the copied audio stream's
// tail from extending the MP4 timeline. When an explicit video-derived
// duration is supplied, also stop at the shortest stream so the final
// mux boundary is deterministic.
args.push("-shortest");
args.push("-t", String(config.durationSeconds));
}
args.push("-y", outputPath);
const processTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;