fix(video): honour the client's requested color range - #146
Conversation
12ae524 to
7d2d29d
Compare
|
Related to pixelforge#24. Limited as the SDR default is right, this just makes us read what the client actually asked for instead of assuming it. |
|
@hgaiser two things that might belong in pixelforge rather than here:
|
|
found a regression, putting into WIP for now something is not right when trying to stream it with HDR AV1. the game starts in SDR regardless, then after the first warning screen it switches to HDR, and whole screen gets green. This seems to be unrelated to this PR though. If you reconnect (or new key frame arrives) the stream recovers. upd: doesn't seem to be related to PR. Works fine with HEVC. |
7d2d29d to
bdcb89f
Compare
ad36df4 to
1160f92
Compare
Regarding 1: I agree, it makes sense to make a builder pattern for ColorDescription 👍 |
|
@lutyjj do you want to work on the pixelforge PR before merging this? Also: is_hdr could maybe also be a member function of ColorDescription |
|
@hgaiser yep, will work on it today/tomorrow :) |
From the hgaiser/moonshine#146 review. The presets pin primaries, transfer and matrix as a group, and full range is the only field that changes on its own, so every consumer ends up writing `ColorDescription { full_range, ..ColorDescription::bt2020_pq() }`. `with_full_range` gives that the same shape as the EncodeConfig builders, and ColorDescription is `#[must_use]` now like the other builder types. `is_hdr` moves the "PQ transfer function is what makes the stream HDR" check onto the type instead of every consumer redefining it; the luma range and primaries don't decide it. The H.273 code points the presets use are named constants now instead of bare numbers.
|
@hgaiser pixelforge side is up: hgaiser/pixelforge#30. I see though that moonshine is using old pin of pixelforge and would require a little bit more work to unblock this PR :) |
|
That's fine, it will be updated soon (#116)
…On Sat, 1 Aug 2026, 19:43 Daniil Rylski, ***@***.***> wrote:
*lutyjj* left a comment (hgaiser/moonshine#146)
<#146 (comment)>
@hgaiser <https://github.com/hgaiser> pixelforge side is up:
hgaiser/pixelforge#30 <hgaiser/pixelforge#30>.
I see though that moonshine is using old pin of pixelforge and would
require a little bit more work to unblock this PR :)
—
Reply to this email directly, view it on GitHub
<#146?email_source=notifications&email_token=AAFO22UPVN5P7W7DG7FRWXT5HYT4BA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMJVGI3DCNJXGEYKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-5152615710>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAFO22RNZYCEVMG5AY74WRD5HYT4BAVCNFSNUABFKJSXA33TNF2G64TZHM3TIMJVGY2TSNZZHNEXG43VMU5TKMBRGE2DENZRGQ42C5QC>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AAFO22SZPUMCSMODNGBRQO35HYT4BA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMJVGI3DCNJXGEYKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJKTGN5XXIZLSL5UW64Y>
and Android
<https://github.com/notifications/mobile/android/AAFO22UBWBYGQDEY3UG76335HYT4BA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMJVGI3DCNJXGEYKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>.
Download it today!
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
From the hgaiser/moonshine#146 review. The presets pin primaries, transfer and matrix as a group, and full range is the only field that changes on its own, so every consumer ends up writing `ColorDescription { full_range, ..ColorDescription::bt2020_pq() }`. `with_full_range` gives that the same shape as the EncodeConfig builders, and ColorDescription is `#[must_use]` now like the other builder types. `is_hdr` moves the "PQ transfer function is what makes the stream HDR" check onto the type instead of every consumer redefining it; the luma range and primaries don't decide it. The H.273 code points the presets use are named constants now instead of bare numbers.
7083d1b to
c08c2d5
Compare
The color converter and the encoder VUI both hardcoded limited-range luma, and `x-nv-video[0].encoderCscMode` was never read. A client that requests full range decodes by expanding 16-235 to 0-255, so limited-range data arrives with black lifted to 16 and white capped below 255. Take bit 0 of the attribute as the range request, matching Sunshine's `colorspace_from_client_config`, and thread it to both the converter's quantisation and the VUI so the data and the signal agree. Decide the HDR mode sent over the control stream from the transfer function rather than by comparing the whole `ColorDescription` against `bt2020_pq()`, whose `full_range` is always false. The luma range is independent of whether a stream is HDR, so the struct comparison reported SDR for every full-range HDR session and the client never left SDR. The key-frame SEI gate asks the same question and is deliberately left as a struct comparison: correcting it newly enables AV1 metadata injection for full-range clients, and that path produces streams the client cannot decode. It is tracked separately. The remaining bits of the field select an SDR colorspace. Only Rec.709 is encoded. Rec.601 doubles as the protocol default for clients that never chose one, so it logs quietly; an explicit request for anything else is warned about rather than silently mis-encoded.
with_full_range replaces struct-update syntax at seven sites and the open-coded transfer-function check moves onto the type, as requested in review. Needs a pixelforge pin at or past the commit that added the API (pixelforge PR 30).
No tag past v0.7.2 yet, so pin the merge commit; swap for a tag once one is cut.
c08c2d5 to
6274fe7
Compare
|
Just tested this, works good as far as I can tell. Thanks! |
Fixes #145.
We hardcode
full_range = falsein the color converter and the encoder VUI, and never readx-nv-video[0].encoderCscMode. Some clients ask for full range (mode 3) and decode accordingly, so our limited-range data lands with black at 16 instead of 0.Sunshine reads bit 0 of the same attribute:
colorspace.full_range = (config.encoderCscMode & 0x1);Was noticed before in #46 (
full_range: falsevs the client's forcedPL_COLOR_LEVELS_FULL), and doesn't look like it got fixed in #47.The remaining bits pick an SDR colorspace. We always encode Rec.709, which is fine as long as the VUI says so, so I left that alone but log a warning on an explicit non-709 request. An absent attribute isn't treated as a request.
Steam logo used to be white on a grey background, now white on proper black.