PR #22767 opened by Marcos Ashton (MarcosAsh)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22767
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22767.patch
## Summary
1. buffer -- av_buffer_alloc/allocz/create (custom free, readonly), ref/unref,
is_writable, get_ref_count, get_opaque, make_writable, realloc (including from
NULL), replace (including with NULL), pool_init/get/uninit cycle, pool_init2
with custom alloc and pool_free callbacks, pool_buffer_get_opaque, and OOM
paths.
Coverage for libavutil/buffer.c: 0.00% -> 90.19% (remaining uncovered lines are
mutex init failures and secondary allocation failure paths).
2. hdr_dynamic_vivid_metadata -- av_dynamic_hdr_vivid_alloc,
av_dynamic_hdr_vivid_create_side_data, defaults, write/read-back of
system_start_code, num_windows, min/avg/var/max RGB params, frame side data
attachment, and OOM paths.
Coverage for libavutil/hdr_dynamic_vivid_metadata.c: 0.00% -> 100.00%
3. tdrdi -- av_tdrdi_alloc with 1 and 3 displays, the inline
av_tdrdi_get_display accessor with pointer consistency checks against
entries_offset + idx * entry_size, write/read-back of display fields, and OOM
paths.
Coverage for libavutil/tdrdi.c: 0.00% -> 100.00%
4. timestamp -- av_ts_make_string with NOPTS, zero, positive, negative, and
INT64 boundary values, av_ts2str, av_ts_make_time_string2 with multiple
timebases, and av_ts_make_time_string pointer variant.
Coverage for libavutil/timestamp.c: 0.00% -> 100.00%
>From 199cfc2e54d626693f278c076b1bb902cbe2879d Mon Sep 17 00:00:00 2001
From: marcos ashton <[email protected]>
Date: Thu, 9 Apr 2026 15:24:48 +0100
Subject: [PATCH 1/4] tests/fate/libavutil: add FATE test for buffer
Test av_buffer_alloc, av_buffer_allocz, av_buffer_create with
custom free callback, AV_BUFFER_FLAG_READONLY, av_buffer_ref,
av_buffer_is_writable, av_buffer_get_ref_count,
av_buffer_make_writable, av_buffer_realloc (including from NULL),
av_buffer_replace (including with NULL), av_buffer_pool
init/get/uninit cycle, av_buffer_pool_init2 with custom alloc
and pool_free callbacks, av_buffer_pool_buffer_get_opaque, and
OOM paths via av_max_alloc.
Coverage for libavutil/buffer.c: 0.00% -> 90.19%
Remaining uncovered lines are mutex init failures and
secondary allocation failure paths.
---
.forgejo/CODEOWNERS | 2 +
libavutil/Makefile | 1 +
libavutil/tests/buffer.c | 251 +++++++++++++++++++++++++++++++++++++++
tests/fate/libavutil.mak | 4 +
tests/ref/fate/buffer | 57 +++++++++
5 files changed, 315 insertions(+)
create mode 100644 libavutil/tests/buffer.c
create mode 100644 tests/ref/fate/buffer
diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS
index 02ca5b331a..a8a4556a48 100644
--- a/.forgejo/CODEOWNERS
+++ b/.forgejo/CODEOWNERS
@@ -231,7 +231,9 @@ doc/.* @GyanD
# tests
# =====
tests/checkasm/riscv/.* @Courmisch
+libavutil/tests/buffer.* @MarcosAsh
tests/ref/.*drawvg.* @ayosec
+tests/ref/fate/buffer @MarcosAsh
tests/ref/fate/sub-mcc.* @programmerjake
# Forgejo
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 38e08a3d5d..903e5cdcad 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -263,6 +263,7 @@ TESTPROGS = adler32
\
base64 \
blowfish \
bprint \
+ buffer \
cast5 \
camellia \
channel_layout \
diff --git a/libavutil/tests/buffer.c b/libavutil/tests/buffer.c
new file mode 100644
index 0000000000..b6e67befb4
--- /dev/null
+++ b/libavutil/tests/buffer.c
@@ -0,0 +1,251 @@
+/*
+ * 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 <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libavutil/buffer.h"
+#include "libavutil/mem.h"
+
+static int custom_free_called;
+static int pool_free_called;
+static int pool_alloc2_called;
+
+static void custom_free(void *opaque, uint8_t *data)
+{
+ custom_free_called = 1;
+ av_free(data);
+}
+
+static AVBufferRef *pool_alloc2(void *opaque, size_t size)
+{
+ pool_alloc2_called = 1;
+ return av_buffer_alloc(size);
+}
+
+static void pool_free_cb(void *opaque)
+{
+ pool_free_called = 1;
+}
+
+int main(void)
+{
+ AVBufferRef *buf, *buf2;
+ AVBufferPool *pool;
+
+ /* av_buffer_alloc */
+ printf("Testing av_buffer_alloc()\n");
+ buf = av_buffer_alloc(64);
+ if (buf) {
+ printf("alloc: size=%zu data=%s\n", buf->size, buf->data ? "set" :
"null");
+ printf("writable: %d\n", av_buffer_is_writable(buf));
+ printf("refcount: %d\n", av_buffer_get_ref_count(buf));
+ av_buffer_unref(&buf);
+ printf("after unref: %s\n", buf == NULL ? "null" : "leaked");
+ }
+
+ /* av_buffer_allocz */
+ printf("\nTesting av_buffer_allocz()\n");
+ buf = av_buffer_allocz(16);
+ if (buf) {
+ int zeroed = 1;
+ for (int i = 0; i < 16; i++)
+ if (buf->data[i] != 0) zeroed = 0;
+ printf("allocz: zeroed=%s\n", zeroed ? "yes" : "no");
+ av_buffer_unref(&buf);
+ }
+
+ /* av_buffer_create with custom free */
+ printf("\nTesting av_buffer_create()\n");
+ {
+ uint8_t *data = av_malloc(32);
+ if (data) {
+ custom_free_called = 0;
+ buf = av_buffer_create(data, 32, custom_free, NULL, 0);
+ if (buf) {
+ printf("create: size=%zu\n", buf->size);
+ printf("opaque: %s\n",
+ av_buffer_get_opaque(buf) == NULL ? "null" : "set");
+ av_buffer_unref(&buf);
+ printf("custom_free called: %s\n",
+ custom_free_called ? "yes" : "no");
+ } else {
+ av_free(data);
+ }
+ }
+ }
+
+ /* av_buffer_create with READONLY flag */
+ printf("\nTesting AV_BUFFER_FLAG_READONLY\n");
+ {
+ uint8_t *data = av_malloc(16);
+ if (data) {
+ buf = av_buffer_create(data, 16, custom_free, NULL,
+ AV_BUFFER_FLAG_READONLY);
+ if (buf) {
+ printf("readonly writable: %d\n", av_buffer_is_writable(buf));
+ av_buffer_unref(&buf);
+ } else {
+ av_free(data);
+ }
+ }
+ }
+
+ /* av_buffer_ref and refcounting */
+ printf("\nTesting av_buffer_ref()\n");
+ buf = av_buffer_alloc(32);
+ if (buf) {
+ buf->data[0] = 0xAB;
+ buf2 = av_buffer_ref(buf);
+ if (buf2) {
+ printf("ref: refcount=%d\n", av_buffer_get_ref_count(buf));
+ printf("shared data: %s\n",
+ buf2->data[0] == 0xAB ? "yes" : "no");
+ printf("writable after ref: %d\n", av_buffer_is_writable(buf));
+ av_buffer_unref(&buf2);
+ printf("refcount after unref: %d\n", av_buffer_get_ref_count(buf));
+ printf("writable after unref: %d\n", av_buffer_is_writable(buf));
+ }
+ av_buffer_unref(&buf);
+ }
+
+ /* av_buffer_make_writable */
+ printf("\nTesting av_buffer_make_writable()\n");
+ buf = av_buffer_alloc(16);
+ if (buf) {
+ buf->data[0] = 0xCD;
+ buf2 = av_buffer_ref(buf);
+ if (buf2) {
+ int ret = av_buffer_make_writable(&buf2);
+ printf("make_writable ret: %d\n", ret >= 0);
+ printf("data preserved: %s\n",
+ buf2->data[0] == 0xCD ? "yes" : "no");
+ printf("now writable: %d\n", av_buffer_is_writable(buf2));
+ printf("original still valid: %s\n",
+ buf->data[0] == 0xCD ? "yes" : "no");
+ av_buffer_unref(&buf2);
+ }
+ av_buffer_unref(&buf);
+ }
+
+ /* av_buffer_realloc */
+ printf("\nTesting av_buffer_realloc()\n");
+ buf = av_buffer_alloc(16);
+ if (buf) {
+ memset(buf->data, 0xEF, 16);
+ av_buffer_realloc(&buf, 32);
+ if (buf) {
+ printf("realloc: size=%zu\n", buf->size);
+ printf("data preserved: %s\n",
+ buf->data[0] == 0xEF ? "yes" : "no");
+ }
+ av_buffer_unref(&buf);
+ }
+ /* realloc from NULL */
+ buf = NULL;
+ av_buffer_realloc(&buf, 8);
+ printf("realloc from null: %s\n", buf ? "OK" : "FAIL");
+ av_buffer_unref(&buf);
+
+ /* av_buffer_replace */
+ printf("\nTesting av_buffer_replace()\n");
+ buf = av_buffer_alloc(8);
+ buf2 = av_buffer_alloc(8);
+ if (buf && buf2) {
+ buf->data[0] = 0x11;
+ buf2->data[0] = 0x22;
+ av_buffer_replace(&buf, buf2);
+ printf("replace: data=0x%02x\n", buf->data[0]);
+ printf("refcount: %d\n", av_buffer_get_ref_count(buf2));
+ }
+ av_buffer_unref(&buf);
+ av_buffer_unref(&buf2);
+
+ /* replace with NULL */
+ buf = av_buffer_alloc(8);
+ if (buf) {
+ av_buffer_replace(&buf, NULL);
+ printf("replace with null: %s\n", buf == NULL ? "OK" : "FAIL");
+ }
+
+ /* av_buffer_pool */
+ printf("\nTesting av_buffer_pool()\n");
+ pool = av_buffer_pool_init(64, NULL);
+ if (pool) {
+ buf = av_buffer_pool_get(pool);
+ if (buf) {
+ printf("pool get: size=%zu\n", buf->size);
+ av_buffer_unref(&buf);
+ }
+ /* get again -- should reuse the released buffer */
+ buf = av_buffer_pool_get(pool);
+ if (buf) {
+ printf("pool reuse: size=%zu\n", buf->size);
+ av_buffer_unref(&buf);
+ }
+ av_buffer_pool_uninit(&pool);
+ printf("pool uninit: %s\n", pool == NULL ? "OK" : "FAIL");
+ }
+
+ /* av_buffer_pool_init2 with custom alloc and pool_free callbacks */
+ printf("\nTesting av_buffer_pool_init2()\n");
+ pool_alloc2_called = 0;
+ pool_free_called = 0;
+ pool = av_buffer_pool_init2(64, NULL, pool_alloc2, pool_free_cb);
+ if (pool) {
+ buf = av_buffer_pool_get(pool);
+ if (buf) {
+ printf("pool2 get: size=%zu\n", buf->size);
+ printf("alloc2 called: %s\n", pool_alloc2_called ? "yes" : "no");
+ printf("pool_buffer_get_opaque: %s\n",
+ av_buffer_pool_buffer_get_opaque(buf) == NULL ? "null" :
"set");
+ av_buffer_unref(&buf);
+ }
+ av_buffer_pool_uninit(&pool);
+ printf("pool_free called: %s\n", pool_free_called ? "yes" : "no");
+ }
+
+ /* OOM paths via av_max_alloc */
+ printf("\nTesting OOM paths\n");
+ av_max_alloc(1);
+ buf = av_buffer_alloc(64);
+ printf("alloc OOM: %s\n", buf ? "FAIL" : "OK");
+ av_buffer_unref(&buf);
+ buf = av_buffer_allocz(64);
+ printf("allocz OOM: %s\n", buf ? "FAIL" : "OK");
+ av_buffer_unref(&buf);
+ pool = av_buffer_pool_init(64, NULL);
+ printf("pool init OOM: %s\n", pool ? "FAIL" : "OK");
+ av_buffer_pool_uninit(&pool);
+ av_max_alloc(INT_MAX);
+
+ buf = av_buffer_alloc(16);
+ if (buf) {
+ av_max_alloc(1);
+ buf2 = av_buffer_ref(buf);
+ printf("ref OOM: %s\n", buf2 ? "FAIL" : "OK");
+ av_buffer_unref(&buf2);
+ printf("realloc OOM: %s\n",
+ av_buffer_realloc(&buf, 1024) < 0 ? "OK" : "FAIL");
+ av_max_alloc(INT_MAX);
+ av_buffer_unref(&buf);
+ }
+
+ return 0;
+}
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index 12143bc248..af78a803e5 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -47,6 +47,10 @@ FATE_LIBAVUTIL += fate-bprint
fate-bprint: libavutil/tests/bprint$(EXESUF)
fate-bprint: CMD = run libavutil/tests/bprint$(EXESUF)
+FATE_LIBAVUTIL += fate-buffer
+fate-buffer: libavutil/tests/buffer$(EXESUF)
+fate-buffer: CMD = run libavutil/tests/buffer$(EXESUF)
+
FATE_LIBAVUTIL += fate-cpu
fate-cpu: libavutil/tests/cpu$(EXESUF)
fate-cpu: CMD = runecho libavutil/tests/cpu$(EXESUF) $(CPUFLAGS:%=-c%)
$(THREADS:%=-t%)
diff --git a/tests/ref/fate/buffer b/tests/ref/fate/buffer
new file mode 100644
index 0000000000..5c2946babf
--- /dev/null
+++ b/tests/ref/fate/buffer
@@ -0,0 +1,57 @@
+Testing av_buffer_alloc()
+alloc: size=64 data=set
+writable: 1
+refcount: 1
+after unref: null
+
+Testing av_buffer_allocz()
+allocz: zeroed=yes
+
+Testing av_buffer_create()
+create: size=32
+opaque: null
+custom_free called: yes
+
+Testing AV_BUFFER_FLAG_READONLY
+readonly writable: 0
+
+Testing av_buffer_ref()
+ref: refcount=2
+shared data: yes
+writable after ref: 0
+refcount after unref: 1
+writable after unref: 1
+
+Testing av_buffer_make_writable()
+make_writable ret: 1
+data preserved: yes
+now writable: 1
+original still valid: yes
+
+Testing av_buffer_realloc()
+realloc: size=32
+data preserved: yes
+realloc from null: OK
+
+Testing av_buffer_replace()
+replace: data=0x22
+refcount: 2
+replace with null: OK
+
+Testing av_buffer_pool()
+pool get: size=64
+pool reuse: size=64
+pool uninit: OK
+
+Testing av_buffer_pool_init2()
+pool2 get: size=64
+alloc2 called: yes
+pool_buffer_get_opaque: null
+pool_free called: yes
+
+Testing OOM paths
+alloc OOM: OK
+allocz OOM: OK
+pool init OOM: OK
+ref OOM: OK
+realloc OOM: OK
--
2.52.0
>From b451d1f127830b14337f5930b8bc54ea7f7dab89 Mon Sep 17 00:00:00 2001
From: marcos ashton <[email protected]>
Date: Thu, 9 Apr 2026 15:31:50 +0100
Subject: [PATCH 2/4] tests/fate/libavutil: add FATE test for
hdr_dynamic_vivid_metadata
Test av_dynamic_hdr_vivid_alloc and
av_dynamic_hdr_vivid_create_side_data. Verifies zero defaults,
write/read-back of system_start_code, num_windows, and
color transform params (min/avg/var/max RGB), frame side
data attachment, and OOM paths via av_max_alloc.
Coverage for libavutil/hdr_dynamic_vivid_metadata.c: 0.00% -> 100.00%
---
.forgejo/CODEOWNERS | 2 +
libavutil/Makefile | 1 +
libavutil/tests/hdr_dynamic_vivid_metadata.c | 100 +++++++++++++++++++
tests/fate/libavutil.mak | 4 +
tests/ref/fate/hdr_dynamic_vivid_metadata | 14 +++
5 files changed, 121 insertions(+)
create mode 100644 libavutil/tests/hdr_dynamic_vivid_metadata.c
create mode 100644 tests/ref/fate/hdr_dynamic_vivid_metadata
diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS
index a8a4556a48..06466e49c4 100644
--- a/.forgejo/CODEOWNERS
+++ b/.forgejo/CODEOWNERS
@@ -232,8 +232,10 @@ doc/.* @GyanD
# =====
tests/checkasm/riscv/.* @Courmisch
libavutil/tests/buffer.* @MarcosAsh
+libavutil/tests/hdr_dynamic_vivid_metadata.* @MarcosAsh
tests/ref/.*drawvg.* @ayosec
tests/ref/fate/buffer @MarcosAsh
+tests/ref/fate/hdr_dynamic_vivid_metadata @MarcosAsh
tests/ref/fate/sub-mcc.* @programmerjake
# Forgejo
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 903e5cdcad..122123f375 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -281,6 +281,7 @@ TESTPROGS = adler32
\
fifo \
film_grain_params \
hash \
+ hdr_dynamic_vivid_metadata \
hmac \
hwdevice \
integer \
diff --git a/libavutil/tests/hdr_dynamic_vivid_metadata.c
b/libavutil/tests/hdr_dynamic_vivid_metadata.c
new file mode 100644
index 0000000000..ece1f5b29f
--- /dev/null
+++ b/libavutil/tests/hdr_dynamic_vivid_metadata.c
@@ -0,0 +1,100 @@
+/*
+ * 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 <limits.h>
+#include <stdio.h>
+
+#include "libavutil/frame.h"
+#include "libavutil/hdr_dynamic_vivid_metadata.h"
+#include "libavutil/mem.h"
+
+int main(void)
+{
+ AVDynamicHDRVivid *vivid;
+ AVFrame *frame;
+ size_t size;
+
+ /* av_dynamic_hdr_vivid_alloc */
+ printf("Testing av_dynamic_hdr_vivid_alloc()\n");
+ vivid = av_dynamic_hdr_vivid_alloc(&size);
+ if (vivid) {
+ printf("alloc: OK, size>0=%s\n", size > 0 ? "yes" : "no");
+ printf("defaults: system_start_code=%u, num_windows=%u\n",
+ vivid->system_start_code, vivid->num_windows);
+
+ /* write and read back */
+ vivid->system_start_code = 0x01;
+ vivid->num_windows = 1;
+ vivid->params[0].minimum_maxrgb = (AVRational){ 100, 1 };
+ vivid->params[0].average_maxrgb = (AVRational){ 500, 1 };
+ vivid->params[0].variance_maxrgb = (AVRational){ 200, 1 };
+ vivid->params[0].maximum_maxrgb = (AVRational){ 1000, 1 };
+ printf("write: system_start_code=%u, num_windows=%u\n",
+ vivid->system_start_code, vivid->num_windows);
+ printf("params[0]: min=%d/%d avg=%d/%d var=%d/%d max=%d/%d\n",
+ vivid->params[0].minimum_maxrgb.num,
+ vivid->params[0].minimum_maxrgb.den,
+ vivid->params[0].average_maxrgb.num,
+ vivid->params[0].average_maxrgb.den,
+ vivid->params[0].variance_maxrgb.num,
+ vivid->params[0].variance_maxrgb.den,
+ vivid->params[0].maximum_maxrgb.num,
+ vivid->params[0].maximum_maxrgb.den);
+ av_free(vivid);
+ }
+
+ /* alloc with NULL size */
+ vivid = av_dynamic_hdr_vivid_alloc(NULL);
+ printf("alloc (no size): %s\n", vivid ? "OK" : "FAIL");
+ av_free(vivid);
+
+ /* av_dynamic_hdr_vivid_create_side_data */
+ printf("\nTesting av_dynamic_hdr_vivid_create_side_data()\n");
+ frame = av_frame_alloc();
+ if (frame) {
+ vivid = av_dynamic_hdr_vivid_create_side_data(frame);
+ if (vivid) {
+ printf("side_data: OK\n");
+ vivid->system_start_code = 0x02;
+ printf("side_data write: system_start_code=%u\n",
+ vivid->system_start_code);
+ } else {
+ printf("side_data: FAIL\n");
+ }
+ av_frame_free(&frame);
+ }
+
+ /* OOM paths via av_max_alloc */
+ printf("\nTesting OOM paths\n");
+ av_max_alloc(1);
+ vivid = av_dynamic_hdr_vivid_alloc(&size);
+ printf("alloc OOM: %s\n", vivid ? "FAIL" : "OK");
+ av_free(vivid);
+ av_max_alloc(INT_MAX);
+
+ frame = av_frame_alloc();
+ if (frame) {
+ av_max_alloc(1);
+ vivid = av_dynamic_hdr_vivid_create_side_data(frame);
+ printf("side_data OOM: %s\n", vivid ? "FAIL" : "OK");
+ av_max_alloc(INT_MAX);
+ av_frame_free(&frame);
+ }
+
+ return 0;
+}
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index af78a803e5..f29fab29b4 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -103,6 +103,10 @@ FATE_LIBAVUTIL += fate-hash
fate-hash: libavutil/tests/hash$(EXESUF)
fate-hash: CMD = run libavutil/tests/hash$(EXESUF)
+FATE_LIBAVUTIL += fate-hdr_dynamic_vivid_metadata
+fate-hdr_dynamic_vivid_metadata:
libavutil/tests/hdr_dynamic_vivid_metadata$(EXESUF)
+fate-hdr_dynamic_vivid_metadata: CMD = run
libavutil/tests/hdr_dynamic_vivid_metadata$(EXESUF)
+
FATE_LIBAVUTIL += fate-hmac
fate-hmac: libavutil/tests/hmac$(EXESUF)
fate-hmac: CMD = run libavutil/tests/hmac$(EXESUF)
diff --git a/tests/ref/fate/hdr_dynamic_vivid_metadata
b/tests/ref/fate/hdr_dynamic_vivid_metadata
new file mode 100644
index 0000000000..f4e8c4f811
--- /dev/null
+++ b/tests/ref/fate/hdr_dynamic_vivid_metadata
@@ -0,0 +1,14 @@
+Testing av_dynamic_hdr_vivid_alloc()
+alloc: OK, size>0=yes
+defaults: system_start_code=0, num_windows=0
+write: system_start_code=1, num_windows=1
+params[0]: min=100/1 avg=500/1 var=200/1 max=1000/1
+alloc (no size): OK
+
+Testing av_dynamic_hdr_vivid_create_side_data()
+side_data: OK
+side_data write: system_start_code=2
+
+Testing OOM paths
+alloc OOM: OK
+side_data OOM: OK
--
2.52.0
>From c20609004d1100f559a26ba68db1a11ce2450a77 Mon Sep 17 00:00:00 2001
From: marcos ashton <[email protected]>
Date: Thu, 9 Apr 2026 15:32:33 +0100
Subject: [PATCH 3/4] tests/fate/libavutil: add FATE test for tdrdi
Test av_tdrdi_alloc with 1 and 3 displays, and the inline
av_tdrdi_get_display accessor. Verifies that the returned
pointer matches entries_offset + idx * entry_size, tests
write/read-back of display width exponent/mantissa and view ID
fields, and OOM paths via av_max_alloc.
Coverage for libavutil/tdrdi.c: 0.00% -> 100.00%
---
.forgejo/CODEOWNERS | 2 +
libavutil/Makefile | 1 +
libavutil/tests/tdrdi.c | 92 ++++++++++++++++++++++++++++++++++++++++
tests/fate/libavutil.mak | 4 ++
tests/ref/fate/tdrdi | 14 ++++++
5 files changed, 113 insertions(+)
create mode 100644 libavutil/tests/tdrdi.c
create mode 100644 tests/ref/fate/tdrdi
diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS
index 06466e49c4..5219fb52e4 100644
--- a/.forgejo/CODEOWNERS
+++ b/.forgejo/CODEOWNERS
@@ -233,10 +233,12 @@ doc/.* @GyanD
tests/checkasm/riscv/.* @Courmisch
libavutil/tests/buffer.* @MarcosAsh
libavutil/tests/hdr_dynamic_vivid_metadata.* @MarcosAsh
+libavutil/tests/tdrdi.* @MarcosAsh
tests/ref/.*drawvg.* @ayosec
tests/ref/fate/buffer @MarcosAsh
tests/ref/fate/hdr_dynamic_vivid_metadata @MarcosAsh
tests/ref/fate/sub-mcc.* @programmerjake
+tests/ref/fate/tdrdi @MarcosAsh
# Forgejo
# =======
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 122123f375..83ca133d04 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -309,6 +309,7 @@ TESTPROGS = adler32
\
softfloat \
spherical \
stereo3d \
+ tdrdi \
timecode \
tree \
twofish \
diff --git a/libavutil/tests/tdrdi.c b/libavutil/tests/tdrdi.c
new file mode 100644
index 0000000000..5daa32f404
--- /dev/null
+++ b/libavutil/tests/tdrdi.c
@@ -0,0 +1,92 @@
+/*
+ * 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 <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "libavutil/mem.h"
+#include "libavutil/tdrdi.h"
+
+int main(void)
+{
+ AV3DReferenceDisplaysInfo *tdrdi;
+ AV3DReferenceDisplay *display;
+ size_t size;
+
+ /* av_tdrdi_alloc with 1 display */
+ printf("Testing av_tdrdi_alloc()\n");
+ tdrdi = av_tdrdi_alloc(1, &size);
+ if (tdrdi) {
+ printf("alloc 1: size>0=%s, num_ref_displays=%u\n",
+ size > 0 ? "yes" : "no", tdrdi->num_ref_displays);
+
+ display = av_tdrdi_get_display(tdrdi, 0);
+ /* pointer consistency check */
+ if ((uint8_t *)display != (uint8_t *)tdrdi + tdrdi->entries_offset)
+ printf("display 0: pointer inconsistent with entries_offset\n");
+
+ /* write and read back */
+ display->exponent_ref_display_width = 3;
+ display->mantissa_ref_display_width = 100;
+ display->left_view_id = 0;
+ display->right_view_id = 1;
+ display = av_tdrdi_get_display(tdrdi, 0);
+ printf("display 0: width_exp=%u width_man=%u left=%u right=%u\n",
+ display->exponent_ref_display_width,
+ display->mantissa_ref_display_width,
+ display->left_view_id, display->right_view_id);
+ av_free(tdrdi);
+ }
+
+ /* alloc with multiple displays */
+ printf("\nTesting multiple displays\n");
+ tdrdi = av_tdrdi_alloc(3, &size);
+ if (tdrdi) {
+ printf("alloc 3: num_ref_displays=%u\n", tdrdi->num_ref_displays);
+ for (int i = 0; i < 3; i++) {
+ display = av_tdrdi_get_display(tdrdi, i);
+ /* verify stride consistency */
+ if ((uint8_t *)display != (uint8_t *)tdrdi + tdrdi->entries_offset
+
+ (size_t)i * tdrdi->entry_size)
+ printf("display %d: pointer inconsistent\n", i);
+ display->exponent_ref_display_width = i + 1;
+ }
+ for (int i = 0; i < 3; i++) {
+ display = av_tdrdi_get_display(tdrdi, i);
+ printf("display %d: width_exp=%u\n", i,
+ display->exponent_ref_display_width);
+ }
+ av_free(tdrdi);
+ }
+
+ /* alloc with NULL size */
+ tdrdi = av_tdrdi_alloc(1, NULL);
+ printf("\nalloc (no size): %s\n", tdrdi ? "OK" : "FAIL");
+ av_free(tdrdi);
+
+ /* OOM paths via av_max_alloc */
+ printf("\nTesting OOM paths\n");
+ av_max_alloc(1);
+ tdrdi = av_tdrdi_alloc(1, &size);
+ printf("alloc OOM: %s\n", tdrdi ? "FAIL" : "OK");
+ av_free(tdrdi);
+ av_max_alloc(INT_MAX);
+
+ return 0;
+}
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index f29fab29b4..a83539a58f 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -188,6 +188,10 @@ FATE_LIBAVUTIL += fate-stereo3d
fate-stereo3d: libavutil/tests/stereo3d$(EXESUF)
fate-stereo3d: CMD = run libavutil/tests/stereo3d$(EXESUF)
+FATE_LIBAVUTIL += fate-tdrdi
+fate-tdrdi: libavutil/tests/tdrdi$(EXESUF)
+fate-tdrdi: CMD = run libavutil/tests/tdrdi$(EXESUF)
+
FATE_LIBAVUTIL += fate-tree
fate-tree: libavutil/tests/tree$(EXESUF)
fate-tree: CMD = run libavutil/tests/tree$(EXESUF)
diff --git a/tests/ref/fate/tdrdi b/tests/ref/fate/tdrdi
new file mode 100644
index 0000000000..a94bf2e3b8
--- /dev/null
+++ b/tests/ref/fate/tdrdi
@@ -0,0 +1,14 @@
+Testing av_tdrdi_alloc()
+alloc 1: size>0=yes, num_ref_displays=1
+display 0: width_exp=3 width_man=100 left=0 right=1
+
+Testing multiple displays
+alloc 3: num_ref_displays=3
+display 0: width_exp=1
+display 1: width_exp=2
+display 2: width_exp=3
+
+alloc (no size): OK
+
+Testing OOM paths
+alloc OOM: OK
--
2.52.0
>From 26bb3c56950ecf1b68935e793cbfe26997aa7af7 Mon Sep 17 00:00:00 2001
From: marcos ashton <[email protected]>
Date: Thu, 9 Apr 2026 15:37:47 +0100
Subject: [PATCH 4/4] tests/fate/libavutil: add FATE test for timestamp
Test av_ts_make_string with NOPTS, zero, positive, negative, and
INT64 boundary values, av_ts2str macro, av_ts_make_time_string2
with various timebases, and av_ts_make_time_string pointer
variant.
Coverage for libavutil/timestamp.c: 0.00% -> 100.00%
---
.forgejo/CODEOWNERS | 2 +
libavutil/Makefile | 1 +
libavutil/tests/timestamp.c | 75 +++++++++++++++++++++++++++++++++++++
tests/fate/libavutil.mak | 4 ++
tests/ref/fate/timestamp | 23 ++++++++++++
5 files changed, 105 insertions(+)
create mode 100644 libavutil/tests/timestamp.c
create mode 100644 tests/ref/fate/timestamp
diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS
index 5219fb52e4..4893eafce1 100644
--- a/.forgejo/CODEOWNERS
+++ b/.forgejo/CODEOWNERS
@@ -234,11 +234,13 @@ tests/checkasm/riscv/.* @Courmisch
libavutil/tests/buffer.* @MarcosAsh
libavutil/tests/hdr_dynamic_vivid_metadata.* @MarcosAsh
libavutil/tests/tdrdi.* @MarcosAsh
+libavutil/tests/timestamp.* @MarcosAsh
tests/ref/.*drawvg.* @ayosec
tests/ref/fate/buffer @MarcosAsh
tests/ref/fate/hdr_dynamic_vivid_metadata @MarcosAsh
tests/ref/fate/sub-mcc.* @programmerjake
tests/ref/fate/tdrdi @MarcosAsh
+tests/ref/fate/timestamp @MarcosAsh
# Forgejo
# =======
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 83ca133d04..b7d6e4906f 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -311,6 +311,7 @@ TESTPROGS = adler32
\
stereo3d \
tdrdi \
timecode \
+ timestamp \
tree \
twofish \
utf8 \
diff --git a/libavutil/tests/timestamp.c b/libavutil/tests/timestamp.c
new file mode 100644
index 0000000000..1edc0a4000
--- /dev/null
+++ b/libavutil/tests/timestamp.c
@@ -0,0 +1,75 @@
+/*
+ * 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 <inttypes.h>
+#include <stdio.h>
+
+#include "libavutil/avutil.h"
+#include "libavutil/macros.h"
+#include "libavutil/rational.h"
+#include "libavutil/timestamp.h"
+
+int main(void)
+{
+ char buf[AV_TS_MAX_STRING_SIZE];
+ static const struct { const char *label; int64_t ts; } ts_vals[] = {
+ { "NOPTS", AV_NOPTS_VALUE },
+ { "0", 0 },
+ { "90000", 90000 },
+ { "-1", -1 },
+ { "INT64_MAX", INT64_MAX },
+ { "INT64_MIN+1", INT64_MIN + 1 },
+ };
+ static const struct { const char *label; int64_t ts; AVRational tb; }
time_vals[] = {
+ { "NOPTS", AV_NOPTS_VALUE, {1, 90000} },
+ { "90000 at 1/90000", 90000, {1, 90000} },
+ { "0 at 1/1000", 0, {1, 1000} },
+ { "48000 at 1/48000", 48000, {1, 48000} },
+ { "44100 at 1/44100", 44100, {1, 44100} },
+ { "-90000 at 1/90000", -90000, {1, 90000} },
+ };
+
+ /* av_ts_make_string */
+ printf("Testing av_ts_make_string()\n");
+ for (int i = 0; i < FF_ARRAY_ELEMS(ts_vals); i++)
+ printf("%s: %s\n", ts_vals[i].label,
+ av_ts_make_string(buf, ts_vals[i].ts));
+
+ /* av_ts2str macro */
+ printf("\nTesting av_ts2str()\n");
+ printf("NOPTS: %s\n", av_ts2str(AV_NOPTS_VALUE));
+ printf("48000: %s\n", av_ts2str(48000));
+
+ /* av_ts_make_time_string2 */
+ printf("\nTesting av_ts_make_time_string2()\n");
+ for (int i = 0; i < FF_ARRAY_ELEMS(time_vals); i++)
+ printf("%s: %s\n", time_vals[i].label,
+ av_ts_make_time_string2(buf, time_vals[i].ts, time_vals[i].tb));
+
+ /* av_ts_make_time_string (AVRational pointer version) */
+ printf("\nTesting av_ts_make_time_string()\n");
+ {
+ AVRational tb = {1, 1000};
+ printf("5000 at 1/1000: %s\n",
+ av_ts_make_time_string(buf, 5000, &tb));
+ printf("NOPTS: %s\n",
+ av_ts_make_time_string(buf, AV_NOPTS_VALUE, &tb));
+ }
+
+ return 0;
+}
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index a83539a58f..e814ee884c 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -232,6 +232,10 @@ FATE_LIBAVUTIL += fate-timecode
fate-timecode: libavutil/tests/timecode$(EXESUF)
fate-timecode: CMD = run libavutil/tests/timecode$(EXESUF)
+FATE_LIBAVUTIL += fate-timestamp
+fate-timestamp: libavutil/tests/timestamp$(EXESUF)
+fate-timestamp: CMD = run libavutil/tests/timestamp$(EXESUF)
+
FATE_LIBAVUTIL += $(FATE_LIBAVUTIL-yes)
FATE-$(CONFIG_AVUTIL) += $(FATE_LIBAVUTIL)
fate-libavutil: $(FATE_LIBAVUTIL)
diff --git a/tests/ref/fate/timestamp b/tests/ref/fate/timestamp
new file mode 100644
index 0000000000..c7b55dada3
--- /dev/null
+++ b/tests/ref/fate/timestamp
@@ -0,0 +1,23 @@
+Testing av_ts_make_string()
+NOPTS: NOPTS
+0: 0
+90000: 90000
+-1: -1
+INT64_MAX: 9223372036854775807
+INT64_MIN+1: -9223372036854775807
+
+Testing av_ts2str()
+NOPTS: NOPTS
+48000: 48000
+
+Testing av_ts_make_time_string2()
+NOPTS: NOPTS
+90000 at 1/90000: 1
+0 at 1/1000: 0
+48000 at 1/48000: 1
+44100 at 1/44100: 1
+-90000 at 1/90000: -1
+
+Testing av_ts_make_time_string()
+5000 at 1/1000: 5
+NOPTS: NOPTS
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]