PR #22645 opened by Priyanshuthapliyal
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22645
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22645.patch

This patch adds FATE coverage for the PDV decoder using generated PDV samples,
bringing `libavcodec/pdvdec.c` from 0% to 88.2% line coverage and 0% to 75%
function coverage.

Signed-off-by: Priyanshu Thapliyal <[email protected]>


>From ba5c1f177c7bac0d398c5c6cfa81d6816bd9b08f Mon Sep 17 00:00:00 2001
From: Priyanshu Thapliyal <[email protected]>
Date: Sat, 28 Mar 2026 01:35:17 +0530
Subject: [PATCH] tests/pdv: add FATE tests for pdvdec

Signed-off-by: Priyanshu Thapliyal <[email protected]>
---
 Makefile                      |   2 +-
 tests/Makefile                |   6 +-
 tests/fate/pdv.mak            |  23 +++
 tests/pdvgen.c                | 275 ++++++++++++++++++++++++++++++++++
 tests/ref/fate/pdv-corrupt    |   6 +
 tests/ref/fate/pdv-delta      |   8 +
 tests/ref/fate/pdv-key        |   6 +
 tests/ref/fate/pdv-skip-all   |   5 +
 tests/ref/fate/pdv-skip-nokey |   7 +
 9 files changed, 336 insertions(+), 2 deletions(-)
 create mode 100644 tests/fate/pdv.mak
 create mode 100644 tests/pdvgen.c
 create mode 100644 tests/ref/fate/pdv-corrupt
 create mode 100644 tests/ref/fate/pdv-delta
 create mode 100644 tests/ref/fate/pdv-key
 create mode 100644 tests/ref/fate/pdv-skip-all
 create mode 100644 tests/ref/fate/pdv-skip-nokey

diff --git a/Makefile b/Makefile
index f296e87ed4..39653b6e40 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ vpath %.ptx  $(SRC_PATH)
 vpath %.metal $(SRC_PATH)
 vpath %/fate_config.sh.template $(SRC_PATH)
 
-TESTTOOLS   = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 audiomatch
+TESTTOOLS   = audiogen videogen rotozoom pdvgen tiny_psnr tiny_ssim base64 
audiomatch
 HOSTPROGS  := $(TESTTOOLS:%=tests/%) doc/print_options
 
 ALLFFLIBS =            \
diff --git a/tests/Makefile b/tests/Makefile
index 4b3fa6a54a..9e097c29ad 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -47,11 +47,14 @@ tests/data/vsynth_lena.yuv: tests/rotozoom$(HOSTEXESUF) | 
tests/data
 tests/data/vsynth3.yuv: tests/videogen$(HOSTEXESUF) | tests/data
        $(M)$< $@ $(FATEW) $(FATEH)
 
+tests/data/pdv-%.pdv: tests/pdvgen$(HOSTEXESUF) | tests/data
+       $(M)./$< $@ $*
+
 tests/test_copy.ffmeta: TAG = COPY
 tests/test_copy.ffmeta: tests/data
        $(M)cp -f $(SRC_PATH)/tests/test.ffmeta tests/test_copy.ffmeta
 
-tests/data/%.sw tests/data/asynth% tests/data/vsynth%.yuv tests/vsynth%/00.pgm 
tests/data/%.nut: TAG = GEN
+tests/data/%.sw tests/data/asynth% tests/data/vsynth%.yuv tests/data/pdv-%.pdv 
tests/vsynth%/00.pgm tests/data/%.nut: TAG = GEN
 
 tests/data/filtergraphs/%: TAG = COPY
 tests/data/filtergraphs/%: $(SRC_PATH)/tests/filtergraphs/% | 
tests/data/filtergraphs
@@ -232,6 +235,7 @@ include $(SRC_PATH)/tests/fate/ogg-opus.mak
 include $(SRC_PATH)/tests/fate/oma.mak
 include $(SRC_PATH)/tests/fate/opus.mak
 include $(SRC_PATH)/tests/fate/pcm.mak
+include $(SRC_PATH)/tests/fate/pdv.mak
 include $(SRC_PATH)/tests/fate/pixfmt.mak
 include $(SRC_PATH)/tests/fate/pixlet.mak
 include $(SRC_PATH)/tests/fate/probe.mak
diff --git a/tests/fate/pdv.mak b/tests/fate/pdv.mak
new file mode 100644
index 0000000000..efbfe28db1
--- /dev/null
+++ b/tests/fate/pdv.mak
@@ -0,0 +1,23 @@
+FATE_PDV += fate-pdv-key
+fate-pdv-key: tests/data/pdv-key.pdv
+fate-pdv-key: CMD = framecrc -i $(TARGET_PATH)/tests/data/pdv-key.pdv 
-frames:v 1
+
+FATE_PDV += fate-pdv-delta
+fate-pdv-delta: tests/data/pdv-delta.pdv
+fate-pdv-delta: CMD = framecrc -i $(TARGET_PATH)/tests/data/pdv-delta.pdv 
-frames:v 3
+
+FATE_PDV += fate-pdv-skip-nokey
+fate-pdv-skip-nokey: tests/data/pdv-mixed.pdv
+fate-pdv-skip-nokey: CMD = framecrc -skip_frame nokey -i 
$(TARGET_PATH)/tests/data/pdv-mixed.pdv -frames:v 4
+
+FATE_PDV += fate-pdv-skip-all
+fate-pdv-skip-all: tests/data/pdv-mixed.pdv
+fate-pdv-skip-all: CMD = framecrc -skip_frame all -i 
$(TARGET_PATH)/tests/data/pdv-mixed.pdv -frames:v 4
+
+FATE_PDV += fate-pdv-corrupt
+fate-pdv-corrupt: tests/data/pdv-corrupt.pdv
+fate-pdv-corrupt: CMD = framecrc -err_detect ignore_err -i 
$(TARGET_PATH)/tests/data/pdv-corrupt.pdv -frames:v 2
+
+FATE_PDV-$(call FRAMECRC, PDV, PDV) += $(FATE_PDV)
+FATE_AVCONV += $(FATE_PDV-yes)
+fate-pdv: $(FATE_PDV-yes)
diff --git a/tests/pdvgen.c b/tests/pdvgen.c
new file mode 100644
index 0000000000..6f874ee9ce
--- /dev/null
+++ b/tests/pdvgen.c
@@ -0,0 +1,275 @@
+/*
+ * Generate synthetic PDV samples for FATE.
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PDV_WIDTH  16
+#define PDV_HEIGHT 8
+
+#define PDV_FPS_30_FLOAT_BITS 0x41F00000U
+
+typedef struct FramePayload {
+    int key;
+    uint8_t *data;
+    int size;
+} FramePayload;
+
+static void put_le16(FILE *f, uint16_t v)
+{
+    fputc(v & 0xFF, f);
+    fputc((v >> 8) & 0xFF, f);
+}
+
+static void put_le32(FILE *f, uint32_t v)
+{
+    fputc(v & 0xFF, f);
+    fputc((v >> 8) & 0xFF, f);
+    fputc((v >> 16) & 0xFF, f);
+    fputc((v >> 24) & 0xFF, f);
+}
+
+static uint32_t adler32_sum(const uint8_t *src, int size)
+{
+    uint32_t a = 1;
+    uint32_t b = 0;
+    int i;
+
+    for (i = 0; i < size; i++) {
+        a += src[i];
+        if (a >= 65521)
+            a -= 65521;
+        b += a;
+        if (b >= 65521)
+            b -= 65521;
+    }
+
+    return (b << 16) | a;
+}
+
+static int make_zlib_stored_packet(const uint8_t *src, int src_size,
+                                   int corrupt, uint8_t **dst, int *dst_size)
+{
+    uint8_t *out;
+    uint8_t *p;
+    uint32_t adler;
+    int blocks;
+    int max_size;
+    int remaining;
+    int offset;
+
+    blocks = (src_size + 65534) / 65535;
+    max_size = 2 + blocks * 5 + src_size + 4;
+
+    out = malloc(max_size);
+    if (!out)
+        return 1;
+
+    p = out;
+
+    *p++ = 0x78;
+    *p++ = 0x01;
+
+    remaining = src_size;
+    offset = 0;
+    while (remaining > 0) {
+        int final = remaining <= 65535;
+        int len = final ? remaining : 65535;
+        uint16_t nlen = (uint16_t)~len;
+
+        *p++ = final ? 0x01 : 0x00;
+        *p++ = len & 0xFF;
+        *p++ = (len >> 8) & 0xFF;
+
+        if (corrupt && final)
+            nlen ^= 1;
+
+        *p++ = nlen & 0xFF;
+        *p++ = (nlen >> 8) & 0xFF;
+
+        memcpy(p, src + offset, len);
+        p += len;
+
+        offset += len;
+        remaining -= len;
+    }
+
+    adler = adler32_sum(src, src_size);
+    *p++ = (adler >> 24) & 0xFF;
+    *p++ = (adler >> 16) & 0xFF;
+    *p++ = (adler >> 8) & 0xFF;
+    *p++ = adler & 0xFF;
+
+    *dst = out;
+    *dst_size = (int)(p - out);
+
+    return 0;
+}
+
+static void fill_absolute_frame(uint8_t *dst, int width, int height, int 
pattern)
+{
+    int row_size = (width + 7) >> 3;
+    int x, y;
+
+    memset(dst, 0, row_size * height);
+
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+            int bit = ((x * (pattern + 1) + y * (pattern + 3) + pattern) ^ (x 
>> 1)) & 1;
+            if (bit)
+                dst[y * row_size + (x >> 3)] |= 0x80 >> (x & 7);
+        }
+    }
+}
+
+static int configure_mode(const char *mode, int *nb_frames, int 
*corrupt_index, int key[4])
+{
+    *corrupt_index = -1;
+
+    if (!strcmp(mode, "key")) {
+        *nb_frames = 1;
+        key[0] = 1;
+    } else if (!strcmp(mode, "delta")) {
+        *nb_frames = 3;
+        key[0] = 1;
+        key[1] = 0;
+        key[2] = 0;
+    } else if (!strcmp(mode, "mixed")) {
+        *nb_frames = 4;
+        key[0] = 1;
+        key[1] = 0;
+        key[2] = 1;
+        key[3] = 0;
+    } else if (!strcmp(mode, "corrupt")) {
+        *nb_frames = 2;
+        key[0] = 1;
+        key[1] = 0;
+        *corrupt_index = 1;
+    } else {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int write_pdv_file(const char *path, int nb_frames, const FramePayload 
*frames)
+{
+    FILE *f;
+    static const uint8_t pdv_magic[16] = {
+        'P', 'l', 'a', 'y', 'd', 'a', 't', 'e', ' ', 'V', 'I', 'D', 0, 0, 0, 0
+    };
+    uint32_t offset = 0;
+    int i;
+
+    f = fopen(path, "wb");
+    if (!f)
+        return 1;
+
+    fwrite(pdv_magic, 1, sizeof(pdv_magic), f);
+    put_le16(f, nb_frames);
+    put_le16(f, 0);
+    put_le32(f, PDV_FPS_30_FLOAT_BITS);
+    put_le16(f, PDV_WIDTH);
+    put_le16(f, PDV_HEIGHT);
+
+    for (i = 0; i < nb_frames; i++) {
+        uint32_t flag = frames[i].key ? 1 : 2;
+        put_le32(f, (offset << 2) | flag);
+        offset += frames[i].size;
+    }
+    put_le32(f, offset << 2);
+
+    for (i = 0; i < nb_frames; i++) {
+        if (fwrite(frames[i].data, 1, frames[i].size, f) != 
(size_t)frames[i].size) {
+            fclose(f);
+            return 1;
+        }
+    }
+
+    fclose(f);
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    FramePayload frames[4] = { 0 };
+    uint8_t *abs = NULL;
+    uint8_t *prev = NULL;
+    uint8_t *raw = NULL;
+    int key[4] = { 0 };
+    int nb_frames;
+    int corrupt_index;
+    int row_size = (PDV_WIDTH + 7) >> 3;
+    int raw_size = row_size * PDV_HEIGHT;
+    int ret = 1;
+    int i, j;
+
+    if (argc != 3) {
+        fprintf(stderr, "usage: %s <output.pdv> <key|delta|mixed|corrupt>\n", 
argv[0]);
+        return 1;
+    }
+
+    if (configure_mode(argv[2], &nb_frames, &corrupt_index, key)) {
+        fprintf(stderr, "unknown mode '%s'\n", argv[2]);
+        return 1;
+    }
+
+    abs = malloc(raw_size);
+    prev = malloc(raw_size);
+    raw = malloc(raw_size);
+    if (!abs || !prev || !raw)
+        goto end;
+
+    memset(prev, 0, raw_size);
+
+    for (i = 0; i < nb_frames; i++) {
+        fill_absolute_frame(abs, PDV_WIDTH, PDV_HEIGHT, i + 1);
+
+        if (key[i]) {
+            memcpy(raw, abs, raw_size);
+        } else {
+            for (j = 0; j < raw_size; j++)
+                raw[j] = abs[j] ^ prev[j];
+        }
+
+        frames[i].key = key[i];
+        if (make_zlib_stored_packet(raw, raw_size, i == corrupt_index,
+                                    &frames[i].data, &frames[i].size))
+            goto end;
+
+        memcpy(prev, abs, raw_size);
+    }
+
+    if (write_pdv_file(argv[1], nb_frames, frames))
+        goto end;
+
+    ret = 0;
+
+end:
+    for (i = 0; i < 4; i++)
+        free(frames[i].data);
+    free(abs);
+    free(prev);
+    free(raw);
+
+    return ret;
+}
diff --git a/tests/ref/fate/pdv-corrupt b/tests/ref/fate/pdv-corrupt
new file mode 100644
index 0000000000..983d82e247
--- /dev/null
+++ b/tests/ref/fate/pdv-corrupt
@@ -0,0 +1,6 @@
+#tb 0: 1/30
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 16x8
+#sar 0: 0/1
+0,          0,          0,        1,       16, 0x6c600cc0
diff --git a/tests/ref/fate/pdv-delta b/tests/ref/fate/pdv-delta
new file mode 100644
index 0000000000..d5d4c53af2
--- /dev/null
+++ b/tests/ref/fate/pdv-delta
@@ -0,0 +1,8 @@
+#tb 0: 1/30
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 16x8
+#sar 0: 0/1
+0,          0,          0,        1,       16, 0x6c600cc0
+0,          1,          1,        1,       16, 0x422407f8
+0,          2,          2,        1,       16, 0x6c600cc0
diff --git a/tests/ref/fate/pdv-key b/tests/ref/fate/pdv-key
new file mode 100644
index 0000000000..983d82e247
--- /dev/null
+++ b/tests/ref/fate/pdv-key
@@ -0,0 +1,6 @@
+#tb 0: 1/30
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 16x8
+#sar 0: 0/1
+0,          0,          0,        1,       16, 0x6c600cc0
diff --git a/tests/ref/fate/pdv-skip-all b/tests/ref/fate/pdv-skip-all
new file mode 100644
index 0000000000..84d7ad7b3f
--- /dev/null
+++ b/tests/ref/fate/pdv-skip-all
@@ -0,0 +1,5 @@
+#tb 0: 1/30
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 16x8
+#sar 0: 0/1
diff --git a/tests/ref/fate/pdv-skip-nokey b/tests/ref/fate/pdv-skip-nokey
new file mode 100644
index 0000000000..d824b2a4df
--- /dev/null
+++ b/tests/ref/fate/pdv-skip-nokey
@@ -0,0 +1,7 @@
+#tb 0: 1/30
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 16x8
+#sar 0: 0/1
+0,          0,          0,        1,       16, 0x6c600cc0
+0,          2,          2,        1,       16, 0x6c600cc0
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to