Commit 283197ce11 for ffmpeg

commit 283197ce1107afe182be91cff0fb4b4e00bfb106
Author: Joss Gray <joss@jossgray.net>
Date:   Sun Jul 12 14:49:49 2026 -0400

    avcodec/notchlc: fix alpha block decoding

    Alpha ramp blocks read their endpoint pair and selector word once per
    16x16 macroblock and then consumed only three selector bits per 4x4 block,
    so every pixel of a block shared one selector and fifteen of the sixteen
    blocks decoded from the wrong data. Read the 64-bit alpha word inside the
    ramp case, once per 4x4 block, and advance the selector after every
    sample.

    The ramp mapping also dropped its divisor: alpha0 + (alpha1 - alpha0) *
    selector scales the endpoint difference by up to seven instead of
    interpolating between the endpoints. Divide by seven, rounding up, as the
    chroma ramps already do.

    Write the interpolation as the non-negative weighted sum
    (alpha0 * (7 - selector) + alpha1 * selector + 6) / 7 rather than the
    equivalent difference form. The difference form has a negative dividend
    when alpha1 < alpha0, and C truncation toward zero then inverts the
    round-up convention, so selector 7 reconstructs alpha1 + 1 instead of
    alpha1. The weighted sum rounds up regardless of endpoint ordering and
    reconstructs both endpoints exactly. Both forms are bit-identical for
    alpha0 <= alpha1; the NotchLC Adobe CC plugin was not observed to emit
    descending pairs, so this only affects streams with descending endpoints.

diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c
index 396089254e..3d23c4e743 100644
--- a/libavcodec/notchlc.c
+++ b/libavcodec/notchlc.c
@@ -298,7 +298,7 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p,
             for (int x = 0; x < avctx->width; x += 16) {
                 unsigned m = bytestream2_get_le32(gb);
                 unsigned offset = bytestream2_get_le32(gb);
-                unsigned alpha0, alpha1;
+                int alpha0, alpha1;
                 uint64_t control;

                 if (offset >= UINT_MAX / 4)
@@ -308,10 +308,6 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p,
                     return AVERROR_INVALIDDATA;

                 bytestream2_seek(&dgb, offset, SEEK_SET);
-                control = bytestream2_get_le64(&dgb);
-                alpha0 = control & 0xFF;
-                alpha1 = (control >> 8) & 0xFF;
-                control = control >> 16;

                 for (int by = 0; by < 4; by++) {
                     for (int bx = 0; bx < 4; bx++) {
@@ -331,9 +327,16 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p,
                             }
                             break;
                         case 2:
+                            control = bytestream2_get_le64(&dgb);
+                            alpha0 = control & 0xFF;
+                            alpha1 = (control >> 8) & 0xFF;
+                            control >>= 16;
                             for (int i = 0; i < 4; i++) {
                                 for (int j = 0; j < 4; j++) {
-                                    dsta[x + (i + by * 4) * alinesize + bx * 4 + j] = (alpha0 + (alpha1 - alpha0) * (control & 7)) << 4;
+                                    const int selector = control & 7;
+
+                                    dsta[x + (i + by * 4) * alinesize + bx * 4 + j] = ((alpha0 * (7 - selector) + alpha1 * selector + 6) / 7) << 4;
+                                    control >>= 3;
                                 }
                             }
                             break;
@@ -341,7 +344,6 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p,
                             return AVERROR_INVALIDDATA;
                         }

-                        control >>= 3;
                         m >>= 2;
                     }
                 }