This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 514f57f85d6dee995f4a6f61405962fc3e8937f7 Author: Jun Zhao <[email protected]> AuthorDate: Fri Mar 6 17:33:46 2026 +0800 Commit: Jun Zhao <[email protected]> CommitDate: Mon Mar 30 14:32:10 2026 +0000 tests/checkasm: add HEVC intra prediction test Add checkasm test for HEVC intra prediction covering DC, planar, and angular modes at all block sizes (4x4 to 32x32) for 8-bit and 10-bit depth. Signed-off-by: Jun Zhao <[email protected]> --- tests/checkasm/Makefile | 3 +- tests/checkasm/checkasm.c | 1 + tests/checkasm/checkasm.h | 1 + tests/checkasm/hevc_pred.c | 227 +++++++++++++++++++++++++++++++++++++++++++++ tests/fate/checkasm.mak | 1 + 5 files changed, 232 insertions(+), 1 deletion(-) diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index 956f139090..bf2d6b7ec2 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -44,7 +44,8 @@ AVCODECOBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dsp.o AVCODECOBJS-$(CONFIG_MPEG4_DECODER) += mpeg4videodsp.o AVCODECOBJS-$(CONFIG_OPUS_DECODER) += opusdsp.o AVCODECOBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o -AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_deblock.o hevc_dequant.o hevc_idct.o hevc_sao.o hevc_pel.o +AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_deblock.o hevc_dequant.o \ + hevc_idct.o hevc_pel.o hevc_pred.o hevc_sao.o AVCODECOBJS-$(CONFIG_PNG_DECODER) += png.o AVCODECOBJS-$(CONFIG_RV34DSP) += rv34dsp.o AVCODECOBJS-$(CONFIG_RV40_DECODER) += rv40dsp.o diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index b38e5926cb..8629f26788 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -190,6 +190,7 @@ static const struct { { "hevc_dequant", checkasm_check_hevc_dequant }, { "hevc_idct", checkasm_check_hevc_idct }, { "hevc_pel", checkasm_check_hevc_pel }, + { "hevc_pred", checkasm_check_hevc_pred }, { "hevc_sao", checkasm_check_hevc_sao }, #endif #if CONFIG_HPELDSP diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index cded57d3ea..43c158e97b 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -113,6 +113,7 @@ void checkasm_check_hevc_deblock(void); void checkasm_check_hevc_dequant(void); void checkasm_check_hevc_idct(void); void checkasm_check_hevc_pel(void); +void checkasm_check_hevc_pred(void); void checkasm_check_hevc_sao(void); void checkasm_check_hpeldsp(void); void checkasm_check_huffyuvdsp(void); diff --git a/tests/checkasm/hevc_pred.c b/tests/checkasm/hevc_pred.c new file mode 100644 index 0000000000..7de9d23e60 --- /dev/null +++ b/tests/checkasm/hevc_pred.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2026 Jun Zhao <[email protected]> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <string.h> +#include "checkasm.h" +#include "libavcodec/hevc/pred.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem_internal.h" + +static const uint32_t pixel_mask[3] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff }; + +#define SIZEOF_PIXEL ((bit_depth + 7) / 8) +#define BUF_SIZE (2 * 64 * 64) /* Enough for 32x32 with stride=64 */ +#define PRED_SIZE 128 /* Increased to 4 * MAX_TB_SIZE to accommodate C code reads */ + +#define randomize_buffers() \ + do { \ + uint32_t mask = pixel_mask[bit_depth - 8]; \ + for (int i = 0; i < BUF_SIZE; i += 4) { \ + uint32_t r = rnd() & mask; \ + AV_WN32A(buf0 + i, r); \ + AV_WN32A(buf1 + i, r); \ + } \ + /* Start from -4 so that AV_WN32A writes \ + * top[-4..-1] and left[-4..-1], ensuring \ + * top[-1] and left[-1] contain known data \ + * since angular pred references them \ + * (e.g. mode 10/26 edge filtering, \ + * mode 18 diagonal, V/H neg extension). */\ + for (int i = -4; i < PRED_SIZE; i += 4) { \ + uint32_t r = rnd() & mask; \ + AV_WN32A(top + i, r); \ + AV_WN32A(left + i, r); \ + } \ + } while (0) + +static void check_pred_dc(HEVCPredContext *h, + uint8_t *buf0, uint8_t *buf1, + uint8_t *top, uint8_t *left, int bit_depth) +{ + const char *const block_name[] = { "4x4", "8x8", "16x16", "32x32" }; + const int block_size[] = { 4, 8, 16, 32 }; + int log2_size; + + declare_func(void, uint8_t *src, const uint8_t *top, + const uint8_t *left, ptrdiff_t stride, + int log2_size, int c_idx); + + /* Test all 4 sizes: 4x4, 8x8, 16x16, 32x32 */ + for (log2_size = 2; log2_size <= 5; log2_size++) { + int size = block_size[log2_size - 2]; + ptrdiff_t stride = 64 * SIZEOF_PIXEL; + + if (check_func(h->pred_dc, "hevc_pred_dc_%s_%d", + block_name[log2_size - 2], bit_depth)) { + /* Test with c_idx=0 (luma, with edge smoothing for size < 32) */ + randomize_buffers(); + call_ref(buf0, top, left, stride, log2_size, 0); + call_new(buf1, top, left, stride, log2_size, 0); + if (memcmp(buf0, buf1, size * stride)) + fail(); + + /* Test with c_idx=1 (chroma, no edge smoothing) */ + randomize_buffers(); + call_ref(buf0, top, left, stride, log2_size, 1); + call_new(buf1, top, left, stride, log2_size, 1); + if (memcmp(buf0, buf1, size * stride)) + fail(); + + bench_new(buf1, top, left, stride, log2_size, 0); + } + } +} + +static void check_pred_planar(HEVCPredContext *h, + uint8_t *buf0, uint8_t *buf1, + uint8_t *top, uint8_t *left, int bit_depth) +{ + const char *const block_name[] = { "4x4", "8x8", "16x16", "32x32" }; + const int block_size[] = { 4, 8, 16, 32 }; + int i; + + declare_func(void, uint8_t *src, const uint8_t *top, + const uint8_t *left, ptrdiff_t stride); + + /* Test all 4 sizes: 4x4, 8x8, 16x16, 32x32 */ + for (i = 0; i < 4; i++) { + int size = block_size[i]; + ptrdiff_t stride = 64 * SIZEOF_PIXEL; + + if (check_func(h->pred_planar[i], "hevc_pred_planar_%s_%d", + block_name[i], bit_depth)) { + randomize_buffers(); + call_ref(buf0, top, left, stride); + call_new(buf1, top, left, stride); + if (memcmp(buf0, buf1, size * stride)) + fail(); + + bench_new(buf1, top, left, stride); + } + } +} + +/* + * Angular prediction modes are divided into categories: + * + * Mode 10: Horizontal pure copy (H pure) + * Mode 26: Vertical pure copy (V pure) + * Modes 2-9: Horizontal positive angle (H pos) - uses left reference + * Modes 11-17: Horizontal negative angle (H neg) - needs reference extension + * Modes 18-25: Vertical negative angle (V neg) - needs reference extension + * Modes 27-34: Vertical positive angle (V pos) - uses top reference + * + * Each category has 4 NEON functions for 4x4, 8x8, 16x16, 32x32 sizes. + */ +static void check_pred_angular(HEVCPredContext *h, + uint8_t *buf0, uint8_t *buf1, + uint8_t *top, uint8_t *left, int bit_depth) +{ + const char *const block_name[] = { "4x4", "8x8", "16x16", "32x32" }; + const int block_size[] = { 4, 8, 16, 32 }; + int i, mode; + + declare_func(void, uint8_t *src, const uint8_t *top, + const uint8_t *left, ptrdiff_t stride, int c_idx, int mode); + + /* Test all 4 sizes */ + for (i = 0; i < 4; i++) { + int size = block_size[i]; + ptrdiff_t stride = 64 * SIZEOF_PIXEL; + + /* Test all 33 angular modes (2-34) */ + for (mode = 2; mode <= 34; mode++) { + const char *mode_category; + + /* Determine mode category for descriptive test name */ + if (mode == 10) + mode_category = "Hpure"; + else if (mode == 26) + mode_category = "Vpure"; + else if (mode >= 2 && mode <= 9) + mode_category = "Hpos"; + else if (mode >= 11 && mode <= 17) + mode_category = "Hneg"; + else if (mode >= 18 && mode <= 25) + mode_category = "Vneg"; + else /* mode >= 27 && mode <= 34 */ + mode_category = "Vpos"; + + if (check_func(h->pred_angular[i], + "hevc_pred_angular_%s_%s_mode%d_%d", + block_name[i], mode_category, mode, bit_depth)) { + /* Test with c_idx=0 (luma) */ + randomize_buffers(); + call_ref(buf0, top, left, stride, 0, mode); + call_new(buf1, top, left, stride, 0, mode); + if (memcmp(buf0, buf1, size * stride)) + fail(); + + /* Test with c_idx=1 (chroma) for modes 10/26 to cover + * the edge filtering skip path */ + if (mode == 10 || mode == 26) { + randomize_buffers(); + call_ref(buf0, top, left, stride, 1, mode); + call_new(buf1, top, left, stride, 1, mode); + if (memcmp(buf0, buf1, size * stride)) + fail(); + } + + bench_new(buf1, top, left, stride, 0, mode); + } + } + } +} + +void checkasm_check_hevc_pred(void) +{ + LOCAL_ALIGNED_32(uint8_t, buf0, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, buf1, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, top_buf, [PRED_SIZE + 16]); + LOCAL_ALIGNED_32(uint8_t, left_buf, [PRED_SIZE + 16]); + /* Add offset of 8 bytes to allow negative indexing (top[-1], left[-1]) */ + uint8_t *top = top_buf + 8; + uint8_t *left = left_buf + 8; + int bit_depth; + + for (bit_depth = 8; bit_depth <= 10; bit_depth += 2) { + HEVCPredContext h; + + ff_hevc_pred_init(&h, bit_depth); + check_pred_dc(&h, buf0, buf1, top, left, bit_depth); + } + report("pred_dc"); + + for (bit_depth = 8; bit_depth <= 10; bit_depth += 2) { + HEVCPredContext h; + + ff_hevc_pred_init(&h, bit_depth); + check_pred_planar(&h, buf0, buf1, top, left, bit_depth); + } + report("pred_planar"); + + for (bit_depth = 8; bit_depth <= 10; bit_depth += 2) { + HEVCPredContext h; + + ff_hevc_pred_init(&h, bit_depth); + check_pred_angular(&h, buf0, buf1, top, left, bit_depth); + } + report("pred_angular"); +} diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak index d75b885db1..2fb1f693b8 100644 --- a/tests/fate/checkasm.mak +++ b/tests/fate/checkasm.mak @@ -30,6 +30,7 @@ FATE_CHECKASM = fate-checkasm-aacencdsp \ fate-checkasm-hevc_dequant \ fate-checkasm-hevc_idct \ fate-checkasm-hevc_pel \ + fate-checkasm-hevc_pred \ fate-checkasm-hevc_sao \ fate-checkasm-hpeldsp \ fate-checkasm-huffyuvdsp \ _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
