[PR] avcodec/hevc/filter: take the deblocking offsets from the q0,0 slice (PR #23916)
charlymp via ffmpeg-devel <[email protected]> Sat, 25 Jul 2026 17:48:44 -0000
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <178500172646.59.9149773776290846700@29965ddac10e> |
PR #23916 opened by charlymp URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23916 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23916.patch Equations 8-348 and 8-350 (luma) and 8-383 (chroma) all read slice_beta_offset_div2 and slice_tc_offset_div2 from the slice that contains the q0,0 sample of the edge being filtered. That is the current CTB for a vertical edge, and the CTB that contains x for a horizontal one, both of its 4 sample groups included. deblocking_filter_CTB() does not derive them: it reuses whatever the loop that ran before left in the shared tc_offset/beta_offset variables. As a result the vertical edges of a CTB can be filtered with the left neighbour's offsets, the first sample group of a horizontal chroma edge uses them everywhere, and Cb and Cr can even end up with different offsets on the first row of a CTB. This only changes the output when a CTB and its left neighbour disagree on the slice deblocking offsets, which needs a slice or tile boundary inside a CTB row with different slice_beta_offset_div2 / slice_tc_offset_div2 on either side. >From 0a7d0bd8a80f1e08a68072c97a68abafdf380e41 Mon Sep 17 00:00:00 2001 From: Charly Morgand-Poyac <[email protected]> Date: Sat, 25 Jul 2026 19:37:30 +0200 Subject: [PATCH] avcodec/hevc/filter: take the deblocking offsets from the q0,0 slice 8.7.2.5.3 and 8.7.2.5.5 read slice_beta_offset_div2 and slice_tc_offset_div2 from the slice that contains the q0,0 sample: the current CTB for a vertical edge, the CTB that contains x for a horizontal one. deblocking_filter_CTB() reused whatever the previous loop had left in tc_offset instead, so vertical edges could take the left neighbour's offsets, and the first sample group of a horizontal chroma edge took them everywhere. Signed-off-by: Charly Morgand-Poyac <[email protected]> --- libavcodec/hevc/filter.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libavcodec/hevc/filter.c b/libavcodec/hevc/filter.c index e897ad5d58..6753e4a528 100644 --- a/libavcodec/hevc/filter.c +++ b/libavcodec/hevc/filter.c @@ -548,6 +548,8 @@ static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext * 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 +624,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 +644,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 +651,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); -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]