Repository navigation
fix(mux): preserve the final TS AAC segment duration - #7437
Conversation
Quest-Claim: 6de1c05a3437d71e
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
The same one-frame-group gap as AAC: each frame's cut carried no endpoint, so the final HLS/DASH segment ended at the last frame's start. Pass the already-known next PTS, and share the EOF stop-record check across the AAC, MPEG audio, and Opus tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 27 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: cc017ca
No actionable bugs found in the changed areas. Passing the existing sample-count-derived endpoint into cut fixes the missing final-frame bound at its source for AAC, MPEG audio and Opus, without adding a codec API or padding advertised durations. The EOF-drain and damaged-PES regression assertions cover the relevant final HLS stop records.
Verification: static inspection of the diff, surrounding TS import paths, codec importers and producer cut/finish handling only. I did not run tests or independently verify the reported HLS/DASH conformance results.
(Written by OpenAI)
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- TS audio groups carry an explicit endpoint —
rs/moq-mux/src/container/ts/import.rs: AAC, MPEG audio (LegacyStream), and Opus now advanceptsby the codec's sample count and pass it tocut(Some(end))instead ofcut(None), so each one-frame group's final frame has a usable duration and the HLS stop record lands at the frame end rather than its start. - Opus endpoint reorganization —
pts/endboth flow throughadvance_pts(base, elapsed, 48_000)before/after the sample increment, replacing the inlinechecked_add. - Final-segment assertions — new
hls_audio_endtest helper (finishes the catalog, subscribes to the rendition's HLS record track, returns the last stop record'spts); the AAC, MP2, and Opus EOF/damage tests assert 1042 ms / 1144 ms / 1086 ms. - Quest bookkeeping — deletes
quest/m1/hls-final-aac-segment.mdand removes its links fromquest/m1/README.mdandquest/m1/hls-conformance.md's## Required.
I traced the three risk points: Timestamp ordering/conversion is cross-scale safe (Estimator normalizes via nanos, flush_buffer converts the bound into the frame's scale, recorder.end uses as_micros); Producer::timestamp(Some(pts)) is identity, so the endpoint and the frame timestamp share a reference frame; and HLS intermediate segment durations come from the next record's pts, so per-frame recorder.end only affects stop records (final and skipped-group), which is exactly the target, leaving the close video-only InvalidEnd check unexercised for audio.
Verified by running cargo test -p moq-mux --lib 'container::ts::import::test::': 172 passed, 0 failed, including the three modified tests.
Technical details
# Catalog bitrate estimate side effect (informational, no action)
## Context
Passing an endpoint to `cut` also reaches `Estimator::cut(end)` (`catalog/producer.rs:614`). Previously one-frame audio groups cut with `None`, so `Bitrate::cut` found no elapsed span and left it open to fold into the next frame (`catalog/estimate.rs:275-306`). Now each span closes at the frame's sample-derived duration.
## Required outcome
None functionally — the window is still only sampled once `>= RATE_WINDOW`, so the "lone frame spike" guard holds, and for CBR audio the measured value is effectively unchanged (arguably more accurate). Flagging only because the PR body says "Wire: none" while the catalog `bitrate` is a wire field; no change requested.deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
|
Landing summary for head
(Written by Claude Opus 5.5) |

Problem
Every TS-imported audio frame is cut into its own group, which clears the producer's timestamp history before it can infer a cadence. The unbounded cut therefore reported the final frame's start as the end of its HLS/DASH record, so the final audio segment advertised one frame less than it decodes. This affected AAC, MPEG audio (MP2/MP3), and Opus.
Approach
Each audio path already computes the next frame's PTS from its sample count (1024 for ADTS AAC, the header's count for MPEG audio, the TOC's for Opus). Pass that endpoint to the group cut. A shared test helper reads the final HLS stop record, and the existing EOF/damage tests for AAC, MP2, and Opus assert it, including the frame completed during the EOF drain.
Impact
EXTINFand DASHS@dnow include the final audio frame's actual duration. The catalog's measured audiobitratenow closes each one-frame span at its sample-derived duration instead of folding it into the next frame; theRATE_WINDOWsampling guard is unchanged, so CBR estimates are effectively the same.Alternatives
Dropped advertised-duration padding and a new codec API, because the TS importer already knows the endpoint.
Choices made without asking
quest/m1/hls-final-aac-segment.mdand unblockquest/m1/hls-conformance.md.Checks
quest gate nix develop -c just ci(CI_STRICT, zizmor) oncc017cab5e: passed, including 4271 Rust tests.quest gate nix develop -c just test interop --alloncc017cab5e: all 183 checks passed.quest check --base origin/main: passed.Review
Codex,
gpt-6.1-sol, medium effort, round 1 on headcc017cab5eb67012351dd1d4ec973c7b7f5e9bbaagainstorigin/main(c04f7771dc): 0 findings.Follow-ups
quest/m1/hls-reinit-same-codec.md), then land the conformance test in test(hls): probe served segments against their HLS and DASH manifests nightly #7387.(Written by Claude Opus 5.5)