* [FFmpeg-devel] [PATCH] lavc: Add unit test for APV entropy decode
@ 2025-04-30 21:09 Mark Thompson
2025-05-02 17:52 ` Michael Niedermayer
2025-05-02 17:58 ` James Almer
0 siblings, 2 replies; 3+ messages in thread
From: Mark Thompson @ 2025-04-30 21:09 UTC (permalink / raw)
To: ffmpeg-devel
---
Cleaned up a bit from use earlier. This program allows testing of changes to entropy decode in a form much easier to debug than a whole stream.
I had a more complete randomised test of transform here as well along with test code for checking intermediates, though it seems like the checkasm only might be preferred. Can add it if useful.
Thanks,
- Mark
libavcodec/Makefile | 1 +
libavcodec/tests/apv.c | 306 ++++++++++++++++++++++++++++++++++++++
tests/fate/libavcodec.mak | 5 +
3 files changed, 312 insertions(+)
create mode 100644 libavcodec/tests/apv.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e674671460..a98621aac4 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1327,6 +1327,7 @@ TESTPROGS = avcodec \
jpeg2000dwt \
mathops \
+TESTPROGS-$(CONFIG_APV_DECODER) += apv
TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER) += av1_levels
TESTPROGS-$(CONFIG_CABAC) += cabac
TESTPROGS-$(CONFIG_GOLOMB) += golomb
diff --git a/libavcodec/tests/apv.c b/libavcodec/tests/apv.c
new file mode 100644
index 0000000000..6d37014f58
--- /dev/null
+++ b/libavcodec/tests/apv.c
@@ -0,0 +1,306 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "libavutil/lfg.h"
+#include "libavutil/random_seed.h"
+
+#include "libavcodec/apv_decode.h"
+#include "libavcodec/apv_dsp.h"
+#include "libavcodec/put_bits.h"
+
+
+// As defined in 7.1.4, for testing.
+// Adds a check to limit loop after reading 16 zero bits to avoid
+// getting stuck reading a stream of zeroes forever (this matches
+// the behaviour of the faster version).
+
+static unsigned int apv_read_vlc_spec(GetBitContext *gbc, int k_param)
+{
+ unsigned int symbol_value = 0;
+ int parse_exp_golomb = 1;
+ int k = k_param;
+ int stop_loop = 0;
+
+ if(get_bits1(gbc) == 1) {
+ parse_exp_golomb = 0;
+ } else {
+ if (get_bits1(gbc) == 0) {
+ symbol_value += (1 << k);
+ parse_exp_golomb = 0;
+ } else {
+ symbol_value += (2 << k);
+ parse_exp_golomb = 1;
+ }
+ }
+ if (parse_exp_golomb) {
+ int read_limit = 0;
+ do {
+ if (get_bits1(gbc) == 1) {
+ stop_loop = 1;
+ } else {
+ if (++read_limit == 16)
+ break;
+ symbol_value += (1 << k);
+ k++;
+ }
+ } while (!stop_loop);
+ }
+ if (k > 0)
+ symbol_value += get_bits(gbc, k);
+
+ return symbol_value;
+}
+
+// As defined in 7.2.4, for testing.
+
+static void apv_write_vlc_spec(PutBitContext *pbc,
+ unsigned int symbol_val, int k_param)
+{
+ int prefix_vlc_table[3][2] = {{1, 0}, {0, 0}, {0, 1}};
+
+ unsigned int symbol_value = symbol_val;
+ int val_prefix_vlc = av_clip(symbol_val >> k_param, 0, 2);
+ int bit_count = 0;
+ int k = k_param;
+
+ while (symbol_value >= (1 << k)) {
+ symbol_value -= (1 << k);
+ if (bit_count < 2)
+ put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]);
+ else
+ put_bits(pbc, 1, 0);
+ if (bit_count >= 2)
+ ++k;
+ ++bit_count;
+ }
+
+ if(bit_count < 2)
+ put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]);
+ else
+ put_bits(pbc, 1, 1);
+
+ if(k > 0)
+ put_bits(pbc, k, symbol_value);
+}
+
+static void binary(char *buf, uint32_t value, int bits)
+{
+ for (int i = 0; i < bits; i++)
+ buf[i] = (value >> (bits - i - 1) & 1) ? '1' : '0';
+ buf[bits] = '\0';
+}
+
+static int test_apv_read_vlc(void)
+{
+ APVVLCLUT lut;
+ int err = 0;
+
+ ff_apv_entropy_build_decode_lut(&lut);
+
+ // Generate all possible 20 bit sequences (padded with zeroes), then
+ // verify that spec and improved parsing functions get the same result
+ // and consume the same number of bits for each possible k_param.
+
+ for (int k = 0; k <= 5; k++) {
+ for (uint32_t b = 0; b < (1 << 20); b++) {
+ uint8_t buf[8] = {
+ b >> 12,
+ b >> 4,
+ b << 4,
+ 0, 0, 0, 0, 0
+ };
+
+ GetBitContext gbc_test, gbc_spec;
+ unsigned int res_test, res_spec;
+ int con_test, con_spec;
+
+ init_get_bits8(&gbc_test, buf, 8);
+ init_get_bits8(&gbc_spec, buf, 8);
+
+ res_test = ff_apv_read_vlc (&gbc_test, k, &lut);
+ res_spec = apv_read_vlc_spec(&gbc_spec, k);
+
+ con_test = get_bits_count(&gbc_test);
+ con_spec = get_bits_count(&gbc_spec);
+
+ if (res_test != res_spec ||
+ con_test != con_spec) {
+ char str[21];
+ binary(str, b, 20);
+ av_log(NULL, AV_LOG_ERROR,
+ "Mismatch reading %s (%d) with k=%d:\n", str, b, k);
+ av_log(NULL, AV_LOG_ERROR,
+ "Test function result %d consumed %d bits.\n",
+ res_test, con_test);
+ av_log(NULL, AV_LOG_ERROR,
+ "Spec function result %d consumed %d bits.\n",
+ res_spec, con_spec);
+ ++err;
+ if (err > 10)
+ return err;
+ }
+ }
+ }
+
+ return err;
+}
+
+static int random_coeff(AVLFG *lfg)
+{
+ // Geometric distribution of code lengths (1-14 bits),
+ // uniform distribution within codes of the length,
+ // equal probability of either sign.
+ int length = (av_lfg_get(lfg) / (UINT_MAX / 14 + 1));
+ int random = av_lfg_get(lfg);
+ int value = (1 << length) + (random & (1 << length) - 1);
+ if (random & (1 << length))
+ return value;
+ else
+ return -value;
+}
+
+static int random_run(AVLFG *lfg)
+{
+ // Expoenential distrbution of run lengths.
+ unsigned int random = av_lfg_get(lfg);
+ for (int len = 0;; len++) {
+ if (random & (1 << len))
+ return len;
+ }
+ // You rolled zero on a 2^32 sided die; well done!
+ return 64;
+}
+
+static int test_apv_entropy_decode_block(void)
+{
+ // Generate random entropy blocks, code them, then ensure they
+ // decode to the same block. Coefficients are weighted to have
+ // roughly equal numbers of each code length.
+
+ APVVLCLUT decode_lut;
+ AVLFG lfg;
+ unsigned int seed = av_get_random_seed();
+ av_lfg_init(&lfg, seed);
+
+ av_log(NULL, AV_LOG_INFO, "seed = %u\n", seed);
+
+ ff_apv_entropy_build_decode_lut(&decode_lut);
+
+ for (int t = 0; t < 100; t++) {
+ APVEntropyState state;
+ int16_t block[64];
+ int16_t block_test[64];
+ uint8_t buffer[1024];
+ PutBitContext pbc;
+ GetBitContext gbc;
+ int bits_written;
+ int pos, run, coeff, level, err;
+ int k_dc, k_run, k_level;
+
+ memset(block, 0, sizeof(block));
+ memset(buffer, 0, sizeof(buffer));
+ init_put_bits(&pbc, buffer, sizeof(buffer));
+
+ // Randomly-constructed state.
+ state.prev_dc = random_coeff(&lfg);
+ state.prev_dc_diff = random_coeff(&lfg);
+ state.prev_1st_ac_level = random_coeff(&lfg);
+
+ state.decode_lut = &decode_lut;
+
+ k_dc = av_clip(state.prev_dc_diff >> 1, 0, 5);
+ k_run = 0;
+ k_level = av_clip(state.prev_1st_ac_level >> 2, 0, 4);
+
+ coeff = random_coeff(&lfg) / 2;
+ block[ff_zigzag_direct[0]] = state.prev_dc + coeff;
+ apv_write_vlc_spec(&pbc, FFABS(coeff), k_dc);
+ if (coeff != 0)
+ put_bits(&pbc, 1, coeff < 0);
+
+ pos = 1;
+ while (pos < 64) {
+ run = random_run(&lfg);
+ if (pos + run > 64)
+ run = 64 - pos;
+ apv_write_vlc_spec(&pbc, run, k_run);
+ k_run = av_clip(run >> 2, 0, 2);
+ pos += run;
+ if (pos < 64) {
+ coeff = random_coeff(&lfg);
+ level = FFABS(coeff) - 1;
+ block[ff_zigzag_direct[pos]] = coeff;
+ apv_write_vlc_spec(&pbc, level, k_level);
+ put_bits(&pbc, 1, coeff < 0);
+ k_level = av_clip((level + 1) >> 2, 0, 4);
+ ++pos;
+ }
+ }
+ bits_written = put_bits_count(&pbc);
+ flush_put_bits(&pbc);
+
+ // Fill output blocm with a distinctive error value.
+ for (int i = 0; i < 64; i++)
+ block_test[i] = -9999;
+ init_get_bits8(&gbc, buffer, sizeof(buffer));
+
+ err = ff_apv_entropy_decode_block(block_test, &gbc, &state);
+ if (err < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n");
+ return 1;
+ } else {
+ int bits_read = get_bits_count(&gbc);
+ if (bits_written != bits_read) {
+ av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n",
+ bits_written, bits_read);
+ return 1;
+ } else {
+ err = 0;
+ for (int i = 0; i < 64; i++) {
+ if (block[i] != block_test[i])
+ ++err;
+ }
+ if (err > 0) {
+ av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err);
+ return err;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ int err;
+
+ err = test_apv_read_vlc();
+ if (err) {
+ av_log(NULL, AV_LOG_ERROR, "Read VLC test failed.\n");
+ return err;
+ }
+
+ err = test_apv_entropy_decode_block();
+ if (err) {
+ av_log(NULL, AV_LOG_ERROR, "Entropy decode block test failed.\n");
+ return err;
+ }
+
+ return 0;
+}
diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
index ef6e6ec40e..5f7ec97ff3 100644
--- a/tests/fate/libavcodec.mak
+++ b/tests/fate/libavcodec.mak
@@ -3,6 +3,11 @@ fate-av1-levels: libavcodec/tests/av1_levels$(EXESUF)
fate-av1-levels: CMD = run libavcodec/tests/av1_levels$(EXESUF)
fate-av1-levels: REF = /dev/null
+FATE_LIBAVCODEC-$(CONFIG_APV_DECODER) += fate-apv
+fate-apv: libavcodec/tests/apv$(EXESUF)
+fate-apv: CMD = run libavcodec/tests/apv$(EXESUF)
+fate-apv: REF = /dev/null
+
FATE_LIBAVCODEC-yes += fate-avpacket
fate-avpacket: libavcodec/tests/avpacket$(EXESUF)
fate-avpacket: CMD = run libavcodec/tests/avpacket$(EXESUF)
--
2.47.2
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH] lavc: Add unit test for APV entropy decode
2025-04-30 21:09 [FFmpeg-devel] [PATCH] lavc: Add unit test for APV entropy decode Mark Thompson
@ 2025-05-02 17:52 ` Michael Niedermayer
2025-05-02 17:58 ` James Almer
1 sibling, 0 replies; 3+ messages in thread
From: Michael Niedermayer @ 2025-05-02 17:52 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 1482 bytes --]
On Wed, Apr 30, 2025 at 10:09:11PM +0100, Mark Thompson wrote:
> ---
> Cleaned up a bit from use earlier. This program allows testing of changes to entropy decode in a form much easier to debug than a whole stream.
>
> I had a more complete randomised test of transform here as well along with test code for checking intermediates, though it seems like the checkasm only might be preferred. Can add it if useful.
>
> Thanks,
>
> - Mark
>
> libavcodec/Makefile | 1 +
> libavcodec/tests/apv.c | 306 ++++++++++++++++++++++++++++++++++++++
> tests/fate/libavcodec.mak | 5 +
> 3 files changed, 312 insertions(+)
> create mode 100644 libavcodec/tests/apv.c
breaks make -j32 fate-apv
TEST apv-422-10
--- /dev/null 2025-01-24 23:36:38.397802529 +0100
+++ tests/data/fate/apv-422-10 2025-05-02 19:49:42.277166925 +0200
@@ -0,0 +1,8 @@
+#tb 0: 1/30
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 320x180
+#sar 0: 1/1
+0, 0, 0, 1, 230400, 0x07f1e56d
+0, 1, 1, 1, 230400, 0x0bd1c913
+0, 2, 2, 1, 230400, 0xefd02824
Test apv-422-10 failed. Look at tests/data/fate/apv-422-10.err for details.
make: *** [tests/Makefile:317: fate-apv-422-10] Error 1
Note "make fate-apv-422-10" works
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
It is what and why we do it that matters, not just one of them.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH] lavc: Add unit test for APV entropy decode
2025-04-30 21:09 [FFmpeg-devel] [PATCH] lavc: Add unit test for APV entropy decode Mark Thompson
2025-05-02 17:52 ` Michael Niedermayer
@ 2025-05-02 17:58 ` James Almer
1 sibling, 0 replies; 3+ messages in thread
From: James Almer @ 2025-05-02 17:58 UTC (permalink / raw)
To: ffmpeg-devel
[-- Attachment #1.1.1: Type: text/plain, Size: 752 bytes --]
On 4/30/2025 6:09 PM, Mark Thompson wrote:
> diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
> index ef6e6ec40e..5f7ec97ff3 100644
> --- a/tests/fate/libavcodec.mak
> +++ b/tests/fate/libavcodec.mak
> @@ -3,6 +3,11 @@ fate-av1-levels: libavcodec/tests/av1_levels$(EXESUF)
> fate-av1-levels: CMD = run libavcodec/tests/av1_levels$(EXESUF)
> fate-av1-levels: REF = /dev/null
>
> +FATE_LIBAVCODEC-$(CONFIG_APV_DECODER) += fate-apv
> +fate-apv: libavcodec/tests/apv$(EXESUF)
> +fate-apv: CMD = run libavcodec/tests/apv$(EXESUF)
> +fate-apv: REF = /dev/null
fate-apv already exists in tests/fate/apv.mak, as a target to run all
apv decoding tests (only one so far).
Maybe just rename it to fate-apv-entropy.
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-05-02 17:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-30 21:09 [FFmpeg-devel] [PATCH] lavc: Add unit test for APV entropy decode Mark Thompson
2025-05-02 17:52 ` Michael Niedermayer
2025-05-02 17:58 ` James Almer
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git