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

Git pushed a commit to branch master
in repository ffmpeg.

The following commit(s) were added to refs/heads/master by this push:
     new 05c6ee22be lavc/hevcdec: skip boundary strength computation for 
identical MvFields
05c6ee22be is described below

commit 05c6ee22be85faa30dbd08a378e85f3e8ee86093
Author:     Charly Morgand-Poyac <[email protected]>
AuthorDate: Sat Jul 4 18:36:31 2026 +0200
Commit:     michaelni <[email protected]>
CommitDate: Wed Oct 14 13:35:57 2026 +0000

    lavc/hevcdec: skip boundary strength computation for identical MvFields
    
    deblocking_boundary_strengths() runs on the full 8x8 grid without
    knowing the PU partitioning, so on inter content the two MvField
    entries it compares are identical most of the time. When they are
    identical and both sides use the same RefPicList the result is always
    0: same references, zero mv deltas. Check for this first, and compare
    whole edge lines at once in the TU internal loops; anything that does
    not match goes through the unchanged code path.
    
    Up to 3% faster single threaded decoding on 4K inter streams.
    
    Signed-off-by: Charly Morgand-Poyac <[email protected]>
---
 libavcodec/hevc/filter.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 65 insertions(+), 2 deletions(-)

diff --git a/libavcodec/hevc/filter.c b/libavcodec/hevc/filter.c
index 4efe751ea4..aee73df034 100644
--- a/libavcodec/hevc/filter.c
+++ b/libavcodec/hevc/filter.c
@@ -675,6 +675,25 @@ static void deblocking_filter_CTB(const HEVCContext *s, 
const HEVCLayerContext *
     }
 }
 
+static av_always_inline int mvf_equal(const MvField *a, const MvField *b)
+{
+    return !memcmp(a, b, offsetof(MvField, pred_flag) + sizeof(a->pred_flag));
+}
+
+static av_always_inline int mvf_run_equal(const MvField *a, const MvField *b, 
int m)
+{
+    const size_t tail = offsetof(MvField, pred_flag) + sizeof(a->pred_flag);
+
+    switch (m) {
+    case 15: return !memcmp(a, b, 15 * sizeof(*a) + tail);
+    case 12: return !memcmp(a, b, 12 * sizeof(*a) + tail);
+    case  7: return !memcmp(a, b,  7 * sizeof(*a) + tail);
+    case  4: return !memcmp(a, b,  4 * sizeof(*a) + tail);
+    case  3: return !memcmp(a, b,  3 * sizeof(*a) + tail);
+    default: return !memcmp(a, b, tail);
+    }
+}
+
 static int boundary_strength(const HEVCContext *s, const MvField *curr, const 
MvField *neigh,
                              const RefPicList *neigh_refPicList)
 {
@@ -769,6 +788,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext 
*lc, const HEVCLayer
         const RefPicList *rpl_top = (lc->boundary_flags & 
BOUNDARY_UPPER_SLICE) ?
                                     ff_hevc_get_ref_list(s->cur_frame, x0, y0 
- 1) :
                                     s->cur_frame->refPicList;
+        int same_rpl = rpl_top == s->cur_frame->refPicList;
         int yp_pu = (y0 - 1) >> log2_min_pu_size;
         int yq_pu =  y0      >> log2_min_pu_size;
         int yp_tu = (y0 - 1) >> log2_min_tu_size;
@@ -786,6 +806,8 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext 
*lc, const HEVCLayer
                     bs = 2;
                 else if (curr_cbf_luma || top_cbf_luma)
                     bs = 1;
+                else if (same_rpl && mvf_equal(curr, top))
+                    bs = 0;
                 else
                     bs = boundary_strength(s, curr, top, rpl_top);
                 l->horizontal_bs[((x0 + i) + y0 * l->bs_width) >> 2] = bs;
@@ -807,6 +829,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext 
*lc, const HEVCLayer
         const RefPicList *rpl_left = (lc->boundary_flags & 
BOUNDARY_LEFT_SLICE) ?
                                      ff_hevc_get_ref_list(s->cur_frame, x0 - 
1, y0) :
                                      s->cur_frame->refPicList;
+        int same_rpl = rpl_left == s->cur_frame->refPicList;
         int xp_pu = (x0 - 1) >> log2_min_pu_size;
         int xq_pu =  x0      >> log2_min_pu_size;
         int xp_tu = (x0 - 1) >> log2_min_tu_size;
@@ -824,6 +847,8 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext 
*lc, const HEVCLayer
                     bs = 2;
                 else if (curr_cbf_luma || left_cbf_luma)
                     bs = 1;
+                else if (same_rpl && mvf_equal(curr, left))
+                    bs = 0;
                 else
                     bs = boundary_strength(s, curr, left, rpl_left);
                 l->vertical_bs[(x0 + (y0 + i) * l->bs_width) >> 2] = bs;
@@ -833,6 +858,44 @@ void 
ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
     if (log2_trafo_size > log2_min_pu_size && !is_intra) {
         const RefPicList *rpl = s->cur_frame->refPicList;
 
+        // whole edge lines can be tested at once when there is one MvField 
entry per 4px segment
+        if (log2_min_pu_size == 2 && log2_trafo_size >= 4 && log2_trafo_size 
<= 6) {
+            int n     = 1 << (log2_trafo_size - 2);
+            int x_pu0 = x0 >> 2;
+
+            // bs for TU internal horizontal PU boundaries
+            for (j = 8; j < (1 << log2_trafo_size); j += 8) {
+                int yq_pu = (y0 + j) >> 2;
+                const MvField *top  = &tab_mvf[(yq_pu - 1) * min_pu_width + 
x_pu0];
+                const MvField *curr = &tab_mvf[ yq_pu      * min_pu_width + 
x_pu0];
+                uint8_t *bs_h = &l->horizontal_bs[(x0 + (y0 + j) * 
l->bs_width) >> 2];
+
+                if (mvf_run_equal(top, curr, n - 1)) {
+                    memset(bs_h, 0, n);
+                } else {
+                    for (i = 0; i < n; i++)
+                        bs_h[i] = mvf_equal(&curr[i], &top[i]) ? 0 : 
boundary_strength(s, &curr[i], &top[i], rpl);
+                }
+            }
+
+            // bs for TU internal vertical PU boundaries
+            for (j = 0; j < (1 << log2_trafo_size); j += 4) {
+                int y_pu = (y0 + j) >> 2;
+                const MvField *row = &tab_mvf[y_pu * min_pu_width + x_pu0];
+                uint8_t *bs_v = &l->vertical_bs[(x0 + (y0 + j) * l->bs_width) 
>> 2];
+
+                // row[1..] vs row[2..] checks all adjacent pairs, a superset 
of the pairs needed
+                if (mvf_run_equal(row + 1, row + 2, n - 4)) {
+                    for (i = 2; i < n; i += 2)
+                        bs_v[i] = 0;
+                } else {
+                    for (i = 2; i < n; i += 2)
+                        bs_v[i] = mvf_equal(&row[i], &row[i - 1]) ? 0 : 
boundary_strength(s, &row[i], &row[i - 1], rpl);
+                }
+            }
+            return;
+        }
+
         // bs for TU internal horizontal PU boundaries
         for (j = 8; j < (1 << log2_trafo_size); j += 8) {
             int yp_pu = (y0 + j - 1) >> log2_min_pu_size;
@@ -843,7 +906,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext 
*lc, const HEVCLayer
                 const MvField *top  = &tab_mvf[yp_pu * min_pu_width + x_pu];
                 const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
 
-                bs = boundary_strength(s, curr, top, rpl);
+                bs = mvf_equal(curr, top) ? 0 : boundary_strength(s, curr, 
top, rpl);
                 l->horizontal_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = 
bs;
             }
         }
@@ -858,7 +921,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext 
*lc, const HEVCLayer
                 const MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
                 const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
 
-                bs = boundary_strength(s, curr, left, rpl);
+                bs = mvf_equal(curr, left) ? 0 : boundary_strength(s, curr, 
left, rpl);
                 l->vertical_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs;
             }
         }

-- 
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