fix(playback): use hev1 when HEVC parameter sets are in-band - #411
Closed
A-wes wants to merge 1 commit into
Closed
Conversation
When stream-copying HEVC into fMP4/HLS, `-tag:v hvc1` asserts that the sample entry carries a complete `HEVCDecoderConfigurationRecord` with VPS, SPS and PPS out-of-band. Some sources — typically WEB-DL repackages from third-party muxers — report extradata that is a bare header-only record with `numOfArrays = 0`, leaving parameter sets in-band in the bitstream. Forcing `hvc1` on those writes an empty 8-byte `hvcC` box, which ExoPlayer-based clients cannot initialise a decoder from. `hev1` degrades gracefully in the same situation. `ffprobe` reports `extradata_size` in its default `-show_streams` output, and per ISO/IEC 14496-15 §8.3.3.1.2 the fixed header of a `HEVCDecoderConfigurationRecord` is exactly 23 bytes, so `extradata_size > 23` is a sound, parsing-free signal for "has real out-of-band parameter sets" — no need to decode the extradata itself. `probe.rs` captures `extradata_size` per HEVC video stream and derives `hevc_params_out_of_band`, exposed as an additive `remux`-namespace field on `MediaStream` (`MediaStreamRemuxExt`, following the existing extension pattern). It is threaded through `TranscodeSession` / `TranscodeParams` / `ProgressiveTranscodeParams` to both `-tag:v` sites via a new `hevc_copy_tag()` helper. The helper defaults to today's `hvc1` whenever the signal is unknown or positive, so a source that works now cannot regress. The HLS master playlist's CODECS attribute follows the same decision, since it has to name the fourcc the segments actually carry — a manifest advertising `hvc1.*` over `hev1` sample entries is rejected by clients that validate CODECS through MSE. `hevc_hls_codec_string()` now takes the tag from its caller: the copy path passes `hevc_copy_tag()`, while the encode path passes `hvc1` unconditionally, because no `-tag:v` is forced there and ffmpeg writes its own `hvc1` regardless of what the source extradata looked like. Note: `-bsf:v extract_extradata` is a commonly cited fix for this symptom and was deliberately not used — it requires Annex-B NAL framing and fails with "No start code is found" against Matroska's length-prefixed HEVC packets, which would break every HEVC copy from an MKV source.
Owner
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.
Hello! So while my 10-bit streams weren't working I tried to use 8-bit alternatives, only to discover that they seem to crash clients too, but this time due to other issue. Unfortunately I do not have deep codecs knowledge, unlike claude, so submitting it as is. Both code in this PR and explanation below are written by Claude. I did verify this fix worked for WEB-DL playback on my NVIDIA Shield
When stream-copying HEVC into fMP4/HLS,
-tag:v hvc1asserts that the sample entry carries a completeHEVCDecoderConfigurationRecordwith VPS, SPS and PPS out-of-band. Some sources — typically WEB-DL repackages from third-party muxers — report extradata that is a bare header-only record withnumOfArrays = 0, leaving parameter sets in-band in the bitstream. Forcinghvc1on those writes an empty 8-bytehvcCbox, which ExoPlayer-based clients cannot initialise a decoder from.hev1degrades gracefully in the same situation.ffprobereportsextradata_sizein its default-show_streamsoutput, and per ISO/IEC 14496-15 §8.3.3.1.2 the fixed header of aHEVCDecoderConfigurationRecordis exactly 23 bytes, soextradata_size > 23is a sound, parsing-free signal for "has real out-of-band parameter sets" — no need to decode the extradata itself.probe.rscapturesextradata_sizeper HEVC video stream and deriveshevc_params_out_of_band, exposed as an additiveremux-namespace field onMediaStream(MediaStreamRemuxExt, following the existing extension pattern). It is threaded throughTranscodeSession/TranscodeParams/ProgressiveTranscodeParamsto both-tag:vsites via a newhevc_copy_tag()helper.The helper defaults to today's
hvc1whenever the signal is unknown or positive, so a source that works now cannot regress.Note:
-bsf:v extract_extradatais a commonly cited fix for this symptom and was deliberately not used — it requires Annex-B NAL framing and fails with "No start code is found" against Matroska's length-prefixed HEVC packets, which would break every HEVC copy from an MKV source.