This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit bc1cf21643f6cb63c0756268f61bf33ebd0b8712
Author:     Lynne <[email protected]>
AuthorDate: Sun Sep 20 15:17:17 2026 +0900
Commit:     Lynne <[email protected]>
CommitDate: Sun Sep 20 16:46:07 2026 +0900

    prores_raw: end a component at 32 zero bits, like the reference decoder
    
    The reference decoder reads every symbol from a 32-bit window that is
    zero-filled past the end of the component's data, and stops decoding the
    component as soon as that window is all zero. Both our decoders checked for
    remaining bits instead, and near the end of the data decoded a zero symbol
    from a short window and stored spurious coefficients of magnitude 1 at the
    end of the last blocks of a tile. The software decoder also ran one
    coefficient past the end of the block array. Decode the way the reference
    does, in both, so their coefficients match it, and each other.
---
 libavcodec/prores_raw.c                       | 81 +++++++++++++-----------
 libavcodec/vulkan/prores_raw_decode.comp.glsl | 88 +++++++++++++++++----------
 2 files changed, 100 insertions(+), 69 deletions(-)

diff --git a/libavcodec/prores_raw.c b/libavcodec/prores_raw.c
index 0b8fc6ac15..f3efb83010 100644
--- a/libavcodec/prores_raw.c
+++ b/libavcodec/prores_raw.c
@@ -67,16 +67,28 @@ static av_cold int decode_init(AVCodecContext *avctx)
     return 0;
 }
 
-static uint16_t get_value(GetBitContext *gb, int16_t codebook)
+/* Decodes a symbol from the next 32 bits, zero-filled past the end of the
+ * data. Returns a negative value once those are all zero, which is where
+ * the reference decoder stops decoding a component. */
+static av_always_inline int get_value(GetBitContext *gb, int16_t codebook)
 {
-    const int16_t switch_bits = codebook >> 8;
-    const int16_t rice_order  = codebook & 0xf;
-    const int16_t exp_order   = (codebook >> 4) & 0xf;
-    int16_t q, bits;
+    const int switch_bits = codebook >> 8;
+    const int rice_order  = codebook & 0xf;
+    const int exp_order   = (codebook >> 4) & 0xf;
+    int left = get_bits_left(gb);
+    uint32_t b;
+    int q, bits;
 
-    uint32_t b = show_bits_long(gb, 32);
+    b = show_bits_long(gb, 32);
+    if (left < 32) {
+        /* The reader has read past the end of the data; mask that off */
+        if (left <= 0)
+            return -1;
+        b &= 0xFFFFFFFFu << (32 - left);
+    }
     if (!b)
-        return 0;
+        return -1;
+
     q = ff_clz(b);
 
     if (b & 0x80000000) {
@@ -90,9 +102,10 @@ static uint16_t get_value(GetBitContext *gb, int16_t 
codebook)
                 (((b << (q + 1)) >> 1) >> (31 - rice_order));
     }
 
+    /* No valid code is longer than the window */
     bits = exp_order + (q << 1) - switch_bits;
     if (bits > 32)
-        return 0; // we do not return a negative error code so that we dont 
produce out of range values on errors
+        return -1;
     skip_bits_long(gb, bits);
     return (b >> (32 - bits)) +
            ((switch_bits + 1) << rice_order) -
@@ -146,11 +159,11 @@ static int decode_comp(AVCodecContext *avctx, TileContext 
*tile,
 
     LOCAL_ALIGNED_32(int32_t, block, [64*16]);
 
-    int16_t sign = 0;
-    int16_t dc_add = 0;
+    int sign = 0;
+    int dc_add = 0;
     int16_t dc_codebook;
 
-    uint16_t ac, rn, ln;
+    int ac, rn, ln;
     int16_t ac_codebook = 49;
     int16_t rn_codebook = 0;
     int16_t ln_codebook = 66;
@@ -169,19 +182,20 @@ static int decode_comp(AVCodecContext *avctx, TileContext 
*tile,
 
     /* Special handling for first block */
     int dc = get_value(&gb, 700);
+    if (dc < 0)
+        goto end;
     int prev_dc = (dc >> 1) ^ -(dc & 1);
-    block[0] = (((dc&1) + (dc>>1) ^ -(int)(dc & 1)) + (dc & 1)) + 1;
+    block[0] = prev_dc + 1;
 
     for (int n = 1; n < nb_blocks; n++) {
-        if (get_bits_left(&gb) <= 0)
-            break;
-
         if ((n & 15) == 1)
             dc_codebook = 100;
         else
             dc_codebook = ff_prores_raw_dc_cb[FFMIN(TODCCODEBOOK(dc), 
DC_CB_MAX)];
 
         dc = get_value(&gb, dc_codebook);
+        if (dc < 0)
+            goto end;
 
         sign = sign ^ dc & 1;
         dc_add = (-sign ^ TODCCODEBOOK(dc)) + sign;
@@ -191,53 +205,48 @@ static int decode_comp(AVCodecContext *avctx, TileContext 
*tile,
         block[n*64] = prev_dc + 1;
     }
 
-    for (int n = nb_blocks; n <= nb_codes;) {
-        if (get_bits_left(&gb) <= 0)
-            break;
-
+    for (int n = nb_blocks; n < nb_codes;) {
         ln = get_value(&gb, ln_codebook);
+        if (ln < 0)
+            goto end;
 
         for (int i = 0; i < ln; i++) {
-            if (get_bits_left(&gb) <= 0)
-                break;
-
-            if ((n + i) >= nb_codes)
-                break;
-
             ac = get_value(&gb, ac_codebook);
+            if (ac < 0)
+                goto end;
             ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
             sign = -get_bits1(&gb);
 
-            idx = scan[(n + i) >> log2_nb_blocks] + (((n + i) & block_mask) << 
6);
+            idx = scan[n >> log2_nb_blocks] + ((n & block_mask) << 6);
             block[idx] = ((ac + 1) ^ sign) - sign;
-        }
 
-        n += ln;
-        if (n >= nb_codes)
-            break;
+            if (++n == nb_codes)
+                goto end;
+        }
 
         rn = get_value(&gb, rn_codebook);
+        if (rn < 0)
+            goto end;
         rn_codebook = ff_prores_raw_rn_cb[FFMIN(rn, RN_CB_MAX)];
 
         n += rn + 1;
         if (n >= nb_codes)
             break;
 
-        if (get_bits_left(&gb) <= 0)
-            break;
-
         ac = get_value(&gb, ac_codebook);
+        if (ac < 0)
+            goto end;
+        ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
+        ln_codebook = ff_prores_raw_ln_cb[FFMIN(ac, LN_CB_MAX)];
         sign = -get_bits1(&gb);
 
         idx = scan[n >> log2_nb_blocks] + ((n & block_mask) << 6);
         block[idx] = ((ac + 1) ^ sign) - sign;
 
-        ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
-        ln_codebook = ff_prores_raw_ln_cb[FFMIN(ac, LN_CB_MAX)];
-
         n++;
     }
 
+end:
     for (int n = 0; n < nb_blocks; n++) {
         uint16_t *ptr = dst + n*16;
         s->prodsp.idct_put_bayer(ptr, linesize, block + n*64, qmat, 
s->lin_curve);
diff --git a/libavcodec/vulkan/prores_raw_decode.comp.glsl 
b/libavcodec/vulkan/prores_raw_decode.comp.glsl
index 3aed23ef7e..a5b9c7b04c 100644
--- a/libavcodec/vulkan/prores_raw_decode.comp.glsl
+++ b/libavcodec/vulkan/prores_raw_decode.comp.glsl
@@ -87,25 +87,47 @@ const int16_t ln_cb[LN_CB_MAX + 1] = {
     I16( 51)
 };
 
+/* Decodes a symbol from the next 32 bits, zero-filled past the end of the
+ * data. Returns a negative value once those are all zero, which is where
+ * the reference decoder stops decoding a component. */
 int get_value(int16_t codebook)
 {
     const int switch_bits = int(codebook >> 8);
     const int rice_order  = int(codebook & I16(0xf));
     const int exp_order   = int((codebook >> 4) & I16(0xf));
+    int left = left_bits(gb);
+    uint b;
+    int q, bits;
 
-    uint32_t b = show_bits(gb, 32);
-    if (expectEXT(b == 0, false))
-        return 0;
-    int q = 31 - findMSB(b);
+    b = show_bits(gb, 32);
+    if (expectEXT(left < 32, false)) {
+        /* The reader has read past the end of the data; mask that off */
+        if (left <= 0)
+            return -1;
+        b &= 0xFFFFFFFFu << (32 - left);
+    }
+    if (expectEXT(b == 0u, false))
+        return -1;
+
+    q = 31 - findMSB(b);
+
+    /* No symbol is longer than the 32 bits show_bits() just made valid */
+    if ((b & 0x80000000u) != 0u) {
+        skip_bits_unchecked(gb, 1 + rice_order);
+        return int((b & 0x7FFFFFFFu) >> (31 - rice_order));
+    }
 
     if (q <= switch_bits) {
-        skip_bits_unchecked(gb, q + rice_order + 1);
+        skip_bits_unchecked(gb, 1 + rice_order + q);
         return int((q << rice_order) +
                    (((b << (q + 1)) >> 1) >> (31 - rice_order)));
     }
 
-    int bits = exp_order + (q << 1) - switch_bits;
-    skip_bits(gb, bits);
+    /* No valid code is longer than the window */
+    bits = exp_order + (q << 1) - switch_bits;
+    if (expectEXT(bits > 32, false))
+        return -1;
+    skip_bits_unchecked(gb, bits);
     return int((b >> (32 - bits)) +
                ((switch_bits + 1) << rice_order) -
                (1 << exp_order));
@@ -119,7 +141,8 @@ void store_val(ivec2 offs, int blk, int c, int16_t v)
                ivec4(v & 0xFFFF));
 }
 
-void read_dc_vals(ivec2 offs, int nb_blocks)
+/* Returns true if the decoding of the component ended */
+bool read_dc_vals(ivec2 offs, int nb_blocks)
 {
     int dc;
     int dc_add;
@@ -128,13 +151,12 @@ void read_dc_vals(ivec2 offs, int nb_blocks)
 
     /* Special handling for first block */
     dc = get_value(I16(700));
+    if (dc < 0)
+        return true;
     prev_dc = (dc >> 1) ^ -(dc & 1);
     store_val(offs, 0, 0, I16(prev_dc));
 
     for (int n = 1; n < nb_blocks; n++) {
-        if (expectEXT(left_bits(gb) <= 0, false))
-            break;
-
         int16_t dc_codebook;
         if ((n & 15) == 1)
             dc_codebook = I16(100);
@@ -142,6 +164,8 @@ void read_dc_vals(ivec2 offs, int nb_blocks)
             dc_codebook = I16(dc_cb[min(TODCCODEBOOK(dc), 13 - 1)]);
 
         dc = get_value(dc_codebook);
+        if (dc < 0)
+            return true;
 
         sign ^= dc & 1;
         dc_add = (-sign ^ TODCCODEBOOK(dc)) + sign;
@@ -150,6 +174,8 @@ void read_dc_vals(ivec2 offs, int nb_blocks)
 
         store_val(offs, n, 0, I16(prev_dc));
     }
+
+    return false;
 }
 
 void read_ac_vals(ivec2 offs, int nb_blocks)
@@ -165,48 +191,44 @@ void read_ac_vals(ivec2 offs, int nb_blocks)
     int sign;
     int16_t val;
 
-    for (int n = nb_blocks; n <= nb_codes;) {
-        if (expectEXT(left_bits(gb) <= 0, false))
-            break;
-
+    for (int n = nb_blocks; n < nb_codes;) {
         ln = get_value(ln_codebook);
-        int loop_end = min(ln, nb_codes - n);
-        for (int i = 0; i < loop_end; i++) {
-            if (expectEXT(left_bits(gb) <= 0, false))
-                break;
+        if (ln < 0)
+            return;
 
+        for (int i = 0; i < ln; i++) {
             ac = get_value(ac_codebook);
+            if (ac < 0)
+                return;
             ac_codebook = ac_cb[min(ac, 95 - 1)];
             sign = -int(get_bit(gb));
 
             val = I16(((ac + 1) ^ sign) - sign);
             store_val(offs, n & block_mask, n >> log2_nb_blocks, val);
 
-            n++;
+            if (++n == nb_codes)
+                return;
         }
 
-        if (expectEXT(n >= nb_codes, false))
-            break;
-
         rn = get_value(rn_codebook);
+        if (rn < 0)
+            return;
         rn_codebook = rn_cb[min(rn, 28 - 1)];
 
         n += rn + 1;
-        if (expectEXT(n >= nb_codes, false))
-            break;
-
-        if (expectEXT(left_bits(gb) <= 0, false))
-            break;
+        if (n >= nb_codes)
+            return;
 
         ac = get_value(ac_codebook);
+        if (ac < 0)
+            return;
+        ac_codebook = ac_cb[min(ac, 95 - 1)];
+        ln_codebook = ln_cb[min(ac, 15 - 1)];
         sign = -int(get_bit(gb));
 
         val = I16(((ac + 1) ^ sign) - sign);
         store_val(offs, n & block_mask, n >> log2_nb_blocks, val);
 
-        ac_codebook = ac_cb[min(ac, 95 - 1)];
-        ln_codebook = ln_cb[min(ac, 15 - 1)];
-
         n++;
     }
 }
@@ -239,6 +261,6 @@ void main(void)
     init_get_bits(gb, u8buf(pkt_offset + header_len + comp_offset[COMP_ID]),
                   size[COMP_ID]);
 
-    read_dc_vals(offs, nb_blocks);
-    read_ac_vals(offs, nb_blocks);
+    if (!read_dc_vals(offs, nb_blocks))
+        read_ac_vals(offs, nb_blocks);
 }

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to