PR #25340 opened by Daniel Brodie (danielbrodie)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25340
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25340.patch

# Summary of changes

`(x << 4) | (x & 0xF)` repeats the low nibble when widening the 8-bit chroma 
endpoints to 12 bits. `(x << 4) | (x >> 4)` replicates the high bits, as #23791 
does for alpha.

Measured against the 16-bit source each file was encoded from (exported by 
Notch's After Effects plugin, 1280x720, every 5th of 300 frames), converted to 
RGB with swscale's default conversion:

| file | before R/G/B (dB) | after R/G/B (dB) | TouchDesigner R/G/B (dB) |
|---|---|---|---|
| flat color, Best, no alpha (with the #25281 fix so it decodes) | 52.9 / 58.1 
/ 51.5 | 57.6 / 63.4 / 55.5 | 57.7 / 63.5 / 55.4 |
| gradient with alpha matte, Optimal | 50.5 / 55.6 / 48.7 | 51.9 / 57.2 / 50.2 
| 52.3 / 58.1 / 52.4 |

On the first file this closes the gap to TouchDesigner. On the second a gap of 
0.4 / 1.0 / 2.2 dB remains; I don't know its cause.

make fate (Windows, MSYS2 MINGW64, full fate-suite): the 15 failures also fail 
on unpatched master.

This conflicts with #23791 in context lines only; I can rebase on whichever 
lands first.

AI disclosure: AI was used for investigation and development of this patch.


>From 8e895910e109b56276a9a7706dbdc3a92a51ceb5 Mon Sep 17 00:00:00 2001
From: Daniel Brodie <[email protected]>
Date: Wed, 21 Oct 2026 14:43:03 -0400
Subject: [PATCH] avcodec/notchlc: replicate the high bits when widening chroma
 endpoints

(x << 4) | (x & 0xF) repeats the low nibble, so 8-bit chroma endpoints
land up to 15 codes off on the 12-bit scale. (x << 4) | (x >> 4) is bit
replication and maps 0..255 exactly onto 0..4095, matching the alpha
expansion.

Signed-off-by: Daniel Brodie <[email protected]>
---
 libavcodec/notchlc.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c
index 396089254e6..3a7c700cc3c 100644
--- a/libavcodec/notchlc.c
+++ b/libavcodec/notchlc.c
@@ -376,10 +376,10 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame 
*p,
                 u1 = bytestream2_get_byte(&dgb);
                 v1 = bytestream2_get_byte(&dgb);
                 loc = bytestream2_get_le32(&dgb);
-                u0 = (u0 << 4) | (u0 & 0xF);
-                v0 = (v0 << 4) | (v0 & 0xF);
-                u1 = (u1 << 4) | (u1 & 0xF);
-                v1 = (v1 << 4) | (v1 & 0xF);
+                u0 = (u0 << 4) | (u0 >> 4);
+                v0 = (v0 << 4) | (v0 >> 4);
+                u1 = (u1 << 4) | (u1 >> 4);
+                v1 = (v1 << 4) | (v1 >> 4);
                 udif = u1 - u0;
                 vdif = v1 - v0;
 
@@ -404,10 +404,10 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame 
*p,
                             u1 = bytestream2_get_byte(&dgb);
                             v1 = bytestream2_get_byte(&dgb);
                             loc = bytestream2_get_le32(&dgb);
-                            u0 = (u0 << 4) | (u0 & 0xF);
-                            v0 = (v0 << 4) | (v0 & 0xF);
-                            u1 = (u1 << 4) | (u1 & 0xF);
-                            v1 = (v1 << 4) | (v1 & 0xF);
+                            u0 = (u0 << 4) | (u0 >> 4);
+                            v0 = (v0 << 4) | (v0 >> 4);
+                            u1 = (u1 << 4) | (u1 >> 4);
+                            v1 = (v1 << 4) | (v1 >> 4);
                             udif = u1 - u0;
                             vdif = v1 - v0;
 
@@ -431,10 +431,10 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame 
*p,
                                     u1 = bytestream2_get_byte(&dgb);
                                     v1 = bytestream2_get_byte(&dgb);
                                     loc = bytestream2_get_le32(&dgb);
-                                    u0 = (u0 << 4) | (u0 & 0xF);
-                                    v0 = (v0 << 4) | (v0 & 0xF);
-                                    u1 = (u1 << 4) | (u1 & 0xF);
-                                    v1 = (v1 << 4) | (v1 & 0xF);
+                                    u0 = (u0 << 4) | (u0 >> 4);
+                                    v0 = (v0 << 4) | (v0 >> 4);
+                                    u1 = (u1 << 4) | (u1 >> 4);
+                                    v1 = (v1 << 4) | (v1 >> 4);
                                     udif = u1 - u0;
                                     vdif = v1 - v0;
 
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to