Repository navigation
obs-codec: AVC and HEVC header extraction writes straight into its bmalloc buffers (Fixes #1302) - #1415
Merged
Conversation
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Oct 18, 2026
zackees
enabled auto-merge
October 18, 2026 16:11
…ts (Refs obs-rust#1302) RED: 1/4 (the no-start-code guard passes). obs_extract_avc_headers and obs_extract_hevc_headers make 5 Rust heap allocations for a normal 256-byte keyframe packet (three growing Vecs, then a copy into bmalloc) and more than one for a packet with very many units. The counting global allocator moves from av1_alloc.rs to alloc_count.rs: one test executable can have only one global allocator. Benchmarks before the fix (Apple M1 Max, record.py options, extract/ only, 5 paired passes; median Rust/C and paired range): avc/extract/256 1.280x (1.203-1.295) hevc/extract/256 1.261x (1.249-1.280) avc/extract/16384 0.382x (0.375-0.408) hevc/extract/16384 0.397x (0.389-0.413) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…alloc buffers (Fixes obs-rust#1302) GREEN: 6/6 allocation tests (one added: packets past the stack-kept units match the C oracle byte for byte), 83/83 obs-tests-codec with the AVC/HEVC parity proptests unchanged, clippy -D warnings, bench fixture checks. - nal::SplitUnits scans the start codes once. It adds up the three output sizes and keeps the ranges of the first 32 units on the stack. for_each gives the units again from those ranges, or for a packet with more units from one more scan, so it never allocates. - packet::write_split_units bmallocs each output at its final size and copies every unit straight into it. It panics instead of writing past an output when the units do not add up to the sizes. - avc::bucket and hevc::bucket name the unit classification that extract_headers used inline; split_headers keeps its Vec API for the tests, pre-sized from SplitUnits. The "very many units" test is tightened from at most one allocation to none: the second scan replaces the heap fallback. Benchmarks (Apple M1 Max, record.py options, extract/ only, 5 paired passes, same load as the RED run; median Rust/C and paired range): avc/extract/256 1.280x -> 0.839x (0.824-0.850) hevc/extract/256 1.261x -> 0.789x (0.751-0.790) avc/extract/16384 0.382x -> 0.302x (0.295-0.307) hevc/extract/16384 0.397x -> 0.302x (0.297-0.305) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zackees
force-pushed
the
perf/1302-nal-extract-alloc
branch
from
October 18, 2026 16:13
57a11b7 to
57b0965
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked: on #1414 (the first two commits). Review only the last two commits; I rebase this PR after #1414 merges. It needs #1414 only for the shared counting allocator in the tests (
alloc_count.rs).Fixes #1302
What and why
obs_extract_avc_headersandobs_extract_hevc_headersgrew threeVecs (packet, header, SEI) unit by unit and then copied each one into a newbmallocbuffer: 5 Rust heap allocations for a normal 256-byte keyframe packet. That fixed cost made the 256-byte cases about 1.25x slower than C. The larger cases were already faster than C because of the faster start-code scan.A second scan only to get the output sizes would double the scan cost, so the fix scans once:
nal::SplitUnitsscans the start codes once. It adds up the three output sizes and keeps the ranges of the first 32 units on the stack (encoders write a few units per packet: parameter sets, SEI, slices).for_eachgives the units again from those ranges. For a packet with more units it scans a second time, so it never allocates.packet::write_split_unitsallocates each output withbmallocat its final size and copies every unit straight into it. It panics instead of writing past an output when the units do not add up to the sizes. Empty outputs stay NULL with size 0.avc::bucketandhevc::bucketname the unit classification thatextract_headersused inline.split_headerskeeps itsVecAPI for the tests.No change to the C ABI or to any output byte (unit order, start codes, the packet/header/SEI split,
bmalloc/bfreeownership).RED → GREEN
rust/obs-codec/tests/codec/nal_alloc.rscounts Rust heap allocations on the calling thread (the counter moves toalloc_count.rs, shared with obs-codec: AV1 output shims write straight into their bmalloc buffers (Fixes #1304) #1414'sav1_alloc.rs: one test executable can have only one global allocator). 1/4 pass (the no-start-code guard): AVC and HEVC 5 allocations each for a normal packet, more than one for a packet with very many units.obs-tests-codec(the AVC/HEVC parity proptests are unchanged), clippy-D warnings,cargo bench ... -- --testfixture checks. Tier 2 runs in PR CI.record.pyoptions, only theextract/cases, 5 paired passes before and after, same host (Apple M1 Max) and load. Median Rust/C and paired range:avc/extract/256hevc/extract/256avc/extract/16384hevc/extract/16384av1/extract/256(not changed here)av1/extract/16384(not changed here)The 256-byte regression was stable on this host (the issue's wide ranges came from a shared host). Both cases are now below C.
Checklist
master(or the description starts with a Stacked: note)docs/features.mdis added or updated (not applicable: no user-visible change; the Rust libobs is not shipped by default)-W..., ratchets): not applicable🤖 Generated with Claude Code