perf(fmp4): box parsing - #7956
Open
itsjamie wants to merge 8 commits into
Open
Conversation
Compare four-byte MP4 box types numerically and carry path offsets through a single recursive search. This avoids temporary strings, subarrays, and path slices during every box traversal. Chromium: CPU improvement: +47.63% (21.599us -> 11.312us) Live heap equivalent: -0.18% (11033.592kb -> 11053.794kb) Wall-time improvement: +45.27% (24.251us -> 13.272us) Anchor drift: -0.28% Firefox: CPU improvement: +51.26% (68.789us -> 33.531us) Live heap equivalent: -0.02% (8937.115kb -> 8938.976kb) Wall-time improvement: +51.28% (68.454us -> 33.347us) Anchor drift: +0.00% WebKit: CPU improvement: +58.74% (50.999us -> 21.041us) Live heap equivalent: +0.03% (7420.412kb -> 7418.292kb) Wall-time improvement: +58.66% (60.177us -> 24.876us) Anchor drift: +1.19% Tests: npm run test:unit; npm run type-check; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-607fd7ce05db7aff6945bd7148a98d31f5777e5128827a879c63c115dbb9dcf1
Make detailed trun sample objects optional and disable them for normal passthrough remuxing. I-frame remuxing retains the existing detail path, and the public helper default remains unchanged. Chromium: CPU inconclusive: +3.48% (11.312us -> 10.918us) Live heap equivalent: -0.03% (11053.794kb -> 11057.34kb) Wall-time inconclusive: +5.23% (13.272us -> 12.578us) Anchor drift: -0.25% Firefox: CPU improvement: +5.46% (33.531us -> 31.699us) Live heap equivalent: -0.00% (8938.976kb -> 8939.095kb) Wall-time inconclusive: +5.34% (33.347us -> 31.567us) Anchor drift: -1.43% WebKit: CPU improvement: +10.39% (21.041us -> 18.855us) Live heap equivalent: -0.00% (7418.292kb -> 7418.555kb) Wall-time improvement: +10.08% (24.876us -> 22.369us) Anchor drift: -3.92% Tests: npm run test:unit; npm run type-check; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-6d5257ae7abdec0a3fc40b0531ee7623c6217ff69676ec6ca5704b2c4197ad4a
Read box sizes and four-byte types directly from the source array inside findBox. This removes helper calls and packed integer comparisons from the hottest traversal loop. Chromium: CPU equivalent: +1.50% (10.918us -> 10.754us) Live heap equivalent: -0.06% (11057.34kb -> 11064.134kb) Wall-time equivalent: +0.86% (12.578us -> 12.47us) Anchor drift: +0.00% Firefox: CPU equivalent: +0.61% (31.699us -> 31.505us) Live heap equivalent: -0.01% (8939.095kb -> 8939.839kb) Wall-time equivalent: +0.71% (31.567us -> 31.343us) Anchor drift: +1.45% WebKit: CPU improvement: +9.80% (18.855us -> 17.007us) Live heap equivalent: -0.08% (7418.555kb -> 7424.614kb) Wall-time improvement: +9.23% (22.369us -> 20.304us) Anchor drift: +4.89% Tests: npm run test:unit; npm run type-check; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-b9a40fddc890735bbf56ee1191a51617e625af4188fa9e28e5a315a26e719c39
Parse video sample timing and SEI messages in one fragment pass and cache the timing result for passthrough remuxing. This avoids walking the same fMP4 samples again on the normal transmux path. When initialization data or chunk metadata is unavailable, fall back to the standalone parseSamples() SEI scan. Existing demuxer call signatures remain valid and metadata event payloads are unchanged. Chromium: CPU inconclusive: +6.74% (10.754us -> 10.029us) Live heap equivalent: -0.18% (11064.134kb -> 11084.145kb) Wall-time improvement: +7.03% (12.47us -> 11.593us) Anchor drift: -0.53% Firefox: CPU inconclusive: +1.26% (31.505us -> 31.108us) Live heap equivalent: -0.12% (8939.839kb -> 8950.293kb) Wall-time inconclusive: +1.19% (31.343us -> 30.972us) Anchor drift: -1.59% WebKit: CPU inconclusive: +0.00% (17.007us -> 17.006us) Live heap equivalent: -0.02% (7424.614kb -> 7426.069kb) Wall-time inconclusive: +0.30% (20.304us -> 20.243us) Anchor drift: -2.15% Tests: npm run test:unit; npm run type-check; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-ff55b1ed04ebcda21221debbc76d0f159db0db16270e21213e1ca02b145ae342
Build unsigned 32-bit MP4 values directly instead of routing every read through the signed helper. This removes a nested call from box, timing, and sample-size parsing. Chromium: CPU equivalent: +1.90% (10.029us -> 9.839us) Live heap equivalent: +0.02% (11084.145kb -> 11082.352kb) Wall-time equivalent: +2.07% (11.593us -> 11.353us) Anchor drift: -0.34% Firefox: CPU improvement: +5.18% (31.108us -> 29.498us) Live heap equivalent: -0.00% (8950.293kb -> 8950.329kb) Wall-time improvement: +5.26% (30.972us -> 29.344us) Anchor drift: +0.29% WebKit: CPU improvement: +11.63% (17.006us -> 15.028us) Live heap equivalent: +0.10% (7426.069kb -> 7418.892kb) Wall-time improvement: +9.75% (20.243us -> 18.27us) Anchor drift: +1.10% Tests: npm run test:unit; npm run type-check; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-d1516adeffeb5d7d28728959d6c943b912af06a8326100dc8fc30082779b089a
Reuse parsed init metadata, scan moof and traf children once, and specialize the common no-detail CMAF trun layout. Guarded compact size reads, constant-duration aggregation, and native EPB search remove work while uncommon layouts continue through the general parser. Chromium: CPU improvement: +6.72% (9.839us -> 9.178us) Live heap equivalent: -0.59% (11082.352kb -> 11148.085kb) Wall-time improvement: +6.32% (11.353us -> 10.635us) Anchor drift: +0.61% Firefox: CPU improvement: +6.47% (29.498us -> 27.589us) Live heap equivalent: -0.14% (8950.329kb -> 8962.675kb) Wall-time improvement: +6.48% (29.344us -> 27.444us) Anchor drift: +0.00% WebKit: CPU improvement: +7.95% (15.028us -> 13.833us) Live heap equivalent: -0.32% (7418.892kb -> 7442.757kb) Wall-time improvement: +8.75% (18.270us -> 16.672us) Anchor drift: +0.31% Tests: npm run test:unit; npm run type-check; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-ad3d19dafc554017f9b08b57f23b81aee89126722dc14fd01a7352ff1453a29c
Flatten moof and traf discovery, reuse a UTF-8 decoder, defer keyframe and EOF work, and scan NAL units with absolute sample ends. Tracking duration presence directly removes repeated allocation and branching while preserving SEI event fields and raw payload bytes. Chromium: CPU improvement: +5.39% (9.160us -> 8.667us) Live heap equivalent: +0.01% (11148.062kb -> 11147.321kb) Wall-time improvement: +5.54% (10.603us -> 10.015us) Anchor drift: -0.53% Firefox: CPU improvement: +6.66% (27.552us -> 25.716us) Live heap equivalent: -0.00% (8962.679kb -> 8962.934kb) Wall-time improvement: +6.66% (27.396us -> 25.571us) Anchor drift: +0.00% WebKit: CPU improvement: +5.15% (13.777us -> 13.067us) Live heap equivalent: +0.09% (7442.659kb -> 7436.056kb) Wall-time inconclusive: +3.98% (16.553us -> 15.895us) Anchor drift: -0.47% Tests: npm run test:unit (1144); npm run type-check; API Extractor; bperf exact checks Bperf-Benchmark: hlsjs.fmp4-box-parsing Bperf-Cycle: cycle-43ec7fa74936d6a0eea57b950d3af10bcd5538e83294303dbdbb49c94a8da4a4
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.
This PR will...
Reduce the CPU and wall time spent parsing fragmented MP4 content in
MP4DemuxerandPassThroughRemuxer.findBoxnow reads box headers and compares four-byte box types directly fromthe source array. Fragment parsing reuses parsed init metadata, flattens
moof/trafdiscovery, specializes the common CMAFtrunlayout, and avoidscreating detailed sample objects unless I-frame remuxing requires them.
Video sample timing and SEI extraction now share one fragment pass. The parsed
timing is handed to passthrough remuxing through a one-shot private cache. When
initialization data or chunk metadata is unavailable, the demuxer falls back to
the standalone
parseSamples()SEI scan. Existing call signatures and metadataevent payloads remain unchanged.
For the complete 60-second video VOD transmux, the overall changes are:
The headline result uses only the complete
video-vod-transmuxworkload. Itfeeds all 15 video fragments from the Angel One HLS asset over 60 seconds.
Traced through the
Transmuxer,MP4Demuxer, and the smaller parsingcases isolate individual operations for regression checks and per-change
attribution. The complete 60-second audio track is retained as
an end-to-end correctness guardrail.
The checks verify box and track-run counts, 1,500 video samples
Why is this Pull Request needed?
findBoxcreated temporary strings, subarrays, and path slices; the initsegment could be parsed independently by the demuxer and remuxer; and video
fragments were traversed separately for SEI messages and sample timing.
The sample parser also created detailed per-sample structures during normal
passthrough remuxing even though only I-frame remuxing consumes those details.
Moving the common work into direct numeric scans and handing already parsed
data between stages substantially reduces CPU and wall time without changing
the generated media or metadata. I would expect this to be most noticeable on
lower performing devices with a much weaker CPU.
Are there any points in the code the reviewer needs to double check?
The main areas I would like reviewed closely are the fast-path boundaries and
the compact sample path is limited to the common CMAF
trunlayout. Other flagcombinations and multiple track runs continue through the general parser.
I-frame remuxing still requests detailed sample data so that keyframe selection
and duration rewriting retain their existing behavior.
Resolves issues:
N/A