PR #24501 opened by Zhao Zhili (quink)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24501
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24501.patch
# Summary of changes
1. avcodec/sao: fix swapped 45 and 135 degree EO class comments
2. add hevc and vvc sao edge aarch64 asm
```
Cortex-A510 Cortex-A715 Cortex-A725
Cortex-X3 Cortex-X925
hevc_sao_edge_8_10_neon: 332.5 (4.07x) 56.9 (5.50x) 57.4 (4.64x)
37.0 (7.38x) 24.2 (7.96x)
hevc_sao_edge_8_12_neon: 321.9 (4.22x) 57.1 (5.58x) 57.7 (4.70x)
37.0 (7.27x) 23.7 (8.12x)
hevc_sao_edge_16_10_neon: 1280.4 (4.11x) 227.3 (5.30x) 227.9 (4.61x)
146.4 (7.27x) 94.9 (8.38x)
hevc_sao_edge_16_12_neon: 1353.7 (3.96x) 227.9 (5.40x) 227.1 (4.63x)
146.4 (7.22x) 94.7 (8.40x)
hevc_sao_edge_32_10_neon: 5249.9 (3.84x) 912.9 (5.15x) 911.5 (4.48x)
592.8 (7.21x) 372.7 (8.95x)
hevc_sao_edge_32_12_neon: 5483.8 (3.67x) 912.6 (5.29x) 912.3 (4.47x)
579.8 (7.21x) 365.2 (9.11x)
hevc_sao_edge_48_10_neon: 11147.5 (4.07x) 2035.5 (5.14x) 2033.9 (4.48x)
1324.3 (7.27x) 815.7 (9.29x)
hevc_sao_edge_48_12_neon: 11179.6 (4.06x) 2035.5 (5.29x) 2035.9 (4.47x)
1324.9 (7.05x) 816.8 (9.25x)
hevc_sao_edge_64_10_neon: 19965.6 (4.03x) 3606.1 (5.15x) 3603.6 (4.49x)
2340.0 (7.27x) 1440.0 (9.42x)
hevc_sao_edge_64_12_neon: 20015.7 (4.02x) 3604.2 (5.30x) 3603.3 (4.49x)
2342.3 (7.07x) 1439.2 (9.40x)
```
```
Cortex-A510 Cortex-A715 Cortex-A725
Cortex-X3 Cortex-X925
vvc_sao_edge_8_10_neon: 308.9 (4.29x) 57.1 (5.47x) 57.4 (4.66x)
36.4 (7.35x) 23.7 (8.13x)
vvc_sao_edge_8_12_neon: 314.6 (4.19x) 57.3 (5.58x) 58.3 (4.59x)
36.4 (7.34x) 23.9 (8.08x)
vvc_sao_edge_16_10_neon: 1202.1 (4.28x) 228.1 (5.26x) 228.6 (4.54x)
144.6 (7.28x) 95.0 (8.39x)
vvc_sao_edge_16_12_neon: 1203.3 (4.28x) 229.4 (5.37x) 239.4 (4.33x)
144.6 (7.22x) 95.0 (8.38x)
vvc_sao_edge_32_10_neon: 4718.8 (4.28x) 913.1 (5.12x) 911.5 (4.42x)
571.5 (7.30x) 366.9 (9.08x)
vvc_sao_edge_32_12_neon: 4737.9 (4.26x) 913.3 (5.28x) 913.0 (4.41x)
571.8 (7.31x) 365.6 (9.15x)
vvc_sao_edge_48_10_neon: 10970.3 (4.16x) 2035.0 (5.13x) 2036.2 (4.43x)
1307.6 (7.14x) 823.6 (9.19x)
vvc_sao_edge_48_12_neon: 10980.7 (4.15x) 2037.3 (5.29x) 2035.0 (4.43x)
1311.2 (7.14x) 824.1 (9.20x)
vvc_sao_edge_64_10_neon: 19127.9 (4.23x) 3605.3 (5.13x) 3628.5 (4.41x)
2315.9 (7.17x) 1452.7 (9.33x)
vvc_sao_edge_64_12_neon: 19136.2 (4.23x) 3606.3 (5.29x) 3629.0 (4.40x)
2320.9 (7.17x) 1448.9 (9.36x)
vvc_sao_edge_80_10_neon: 29560.9 (4.29x) 5624.0 (5.30x) 5657.5 (4.64x)
3610.8 (7.17x) 2252.1 (9.44x)
vvc_sao_edge_80_12_neon: 29644.8 (4.28x) 5626.8 (5.48x) 5661.2 (4.64x)
3614.4 (7.18x) 2250.3 (9.46x)
vvc_sao_edge_96_10_neon: 42316.0 (4.29x) 8088.8 (5.28x) 8135.3 (4.61x)
5188.5 (7.20x) 3236.3 (9.49x)
vvc_sao_edge_96_12_neon: 42863.0 (4.23x) 8091.9 (5.45x) 8136.9 (4.61x)
5190.6 (7.21x) 3236.1 (9.48x)
vvc_sao_edge_112_10_neon: 57410.2 (4.30x) 11001.8 (5.27x) 11056.2 (4.59x)
7066.3 (7.19x) 4407.8 (9.48x)
vvc_sao_edge_112_12_neon: 57372.5 (4.30x) 11006.7 (5.44x) 11054.2 (4.59x)
7074.3 (7.19x) 4400.6 (9.52x)
vvc_sao_edge_128_10_neon: 75737.0 (4.26x) 14401.4 (5.26x) 14468.5 (4.57x)
9227.8 (7.22x) 5729.6 (9.54x)
vvc_sao_edge_128_12_neon: 75824.1 (4.25x) 14404.0 (5.42x) 14472.1 (4.57x)
9222.1 (7.20x) 5730.8 (9.55x)
```
>From cacbdad1ae8c1e85af640c9ee98a93b6fa1cc2cd Mon Sep 17 00:00:00 2001
From: Zhao Zhili <[email protected]>
Date: Fri, 11 Sep 2026 21:57:11 +0800
Subject: [PATCH 1/3] avcodec/sao: fix swapped 45 and 135 degree EO class
comments
The position tables are indexed by sao_eo_class: index 2 is SAO_EO_135D,
with neighbours at (-1,-1) and (1,1), and index 3 is SAO_EO_45D.
Signed-off-by: Zhao Zhili <[email protected]>
---
libavcodec/aarch64/h26x/sao_neon.S | 8 ++++----
libavcodec/arm/hevcdsp_init_neon.c | 4 ++--
libavcodec/h26x/h2656_sao_template.c | 4 ++--
libavcodec/wasm/hevc/sao.c | 8 ++++----
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/libavcodec/aarch64/h26x/sao_neon.S
b/libavcodec/aarch64/h26x/sao_neon.S
index 354614ecab..90022fcfc7 100644
--- a/libavcodec/aarch64/h26x/sao_neon.S
+++ b/libavcodec/aarch64/h26x/sao_neon.S
@@ -103,14 +103,14 @@ endfunc
.Lhevc_sao_edge_pos:
.word 1 // horizontal
.word HEVC_SAO_STRIDE // vertical
-.word HEVC_SAO_STRIDE + 1 // 45 degree
-.word HEVC_SAO_STRIDE - 1 // 135 degree
+.word HEVC_SAO_STRIDE + 1 // 135 degree
+.word HEVC_SAO_STRIDE - 1 // 45 degree
.Lvvc_sao_edge_pos:
.word 1 // horizontal
.word VVC_SAO_STRIDE // vertical
-.word VVC_SAO_STRIDE + 1 // 45 degree
-.word VVC_SAO_STRIDE - 1 // 135 degree
+.word VVC_SAO_STRIDE + 1 // 135 degree
+.word VVC_SAO_STRIDE - 1 // 45 degree
function ff_vvc_sao_edge_filter_16x16_8_neon, export=1
adr x7, .Lvvc_sao_edge_pos
diff --git a/libavcodec/arm/hevcdsp_init_neon.c
b/libavcodec/arm/hevcdsp_init_neon.c
index 6f113618c0..1bda997ceb 100644
--- a/libavcodec/arm/hevcdsp_init_neon.c
+++ b/libavcodec/arm/hevcdsp_init_neon.c
@@ -177,8 +177,8 @@ void ff_hevc_sao_edge_filter_neon_8_wrapper(uint8_t *_dst,
const uint8_t *_src,
static const int8_t pos[4][2][2] = {
{ { -1, 0 }, { 1, 0 } }, // horizontal
{ { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
+ { { -1, -1 }, { 1, 1 } }, // 135 degree
+ { { 1, -1 }, { -1, 1 } }, // 45 degree
};
uint8_t *dst = _dst;
const uint8_t *src = _src;
diff --git a/libavcodec/h26x/h2656_sao_template.c
b/libavcodec/h26x/h2656_sao_template.c
index b3eb8a3deb..a5028315a7 100644
--- a/libavcodec/h26x/h2656_sao_template.c
+++ b/libavcodec/h26x/h2656_sao_template.c
@@ -54,8 +54,8 @@ static void FUNC(sao_edge_filter)(uint8_t *_dst, const
uint8_t *_src, ptrdiff_t
static const int8_t pos[4][2][2] = {
{ { -1, 0 }, { 1, 0 } }, // horizontal
{ { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
+ { { -1, -1 }, { 1, 1 } }, // 135 degree
+ { { 1, -1 }, { -1, 1 } }, // 45 degree
};
pixel *dst = (pixel *)_dst;
const pixel *src = (const pixel *)_src;
diff --git a/libavcodec/wasm/hevc/sao.c b/libavcodec/wasm/hevc/sao.c
index a863b8e720..89e6b2cf07 100644
--- a/libavcodec/wasm/hevc/sao.c
+++ b/libavcodec/wasm/hevc/sao.c
@@ -124,8 +124,8 @@ void ff_hevc_sao_edge_filter_8x8_8_simd128(uint8_t *dst,
const uint8_t *src,
static const int8_t pos[4][2][2] = {
{ { -1, 0 }, { 1, 0 } }, // horizontal
{ { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
+ { { -1, -1 }, { 1, 1 } }, // 135 degree
+ { { 1, -1 }, { -1, 1 } }, // 45 degree
};
int a_stride, b_stride;
ptrdiff_t stride_src = (2 * HEVC_MAX_PB_SIZE +
AV_INPUT_BUFFER_PADDING_SIZE);
@@ -194,8 +194,8 @@ void ff_hevc_sao_edge_filter_16x16_8_simd128(uint8_t *dst,
const uint8_t *src,
static const int8_t pos[4][2][2] = {
{ { -1, 0 }, { 1, 0 } }, // horizontal
{ { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
+ { { -1, -1 }, { 1, 1 } }, // 135 degree
+ { { 1, -1 }, { -1, 1 } }, // 45 degree
};
int a_stride, b_stride;
ptrdiff_t stride_src = (2 * HEVC_MAX_PB_SIZE +
AV_INPUT_BUFFER_PADDING_SIZE);
--
2.52.0
>From 63f816566112f13ef2eae7c12bf86a00339b7537 Mon Sep 17 00:00:00 2001
From: Zhao Zhili <[email protected]>
Date: Tue, 15 Sep 2026 11:45:31 +0800
Subject: [PATCH 2/3] avcodec/aarch64: add NEON HEVC SAO edge 10 and 12 bit
Cortex-A510 Cortex-A715 Cortex-A725
Cortex-X3 Cortex-X925
hevc_sao_edge_8_10_neon: 332.5 (4.07x) 56.9 (5.50x) 57.4 (4.64x)
37.0 (7.38x) 24.2 (7.96x)
hevc_sao_edge_8_12_neon: 321.9 (4.22x) 57.1 (5.58x) 57.7 (4.70x)
37.0 (7.27x) 23.7 (8.12x)
hevc_sao_edge_16_10_neon: 1280.4 (4.11x) 227.3 (5.30x) 227.9 (4.61x)
146.4 (7.27x) 94.9 (8.38x)
hevc_sao_edge_16_12_neon: 1353.7 (3.96x) 227.9 (5.40x) 227.1 (4.63x)
146.4 (7.22x) 94.7 (8.40x)
hevc_sao_edge_32_10_neon: 5249.9 (3.84x) 912.9 (5.15x) 911.5 (4.48x)
592.8 (7.21x) 372.7 (8.95x)
hevc_sao_edge_32_12_neon: 5483.8 (3.67x) 912.6 (5.29x) 912.3 (4.47x)
579.8 (7.21x) 365.2 (9.11x)
hevc_sao_edge_48_10_neon: 11147.5 (4.07x) 2035.5 (5.14x) 2033.9 (4.48x)
1324.3 (7.27x) 815.7 (9.29x)
hevc_sao_edge_48_12_neon: 11179.6 (4.06x) 2035.5 (5.29x) 2035.9 (4.47x)
1324.9 (7.05x) 816.8 (9.25x)
hevc_sao_edge_64_10_neon: 19965.6 (4.03x) 3606.1 (5.15x) 3603.6 (4.49x)
2340.0 (7.27x) 1440.0 (9.42x)
hevc_sao_edge_64_12_neon: 20015.7 (4.02x) 3604.2 (5.30x) 3603.3 (4.49x)
2342.3 (7.07x) 1439.2 (9.40x)
Signed-off-by: Zhao Zhili <[email protected]>
---
libavcodec/aarch64/h26x/dsp.h | 22 ++--
libavcodec/aarch64/h26x/sao_neon.S | 118 +++++++++++++++++++++-
libavcodec/aarch64/hevcdsp_init_aarch64.c | 10 ++
3 files changed, 139 insertions(+), 11 deletions(-)
diff --git a/libavcodec/aarch64/h26x/dsp.h b/libavcodec/aarch64/h26x/dsp.h
index 0cbbdc3157..dab5163c60 100644
--- a/libavcodec/aarch64/h26x/dsp.h
+++ b/libavcodec/aarch64/h26x/dsp.h
@@ -32,15 +32,21 @@ void ff_h26x_sao_band_filter_16x16_8_neon(uint8_t *_dst,
const uint8_t *_src,
ptrdiff_t stride_dst, ptrdiff_t
stride_src,
const int16_t *sao_offset_val, int
sao_left_class,
int width, int height);
-void ff_hevc_sao_edge_filter_16x16_8_neon(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride_dst,
- const int16_t *sao_offset_val, int
eo, int width, int height);
-void ff_hevc_sao_edge_filter_8x8_8_neon(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride_dst,
- const int16_t *sao_offset_val, int eo,
int width, int height);
+#define SAO_EDGE_FILTER_PROTO(codec, size, depth) \
+ void ff_##codec##_sao_edge_filter_##size##_##depth##_neon( \
+ uint8_t *dst, const uint8_t *src, ptrdiff_t stride_dst, \
+ const int16_t *sao_offset_val, int eo, int width, int height)
-void ff_vvc_sao_edge_filter_16x16_8_neon(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride_dst,
- const int16_t *sao_offset_val, int
eo, int width, int height);
-void ff_vvc_sao_edge_filter_8x8_8_neon(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride_dst,
- const int16_t *sao_offset_val, int eo,
int width, int height);
+SAO_EDGE_FILTER_PROTO(hevc, 16x16, 8);
+SAO_EDGE_FILTER_PROTO(hevc, 8x8, 8);
+SAO_EDGE_FILTER_PROTO(hevc, 16x16, 10);
+SAO_EDGE_FILTER_PROTO(hevc, 8x8, 10);
+SAO_EDGE_FILTER_PROTO(hevc, 16x16, 12);
+SAO_EDGE_FILTER_PROTO(hevc, 8x8, 12);
+SAO_EDGE_FILTER_PROTO(vvc, 16x16, 8);
+SAO_EDGE_FILTER_PROTO(vvc, 8x8, 8);
+
+#undef SAO_EDGE_FILTER_PROTO
#define NEON8_FNPROTO_PARTIAL_6(fn, args, ext) \
void ff_hevc_put_hevc_##fn##_h4_8_neon##ext args; \
diff --git a/libavcodec/aarch64/h26x/sao_neon.S
b/libavcodec/aarch64/h26x/sao_neon.S
index 90022fcfc7..bc6e323deb 100644
--- a/libavcodec/aarch64/h26x/sao_neon.S
+++ b/libavcodec/aarch64/h26x/sao_neon.S
@@ -100,12 +100,18 @@ function ff_h26x_sao_band_filter_16x16_8_neon, export=1
ret
endfunc
-.Lhevc_sao_edge_pos:
+.Lhevc_sao_edge_pos_8:
.word 1 // horizontal
.word HEVC_SAO_STRIDE // vertical
.word HEVC_SAO_STRIDE + 1 // 135 degree
.word HEVC_SAO_STRIDE - 1 // 45 degree
+.Lhevc_sao_edge_pos_16bit:
+.word 2 // horizontal
+.word HEVC_SAO_STRIDE // vertical
+.word HEVC_SAO_STRIDE + 2 // 135 degree
+.word HEVC_SAO_STRIDE - 2 // 45 degree
+
.Lvvc_sao_edge_pos:
.word 1 // horizontal
.word VVC_SAO_STRIDE // vertical
@@ -121,7 +127,7 @@ endfunc
// ff_hevc_sao_edge_filter_16x16_8_neon(char *dst, char *src, ptrdiff
stride_dst,
// int16 *sao_offset_val, int eo, int
width, int height)
function ff_hevc_sao_edge_filter_16x16_8_neon, export=1
- adr x7, .Lhevc_sao_edge_pos
+ adr x7, .Lhevc_sao_edge_pos_8
mov x15, #HEVC_SAO_STRIDE
1:
ld1 {v3.8h}, [x3] // load sao_offset_val
@@ -179,6 +185,83 @@ function ff_hevc_sao_edge_filter_16x16_8_neon, export=1
ret
endfunc
+/* Permutes sao_offset_val into the byte table v28 by edge_idx = { 1, 2, 0, 3,
4 }.
+ * v29: bias 2
+ * v30: 0 for clip lower bound
+ * v31: clip higher bound, not set by this macro
+ */
+.macro sao_edge_offsets_init
+ ld1 {v6.8h}, [x3]
+ movi v29.8b, #2
+ movi v30.8h, #0
+ mov v7.16b, v6.16b
+ mov v6.h[0], v7.h[1]
+ mov v6.h[1], v7.h[2]
+ mov v6.h[2], v7.h[0]
+ xtn v28.8b, v6.8h
+.endm
+
+/* Filters one 8-pixel chunk
+ * v0: cur, and hold clipped result
+ * v1: a
+ * v2: b
+ */
+.macro sao_edge_filter8
+ cmhi v16.8h, v1.8h, v0.8h
+ cmhi v17.8h, v0.8h, v1.8h
+ cmhi v18.8h, v2.8h, v0.8h
+ cmhi v19.8h, v0.8h, v2.8h
+ add v20.8h, v16.8h, v18.8h
+ add v21.8h, v17.8h, v19.8h
+ sub v20.8h, v20.8h, v21.8h // CMP(cur, a) + CMP(cur,
b)
+ xtn v20.8b, v20.8h
+ add v20.8b, v20.8b, v29.8b // offset table index
+ tbl v16.8b, {v28.16b}, v20.8b
+ saddw v0.8h, v0.8h, v16.8b
+ smax v0.8h, v0.8h, v30.8h
+ smin v0.8h, v0.8h, v31.8h
+.endm
+
+// ff_hevc_sao_edge_filter_16x16_12_neon(char *dst, char *src, ptrdiff
stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_hevc_sao_edge_filter_16x16_12_neon, export=1
+ mvni v31.8h, #0xf0, lsl #8 // 4095
+ b .Lhevc_sao_edge_16bit
+endfunc
+
+// ff_hevc_sao_edge_filter_16x16_10_neon(char *dst, char *src, ptrdiff
stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_hevc_sao_edge_filter_16x16_10_neon, export=1
+ mvni v31.8h, #0xfc, lsl #8 // 1023
+.Lhevc_sao_edge_16bit:
+ adr x7, .Lhevc_sao_edge_pos_16bit
+ mov x15, #HEVC_SAO_STRIDE
+ add w5, w5, #7
+ ldr w4, [x7, w4, uxtw #2] // a/b offsets in bytes
+ bic w5, w5, #7
+ sao_edge_offsets_init
+ lsl w5, w5, #1 // width in bytes,
multiple of 16
+ sub x15, x15, x5 // src step to the next
line
+ sub x16, x2, x5 // dst step to the next
line
+1:
+ lsr x14, x5, #4 // 8-pixel groups
+ sub x12, x1, x4
+ add x13, x1, x4
+2:
+ ldr q0, [x1], #16
+ ldr q1, [x12], #16
+ ldr q2, [x13], #16
+ subs x14, x14, #1
+ sao_edge_filter8
+ str q0, [x0], #16
+ b.ne 2b
+ subs w6, w6, #1
+ add x1, x1, x15
+ add x0, x0, x16
+ b.ne 1b
+ ret
+endfunc
+
function ff_vvc_sao_edge_filter_8x8_8_neon, export=1
adr x7, .Lvvc_sao_edge_pos
mov x15, #VVC_SAO_STRIDE
@@ -188,7 +271,7 @@ endfunc
// ff_hevc_sao_edge_filter_8x8_8_neon(char *dst, char *src, ptrdiff stride_dst,
// int16 *sao_offset_val, int eo, int
width, int height)
function ff_hevc_sao_edge_filter_8x8_8_neon, export=1
- adr x7, .Lhevc_sao_edge_pos
+ adr x7, .Lhevc_sao_edge_pos_8
mov x15, #HEVC_SAO_STRIDE
1:
ldr w4, [x7, w4, uxtw #2]
@@ -235,3 +318,32 @@ function ff_hevc_sao_edge_filter_8x8_8_neon, export=1
b.ne 1b
ret
endfunc
+
+// ff_hevc_sao_edge_filter_8x8_12_neon(char *dst, char *src, ptrdiff
stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_hevc_sao_edge_filter_8x8_12_neon, export=1
+ mvni v31.8h, #0xf0, lsl #8 // 4095
+ b .Lhevc_sao_edge_8x8_16bit
+endfunc
+
+// ff_hevc_sao_edge_filter_8x8_10_neon(char *dst, char *src, ptrdiff
stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_hevc_sao_edge_filter_8x8_10_neon, export=1
+ mvni v31.8h, #0xfc, lsl #8 // 1023
+.Lhevc_sao_edge_8x8_16bit:
+ adr x7, .Lhevc_sao_edge_pos_16bit
+ mov x15, #HEVC_SAO_STRIDE
+ ldr w4, [x7, w4, uxtw #2] // a/b offsets in bytes
+ sao_edge_offsets_init
+ sub x9, x1, x4 // a neighbours
+ add x10, x1, x4 // b neighbours
+1:
+ ld1 {v0.8h}, [x1], x15
+ ld1 {v1.8h}, [x9], x15
+ ld1 {v2.8h}, [x10], x15
+ subs w6, w6, #1
+ sao_edge_filter8
+ st1 {v0.8h}, [x0], x2
+ b.ne 1b
+ ret
+endfunc
diff --git a/libavcodec/aarch64/hevcdsp_init_aarch64.c
b/libavcodec/aarch64/hevcdsp_init_aarch64.c
index a2ca8aa124..12f8d93803 100644
--- a/libavcodec/aarch64/hevcdsp_init_aarch64.c
+++ b/libavcodec/aarch64/hevcdsp_init_aarch64.c
@@ -338,6 +338,11 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c,
const int bit_depth)
c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_neon;
c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_neon;
c->dequant = hevc_dequant_10_neon;
+ c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8x8_10_neon;
+ c->sao_edge_filter[1] =
+ c->sao_edge_filter[2] =
+ c->sao_edge_filter[3] =
+ c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_16x16_10_neon;
}
if (bit_depth == 12) {
c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_neon;
@@ -353,5 +358,10 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c,
const int bit_depth)
c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_neon;
c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_neon;
c->dequant = hevc_dequant_12_neon;
+ c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8x8_12_neon;
+ c->sao_edge_filter[1] =
+ c->sao_edge_filter[2] =
+ c->sao_edge_filter[3] =
+ c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_16x16_12_neon;
}
}
--
2.52.0
>From a4b9409bf4339f6dfa9e929b1ccdec0f6aa6becf Mon Sep 17 00:00:00 2001
From: Zhao Zhili <[email protected]>
Date: Tue, 15 Sep 2026 11:46:01 +0800
Subject: [PATCH 3/3] avcodec/aarch64: add NEON VVC SAO edge 10 and 12 bit
Cortex-A510 Cortex-A715 Cortex-A725
Cortex-X3 Cortex-X925
vvc_sao_edge_8_10_neon: 308.9 (4.29x) 57.1 (5.47x) 57.4 (4.66x)
36.4 (7.35x) 23.7 (8.13x)
vvc_sao_edge_8_12_neon: 314.6 (4.19x) 57.3 (5.58x) 58.3 (4.59x)
36.4 (7.34x) 23.9 (8.08x)
vvc_sao_edge_16_10_neon: 1202.1 (4.28x) 228.1 (5.26x) 228.6 (4.54x)
144.6 (7.28x) 95.0 (8.39x)
vvc_sao_edge_16_12_neon: 1203.3 (4.28x) 229.4 (5.37x) 239.4 (4.33x)
144.6 (7.22x) 95.0 (8.38x)
vvc_sao_edge_32_10_neon: 4718.8 (4.28x) 913.1 (5.12x) 911.5 (4.42x)
571.5 (7.30x) 366.9 (9.08x)
vvc_sao_edge_32_12_neon: 4737.9 (4.26x) 913.3 (5.28x) 913.0 (4.41x)
571.8 (7.31x) 365.6 (9.15x)
vvc_sao_edge_48_10_neon: 10970.3 (4.16x) 2035.0 (5.13x) 2036.2 (4.43x)
1307.6 (7.14x) 823.6 (9.19x)
vvc_sao_edge_48_12_neon: 10980.7 (4.15x) 2037.3 (5.29x) 2035.0 (4.43x)
1311.2 (7.14x) 824.1 (9.20x)
vvc_sao_edge_64_10_neon: 19127.9 (4.23x) 3605.3 (5.13x) 3628.5 (4.41x)
2315.9 (7.17x) 1452.7 (9.33x)
vvc_sao_edge_64_12_neon: 19136.2 (4.23x) 3606.3 (5.29x) 3629.0 (4.40x)
2320.9 (7.17x) 1448.9 (9.36x)
vvc_sao_edge_80_10_neon: 29560.9 (4.29x) 5624.0 (5.30x) 5657.5 (4.64x)
3610.8 (7.17x) 2252.1 (9.44x)
vvc_sao_edge_80_12_neon: 29644.8 (4.28x) 5626.8 (5.48x) 5661.2 (4.64x)
3614.4 (7.18x) 2250.3 (9.46x)
vvc_sao_edge_96_10_neon: 42316.0 (4.29x) 8088.8 (5.28x) 8135.3 (4.61x)
5188.5 (7.20x) 3236.3 (9.49x)
vvc_sao_edge_96_12_neon: 42863.0 (4.23x) 8091.9 (5.45x) 8136.9 (4.61x)
5190.6 (7.21x) 3236.1 (9.48x)
vvc_sao_edge_112_10_neon: 57410.2 (4.30x) 11001.8 (5.27x) 11056.2 (4.59x)
7066.3 (7.19x) 4407.8 (9.48x)
vvc_sao_edge_112_12_neon: 57372.5 (4.30x) 11006.7 (5.44x) 11054.2 (4.59x)
7074.3 (7.19x) 4400.6 (9.52x)
vvc_sao_edge_128_10_neon: 75737.0 (4.26x) 14401.4 (5.26x) 14468.5 (4.57x)
9227.8 (7.22x) 5729.6 (9.54x)
vvc_sao_edge_128_12_neon: 75824.1 (4.25x) 14404.0 (5.42x) 14472.1 (4.57x)
9222.1 (7.20x) 5730.8 (9.55x)
Signed-off-by: Zhao Zhili <[email protected]>
---
libavcodec/aarch64/h26x/dsp.h | 4 +++
libavcodec/aarch64/h26x/sao_neon.S | 42 ++++++++++++++++++++++++++++++
libavcodec/aarch64/vvc/dsp_init.c | 8 ++++++
3 files changed, 54 insertions(+)
diff --git a/libavcodec/aarch64/h26x/dsp.h b/libavcodec/aarch64/h26x/dsp.h
index dab5163c60..2b8eae130a 100644
--- a/libavcodec/aarch64/h26x/dsp.h
+++ b/libavcodec/aarch64/h26x/dsp.h
@@ -45,6 +45,10 @@ SAO_EDGE_FILTER_PROTO(hevc, 16x16, 12);
SAO_EDGE_FILTER_PROTO(hevc, 8x8, 12);
SAO_EDGE_FILTER_PROTO(vvc, 16x16, 8);
SAO_EDGE_FILTER_PROTO(vvc, 8x8, 8);
+SAO_EDGE_FILTER_PROTO(vvc, 16x16, 10);
+SAO_EDGE_FILTER_PROTO(vvc, 8x8, 10);
+SAO_EDGE_FILTER_PROTO(vvc, 16x16, 12);
+SAO_EDGE_FILTER_PROTO(vvc, 8x8, 12);
#undef SAO_EDGE_FILTER_PROTO
diff --git a/libavcodec/aarch64/h26x/sao_neon.S
b/libavcodec/aarch64/h26x/sao_neon.S
index bc6e323deb..b2c3cdc8d3 100644
--- a/libavcodec/aarch64/h26x/sao_neon.S
+++ b/libavcodec/aarch64/h26x/sao_neon.S
@@ -118,6 +118,12 @@ endfunc
.word VVC_SAO_STRIDE + 1 // 135 degree
.word VVC_SAO_STRIDE - 1 // 45 degree
+.Lvvc_sao_edge_pos_16bit:
+.word 2 // horizontal
+.word VVC_SAO_STRIDE // vertical
+.word VVC_SAO_STRIDE + 2 // 135 degree
+.word VVC_SAO_STRIDE - 2 // 45 degree
+
function ff_vvc_sao_edge_filter_16x16_8_neon, export=1
adr x7, .Lvvc_sao_edge_pos
mov x15, #VVC_SAO_STRIDE
@@ -222,6 +228,23 @@ endfunc
smin v0.8h, v0.8h, v31.8h
.endm
+// ff_vvc_sao_edge_filter_16x16_12_neon(char *dst, char *src, ptrdiff
stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_vvc_sao_edge_filter_16x16_12_neon, export=1
+ mvni v31.8h, #0xf0, lsl #8 // 4095
+ b .Lvvc_sao_edge_16x16_16bit
+endfunc
+
+// ff_vvc_sao_edge_filter_16x16_10_neon(char *dst, char *src, ptrdiff
stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_vvc_sao_edge_filter_16x16_10_neon, export=1
+ mvni v31.8h, #0xfc, lsl #8 // 1023
+.Lvvc_sao_edge_16x16_16bit:
+ adr x7, .Lvvc_sao_edge_pos_16bit
+ mov x15, #VVC_SAO_STRIDE
+ b .Lh26x_sao_edge_16x16_16bit
+endfunc
+
// ff_hevc_sao_edge_filter_16x16_12_neon(char *dst, char *src, ptrdiff
stride_dst,
// int16 *sao_offset_val, int eo, int
width, int height)
function ff_hevc_sao_edge_filter_16x16_12_neon, export=1
@@ -236,6 +259,7 @@ function ff_hevc_sao_edge_filter_16x16_10_neon, export=1
.Lhevc_sao_edge_16bit:
adr x7, .Lhevc_sao_edge_pos_16bit
mov x15, #HEVC_SAO_STRIDE
+.Lh26x_sao_edge_16x16_16bit:
add w5, w5, #7
ldr w4, [x7, w4, uxtw #2] // a/b offsets in bytes
bic w5, w5, #7
@@ -319,6 +343,23 @@ function ff_hevc_sao_edge_filter_8x8_8_neon, export=1
ret
endfunc
+// ff_vvc_sao_edge_filter_8x8_12_neon(char *dst, char *src, ptrdiff stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_vvc_sao_edge_filter_8x8_12_neon, export=1
+ mvni v31.8h, #0xf0, lsl #8 // 4095
+ b .Lvvc_sao_edge_8x8_16bit
+endfunc
+
+// ff_vvc_sao_edge_filter_8x8_10_neon(char *dst, char *src, ptrdiff stride_dst,
+// int16 *sao_offset_val, int eo, int
width, int height)
+function ff_vvc_sao_edge_filter_8x8_10_neon, export=1
+ mvni v31.8h, #0xfc, lsl #8 // 1023
+.Lvvc_sao_edge_8x8_16bit:
+ adr x7, .Lvvc_sao_edge_pos_16bit
+ mov x15, #VVC_SAO_STRIDE
+ b .Lh26x_sao_edge_8x8_16bit
+endfunc
+
// ff_hevc_sao_edge_filter_8x8_12_neon(char *dst, char *src, ptrdiff
stride_dst,
// int16 *sao_offset_val, int eo, int
width, int height)
function ff_hevc_sao_edge_filter_8x8_12_neon, export=1
@@ -333,6 +374,7 @@ function ff_hevc_sao_edge_filter_8x8_10_neon, export=1
.Lhevc_sao_edge_8x8_16bit:
adr x7, .Lhevc_sao_edge_pos_16bit
mov x15, #HEVC_SAO_STRIDE
+.Lh26x_sao_edge_8x8_16bit:
ldr w4, [x7, w4, uxtw #2] // a/b offsets in bytes
sao_edge_offsets_init
sub x9, x1, x4 // a neighbours
diff --git a/libavcodec/aarch64/vvc/dsp_init.c
b/libavcodec/aarch64/vvc/dsp_init.c
index 53bf9f9edd..8936a4606a 100644
--- a/libavcodec/aarch64/vvc/dsp_init.c
+++ b/libavcodec/aarch64/vvc/dsp_init.c
@@ -372,6 +372,10 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const
int bd)
c->inter.put[1][5][1][1] =
c->inter.put[1][6][1][1] = ff_vvc_put_chroma_hv_x16_10_neon;
+ c->sao.edge_filter[0] = ff_vvc_sao_edge_filter_8x8_10_neon;
+ for (int i = 1; i < FF_ARRAY_ELEMS(c->sao.edge_filter); i++)
+ c->sao.edge_filter[i] = ff_vvc_sao_edge_filter_16x16_10_neon;
+
c->alf.filter[LUMA] = alf_filter_luma_10_neon;
c->alf.filter[CHROMA] = alf_filter_chroma_10_neon;
c->alf.classify = alf_classify_10_neon;
@@ -424,6 +428,10 @@ void ff_vvc_dsp_init_aarch64(VVCDSPContext *const c, const
int bd)
c->inter.put[1][5][1][1] =
c->inter.put[1][6][1][1] = ff_vvc_put_chroma_hv_x16_12_neon;
+ c->sao.edge_filter[0] = ff_vvc_sao_edge_filter_8x8_12_neon;
+ for (int i = 1; i < FF_ARRAY_ELEMS(c->sao.edge_filter); i++)
+ c->sao.edge_filter[i] = ff_vvc_sao_edge_filter_16x16_12_neon;
+
c->alf.filter[LUMA] = alf_filter_luma_12_neon;
c->alf.filter[CHROMA] = alf_filter_chroma_12_neon;
c->alf.classify = alf_classify_12_neon;
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]