At 10,000 feet

Setting: a video pipeline that encodes live HEVC (H.265) on an NVIDIA Blackwell GPU’s hardware encoder (NVENC) and serves it to browsers as fragmented MP4 via Media Source Extensions (MSE), which binds playback to one codec configuration.

Problem: browser playback would intermittently freeze. The trail led to the codec-configuration bytes themselves.

What this note establishes: every encoder restart emits different HEVC decoder-configuration bytes (the hvcC record) with identical settings - 5-16 distinct configurations per stream across thousands of segments. NVIDIA has reproduced run-to-run nondeterminism in this encoder’s HEVC parameter sets (forum report 2026-01-16, internal bug 5830620, no fixed driver named). The per-restart hvcC counts and the browser consequence are the new part.

Takeaway: mux browser-bound HEVC with -tag:v hvc1, pinning parameter sets out-of-band as Apple’s HLS spec already requires - low-risk and spec-correct even though the drift-causes-freezes link is unproven.

Notes. Measured on one Blackwell-class NVENC GPU feeding HEVC into fragmented MP4 for browser playback, not tried across other Blackwell SKUs, drivers, or ffmpeg versions. No warranty, corrections welcome.

The finding: hvcC bytes drift across encoder restarts

Same GPU, same encoder flags. Each restart (process respawn, watchdog kick, pipeline re-init) produced a new hvcC value, rewriting VPS / SPS / HRD fields. Hashing the hvcC box body across recorded segments:

Stream Segments scanned Distinct hvcC values
A 4623 6
B 3167 5
C 1728 5
D 333 12
E 2865 16

The codec string flip

Separately, a fixed generational difference (not the per-restart drift): Turing emitted hev1.1.2.L150.90, Blackwell hev1.1.6.L150.90 (general_profile_compatibility_flags 0x40 -> 0x60). Same class of surprise: the bytes a browser decoder keys off move across GPU generations and across restarts.

Why this matters for browsers (standard background)

HEVC parameter sets (VPS/SPS/PPS) can live in-band (the hev1 sample-entry tag many muxers pick by default, allowed to change over the stream) or out-of-band only (hvc1, must not change within the track). MSE binds a SourceBuffer to a single decoder configuration, and Apple’s HLS authoring spec requires hvc1 for exactly this reason. Nuance: -tag:v hvc1 is an MP4 sample-entry property - a no-op on TS - so in an encode-to-TS-then-remux pipeline the tag belongs on the remux stage.

The hev1 default is common. go2rtc, a camera-stream relay, writes hev1 for H.265 fragmented MP4 (pkg/iso/codecs.go on master, 2026-09-09). Two PRs switch it to hvc1: #2253 (opened 2026-05-12, no activity since) and #2464 (opened 2026-08-30, closed by its author 2026-09-09 as not fixing his case). Neither has landed.

Honesty

  • Measured: the drift (table above). After applying hvc1: codec_tag_string=hvc1 on fresh segments, and an MP4Box-style container check (the parser class Chrome uses) passed.
  • Not proven: that the drift causes the MSE freezes. Freezes stopped after hvc1 - equally consistent with a genuine fix, with MSE merely tolerating ongoing drift, or with coincidence (few restarts had accumulated yet).
  • Debatable mechanism: a properly authored out-of-band hvc1 configuration arguably should not be sensitive to in-band SPS drift at all. Hold the causal story loosely.
  • Prior art: an NVIDIA developer-forum thread (RTX 5050, driver 580.126.09) reports the HEVC level flipping between 5.1 and 6.2 run to run with level set to auto. Not in it: the hvcC hashing, the per-stream distinct-config counts, the MSE consequence and the Turing-to-Blackwell profile flag flip.

Fallback if hvc1 is not enough (unverified)

Clamp the parameter sets at the bitstream level with the hevc_metadata filter, normalizing every VUI/HRD field to fixed values before muxing.

References

Licensed under the site footer’s CC BY 4.0. If this saved you a debugging session, the optional thanks link in the footer is appreciated, no obligation.