diff --git a/packages/producer/src/services/render/audioPadTrim.test.ts b/packages/producer/src/services/render/audioPadTrim.test.ts index 57efe884a..ee1931b5b 100644 --- a/packages/producer/src/services/render/audioPadTrim.test.ts +++ b/packages/producer/src/services/render/audioPadTrim.test.ts @@ -91,6 +91,7 @@ describe("buildPadTrimAudioArgs", () => { expect(operation).toBe("trim"); const filterIdx = args.indexOf("-af"); expect(args[filterIdx + 1]).toBe("atrim=duration=15.000000,asetpts=PTS-STARTPTS"); + expect(args[args.indexOf("-t") + 1]).toBe("15.000000"); const codecIdx = args.indexOf("-c:a"); expect(args[codecIdx + 1]).toBe("aac"); expect(args[args.indexOf("-b:a") + 1]).toBe("192k"); diff --git a/packages/producer/src/services/render/audioPadTrim.ts b/packages/producer/src/services/render/audioPadTrim.ts index eca322760..f7a40cf23 100644 --- a/packages/producer/src/services/render/audioPadTrim.ts +++ b/packages/producer/src/services/render/audioPadTrim.ts @@ -201,6 +201,12 @@ export function buildPadTrimAudioPlan( audioPath, "-af", `atrim=duration=${targetSec},asetpts=PTS-STARTPTS`, + // `atrim` limits decoded samples but does not cap muxer timestamps + // introduced by encoder delay/flush. The output duration contract + // is enforced at the container boundary as well; without `-t`, a + // long primed source can retain its original tail after re-encode. + "-t", + targetSec, "-c:a", "aac", "-b:a",