fix(transcoder): codec-aware decoder so an HEVC source stops crash-looping the subprocess#15
Merged
Merged
Conversation
…oping the subprocess The transcoder always built an H.264 decoder at startup and never changed it. A raw-TS source whose video is HEVC — or an established stream whose upstream mux switches H.264→HEVC mid-session — fed H.265 NAL units into the H.264 decoder, which returns AVERROR_INVALIDDATA on every packet. The supervisor escalated that to a terminal error and respawned, hit the same first frame, and respawned again: a permanent per-stream crash loop with restart_count climbing and no transcoded output. On GPU hosts the cuvid parser instead produced silent black/audio-only. Either mode was permanent. Make decoder selection codec-aware. Both decode paths now call ensureVideoDecoder before handing the frame to the decoder: when the active decoder's family differs from the incoming codec it flushes the old decoder through the surviving encoder, rebuilds via newDecoderWithFallback using a codec-and-lane-aware name (H.265 → hevc / hevc_cuvid, preserving the GPU vs CPU lane of the current decoder; cuvid degrades to CPU if NVDEC can't open it), rebinds the GPU scale graphs to the new decoder's CUDA pool, and resets the keyframe gate so decode resumes on the new codec's first IRAP. The encoder is never rebuilt — it operates on decoded frames and is codec-agnostic — so the output stream stays continuous. This handles both HEVC-from-first-frame and a mid-stream codec switch. The AV-path keyframe gate is now codec-aware too (HEVC IRAP detection); the raw-TS path already tagged keyframes per codec at demux. When HEVC decode is genuinely unavailable in the linked libav, the rebuild surfaces one descriptive error instead of the opaque invalid-data respawn loop. Tests: TestDecoderCodecFamily, TestVideoDecoderNameForCodec, TestEnsureVideoDecoder_NoRebuildPaths, TestIsVideoKeyframeAnnexB.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
Problem (audit A-3, HIGH)
The transcoder built an H.264 decoder at startup and never changed it. A raw-TS source (UDP / HLS-pull / SRT / file) whose video is HEVC — or an established stream whose upstream mux switches H.264→HEVC mid-session — fed H.265 NAL units into the H.264 decoder, which returns
AVERROR_INVALIDDATAon every packet. The supervisor escalated that to a terminal error → respawn → same first frame → respawn again: a permanent per-stream crash loop (restart_countclimbing, no transcoded output). On NVENC hosts the cuvid parser instead produced silent black / audio-only. Either mode was permanent; only a manual restart "recovered" (into the same loop).Fix
Make decoder selection codec-aware. Both decode paths (
ProcessPacketAV-path anddecodeAndEncodeESFramesraw-TS path) now callensureVideoDecoder(codec)before handing the frame to the decoder. When the active decoder's family (decoderCodecFamily) differs from the incoming codec it:newDecoderWithFallbackusingvideoDecoderNameForCodec—esCodecH265 → hevc/hevc_cuvid, preserving the GPU (cuvid) vs CPU lane of the current decoder; cuvid degrades to CPU if NVDEC can't open it,MarkSourceChanged, same asswitchInputGPU),The encoder is never rebuilt — it operates on decoded YUV/CUDA frames and is codec-agnostic — so the output stream stays continuous. This handles HEVC-from-first-frame and a mid-stream H.264→HEVC switch. The AV-path keyframe gate is now codec-aware too (
isVideoKeyframeAnnexB→ HEVC IRAP detection); the raw-TS path already taggedf.keyframeper codec at demux time.If HEVC decode is genuinely unavailable in the linked libavcodec, the rebuild surfaces one descriptive error (
decoder "hevc" not available…) instead of the opaque invalid-data respawn loop.Test
TestDecoderCodecFamily,TestVideoDecoderNameForCodec(incl. GPU/CPU-lane preservation),TestEnsureVideoDecoder_NoRebuildPaths(hot-path no-op decisions),TestIsVideoKeyframeAnnexB(codec-aware gate + dispatch divergence).go test -race ./internal/transcoder/native/green,golangci-lint0 issues, fullgo build ./...green.