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]

Reply via email to