Skip to content

fix(mux): finished importers release their input storage - #6543

Merged
kixelated merged 4 commits into
mainfrom
quest/m1/release-audit/finished-import-scratch
Oct 23, 2026
Merged

kixelated merged 4 commits into
mainfrom
quest/m1/release-audit/finished-import-scratch

Conversation

@kixelated

@kixelated kixelated commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Bindings keep every finished importer until its broadcast ends (Finished::keep in rs/moq-ffi), so the track stays listed and its catalog rendition stays published for late readers. That also kept each parser's input storage. On a long-lived broadcast that retires sources, every retired source pinned its largest write or element.

Measured first with a counting allocator, using real ffmpeg-made 720p, 4 Mb/s inputs (H.264/H.265 Annex-B, fMP4, CMAF, MKV, TS, FLV). This is what dropping a finished importer freed while its tracks were still held:

input write size before after
4 KiB 64 KB to 1 MB (fMP4 is about 1 MB at every write size) 0 to 42 KB
1 MiB about 2.1 MB, every format 0 to 42 KB

After the fix, what remains is the same at every write size and input length, and it is the same per source for 1 or 8 retired sources: bookkeeping only. A finished moq_video::encode::Producer dropped from about 2 MB to about 0 for 1 MiB access units.

Two kinds of allocation outlived EOF:

  • Parser input storage: splitter tail (H.264/H.265/AV1, in import::Track, import::TrackStream, the TS H.264/H.265 streams, and moq_video::encode::Producer), the fMP4/MKV/FLV buffer, and the TS packet scratch. Each owner now drops it in finish. MKV also kept its whole last element, because it retains the bytes from the last emitted tag onward.
  • Retained parameter sets: last_sps (H.264/H.265) and last_seq (AV1) were slices of find_sps's copy of the whole keyframe. Each one pinned a full access-unit copy, live and after finish. They now own just the parameter set.

Kept as is: tracks, catalog renditions, clean media tails, broadcast finish, and late lookup and read. Only scratch the importer can no longer use is dropped. The FFI wrappers and the audio codec lifetime from moq-dev/moq#6421 are unchanged.

Tests

Inline tests in rs/moq-mux/src/import/mod.rs and rs/moq-video/src/encode/producer.rs install a counting allocator for each crate's unit-test binary. It counts only on the measuring thread, like rs/moq-audio/src/capture/buffer.rs, so other tests are unaffected. Each source buffers a 1 MiB element (an access unit, a free atom, a script tag, a block) or a 1 MiB write. Each test retires 1 and then 4 sources on one broadcast, holds every published track, and asserts that dropping the finished importers frees less than a quarter of 1 MiB per source.

  • With the fix: every source frees almost nothing (the net change is -58 KB to +31 KB, because a drop also republishes the catalog).
  • Without it, all 7 tests fail: 1 to 3 MB per source.
  • TS H.264/H.265 splitter release and the H.265/AV1 parameter-set copies follow the same pattern but have no dedicated test. The measurement above covered TS.

Public API and wire impact

  • Public API: none. No signatures change. finish on import::{Track, TrackStream, Container}, the container importers, and encode::Producer now drops internal scratch. Decoding after finish was already invalid, because the track is finished.
  • Wire: none.
  • moq-ffi is unchanged, so the bindings, docs, and drafts need no sync.

Consumer: long-lived binding broadcasts (rs/moq-ffi video.rs / media.rs) that retire video or imported media sources.

Follow-ups (not in this PR)

  • find_sps / find_sequence_header copy the whole keyframe on every keyframe just to scan for one parameter set. Scanning the frame's Bytes would make this zero-copy.
  • While a source is live, a splitter's parameter-set cache (Split::sps/pps) still pins one earlier input allocation. The cost is bounded per live source.
  • Dropping a finished importer allocates and frees about 390 KB per track, with almost zero net change. This was seen in the counting tests and its source was not identified.
  • fMP4/MKV/FLV finish silently discards a truncated trailing element. Under the fail-loud rule, finish should probably refuse instead.

Quest: deletes quest/m1/release-audit/finished-import-scratch.md and its epic link.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EeyiEy5FWz3z44DYZVo7vU

(Written by Claude Opus 5.5)

A binding keeps each finished importer until its broadcast ends, so the
track and its catalog rendition stay published for late readers. That
also kept every parser's input storage: splitter tails, container
atom/tag/element buffers, TS packet scratch, and a retained SPS or
sequence header sliced from a whole access unit.

Release that storage at its owner on finish, and copy retained parameter
sets so they no longer pin the access unit they came from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeyiEy5FWz3z44DYZVo7vU
@kixelated kixelated changed the title Release finished importer scratch fix(mux): finished importers release their input storage Oct 23, 2026
@kixelated
kixelated marked this pull request as ready for review October 23, 2026 11:54
@kixelated

Copy link
Copy Markdown
Collaborator Author

Outcome: finished importers and moq-video producers now drop their parser input storage, and the parameter sets they keep own their own bytes. Without the fix, all 7 new allocation-counting tests fail, with 1-3 MB still held per retired source. With it they pass. just check passed: 3706 + 519 + 226 tests. There are no open decisions. Follow-ups are listed in the PR body.

(Written by Claude Opus 5.5)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T21:01:22.051495Z de4b0d5 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46fa878feb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-mux/tests/finished.rs Outdated
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You'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 17 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bde3633f-0118-4bff-b337-9570f5c6215f
📥 Commits

Reviewing files that changed from the base of the PR and between 46fa878 and de4b0d5.

📒 Files selected for processing: 12
  • quest/m1/release-audit/README.md
  • quest/m1/release-audit/finished-import-scratch.md
  • rs/moq-mux/src/codec/av1/import.rs
  • rs/moq-mux/src/codec/h264/import.rs
  • rs/moq-mux/src/codec/h265/import.rs
  • rs/moq-mux/src/container/flv/import.rs
  • rs/moq-mux/src/container/fmp4/import.rs
  • rs/moq-mux/src/container/mkv/import.rs
  • rs/moq-mux/src/container/ts/import.rs
  • rs/moq-mux/src/import/mod.rs
  • rs/moq-mux/src/import/track.rs
  • rs/moq-video/src/encode/producer.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5ca47b9b-8049-4f3b-bbe6-0189a9c42599
📥 Commits

Reviewing files that changed from the base of the PR and between 4381af6 and 46fa878.

📒 Files selected for processing: 13
  • quest/m1/release-audit/README.md
  • quest/m1/release-audit/finished-import-scratch.md
  • rs/moq-mux/src/codec/av1/import.rs
  • rs/moq-mux/src/codec/h264/import.rs
  • rs/moq-mux/src/codec/h265/import.rs
  • rs/moq-mux/src/container/flv/import.rs
  • rs/moq-mux/src/container/fmp4/import.rs
  • rs/moq-mux/src/container/mkv/import.rs
  • rs/moq-mux/src/container/ts/import.rs
  • rs/moq-mux/src/import/track.rs
  • rs/moq-mux/tests/finished.rs
  • rs/moq-video/src/encode/producer.rs
  • rs/moq-video/tests/finished.rs
💤 Files with no reviewable changes: 2
  • quest/m1/release-audit/README.md
  • quest/m1/release-audit/finished-import-scratch.md

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.

Walkthrough

The change copies AV1, H.264, and H.265 configuration bytes into owned storage. Import finish paths clear buffered input or reset selected splitters before finishing. New integration tests measure heap bytes released after finished importers and producers are dropped while published tracks remain held. The release-audit quest document and its Required-list entry are removed.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 46fa8

The storage-release change is ready to merge after normal checks; no merge-blocking issue was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 73.53% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 34 functions across 11 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: finished importers release their retained input storage.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description directly explains the importer memory-release changes, retained tracks and renditions, parameter-set ownership, tests, and related documentation cleanup.
✨ Finishing Touches
✨ Simplify code
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

kixelated and others added 2 commits October 23, 2026 13:52
They are not Client/Server session tests, so they belong in inline test
modules. The counting allocator counts only on a measuring thread, so it
can serve each crate's unit-test binary without disturbing other tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary:

  • Addressed the Codex test-placement finding: the finished-importer allocator tests moved from rs/moq-mux/tests/finished.rs and rs/moq-video/tests/finished.rs into inline test modules (rs/moq-mux/src/import/mod.rs, rs/moq-video/src/encode/producer.rs), per rs/AGENTS.md. Test logic is unchanged; the counting allocator counts only on the measuring thread, so other unit tests are unaffected.
  • Merged origin/main (clean). just check and quest check pass on the merged head.
  • No public API or wire change.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 23, 2026
@kixelated
kixelated added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 013a3de Oct 23, 2026
10 checks passed
@kixelated
kixelated deleted the quest/m1/release-audit/finished-import-scratch branch October 23, 2026 23:27
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