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]