player: fix HEVC color (BT.709 limited range)

The built-in WASM player (frontend/static/vendor/hevcjs/hevc-core.js)
rendered washed-out, green/red-shifted video. Two causes, both fixed:

- VideoFrame path (Chrome): the I420 VideoFrame was created without a
  colorSpace, so the browser defaulted to BT.601 limited -> hue shift,
  and guessed the range -> washout. Set explicit BT.709, fullRange:false.
- WebGL fallback shader: used BT.709 FULL-range coefficients on
  limited-range camera output -> washout/desaturation. Switched to
  BT.709 limited-range conversion ((Y-16)*255/219, chroma centered 128).

VERSION -> 0.0.116.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-01 16:03:30 +05:00
parent 00cfca1a57
commit d1ef54af27
2 changed files with 13 additions and 8 deletions
+1 -1
View File
@@ -1 +1 @@
0.0.115
0.0.116
+12 -7
View File
@@ -286,7 +286,11 @@ var FrameRenderer = class _FrameRenderer {
format: "I420",
codedWidth: w,
codedHeight: h,
timestamp
timestamp,
// Hikvision H.265 — BT.709, TV/limited range. Без явного colorSpace браузер для
// I420 по умолчанию берёт BT.601 (зелёно-красный сдвиг) и неверный диапазон
// (белёсость). Задаём явно, чтобы YUV→RGB шёл по правильной матрице и диапазону.
colorSpace: { primaries: "bt709", transfer: "bt709", matrix: "bt709", fullRange: false }
});
await this._writer.write(videoFrame);
videoFrame.close();
@@ -394,12 +398,13 @@ var FRAGMENT_SRC = `
uniform sampler2D u_texCb;
uniform sampler2D u_texCr;
void main() {
float y = texture2D(u_texY, v_tex).r;
float cb = texture2D(u_texCb, v_tex).r - 0.5;
float cr = texture2D(u_texCr, v_tex).r - 0.5;
float r = y + 1.5748 * cr;
float g = y - 0.1873 * cb - 0.4681 * cr;
float b = y + 1.8556 * cb;
// BT.709 limited range (TV): Y∈[16,235]/255 → (Y-16)*255/219; Cb/Cr∈[16,240]/255 центр 128/255.
float y = (texture2D(u_texY, v_tex).r - 0.0627451) * 1.1643836;
float cb = texture2D(u_texCb, v_tex).r - 0.5019608;
float cr = texture2D(u_texCr, v_tex).r - 0.5019608;
float r = y + 1.7927411 * cr;
float g = y - 0.2132486 * cb - 0.5329093 * cr;
float b = y + 2.1124018 * cb;
gl_FragColor = vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), 1.0);
}
`;