Skip to content

State the audio duration instead of inferring it - #294

Merged
ralyodio merged 1 commit into
masterfrom
fix-audio-duration
Sep 24, 2026
Merged

ralyodio merged 1 commit into
masterfrom
fix-audio-duration

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

The narrated master shipped with no audio stream at all, and before that with 2.3 seconds of audio against five seconds of picture. Both came from the same wrong assumption about -shortest.

In ffmpeg 4.x, -shortest keys off input durations. Pairing it with apad — whose output is infinite by design — does not trim the padded stream back to the video. It either left the original speech length alone or dropped the stream entirely.

The output duration is now stated outright with -t. That isn't a workaround for -shortest; it's the thing actually being asserted — that picture and sound are the same length.

Verified against real ffmpeg this time

The pipeline test now encodes a 2.3s tone over 150 frames and asserts the muxed result has an audio stream whose duration is within one AAC frame of five seconds.

Both previous failures pass an arguments-only check — a short track and a missing track both look fine if you only inspect the flag list — which is exactly why neither was caught before production. I'd been verifying the wrong thing.

Context

Narration itself is confirmed working end to end in production: 91 KB of audio, script "Crypto Payments, No Custody. Get started free at coinpayportal.com.", generated from the campaign's approved copy. The same revision produced all three animated banners at exact IAB sizes (300×250 / 728×90 / 320×50) and 146 KB / 121 KB / 41 KB, inside the 150 KB budget, plus correct avc1.64001F HLS codecs. This was the last thing between that and a finished narrated revision.

2582 passed / 1 failed (pre-existing tracker-geo). Typechecks clean.

The narrated master shipped with no audio stream at all, and before that with
2.3 seconds of audio against five seconds of picture. Both came from the same
wrong assumption about -shortest: in ffmpeg 4.x it keys off INPUT durations, so
pairing it with apad — whose output is infinite by design — does not trim the
padded stream back to the video. It either left the original speech length
alone or dropped the stream.

The output duration is now stated outright with -t. That is not a workaround
for -shortest; it is the thing actually being asserted, which is that picture
and sound are the same length.

Verified against real ffmpeg rather than by reading the argument list. The
pipeline test now encodes a 2.3s tone over 150 frames and asserts the muxed
result has an audio stream whose duration is within one AAC frame of five
seconds. Both previous failures — the short track and the missing track — pass
an arguments-only check, which is why neither was caught before production.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

48 finding(s)

HIGH/CRITICAL: 2 | MEDIUM: 31 | LOW: 15

Severity Rule Location
HIGH tls-verification-disabled lib/onion.ts:48
HIGH secret-generic-credential lib/sp/platforms/facebook.ts:32
MEDIUM js-unescaped-html-sink app/(app)/dashboard/admin/email-broadcast/EmailBroadcastForm.tsx:125
MEDIUM js-unescaped-html-sink app/(app)/dashboard/projects/[id]/autoblog/articles/[articleId]/page.tsx:214
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:67
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:97
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:104
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:110
MEDIUM js-unescaped-html-sink app/(marketing)/recent/page.tsx:186
MEDIUM js-unescaped-html-sink app/(marketing)/recent/page.tsx:190
MEDIUM js-unescaped-html-sink app/c/[project]/[slug]/page.tsx:77
MEDIUM js-unescaped-html-sink app/c/[project]/page.tsx:57
MEDIUM js-unescaped-html-sink app/careers.js/route.ts:228
MEDIUM js-unescaped-html-sink app/careers.js/route.ts:285
MEDIUM js-unescaped-html-sink app/layout.tsx:129
MEDIUM js-open-redirect app/login/form.tsx:39
MEDIUM js-unescaped-html-sink app/r/[token]/page.tsx:176
MEDIUM js-open-redirect app/signup/form.tsx:43
MEDIUM js-open-redirect components/billing/buy-credits-modal.tsx:98
MEDIUM js-unescaped-html-sink components/json-ld.tsx:8
MEDIUM js-unescaped-html-sink components/report/markdown-view.tsx:15
MEDIUM js-unescaped-html-sink lib/careers/page-templates.ts:198
MEDIUM js-dynamic-code-execution lib/crawl-limits.ts:67
MEDIUM redos-nested-quantifier lib/emailMarkdown.ts:41
MEDIUM redos-nested-quantifier lib/emailMarkdown.ts:324
MEDIUM redos-nested-quantifier lib/lx/articleGen.ts:99
MEDIUM redos-nested-quantifier lib/tracker/agent-gate.ts:61
MEDIUM sh-remote-script-execution prober/deploy/provision.sh:30
MEDIUM sql-template-interpolation scripts/detect-slot-themes.ts:31
MEDIUM sql-template-interpolation scripts/purge-constructed-keywords.ts:163
MEDIUM sql-template-interpolation scripts/purge-offniche-keywords.ts:124
MEDIUM js-dynamic-code-execution scripts/test-crawl-limits.mjs:14
MEDIUM js-dynamic-code-execution scripts/test-crawl-limits.mjs:24
LOW secret-generic-credential app/(marketing)/docs/autoblog-webhook/page.tsx:145
LOW secret-generic-credential lib/sp/platforms/linkedin.ts:25
LOW js-dynamic-code-execution tests/careers-page-templates.test.ts:21
LOW js-dynamic-code-execution tests/careers-widget-script.test.ts:19
LOW js-dynamic-code-execution tests/careers-widget-script.test.ts:69
LOW js-dynamic-code-execution tests/contract/ad-visitor-id.test.ts:51
LOW js-dynamic-code-execution tests/contract/ad-visitor-id.test.ts:52
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:20
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:24
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:25
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:26
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:31
LOW js-dynamic-code-execution tests/contract/ads-click-cooldown-redis.test.ts:35
LOW secret-generic-credential tests/contract/posthog-integration.test.ts:13
LOW secret-generic-credential tests/lead-campaign.test.ts:16

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 091d5da into master Sep 24, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant