Commit 21441b3400 for ffmpeg

commit 21441b3400342e1d4d2273f28bddd2368fd0cca4
Author: Charly Morgand-Poyac <charly.morgand-poyac@bbright.com>
Date:   Sat Jul 25 19:37:30 2026 +0200

    avcodec/hevc/filter: fix deblocking offsets taken from the wrong CTB

    Equations 8-348, 8-350 and 8-383 take slice_beta_offset_div2 and
    slice_tc_offset_div2 from the slice that contains the q0,0 sample of the
    edge: the current CTB for a vertical edge, and for a horizontal one the CTB
    that contains the sample group.

    deblocking_filter_CTB() reused whatever the previous loop had left in
    tc_offset and beta_offset instead. Vertical edges could take the left CTB's
    offsets, and each horizontal chroma sample group mixed the offsets of both
    CTBs.

    This only changes the output when a CTB and its left neighbour come from
    slices with different deblocking offsets.

    Fixes: 65746bfbae3d1077656b48820f0c18c5703e34f7 (hevc_filter: run vertical and horizontal together)
    Fixes: fa0506e4136b5b883205c82809a113f5edcd200b (hevc/rext: update boundary strength for chroma deblocking filter)
    Signed-off-by: Charly Morgand-Poyac <charly.morgand-poyac@bbright.com>

diff --git a/libavcodec/hevc/filter.c b/libavcodec/hevc/filter.c
index aee73df034..a4f1b24db7 100644
--- a/libavcodec/hevc/filter.c
+++ b/libavcodec/hevc/filter.c
@@ -540,14 +540,13 @@ static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext *
     if (y_end > sps->height)
         y_end = sps->height;

-    tc_offset   = cur_tc_offset;
-    beta_offset = cur_beta_offset;
-
     x_end2 = x_end;
     if (x_end2 != sps->width)
         x_end2 -= 8;
     for (y = y0; y < y_end; y += 8) {
         // vertical filtering luma
+        tc_offset   = cur_tc_offset;
+        beta_offset = cur_beta_offset;
         for (x = x0 ? x0 : 8; x < x_end; x += 8) {
             const int bs0 = l->vertical_bs[(x +  y      * l->bs_width) >> 2];
             const int bs1 = l->vertical_bs[(x + (y + 4) * l->bs_width) >> 2];
@@ -622,8 +621,8 @@ static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext *
                         const int qp1 = (get_qPy(sps, l->qp_y_tab, x - 1, y + (4 * v)) +
                                          get_qPy(sps, l->qp_y_tab, x,     y + (4 * v)) + 1) >> 1;

-                        c_tc[0] = (bs0 == 2) ? chroma_tc(pps, sps, qp0, chroma, tc_offset) : 0;
-                        c_tc[1] = (bs1 == 2) ? chroma_tc(pps, sps, qp1, chroma, tc_offset) : 0;
+                        c_tc[0] = (bs0 == 2) ? chroma_tc(pps, sps, qp0, chroma, cur_tc_offset) : 0;
+                        c_tc[1] = (bs1 == 2) ? chroma_tc(pps, sps, qp1, chroma, cur_tc_offset) : 0;
                         src       = &data[chroma][(y >> sps->vshift[chroma]) * linesize[chroma] + ((x >> sps->hshift[chroma]) << sps->pixel_shift)];
                         if (pcmf) {
                             no_p[0] = get_pcm(sps, l->is_pcm, x - 1, y);
@@ -642,7 +641,6 @@ static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext *
                     continue;

                 // horizontal filtering chroma
-                tc_offset = x0 ? left_tc_offset : cur_tc_offset;
                 x_end2 = x_end;
                 if (x_end != sps->width)
                     x_end2 = x_end - 8 * h;
@@ -650,13 +648,14 @@ static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext *
                     const int bs0 = l->horizontal_bs[( x          + y * l->bs_width) >> 2];
                     const int bs1 = l->horizontal_bs[((x + 4 * h) + y * l->bs_width) >> 2];
                     if ((bs0 == 2) || (bs1 == 2)) {
+                        const int off = x >= x0 ? cur_tc_offset : left_tc_offset;
                         const int qp0 = bs0 == 2 ? (get_qPy(sps, l->qp_y_tab, x,           y - 1) +
                                                     get_qPy(sps, l->qp_y_tab, x,           y)     + 1) >> 1 : 0;
                         const int qp1 = bs1 == 2 ? (get_qPy(sps, l->qp_y_tab, x + (4 * h), y - 1) +
                                                     get_qPy(sps, l->qp_y_tab, x + (4 * h), y)     + 1) >> 1 : 0;

-                        c_tc[0]   = bs0 == 2 ? chroma_tc(pps, sps, qp0, chroma, tc_offset)     : 0;
-                        c_tc[1]   = bs1 == 2 ? chroma_tc(pps, sps, qp1, chroma, cur_tc_offset) : 0;
+                        c_tc[0]   = bs0 == 2 ? chroma_tc(pps, sps, qp0, chroma, off) : 0;
+                        c_tc[1]   = bs1 == 2 ? chroma_tc(pps, sps, qp1, chroma, off) : 0;
                         src       = &data[chroma][(y >> sps->vshift[1]) * linesize[chroma] + ((x >> sps->hshift[1]) << sps->pixel_shift)];
                         if (pcmf) {
                             no_p[0] = get_pcm(sps, l->is_pcm, x,           y - 1);