fix(video): fall back to SDR when HDR isn't supported - #5429
Conversation
|
Thank you for the PR submission, but it looks like you used AI to create this PR. Please read and follow our Contributing guidelines and specifically our AI Usage policy. Additionally, please update the PR to use the correct template. You can find it at https://github.com/LizardByte/.github/blob/master/.github/pull_request_template.md?plain=1 |
|
Hi @ReenigneArcher , fair callout, and sorry for the friction. To be clear about what AI was actually used for here:
Should have disclosed all this and used the template from the start instead of after the fact. Let me know if anything else needs fixing before this gets a real look. |
|
Thanks for the clarification. And to clarify on my side, using AI is no problem. I just do not want to have a discussion with LLMs in PR reviews or read scientific reports for PR descriptions (often far longer than the actual changes to the code). Anyway, the PR seems fine to me. Thanks! |
|
When a client requests HDR (dynamicRange) but the active capture/encode device combination can't deliver it (e.g. NvFBC's CUDA path on Linux, which only ever produces NV12/YUV444P frames regardless of what the encoder itself supports), make_avcodec_encode_session() failed the whole session instead of falling back to SDR like H.264 already does by design. Since the client doesn't learn that its request was rejected, it just reconnects and asks for the same unsupported HDR config again, forever - visible as an infinite Creating encoder [hevc_nvenc] retry loop, even though each individual attempt actually fails cleanly. This introduces a local, possibly-downgraded dynamicRange flag that falls back to SDR (matching colorspace/bit depth) instead of aborting the session when the requested dynamic range isn't supported for the active chroma sampling mode. The startup capability probe is unaffected, since it calls this same function before the capability flag has been determined.
a4dae4d to
0885101
Compare
Bundle ReportBundle size has no change ✅ |
Centralizes dynamic-range negotiation in a new `resolve_dynamic_range` helper that normalizes client video config against probed encoder capabilities before capture starts. Encoder setup now treats unsupported HDR requests as invalid (instead of downgrading in-place), since fallback to SDR is handled earlier and consistently. Added parameterized unit tests covering codec/chroma capability combinations, SDR passthrough, and preservation of non-dynamic-range config fields.
6f45e87 to
d116212
Compare
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5429 +/- ##
==========================================
+ Coverage 33.90% 33.94% +0.03%
==========================================
Files 104 104
Lines 25197 25212 +15
Branches 11152 11156 +4
==========================================
+ Hits 8543 8557 +14
- Misses 14399 14862 +463
+ Partials 2255 1793 -462
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 32 files with indirect coverage changes Continue to review full report in Codecov by Harness.
|



Description
When a client requests HDR (
dynamicRange) for HEVC or AV1 but the active capture/encodedevice combination can't actually deliver it,
make_avcodec_encode_session()fails thesession outright (
return nullptr) instead of falling back to SDR the way it already doesfor H.264 (
encoder.h264[DYNAMIC_RANGE]is hardcodedfalse, so H.264 never even attemptsHDR).
On Linux, NvFBC capture always uses the
cuda::cuda_tencode-device class(
src/platform/linux/cuda.cpp), which only ever producesAV_PIX_FMT_NV12/AV_PIX_FMT_YUV444Pframes — no P010/10-bit path, regardless of what the encoder itselfsupports. The sibling class
gl_cuda_vram_t(GL/dmabuf capture path) does supportAV_PIX_FMT_P010LE, so this is a gap specific to the NvFBC+CUDA path, not a hardwarelimitation. Confirmed on an NVIDIA Quadro T1000 (Turing):
ffmpeg -c:v hevc_nvenc -profile:v main10encodes 10-bit HEVC fine outside of Sunshine, but inside Sunshine with
capture = nvfbcanyclient HDR-HEVC request fails with:
Some clients (observed with the LG webOS Moonlight app,
mariotaku/moonlight-tv) don't giveup after the failed session — they silently reconnect and request the same HDR-HEVC config
again, forever. Sunshine fails every attempt cleanly (no loop inside Sunshine itself), but
from the outside it looks like a permanent hang.
This PR makes
make_avcodec_encode_session()downgrade to SDR in place instead of failingthe session, mirroring what H.264 already does: a local
dynamicRangebool starts asconfig.dynamicRange, gets set tofalse(plusencode_device->colorspacecorrected torec709/8-bit) when the YUV444 or 4:2:0 checks find HDR unsupported, and every later use ofconfig.dynamicRangein the function reads this local instead. The startup capability probe(
probe_encoders()/test_yuv420_hdr()) is unaffected, since it already reads the resultingencoder.hevc[DYNAMIC_RANGE]flag and skips advertising HDR when this path degrades it.Screenshot
N/A — server-side encode path change, no UI.
Issues Fixed or Closed
Roadmap Issues
Type of Change
Checklist
Manually verified on real hardware (Quadro T1000, NvFBC capture) and a real client (LG webOS
Moonlight): HDR-HEVC request now logs a
falling back to SDRwarning, the session startssuccessfully, and streaming is stable with zero reconnect loop. HDR still works correctly for
capture paths that support it (unaffected by this change).
AI Usage
See our AI usage policy.