Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file
@ 2025-01-25 20:21 James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 02/14] avutil/frame: allow the addition of internal fields to AVSideDataDescriptor James Almer
                   ` (12 more replies)
  0 siblings, 13 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

Should reduce clutter in frame.c, plus allow us to make opaque changes to
side data handling.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/Makefile    |   1 +
 libavutil/frame.c     | 318 +-----------------------------------------
 libavutil/side_data.c | 313 +++++++++++++++++++++++++++++++++++++++++
 libavutil/side_data.h |  30 ++++
 4 files changed, 351 insertions(+), 311 deletions(-)
 create mode 100644 libavutil/side_data.c
 create mode 100644 libavutil/side_data.h

diff --git a/libavutil/Makefile b/libavutil/Makefile
index f8031815bd..7677a04d12 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -171,6 +171,7 @@ OBJS = adler32.o                                                        \
        rc4.o                                                            \
        ripemd.o                                                         \
        samplefmt.o                                                      \
+       side_data.o                                                      \
        sha.o                                                            \
        sha512.o                                                         \
        slicethread.o                                                    \
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 10b59545f0..70a3b59123 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -26,41 +26,9 @@
 #include "imgutils.h"
 #include "mem.h"
 #include "samplefmt.h"
+#include "side_data.h"
 #include "hwcontext.h"
 
-static const AVSideDataDescriptor sd_props[] = {
-    [AV_FRAME_DATA_PANSCAN]                     = { "AVPanScan",                                    AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_A53_CC]                      = { "ATSC A53 Part 4 Closed Captions" },
-    [AV_FRAME_DATA_MATRIXENCODING]              = { "AVMatrixEncoding" },
-    [AV_FRAME_DATA_DOWNMIX_INFO]                = { "Metadata relevant to a downmix procedure" },
-    [AV_FRAME_DATA_AFD]                         = { "Active format description" },
-    [AV_FRAME_DATA_MOTION_VECTORS]              = { "Motion vectors",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_SKIP_SAMPLES]                = { "Skip samples" },
-    [AV_FRAME_DATA_GOP_TIMECODE]                = { "GOP timecode" },
-    [AV_FRAME_DATA_S12M_TIMECODE]               = { "SMPTE 12-1 timecode" },
-    [AV_FRAME_DATA_DYNAMIC_HDR_PLUS]            = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)",   AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_DYNAMIC_HDR_VIVID]           = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_REGIONS_OF_INTEREST]         = { "Regions Of Interest",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_VIDEO_ENC_PARAMS]            = { "Video encoding parameters" },
-    [AV_FRAME_DATA_FILM_GRAIN_PARAMS]           = { "Film grain parameters" },
-    [AV_FRAME_DATA_DETECTION_BBOXES]            = { "Bounding boxes for object detection and classification", AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_DOVI_RPU_BUFFER]             = { "Dolby Vision RPU Data",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_DOVI_METADATA]               = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_LCEVC]                       = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_VIEW_ID]                     = { "View ID" },
-    [AV_FRAME_DATA_STEREO3D]                    = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_REPLAYGAIN]                  = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_DISPLAYMATRIX]               = { "3x3 displaymatrix",                            AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_AUDIO_SERVICE_TYPE]          = { "Audio service type",                           AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA]  = { "Mastering display metadata",                   AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL]         = { "Content light level metadata",                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { "Ambient viewing environment",                  AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_SPHERICAL]                   = { "Spherical Mapping",                            AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_ICC_PROFILE]                 = { "ICC profile",                                  AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_SEI_UNREGISTERED]            = { "H.26[45] User Data Unregistered SEI message",  AV_SIDE_DATA_PROP_MULTI },
-    [AV_FRAME_DATA_VIDEO_HINT]                  = { "Encoding video hint",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-};
-
 static void get_frame_defaults(AVFrame *frame)
 {
     memset(frame, 0, sizeof(*frame));
@@ -87,67 +55,6 @@ FF_ENABLE_DEPRECATION_WARNINGS
     frame->flags               = 0;
 }
 
-static void free_side_data(AVFrameSideData **ptr_sd)
-{
-    AVFrameSideData *sd = *ptr_sd;
-
-    av_buffer_unref(&sd->buf);
-    av_dict_free(&sd->metadata);
-    av_freep(ptr_sd);
-}
-
-static void wipe_side_data(AVFrameSideData ***sd, int *nb_side_data)
-{
-    for (int i = 0; i < *nb_side_data; i++) {
-        free_side_data(&((*sd)[i]));
-    }
-    *nb_side_data = 0;
-
-    av_freep(sd);
-}
-
-static void frame_side_data_wipe(AVFrame *frame)
-{
-    wipe_side_data(&frame->side_data, &frame->nb_side_data);
-}
-
-void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd)
-{
-    wipe_side_data(sd, nb_sd);
-}
-
-static void remove_side_data(AVFrameSideData ***sd, int *nb_side_data,
-                             const enum AVFrameSideDataType type)
-{
-    for (int i = *nb_side_data - 1; i >= 0; i--) {
-        AVFrameSideData *entry = ((*sd)[i]);
-        if (entry->type != type)
-            continue;
-
-        free_side_data(&entry);
-
-        ((*sd)[i]) = ((*sd)[*nb_side_data - 1]);
-        (*nb_side_data)--;
-    }
-}
-
-static void remove_side_data_by_entry(AVFrameSideData ***sd, int *nb_sd,
-                                      const AVFrameSideData *target)
-{
-    for (int i = *nb_sd - 1; i >= 0; i--) {
-        AVFrameSideData *entry = ((*sd)[i]);
-        if (entry != target)
-            continue;
-
-        free_side_data(&entry);
-
-        ((*sd)[i]) = ((*sd)[*nb_sd - 1]);
-        (*nb_sd)--;
-
-        return;
-    }
-}
-
 AVFrame *av_frame_alloc(void)
 {
     AVFrame *frame = av_malloc(sizeof(*frame));
@@ -377,7 +284,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
             sd_dst = av_frame_new_side_data(dst, sd_src->type,
                                             sd_src->size);
             if (!sd_dst) {
-                frame_side_data_wipe(dst);
+                av_frame_side_data_free(&dst->side_data, &dst->nb_side_data);
                 return AVERROR(ENOMEM);
             }
             memcpy(sd_dst->data, sd_src->data, sd_src->size);
@@ -386,7 +293,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
             sd_dst = av_frame_new_side_data_from_buf(dst, sd_src->type, ref);
             if (!sd_dst) {
                 av_buffer_unref(&ref);
-                frame_side_data_wipe(dst);
+                av_frame_side_data_free(&dst->side_data, &dst->nb_side_data);
                 return AVERROR(ENOMEM);
             }
         }
@@ -526,7 +433,7 @@ int av_frame_replace(AVFrame *dst, const AVFrame *src)
     if (ret < 0)
         goto fail;
 
-    frame_side_data_wipe(dst);
+    av_frame_side_data_free(&dst->side_data, &dst->nb_side_data);
     av_dict_free(&dst->metadata);
     ret = frame_copy_props(dst, src, 0);
     if (ret < 0)
@@ -625,7 +532,7 @@ void av_frame_unref(AVFrame *frame)
     if (!frame)
         return;
 
-    frame_side_data_wipe(frame);
+    av_frame_side_data_free(&frame->side_data, &frame->nb_side_data);
 
     for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++)
         av_buffer_unref(&frame->buf[i]);
@@ -758,54 +665,12 @@ AVBufferRef *av_frame_get_plane_buffer(const AVFrame *frame, int plane)
     return NULL;
 }
 
-static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
-                                                   int *nb_sd,
-                                                   enum AVFrameSideDataType type,
-                                                   AVBufferRef *buf, uint8_t *data,
-                                                   size_t size)
-{
-    AVFrameSideData *ret, **tmp;
-
-    // *nb_sd + 1 needs to fit into an int and a size_t.
-    if ((unsigned)*nb_sd >= FFMIN(INT_MAX, SIZE_MAX))
-        return NULL;
-
-    tmp = av_realloc_array(*sd, sizeof(**sd), *nb_sd + 1);
-    if (!tmp)
-        return NULL;
-    *sd = tmp;
-
-    ret = av_mallocz(sizeof(*ret));
-    if (!ret)
-        return NULL;
-
-    ret->buf = buf;
-    ret->data = data;
-    ret->size = size;
-    ret->type = type;
-
-    (*sd)[(*nb_sd)++] = ret;
-
-    return ret;
-}
-
-static AVFrameSideData *add_side_data_from_buf(AVFrameSideData ***sd,
-                                               int *nb_sd,
-                                               enum AVFrameSideDataType type,
-                                               AVBufferRef *buf)
-{
-    if (!buf)
-        return NULL;
-
-    return add_side_data_from_buf_ext(sd, nb_sd, type, buf, buf->data, buf->size);
-}
-
 AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame,
                                                  enum AVFrameSideDataType type,
                                                  AVBufferRef *buf)
 {
     return
-        add_side_data_from_buf(
+        ff_frame_side_data_add_from_buf(
             &frame->side_data, &frame->nb_side_data, type, buf);
 }
 
@@ -821,161 +686,6 @@ AVFrameSideData *av_frame_new_side_data(AVFrame *frame,
     return ret;
 }
 
-static AVFrameSideData *replace_side_data_from_buf(AVFrameSideData *dst,
-                                                   AVBufferRef *buf, int flags)
-{
-    if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
-        return NULL;
-
-    av_dict_free(&dst->metadata);
-    av_buffer_unref(&dst->buf);
-    dst->buf  = buf;
-    dst->data = buf->data;
-    dst->size = buf->size;
-    return dst;
-}
-
-AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
-                                        enum AVFrameSideDataType type,
-                                        size_t size, unsigned int flags)
-{
-    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
-    AVBufferRef     *buf = av_buffer_alloc(size);
-    AVFrameSideData *ret = NULL;
-
-    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
-        remove_side_data(sd, nb_sd, type);
-    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
-        (ret = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) {
-        ret = replace_side_data_from_buf(ret, buf, flags);
-        if (!ret)
-            av_buffer_unref(&buf);
-        return ret;
-    }
-
-    ret = add_side_data_from_buf(sd, nb_sd, type, buf);
-    if (!ret)
-        av_buffer_unref(&buf);
-
-    return ret;
-}
-
-AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd,
-                                        enum AVFrameSideDataType type,
-                                        AVBufferRef **pbuf, unsigned int flags)
-{
-    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
-    AVFrameSideData *sd_dst  = NULL;
-    AVBufferRef *buf = *pbuf;
-
-    if ((flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF) && !(buf = av_buffer_ref(*pbuf)))
-        return NULL;
-    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
-        remove_side_data(sd, nb_sd, type);
-    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
-        (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) {
-        sd_dst = replace_side_data_from_buf(sd_dst, buf, flags);
-    } else
-        sd_dst = add_side_data_from_buf(sd, nb_sd, type, buf);
-
-    if (sd_dst && !(flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF))
-        *pbuf = NULL;
-    else if (!sd_dst && (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF))
-        av_buffer_unref(&buf);
-    return sd_dst;
-}
-
-int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
-                             const AVFrameSideData *src, unsigned int flags)
-{
-    const AVSideDataDescriptor *desc;
-    AVBufferRef     *buf    = NULL;
-    AVFrameSideData *sd_dst = NULL;
-    int              ret    = AVERROR_BUG;
-
-    if (!sd || !src || !nb_sd || (*nb_sd && !*sd))
-        return AVERROR(EINVAL);
-
-    desc = av_frame_side_data_desc(src->type);
-    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
-        remove_side_data(sd, nb_sd, src->type);
-    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
-        (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, src->type))) {
-        AVDictionary *dict = NULL;
-
-        if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
-            return AVERROR(EEXIST);
-
-        ret = av_dict_copy(&dict, src->metadata, 0);
-        if (ret < 0)
-            return ret;
-
-        ret = av_buffer_replace(&sd_dst->buf, src->buf);
-        if (ret < 0) {
-            av_dict_free(&dict);
-            return ret;
-        }
-
-        av_dict_free(&sd_dst->metadata);
-        sd_dst->metadata = dict;
-        sd_dst->data     = src->data;
-        sd_dst->size     = src->size;
-        return 0;
-    }
-
-    buf = av_buffer_ref(src->buf);
-    if (!buf)
-        return AVERROR(ENOMEM);
-
-    sd_dst = add_side_data_from_buf_ext(sd, nb_sd, src->type, buf,
-                                        src->data, src->size);
-    if (!sd_dst) {
-        av_buffer_unref(&buf);
-        return AVERROR(ENOMEM);
-    }
-
-    ret = av_dict_copy(&sd_dst->metadata, src->metadata, 0);
-    if (ret < 0) {
-        remove_side_data_by_entry(sd, nb_sd, sd_dst);
-        return ret;
-    }
-
-    return 0;
-}
-
-const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *sd,
-                                                const int nb_sd,
-                                                enum AVFrameSideDataType type)
-{
-    for (int i = 0; i < nb_sd; i++) {
-        if (sd[i]->type == type)
-            return sd[i];
-    }
-    return NULL;
-}
-
-void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd,
-                               enum AVFrameSideDataType type)
-{
-    remove_side_data(sd, nb_sd, type);
-}
-
-void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd,
-                                        int props)
-{
-    for (int i = *nb_sd - 1; i >= 0; i--) {
-        AVFrameSideData *entry = ((*sd)[i]);
-        const AVSideDataDescriptor *desc = av_frame_side_data_desc(entry->type);
-        if (!desc || !(desc->props & props))
-            continue;
-
-        free_side_data(&entry);
-
-        ((*sd)[i]) = ((*sd)[*nb_sd - 1]);
-        (*nb_sd)--;
-    }
-}
-
 AVFrameSideData *av_frame_get_side_data(const AVFrame *frame,
                                         enum AVFrameSideDataType type)
 {
@@ -1044,21 +754,7 @@ int av_frame_copy(AVFrame *dst, const AVFrame *src)
 
 void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type)
 {
-    remove_side_data(&frame->side_data, &frame->nb_side_data, type);
-}
-
-const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type)
-{
-    unsigned t = type;
-    if (t < FF_ARRAY_ELEMS(sd_props) && sd_props[t].name)
-        return &sd_props[t];
-    return NULL;
-}
-
-const char *av_frame_side_data_name(enum AVFrameSideDataType type)
-{
-    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
-    return desc ? desc->name : NULL;
+    av_frame_side_data_remove(&frame->side_data, &frame->nb_side_data, type);
 }
 
 static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame,
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
new file mode 100644
index 0000000000..b071971c9d
--- /dev/null
+++ b/libavutil/side_data.c
@@ -0,0 +1,313 @@
+/*
+ * 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 "avassert.h"
+#include "buffer.h"
+#include "common.h"
+#include "dict.h"
+#include "frame.h"
+#include "mem.h"
+#include "side_data.h"
+
+static const AVSideDataDescriptor sd_props[] = {
+    [AV_FRAME_DATA_PANSCAN]                     = { "AVPanScan",                                    AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+    [AV_FRAME_DATA_A53_CC]                      = { "ATSC A53 Part 4 Closed Captions" },
+    [AV_FRAME_DATA_MATRIXENCODING]              = { "AVMatrixEncoding" },
+    [AV_FRAME_DATA_DOWNMIX_INFO]                = { "Metadata relevant to a downmix procedure" },
+    [AV_FRAME_DATA_AFD]                         = { "Active format description" },
+    [AV_FRAME_DATA_MOTION_VECTORS]              = { "Motion vectors",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+    [AV_FRAME_DATA_SKIP_SAMPLES]                = { "Skip samples" },
+    [AV_FRAME_DATA_GOP_TIMECODE]                = { "GOP timecode" },
+    [AV_FRAME_DATA_S12M_TIMECODE]               = { "SMPTE 12-1 timecode" },
+    [AV_FRAME_DATA_DYNAMIC_HDR_PLUS]            = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)",   AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_DYNAMIC_HDR_VIVID]           = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_REGIONS_OF_INTEREST]         = { "Regions Of Interest",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+    [AV_FRAME_DATA_VIDEO_ENC_PARAMS]            = { "Video encoding parameters" },
+    [AV_FRAME_DATA_FILM_GRAIN_PARAMS]           = { "Film grain parameters" },
+    [AV_FRAME_DATA_DETECTION_BBOXES]            = { "Bounding boxes for object detection and classification", AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+    [AV_FRAME_DATA_DOVI_RPU_BUFFER]             = { "Dolby Vision RPU Data",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_DOVI_METADATA]               = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_LCEVC]                       = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+    [AV_FRAME_DATA_VIEW_ID]                     = { "View ID" },
+    [AV_FRAME_DATA_STEREO3D]                    = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL },
+    [AV_FRAME_DATA_REPLAYGAIN]                  = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL },
+    [AV_FRAME_DATA_DISPLAYMATRIX]               = { "3x3 displaymatrix",                            AV_SIDE_DATA_PROP_GLOBAL },
+    [AV_FRAME_DATA_AUDIO_SERVICE_TYPE]          = { "Audio service type",                           AV_SIDE_DATA_PROP_GLOBAL },
+    [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA]  = { "Mastering display metadata",                   AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL]         = { "Content light level metadata",                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { "Ambient viewing environment",                  AV_SIDE_DATA_PROP_GLOBAL },
+    [AV_FRAME_DATA_SPHERICAL]                   = { "Spherical Mapping",                            AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+    [AV_FRAME_DATA_ICC_PROFILE]                 = { "ICC profile",                                  AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+    [AV_FRAME_DATA_SEI_UNREGISTERED]            = { "H.26[45] User Data Unregistered SEI message",  AV_SIDE_DATA_PROP_MULTI },
+    [AV_FRAME_DATA_VIDEO_HINT]                  = { "Encoding video hint",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+};
+
+const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type)
+{
+    unsigned t = type;
+    if (t < FF_ARRAY_ELEMS(sd_props) && sd_props[t].name)
+        return &sd_props[t];
+    return NULL;
+}
+
+const char *av_frame_side_data_name(enum AVFrameSideDataType type)
+{
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
+    return desc ? desc->name : NULL;
+}
+
+static void free_side_data_entry(AVFrameSideData **ptr_sd)
+{
+    AVFrameSideData *sd = *ptr_sd;
+
+    av_buffer_unref(&sd->buf);
+    av_dict_free(&sd->metadata);
+    av_freep(ptr_sd);
+}
+
+static void remove_side_data_by_entry(AVFrameSideData ***sd, int *nb_sd,
+                                      const AVFrameSideData *target)
+{
+    for (int i = *nb_sd - 1; i >= 0; i--) {
+        AVFrameSideData *entry = ((*sd)[i]);
+        if (entry != target)
+            continue;
+
+        free_side_data_entry(&entry);
+
+        ((*sd)[i]) = ((*sd)[*nb_sd - 1]);
+        (*nb_sd)--;
+
+        return;
+    }
+}
+
+void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd,
+                               enum AVFrameSideDataType type)
+{
+    for (int i = *nb_sd - 1; i >= 0; i--) {
+        AVFrameSideData *entry = ((*sd)[i]);
+        if (entry->type != type)
+            continue;
+
+        free_side_data_entry(&entry);
+
+        ((*sd)[i]) = ((*sd)[*nb_sd - 1]);
+        (*nb_sd)--;
+    }
+}
+
+void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd,
+                                        int props)
+{
+    for (int i = *nb_sd - 1; i >= 0; i--) {
+        AVFrameSideData *entry = ((*sd)[i]);
+        const AVSideDataDescriptor *desc = av_frame_side_data_desc(entry->type);
+        if (!desc || !(desc->props & props))
+            continue;
+
+        free_side_data_entry(&entry);
+
+        ((*sd)[i]) = ((*sd)[*nb_sd - 1]);
+        (*nb_sd)--;
+    }
+}
+
+void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd)
+{
+    for (int i = 0; i < *nb_sd; i++)
+        free_side_data_entry(&((*sd)[i]));
+    *nb_sd = 0;
+
+    av_freep(sd);
+}
+
+static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
+                                                   int *nb_sd,
+                                                   enum AVFrameSideDataType type,
+                                                   AVBufferRef *buf, uint8_t *data,
+                                                   size_t size)
+{
+    AVFrameSideData *ret, **tmp;
+
+    // *nb_sd + 1 needs to fit into an int and a size_t.
+    if ((unsigned)*nb_sd >= FFMIN(INT_MAX, SIZE_MAX))
+        return NULL;
+
+    tmp = av_realloc_array(*sd, sizeof(**sd), *nb_sd + 1);
+    if (!tmp)
+        return NULL;
+    *sd = tmp;
+
+    ret = av_mallocz(sizeof(*ret));
+    if (!ret)
+        return NULL;
+
+    ret->buf = buf;
+    ret->data = data;
+    ret->size = size;
+    ret->type = type;
+
+    (*sd)[(*nb_sd)++] = ret;
+
+    return ret;
+}
+
+AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd,
+                                                 int *nb_sd,
+                                                 enum AVFrameSideDataType type,
+                                                 AVBufferRef *buf)
+{
+    if (!buf)
+        return NULL;
+
+    return add_side_data_from_buf_ext(sd, nb_sd, type, buf, buf->data, buf->size);
+}
+
+static AVFrameSideData *replace_side_data_from_buf(AVFrameSideData *dst,
+                                                   AVBufferRef *buf, int flags)
+{
+    if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
+        return NULL;
+
+    av_dict_free(&dst->metadata);
+    av_buffer_unref(&dst->buf);
+    dst->buf  = buf;
+    dst->data = buf->data;
+    dst->size = buf->size;
+    return dst;
+}
+
+AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
+                                        enum AVFrameSideDataType type,
+                                        size_t size, unsigned int flags)
+{
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
+    AVBufferRef     *buf = av_buffer_alloc(size);
+    AVFrameSideData *ret = NULL;
+
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
+        av_frame_side_data_remove(sd, nb_sd, type);
+    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
+        (ret = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) {
+        ret = replace_side_data_from_buf(ret, buf, flags);
+        if (!ret)
+            av_buffer_unref(&buf);
+        return ret;
+    }
+
+    ret = ff_frame_side_data_add_from_buf(sd, nb_sd, type, buf);
+    if (!ret)
+        av_buffer_unref(&buf);
+
+    return ret;
+}
+
+AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd,
+                                        enum AVFrameSideDataType type,
+                                        AVBufferRef **pbuf, unsigned int flags)
+{
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
+    AVFrameSideData *sd_dst  = NULL;
+    AVBufferRef *buf = *pbuf;
+
+    if ((flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF) && !(buf = av_buffer_ref(*pbuf)))
+        return NULL;
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
+        av_frame_side_data_remove(sd, nb_sd, type);
+    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
+        (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) {
+        sd_dst = replace_side_data_from_buf(sd_dst, buf, flags);
+    } else
+        sd_dst = ff_frame_side_data_add_from_buf(sd, nb_sd, type, buf);
+
+    if (sd_dst && !(flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF))
+        *pbuf = NULL;
+    else if (!sd_dst && (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF))
+        av_buffer_unref(&buf);
+    return sd_dst;
+}
+
+int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
+                             const AVFrameSideData *src, unsigned int flags)
+{
+    const AVSideDataDescriptor *desc;
+    AVBufferRef     *buf    = NULL;
+    AVFrameSideData *sd_dst = NULL;
+    int              ret    = AVERROR_BUG;
+
+    if (!sd || !src || !nb_sd || (*nb_sd && !*sd))
+        return AVERROR(EINVAL);
+
+    desc = av_frame_side_data_desc(src->type);
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
+        av_frame_side_data_remove(sd, nb_sd, src->type);
+    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
+        (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, src->type))) {
+        AVDictionary *dict = NULL;
+
+        if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
+            return AVERROR(EEXIST);
+
+        ret = av_dict_copy(&dict, src->metadata, 0);
+        if (ret < 0)
+            return ret;
+
+        ret = av_buffer_replace(&sd_dst->buf, src->buf);
+        if (ret < 0) {
+            av_dict_free(&dict);
+            return ret;
+        }
+
+        av_dict_free(&sd_dst->metadata);
+        sd_dst->metadata = dict;
+        sd_dst->data     = src->data;
+        sd_dst->size     = src->size;
+        return 0;
+    }
+
+    buf = av_buffer_ref(src->buf);
+    if (!buf)
+        return AVERROR(ENOMEM);
+
+    sd_dst = add_side_data_from_buf_ext(sd, nb_sd, src->type, buf,
+                                        src->data, src->size);
+    if (!sd_dst) {
+        av_buffer_unref(&buf);
+        return AVERROR(ENOMEM);
+    }
+
+    ret = av_dict_copy(&sd_dst->metadata, src->metadata, 0);
+    if (ret < 0) {
+        remove_side_data_by_entry(sd, nb_sd, sd_dst);
+        return ret;
+    }
+
+    return 0;
+}
+
+const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *sd,
+                                                const int nb_sd,
+                                                enum AVFrameSideDataType type)
+{
+    for (int i = 0; i < nb_sd; i++) {
+        if (sd[i]->type == type)
+            return sd[i];
+    }
+    return NULL;
+}
diff --git a/libavutil/side_data.h b/libavutil/side_data.h
new file mode 100644
index 0000000000..8275aa35a5
--- /dev/null
+++ b/libavutil/side_data.h
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+
+#ifndef AVUTIL_SIDE_DATA_H
+#define AVUTIL_SIDE_DATA_H
+
+#include "buffer.h"
+#include "frame.h"
+
+AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd,
+                                                 int *nb_sd,
+                                                 enum AVFrameSideDataType type,
+                                                 AVBufferRef *buf);
+
+#endif // AVUTIL_SIDE_DATA_H
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 02/14] avutil/frame: allow the addition of internal fields to AVSideDataDescriptor
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 03/14] avutil/frame: allow the addition of internal fields to AVFrameSideData James Almer
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

Will be useful in the following commits to add fields that don't need to be
exposed.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/side_data.c | 70 +++++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 33 deletions(-)

diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index b071971c9d..5770be0639 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -24,44 +24,48 @@
 #include "mem.h"
 #include "side_data.h"
 
-static const AVSideDataDescriptor sd_props[] = {
-    [AV_FRAME_DATA_PANSCAN]                     = { "AVPanScan",                                    AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_A53_CC]                      = { "ATSC A53 Part 4 Closed Captions" },
-    [AV_FRAME_DATA_MATRIXENCODING]              = { "AVMatrixEncoding" },
-    [AV_FRAME_DATA_DOWNMIX_INFO]                = { "Metadata relevant to a downmix procedure" },
-    [AV_FRAME_DATA_AFD]                         = { "Active format description" },
-    [AV_FRAME_DATA_MOTION_VECTORS]              = { "Motion vectors",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_SKIP_SAMPLES]                = { "Skip samples" },
-    [AV_FRAME_DATA_GOP_TIMECODE]                = { "GOP timecode" },
-    [AV_FRAME_DATA_S12M_TIMECODE]               = { "SMPTE 12-1 timecode" },
-    [AV_FRAME_DATA_DYNAMIC_HDR_PLUS]            = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)",   AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_DYNAMIC_HDR_VIVID]           = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_REGIONS_OF_INTEREST]         = { "Regions Of Interest",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_VIDEO_ENC_PARAMS]            = { "Video encoding parameters" },
-    [AV_FRAME_DATA_FILM_GRAIN_PARAMS]           = { "Film grain parameters" },
-    [AV_FRAME_DATA_DETECTION_BBOXES]            = { "Bounding boxes for object detection and classification", AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_DOVI_RPU_BUFFER]             = { "Dolby Vision RPU Data",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_DOVI_METADATA]               = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_LCEVC]                       = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_VIEW_ID]                     = { "View ID" },
-    [AV_FRAME_DATA_STEREO3D]                    = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_REPLAYGAIN]                  = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_DISPLAYMATRIX]               = { "3x3 displaymatrix",                            AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_AUDIO_SERVICE_TYPE]          = { "Audio service type",                           AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA]  = { "Mastering display metadata",                   AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL]         = { "Content light level metadata",                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { "Ambient viewing environment",                  AV_SIDE_DATA_PROP_GLOBAL },
-    [AV_FRAME_DATA_SPHERICAL]                   = { "Spherical Mapping",                            AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
-    [AV_FRAME_DATA_ICC_PROFILE]                 = { "ICC profile",                                  AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
-    [AV_FRAME_DATA_SEI_UNREGISTERED]            = { "H.26[45] User Data Unregistered SEI message",  AV_SIDE_DATA_PROP_MULTI },
-    [AV_FRAME_DATA_VIDEO_HINT]                  = { "Encoding video hint",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+typedef struct FFSideDataDescriptor {
+    AVSideDataDescriptor p;
+} FFSideDataDescriptor;
+
+static const FFSideDataDescriptor sd_props[] = {
+    [AV_FRAME_DATA_PANSCAN]                     = { .p = { "AVPanScan",                                    AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_A53_CC]                      = { .p = { "ATSC A53 Part 4 Closed Captions" } },
+    [AV_FRAME_DATA_MATRIXENCODING]              = { .p = { "AVMatrixEncoding" } },
+    [AV_FRAME_DATA_DOWNMIX_INFO]                = { .p = { "Metadata relevant to a downmix procedure" } },
+    [AV_FRAME_DATA_AFD]                         = { .p = { "Active format description" } },
+    [AV_FRAME_DATA_MOTION_VECTORS]              = { .p = { "Motion vectors",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_SKIP_SAMPLES]                = { .p = { "Skip samples" } },
+    [AV_FRAME_DATA_GOP_TIMECODE]                = { .p = { "GOP timecode" } },
+    [AV_FRAME_DATA_S12M_TIMECODE]               = { .p = { "SMPTE 12-1 timecode" } },
+    [AV_FRAME_DATA_DYNAMIC_HDR_PLUS]            = { .p = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)",   AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_DYNAMIC_HDR_VIVID]           = { .p = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_REGIONS_OF_INTEREST]         = { .p = { "Regions Of Interest",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_VIDEO_ENC_PARAMS]            = { .p = { "Video encoding parameters" } },
+    [AV_FRAME_DATA_FILM_GRAIN_PARAMS]           = { .p = { "Film grain parameters" } },
+    [AV_FRAME_DATA_DETECTION_BBOXES]            = { .p = { "Bounding boxes for object detection and classification", AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_DOVI_RPU_BUFFER]             = { .p = { "Dolby Vision RPU Data",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_DOVI_METADATA]               = { .p = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_LCEVC]                       = { .p = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_VIEW_ID]                     = { .p = { "View ID" } },
+    [AV_FRAME_DATA_STEREO3D]                    = { .p = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL } },
+    [AV_FRAME_DATA_REPLAYGAIN]                  = { .p = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL } },
+    [AV_FRAME_DATA_DISPLAYMATRIX]               = { .p = { "3x3 displaymatrix",                            AV_SIDE_DATA_PROP_GLOBAL } },
+    [AV_FRAME_DATA_AUDIO_SERVICE_TYPE]          = { .p = { "Audio service type",                           AV_SIDE_DATA_PROP_GLOBAL } },
+    [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA]  = { .p = { "Mastering display metadata",                   AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL]         = { .p = { "Content light level metadata",                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { .p = { "Ambient viewing environment",                  AV_SIDE_DATA_PROP_GLOBAL } },
+    [AV_FRAME_DATA_SPHERICAL]                   = { .p = { "Spherical Mapping",                            AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_ICC_PROFILE]                 = { .p = { "ICC profile",                                  AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_SEI_UNREGISTERED]            = { .p = { "H.26[45] User Data Unregistered SEI message",  AV_SIDE_DATA_PROP_MULTI } },
+    [AV_FRAME_DATA_VIDEO_HINT]                  = { .p = { "Encoding video hint",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
 };
 
 const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type)
 {
     unsigned t = type;
-    if (t < FF_ARRAY_ELEMS(sd_props) && sd_props[t].name)
-        return &sd_props[t];
+    if (t < FF_ARRAY_ELEMS(sd_props) && sd_props[t].p.name)
+        return &sd_props[t].p;
     return NULL;
 }
 
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 03/14] avutil/frame: allow the addition of internal fields to AVFrameSideData
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 02/14] avutil/frame: allow the addition of internal fields to AVSideDataDescriptor James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 04/14] avutil/frame: schedule making AVFrameSideData.buf internal James Almer
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

Will be useful in the following commits to add fields that don't need to be
exposed.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/side_data.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index 5770be0639..eb6e001f94 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -24,6 +24,10 @@
 #include "mem.h"
 #include "side_data.h"
 
+typedef struct FFFrameSideData {
+    AVFrameSideData p;
+} FFFrameSideData;
+
 typedef struct FFSideDataDescriptor {
     AVSideDataDescriptor p;
 } FFSideDataDescriptor;
@@ -147,6 +151,7 @@ static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
                                                    AVBufferRef *buf, uint8_t *data,
                                                    size_t size)
 {
+    FFFrameSideData *sdp;
     AVFrameSideData *ret, **tmp;
 
     // *nb_sd + 1 needs to fit into an int and a size_t.
@@ -158,10 +163,11 @@ static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
         return NULL;
     *sd = tmp;
 
-    ret = av_mallocz(sizeof(*ret));
-    if (!ret)
+    sdp = av_mallocz(sizeof(*sdp));
+    if (!sdp)
         return NULL;
 
+    ret = &sdp->p;
     ret->buf = buf;
     ret->data = data;
     ret->size = size;
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 04/14] avutil/frame: schedule making AVFrameSideData.buf internal
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 02/14] avutil/frame: allow the addition of internal fields to AVSideDataDescriptor James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 03/14] avutil/frame: allow the addition of internal fields to AVFrameSideData James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 05/14] avutil/frame: add functions to check and ensure a side data entry is writable James Almer
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

This is in preparation for a new type of backing for the side data that will be
introduced in a following commit. The user only cares about the data pointer.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/frame.h     |  3 +++
 libavutil/side_data.c | 48 +++++++++++++++++++++++++++++++++++++++++++
 libavutil/version.h   |  1 +
 3 files changed, 52 insertions(+)

diff --git a/libavutil/frame.h b/libavutil/frame.h
index 628f2b5b3a..019adaac0e 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -267,7 +267,10 @@ typedef struct AVFrameSideData {
     uint8_t *data;
     size_t   size;
     AVDictionary *metadata;
+#if FF_API_SIDE_DATA_BUF
+    attribute_deprecated
     AVBufferRef *buf;
+#endif
 } AVFrameSideData;
 
 enum AVSideDataProps {
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index eb6e001f94..7be1c346cd 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -26,6 +26,10 @@
 
 typedef struct FFFrameSideData {
     AVFrameSideData p;
+
+#if FF_API_SIDE_DATA_BUF == 0
+    AVBufferRef *buf;
+#endif
 } FFFrameSideData;
 
 typedef struct FFSideDataDescriptor {
@@ -65,6 +69,16 @@ static const FFSideDataDescriptor sd_props[] = {
     [AV_FRAME_DATA_VIDEO_HINT]                  = { .p = { "Encoding video hint",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
 };
 
+static FFFrameSideData *sdp_from_sd(AVFrameSideData *sd)
+{
+    return (FFFrameSideData *)sd;
+}
+
+static const FFFrameSideData *csdp_from_sd(const AVFrameSideData *sd)
+{
+    return (const FFFrameSideData *)sd;
+}
+
 const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type)
 {
     unsigned t = type;
@@ -82,8 +96,15 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type)
 static void free_side_data_entry(AVFrameSideData **ptr_sd)
 {
     AVFrameSideData *sd = *ptr_sd;
+    FFFrameSideData *sdp = sdp_from_sd(sd);
 
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
     av_buffer_unref(&sd->buf);
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+    av_buffer_unref(&sdp->buf);
+#endif
     av_dict_free(&sd->metadata);
     av_freep(ptr_sd);
 }
@@ -168,7 +189,13 @@ static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
         return NULL;
 
     ret = &sdp->p;
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
     ret->buf = buf;
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+    sdp->buf = buf;
+#endif
     ret->data = data;
     ret->size = size;
     ret->type = type;
@@ -196,8 +223,15 @@ static AVFrameSideData *replace_side_data_from_buf(AVFrameSideData *dst,
         return NULL;
 
     av_dict_free(&dst->metadata);
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
     av_buffer_unref(&dst->buf);
     dst->buf  = buf;
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+    av_buffer_unref(&sdp_from_sd(dst)->buf);
+    sdp_from_sd(dst)->buf = buf;
+#endif
     dst->data = buf->data;
     dst->size = buf->size;
     return dst;
@@ -257,6 +291,7 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
                              const AVFrameSideData *src, unsigned int flags)
 {
     const AVSideDataDescriptor *desc;
+    const FFFrameSideData *srcp = csdp_from_sd(src);
     AVBufferRef     *buf    = NULL;
     AVFrameSideData *sd_dst = NULL;
     int              ret    = AVERROR_BUG;
@@ -269,6 +304,7 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
         av_frame_side_data_remove(sd, nb_sd, src->type);
     if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
         (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, src->type))) {
+        FFFrameSideData *dstp = sdp_from_sd(sd_dst);
         AVDictionary *dict = NULL;
 
         if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
@@ -278,7 +314,13 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
         if (ret < 0)
             return ret;
 
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
         ret = av_buffer_replace(&sd_dst->buf, src->buf);
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+        ret = av_buffer_replace(&dstp->buf, srcp->buf);
+#endif
         if (ret < 0) {
             av_dict_free(&dict);
             return ret;
@@ -291,7 +333,13 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
         return 0;
     }
 
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
     buf = av_buffer_ref(src->buf);
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+    buf = av_buffer_ref(srcp->buf);
+#endif
     if (!buf)
         return AVERROR(ENOMEM);
 
diff --git a/libavutil/version.h b/libavutil/version.h
index a6f344a4c3..e736484a1e 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -117,6 +117,7 @@
 #define FF_API_VULKAN_FIXED_QUEUES      (LIBAVUTIL_VERSION_MAJOR < 60)
 #define FF_API_OPT_INT_LIST             (LIBAVUTIL_VERSION_MAJOR < 60)
 #define FF_API_OPT_PTR                  (LIBAVUTIL_VERSION_MAJOR < 60)
+#define FF_API_SIDE_DATA_BUF            (LIBAVUTIL_VERSION_MAJOR < 60)
 
 /**
  * @}
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 05/14] avutil/frame: add functions to check and ensure a side data entry is writable
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (2 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 04/14] avutil/frame: schedule making AVFrameSideData.buf internal James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 06/14] avutil/frame: av_frame_side_data_new_struct() James Almer
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/frame.h     | 19 ++++++++++++++++++
 libavutil/side_data.c | 45 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/libavutil/frame.h b/libavutil/frame.h
index 019adaac0e..aa4e619ad2 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -1207,6 +1207,25 @@ void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd,
 void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd,
                                         int props);
 
+/**
+ * Check whether the data described by a given AVFrameSideData can be
+ * written to.
+ *
+ * @return 1 if the caller may write to the data, 0 otherwise.
+ */
+int av_frame_side_data_is_writable(const AVFrameSideData *sd);
+
+/**
+ * Create a writable reference for the data described by a given
+ * AVFrameSideData, avoiding data copy if possible.
+ *
+ * @param sd Side data whose data should be made writable.
+ *
+ * @return 0 on success, a negative AVERROR on failure. On failure, the
+ *         side data is unchanged.
+ */
+int av_frame_side_data_make_writable(AVFrameSideData *sd);
+
 /**
  * @}
  */
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index 7be1c346cd..8fb9dfed2b 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -369,3 +369,48 @@ const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *s
     }
     return NULL;
 }
+
+int av_frame_side_data_is_writable(const AVFrameSideData *sd)
+{
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
+    return !!av_buffer_is_writable(sd->buf);
+#else
+    const FFFrameSideData *sdp = csdp_from_sd(sd);
+    return !!av_buffer_is_writable(sdp->buf);
+#endif
+}
+
+int av_frame_side_data_make_writable(AVFrameSideData *sd)
+{
+    FFFrameSideData *sdp = sdp_from_sd(sd);
+    AVBufferRef *buf = NULL;
+
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (av_buffer_is_writable(sd->buf))
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+    if (av_buffer_is_writable(sdp->buf))
+#endif
+        return 0;
+
+    buf = av_buffer_alloc(sd->size);
+    if (!buf)
+        return AVERROR(ENOMEM);
+
+    if (sd->size)
+        memcpy(buf->data, sd->data, sd->size);
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
+    av_buffer_unref(&sd->buf);
+    sd->buf  = buf;
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+    av_buffer_unref(&sdp->buf);
+    sdp->buf = buf;
+#endif
+    sd->data = buf->data;
+
+    return 0;
+}
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 06/14] avutil/frame: av_frame_side_data_new_struct()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (3 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 05/14] avutil/frame: add functions to check and ensure a side data entry is writable James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 07/14] avutil/frame: add support for RefStruct as backing for side data James Almer
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

As well as the AV_SIDE_DATA_PROP_STRUCT prop, to define types that describe
a fixed-size C struct and not a flat byte array.
This excludes types like VIDEO_ENC_PARAMS as the struct it describes may have
extra bytes allocated past the end of the struct.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/ambient_viewing_environment.c |  9 ++-
 libavutil/frame.h                       | 11 ++++
 libavutil/mastering_display_metadata.c  |  9 ++-
 libavutil/side_data.c                   | 78 +++++++++++++++++++++----
 libavutil/side_data.h                   |  4 ++
 libavutil/spherical.c                   | 10 +++-
 6 files changed, 102 insertions(+), 19 deletions(-)

diff --git a/libavutil/ambient_viewing_environment.c b/libavutil/ambient_viewing_environment.c
index e359727776..ee2e9427cd 100644
--- a/libavutil/ambient_viewing_environment.c
+++ b/libavutil/ambient_viewing_environment.c
@@ -20,9 +20,12 @@
 
 #include "ambient_viewing_environment.h"
 #include "mem.h"
+#include "side_data.h"
 
-static void get_defaults(AVAmbientViewingEnvironment *env)
+void ff_ave_get_defaults(void *obj)
 {
+    AVAmbientViewingEnvironment *env = obj;
+
     env->ambient_illuminance =
     env->ambient_light_x     =
     env->ambient_light_y     = (AVRational) { 0, 1 };
@@ -35,7 +38,7 @@ AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size)
     if (!env)
         return NULL;
 
-    get_defaults(env);
+    ff_ave_get_defaults(env);
 
      if (size)
         *size = sizeof(*env);
@@ -53,7 +56,7 @@ AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVF
         return NULL;
 
     memset(side_data->data, 0, side_data->size);
-    get_defaults((AVAmbientViewingEnvironment *)side_data->data);
+    ff_ave_get_defaults(side_data->data);
 
     return (AVAmbientViewingEnvironment *)side_data->data;
 }
diff --git a/libavutil/frame.h b/libavutil/frame.h
index aa4e619ad2..1feb11506a 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -300,6 +300,13 @@ enum AVSideDataProps {
      * adapting to a different set of primaries or transfer characteristics.
      */
     AV_SIDE_DATA_PROP_COLOR_DEPENDENT = (1 << 3),
+
+    /**
+     * Side data stores a fixed-size C struct and not a flat byte array.
+     * Entries of this type should be allocated with
+     * @ref av_frame_side_data_new_struct(), and their size is not user settable.
+     */
+    AV_SIDE_DATA_PROP_STRUCT = (1 << 5),
 };
 
 /**
@@ -1117,6 +1124,10 @@ AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
                                         enum AVFrameSideDataType type,
                                         size_t size, unsigned int flags);
 
+AVFrameSideData *av_frame_side_data_new_struct(AVFrameSideData ***sd, int *nb_sd,
+                                               enum AVFrameSideDataType type,
+                                               unsigned int flags);
+
 /**
  * Add a new side data entry to an array from an existing AVBufferRef.
  *
diff --git a/libavutil/mastering_display_metadata.c b/libavutil/mastering_display_metadata.c
index dd37ed7d0e..4948f30523 100644
--- a/libavutil/mastering_display_metadata.c
+++ b/libavutil/mastering_display_metadata.c
@@ -24,9 +24,12 @@
 
 #include "mastering_display_metadata.h"
 #include "mem.h"
+#include "side_data.h"
 
-static void get_defaults(AVMasteringDisplayMetadata *mastering)
+void ff_mdm_get_defaults(void *obj)
 {
+    AVMasteringDisplayMetadata *mastering = obj;
+
     for (int i = 0; i < 3; i++)
         for (int j = 0; j < 2; j++)
             mastering->display_primaries[i][j] = (AVRational) { 0, 1 };
@@ -47,7 +50,7 @@ AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *siz
     if (!mastering)
         return NULL;
 
-    get_defaults(mastering);
+    ff_mdm_get_defaults(mastering);
 
     if (size)
         *size = sizeof(*mastering);
@@ -64,7 +67,7 @@ AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFra
         return NULL;
 
     memset(side_data->data, 0, sizeof(AVMasteringDisplayMetadata));
-    get_defaults((AVMasteringDisplayMetadata *)side_data->data);
+    ff_mdm_get_defaults(side_data->data);
 
     return (AVMasteringDisplayMetadata *)side_data->data;
 }
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index 8fb9dfed2b..671dcecb82 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -22,8 +22,21 @@
 #include "dict.h"
 #include "frame.h"
 #include "mem.h"
+#include "refstruct.h"
 #include "side_data.h"
 
+// headers for struct sizes
+#include "libavcodec/defs.h"
+#include "ambient_viewing_environment.h"
+#include "downmix_info.h"
+#include "hdr_dynamic_metadata.h"
+#include "hdr_dynamic_vivid_metadata.h"
+#include "mastering_display_metadata.h"
+#include "motion_vector.h"
+#include "replaygain.h"
+#include "spherical.h"
+#include "stereo3d.h"
+
 typedef struct FFFrameSideData {
     AVFrameSideData p;
 
@@ -34,36 +47,54 @@ typedef struct FFFrameSideData {
 
 typedef struct FFSideDataDescriptor {
     AVSideDataDescriptor p;
+
+    void (*init)(void *obj);
+
+    size_t size;
 } FFSideDataDescriptor;
 
 static const FFSideDataDescriptor sd_props[] = {
-    [AV_FRAME_DATA_PANSCAN]                     = { .p = { "AVPanScan",                                    AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_PANSCAN]                     = { .p = { "AVPanScan",                                    AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+                                                    .size = sizeof(AVPanScan) },
     [AV_FRAME_DATA_A53_CC]                      = { .p = { "ATSC A53 Part 4 Closed Captions" } },
     [AV_FRAME_DATA_MATRIXENCODING]              = { .p = { "AVMatrixEncoding" } },
-    [AV_FRAME_DATA_DOWNMIX_INFO]                = { .p = { "Metadata relevant to a downmix procedure" } },
+    [AV_FRAME_DATA_DOWNMIX_INFO]                = { .p = { "Metadata relevant to a downmix procedure",     AV_SIDE_DATA_PROP_STRUCT },
+                                                    .size = sizeof(AVDownmixInfo) },
     [AV_FRAME_DATA_AFD]                         = { .p = { "Active format description" } },
-    [AV_FRAME_DATA_MOTION_VECTORS]              = { .p = { "Motion vectors",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_MOTION_VECTORS]              = { .p = { "Motion vectors",                               AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+                                                    .size = sizeof(AVMotionVector) },
     [AV_FRAME_DATA_SKIP_SAMPLES]                = { .p = { "Skip samples" } },
     [AV_FRAME_DATA_GOP_TIMECODE]                = { .p = { "GOP timecode" } },
     [AV_FRAME_DATA_S12M_TIMECODE]               = { .p = { "SMPTE 12-1 timecode" } },
-    [AV_FRAME_DATA_DYNAMIC_HDR_PLUS]            = { .p = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)",   AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
-    [AV_FRAME_DATA_DYNAMIC_HDR_VIVID]           = { .p = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
+    [AV_FRAME_DATA_DYNAMIC_HDR_PLUS]            = { .p = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)",   AV_SIDE_DATA_PROP_STRUCT| AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+                                                    .size = sizeof(AVDynamicHDRPlus) },
+    [AV_FRAME_DATA_DYNAMIC_HDR_VIVID]           = { .p = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+                                                    .size = sizeof(AVDynamicHDRVivid) },
     [AV_FRAME_DATA_REGIONS_OF_INTEREST]         = { .p = { "Regions Of Interest",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
     [AV_FRAME_DATA_VIDEO_ENC_PARAMS]            = { .p = { "Video encoding parameters" } },
-    [AV_FRAME_DATA_FILM_GRAIN_PARAMS]           = { .p = { "Film grain parameters" } },
+    [AV_FRAME_DATA_FILM_GRAIN_PARAMS]           = { .p = { "Film grain parameters",                        AV_SIDE_DATA_PROP_STRUCT } },
     [AV_FRAME_DATA_DETECTION_BBOXES]            = { .p = { "Bounding boxes for object detection and classification", AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
     [AV_FRAME_DATA_DOVI_RPU_BUFFER]             = { .p = { "Dolby Vision RPU Data",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
     [AV_FRAME_DATA_DOVI_METADATA]               = { .p = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
     [AV_FRAME_DATA_LCEVC]                       = { .p = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
     [AV_FRAME_DATA_VIEW_ID]                     = { .p = { "View ID" } },
-    [AV_FRAME_DATA_STEREO3D]                    = { .p = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL } },
-    [AV_FRAME_DATA_REPLAYGAIN]                  = { .p = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL } },
+    [AV_FRAME_DATA_STEREO3D]                    = { .p = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
+                                                    .size = sizeof(AVStereo3D) },
+    [AV_FRAME_DATA_REPLAYGAIN]                  = { .p = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
+                                                    .size = sizeof(AVReplayGain) },
     [AV_FRAME_DATA_DISPLAYMATRIX]               = { .p = { "3x3 displaymatrix",                            AV_SIDE_DATA_PROP_GLOBAL } },
     [AV_FRAME_DATA_AUDIO_SERVICE_TYPE]          = { .p = { "Audio service type",                           AV_SIDE_DATA_PROP_GLOBAL } },
-    [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA]  = { .p = { "Mastering display metadata",                   AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
-    [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL]         = { .p = { "Content light level metadata",                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
-    [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { .p = { "Ambient viewing environment",                  AV_SIDE_DATA_PROP_GLOBAL } },
-    [AV_FRAME_DATA_SPHERICAL]                   = { .p = { "Spherical Mapping",                            AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
+    [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA]  = { .p = { "Mastering display metadata",                   AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+                                                    .init = ff_mdm_get_defaults,
+                                                    .size = sizeof(AVMasteringDisplayMetadata) },
+    [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL]         = { .p = { "Content light level metadata",                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
+                                                    .size = sizeof(AVContentLightMetadata) },
+    [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { .p = { "Ambient viewing environment",                  AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
+                                                    .init = ff_ave_get_defaults,
+                                                    .size = sizeof(AVAmbientViewingEnvironment) },
+    [AV_FRAME_DATA_SPHERICAL]                   = { .p = { "Spherical Mapping",                            AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
+                                                    .init = ff_spherical_get_defaults,
+                                                    .size = sizeof(AVSphericalMapping) },
     [AV_FRAME_DATA_ICC_PROFILE]                 = { .p = { "ICC profile",                                  AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
     [AV_FRAME_DATA_SEI_UNREGISTERED]            = { .p = { "H.26[45] User Data Unregistered SEI message",  AV_SIDE_DATA_PROP_MULTI } },
     [AV_FRAME_DATA_VIDEO_HINT]                  = { .p = { "Encoding video hint",                          AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
@@ -79,6 +110,11 @@ static const FFFrameSideData *csdp_from_sd(const AVFrameSideData *sd)
     return (const FFFrameSideData *)sd;
 }
 
+static const FFSideDataDescriptor *dp_from_desc(const AVSideDataDescriptor *desc)
+{
+    return (const FFSideDataDescriptor *)desc;
+}
+
 const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type)
 {
     unsigned t = type;
@@ -287,6 +323,24 @@ AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd,
     return sd_dst;
 }
 
+AVFrameSideData *av_frame_side_data_new_struct(AVFrameSideData ***sd, int *nb_sd,
+                                               enum AVFrameSideDataType type,
+                                               unsigned int flags)
+{
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
+    const FFSideDataDescriptor *dp = dp_from_desc(desc);
+    AVFrameSideData *ret;
+
+    if (!desc || !(desc->props & AV_SIDE_DATA_PROP_STRUCT))
+        return NULL;
+
+    av_assert0(dp->size);
+    ret = av_frame_side_data_new(sd, nb_sd, type, dp->size, flags);
+    if (ret && dp->init)
+         dp->init(ret->data);
+    return ret;
+}
+
 int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
                              const AVFrameSideData *src, unsigned int flags)
 {
diff --git a/libavutil/side_data.h b/libavutil/side_data.h
index 8275aa35a5..5d25833882 100644
--- a/libavutil/side_data.h
+++ b/libavutil/side_data.h
@@ -27,4 +27,8 @@ AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd,
                                                  enum AVFrameSideDataType type,
                                                  AVBufferRef *buf);
 
+void ff_mdm_get_defaults(void *obj);
+void ff_ave_get_defaults(void *obj);
+void ff_spherical_get_defaults(void *obj);
+
 #endif // AVUTIL_SIDE_DATA_H
diff --git a/libavutil/spherical.c b/libavutil/spherical.c
index 64ade1d0ec..4ef2c225c2 100644
--- a/libavutil/spherical.c
+++ b/libavutil/spherical.c
@@ -21,15 +21,23 @@
 #include "avstring.h"
 #include "macros.h"
 #include "mem.h"
+#include "side_data.h"
 #include "spherical.h"
 
+void ff_spherical_get_defaults(void *obj)
+{
+    AVSphericalMapping *spherical = obj;
+
+    spherical->projection = AV_SPHERICAL_RECTILINEAR;
+}
+
 AVSphericalMapping *av_spherical_alloc(size_t *size)
 {
     AVSphericalMapping *spherical = av_mallocz(sizeof(AVSphericalMapping));
     if (!spherical)
         return NULL;
 
-    spherical->projection = AV_SPHERICAL_RECTILINEAR;
+    ff_spherical_get_defaults(spherical);
 
     if (size)
         *size = sizeof(*spherical);
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 07/14] avutil/frame: add support for RefStruct as backing for side data
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (4 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 06/14] avutil/frame: av_frame_side_data_new_struct() James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type James Almer
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

With this, complex structs can be used as side data entries.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/frame.c     |   7 +-
 libavutil/side_data.c | 209 +++++++++++++++++++++++++++++++++++++++++-
 libavutil/side_data.h |   3 +
 3 files changed, 210 insertions(+), 9 deletions(-)

diff --git a/libavutil/frame.c b/libavutil/frame.c
index 70a3b59123..05138a4919 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -281,13 +281,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
             && (src->width != dst->width || src->height != dst->height))
             continue;
         if (force_copy) {
-            sd_dst = av_frame_new_side_data(dst, sd_src->type,
-                                            sd_src->size);
+            sd_dst = ff_frame_side_data_copy(&dst->side_data, &dst->nb_side_data,
+                                             sd_src);
             if (!sd_dst) {
                 av_frame_side_data_free(&dst->side_data, &dst->nb_side_data);
                 return AVERROR(ENOMEM);
             }
-            memcpy(sd_dst->data, sd_src->data, sd_src->size);
         } else {
             AVBufferRef *ref = av_buffer_ref(sd_src->buf);
             sd_dst = av_frame_new_side_data_from_buf(dst, sd_src->type, ref);
@@ -296,8 +295,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
                 av_frame_side_data_free(&dst->side_data, &dst->nb_side_data);
                 return AVERROR(ENOMEM);
             }
+            av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0);
         }
-        av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0);
     }
 
     ret = av_buffer_replace(&dst->opaque_ref, src->opaque_ref);
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index 671dcecb82..597228baf1 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -43,12 +43,22 @@ typedef struct FFFrameSideData {
 #if FF_API_SIDE_DATA_BUF == 0
     AVBufferRef *buf;
 #endif
+    void *refstruct;
 } FFFrameSideData;
 
+enum FFSideDataProps {
+    FF_SIDE_DATA_PROP_REFSTRUCT = (1 << 0),
+};
+
 typedef struct FFSideDataDescriptor {
     AVSideDataDescriptor p;
 
+
+    unsigned props;
+
     void (*init)(void *obj);
+    int  (*copy)(void *dst, const void *src);
+    void (*uninit)(AVRefStructOpaque opaque, void *obj);
 
     size_t size;
 } FFSideDataDescriptor;
@@ -141,6 +151,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
 #else
     av_buffer_unref(&sdp->buf);
 #endif
+    av_refstruct_unref(&sdp->refstruct);
     av_dict_free(&sd->metadata);
     av_freep(ptr_sd);
 }
@@ -208,6 +219,8 @@ static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
                                                    AVBufferRef *buf, uint8_t *data,
                                                    size_t size)
 {
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
+    const FFSideDataDescriptor *dp = dp_from_desc(desc);
     FFFrameSideData *sdp;
     AVFrameSideData *ret, **tmp;
 
@@ -215,6 +228,9 @@ static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd,
     if ((unsigned)*nb_sd >= FFMIN(INT_MAX, SIZE_MAX))
         return NULL;
 
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT))
+        return NULL;
+
     tmp = av_realloc_array(*sd, sizeof(**sd), *nb_sd + 1);
     if (!tmp)
         return NULL;
@@ -255,9 +271,15 @@ AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd,
 static AVFrameSideData *replace_side_data_from_buf(AVFrameSideData *dst,
                                                    AVBufferRef *buf, int flags)
 {
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(dst->type);
+    const FFSideDataDescriptor *dp = dp_from_desc(desc);
+
     if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
         return NULL;
 
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT))
+        return NULL;
+
     av_dict_free(&dst->metadata);
 #if FF_API_SIDE_DATA_BUF
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -323,6 +345,64 @@ AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd,
     return sd_dst;
 }
 
+static AVFrameSideData *add_side_data_from_refstruct(AVFrameSideData ***sd,
+                                                     int *nb_sd,
+                                                     enum AVFrameSideDataType type,
+                                                     void *obj, size_t size)
+{
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
+    const FFSideDataDescriptor *dp = dp_from_desc(desc);
+    FFFrameSideData *sdp;
+    AVFrameSideData *ret, **tmp;
+
+    // *nb_sd + 1 needs to fit into an int and a size_t.
+    if ((unsigned)*nb_sd >= FFMIN(INT_MAX, SIZE_MAX))
+        return NULL;
+
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT))
+        return NULL;
+
+    tmp = av_realloc_array(*sd, sizeof(**sd), *nb_sd + 1);
+    if (!tmp)
+        return NULL;
+    *sd = tmp;
+
+    sdp = av_mallocz(sizeof(*sdp));
+    if (!sdp)
+        return NULL;
+
+    sdp->refstruct = obj;
+    ret = &sdp->p;
+    ret->data = obj;
+    ret->size = size;
+    ret->type = type;
+
+    (*sd)[(*nb_sd)++] = ret;
+
+    return ret;
+}
+
+static AVFrameSideData *replace_side_data_from_refstruct(AVFrameSideData *sd,
+                                                         void *obj, size_t size, int flags)
+{
+    FFFrameSideData *sdp = sdp_from_sd(sd);
+
+    if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
+        return NULL;
+
+    av_dict_free(&sd->metadata);
+#if FF_API_SIDE_DATA_BUF
+FF_DISABLE_DEPRECATION_WARNINGS
+    av_buffer_unref(&sd->buf);
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    av_refstruct_unref(&sdp->refstruct);
+    sdp->refstruct = obj;
+    sd->data = obj;
+    sd->size = size;
+    return sd;
+}
+
 AVFrameSideData *av_frame_side_data_new_struct(AVFrameSideData ***sd, int *nb_sd,
                                                enum AVFrameSideDataType type,
                                                unsigned int flags)
@@ -330,36 +410,110 @@ AVFrameSideData *av_frame_side_data_new_struct(AVFrameSideData ***sd, int *nb_sd
     const AVSideDataDescriptor *desc = av_frame_side_data_desc(type);
     const FFSideDataDescriptor *dp = dp_from_desc(desc);
     AVFrameSideData *ret;
+    void *obj;
 
     if (!desc || !(desc->props & AV_SIDE_DATA_PROP_STRUCT))
         return NULL;
 
     av_assert0(dp->size);
+
+    if (!(dp->props & FF_SIDE_DATA_PROP_REFSTRUCT)) {
     ret = av_frame_side_data_new(sd, nb_sd, type, dp->size, flags);
     if (ret && dp->init)
          dp->init(ret->data);
     return ret;
+    }
+
+    if (!(obj = av_refstruct_alloc_ext(dp->size, 0, NULL, dp->uninit)))
+        return NULL;
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
+        av_frame_side_data_remove(sd, nb_sd, type);
+    if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
+        (ret = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) {
+        ret = replace_side_data_from_refstruct(ret, obj, dp->size, flags);
+        if (!ret)
+            av_refstruct_unref(&obj);
+        return ret;
+    }
+
+    ret = add_side_data_from_refstruct(sd, nb_sd, type, obj, dp->size);
+    if (!ret)
+        av_refstruct_unref(&obj);
+
+    return ret;
+}
+
+AVFrameSideData *ff_frame_side_data_copy(AVFrameSideData ***sd, int *nb_sd,
+                                         const AVFrameSideData *src)
+{
+    const AVSideDataDescriptor *desc;
+    const FFSideDataDescriptor *dp;
+    const FFFrameSideData *srcp = csdp_from_sd(src);
+    AVBufferRef     *buf    = NULL;
+    AVFrameSideData *sd_dst = NULL;
+    void            *obj    = NULL;
+    int              ret    = AVERROR_BUG;
+
+    if (!sd || !src || !nb_sd || (*nb_sd && !*sd))
+        return NULL;
+
+    desc = av_frame_side_data_desc(src->type);
+    dp = dp_from_desc(desc);
+
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT)) {
+        obj = av_refstruct_alloc_ext(dp->size, 0, NULL, dp->uninit);
+        if (!obj || dp->copy(obj, srcp->refstruct) < 0) {
+            av_refstruct_unref(&obj);
+            return NULL;
+        }
+        sd_dst = add_side_data_from_refstruct(sd, nb_sd, src->type, obj,
+                                              dp->size);
+    } else {
+        buf = av_buffer_alloc(src->size);
+        if (!buf)
+            return NULL;
+        memcpy(buf->data, src->data, src->size);
+        sd_dst = ff_frame_side_data_add_from_buf(sd, nb_sd, src->type, buf);
+    }
+    if (!sd_dst) {
+        av_buffer_unref(&buf);
+        av_refstruct_unref(&obj);
+        return NULL;
+    }
+
+    ret = av_dict_copy(&sd_dst->metadata, src->metadata, 0);
+    if (ret < 0) {
+        remove_side_data_by_entry(sd, nb_sd, sd_dst);
+        return NULL;
+    }
+
+    return sd_dst;
 }
 
 int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
                              const AVFrameSideData *src, unsigned int flags)
 {
     const AVSideDataDescriptor *desc;
+    const FFSideDataDescriptor *dp;
     const FFFrameSideData *srcp = csdp_from_sd(src);
     AVBufferRef     *buf    = NULL;
     AVFrameSideData *sd_dst = NULL;
+    void            *obj    = NULL;
     int              ret    = AVERROR_BUG;
 
     if (!sd || !src || !nb_sd || (*nb_sd && !*sd))
         return AVERROR(EINVAL);
 
     desc = av_frame_side_data_desc(src->type);
+    dp = dp_from_desc(desc);
     if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
         av_frame_side_data_remove(sd, nb_sd, src->type);
     if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) &&
         (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, src->type))) {
         FFFrameSideData *dstp = sdp_from_sd(sd_dst);
         AVDictionary *dict = NULL;
+        uint8_t *data;
+        size_t size;
 
         if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
             return AVERROR(EEXIST);
@@ -368,6 +522,11 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
         if (ret < 0)
             return ret;
 
+        if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT)) {
+            av_refstruct_replace(&dstp->refstruct, srcp->refstruct);
+            data = dstp->refstruct;
+            size = dp->size;
+        } else {
 #if FF_API_SIDE_DATA_BUF
 FF_DISABLE_DEPRECATION_WARNINGS
         ret = av_buffer_replace(&sd_dst->buf, src->buf);
@@ -375,6 +534,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
 #else
         ret = av_buffer_replace(&dstp->buf, srcp->buf);
 #endif
+            data = src->data;
+            size = src->size;
+        }
         if (ret < 0) {
             av_dict_free(&dict);
             return ret;
@@ -382,11 +544,16 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
         av_dict_free(&sd_dst->metadata);
         sd_dst->metadata = dict;
-        sd_dst->data     = src->data;
-        sd_dst->size     = src->size;
+        sd_dst->data     = data;
+        sd_dst->size     = size;
         return 0;
     }
 
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT)) {
+        obj = av_refstruct_ref(srcp->refstruct);
+        sd_dst = add_side_data_from_refstruct(sd, nb_sd, src->type, obj,
+                                              dp->size);
+    } else {
 #if FF_API_SIDE_DATA_BUF
 FF_DISABLE_DEPRECATION_WARNINGS
     buf = av_buffer_ref(src->buf);
@@ -399,8 +566,10 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
     sd_dst = add_side_data_from_buf_ext(sd, nb_sd, src->type, buf,
                                         src->data, src->size);
+    }
     if (!sd_dst) {
         av_buffer_unref(&buf);
+        av_refstruct_unref(&obj);
         return AVERROR(ENOMEM);
     }
 
@@ -426,20 +595,46 @@ const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *s
 
 int av_frame_side_data_is_writable(const AVFrameSideData *sd)
 {
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(sd->type);
+    const FFSideDataDescriptor *dp = dp_from_desc(desc);
+    const FFFrameSideData *sdp = csdp_from_sd(sd);
+
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT)) {
+        return av_refstruct_exclusive(sdp->refstruct);
+    } else {
 #if FF_API_SIDE_DATA_BUF
 FF_DISABLE_DEPRECATION_WARNINGS
     return !!av_buffer_is_writable(sd->buf);
 #else
-    const FFFrameSideData *sdp = csdp_from_sd(sd);
     return !!av_buffer_is_writable(sdp->buf);
 #endif
+    }
 }
 
 int av_frame_side_data_make_writable(AVFrameSideData *sd)
 {
+    const AVSideDataDescriptor *desc = av_frame_side_data_desc(sd->type);
+    const FFSideDataDescriptor *dp = dp_from_desc(desc);
     FFFrameSideData *sdp = sdp_from_sd(sd);
     AVBufferRef *buf = NULL;
-
+    void *obj = NULL;
+    uint8_t *data;
+
+    if (dp && (dp->props & FF_SIDE_DATA_PROP_REFSTRUCT)) {
+        void *obj;
+        int ret;
+        if (av_refstruct_exclusive(sdp->refstruct))
+            return 0;
+        obj = av_refstruct_alloc_ext(dp->size, 0, NULL, dp->uninit);
+        if (!obj)
+            return AVERROR(ENOMEM);
+        ret = dp->copy(obj, sdp->refstruct);
+        if (ret < 0) {
+            av_refstruct_unref(&obj);
+            return ret;
+        }
+        data = obj;
+    } else {
 #if FF_API_SIDE_DATA_BUF
 FF_DISABLE_DEPRECATION_WARNINGS
     if (av_buffer_is_writable(sd->buf))
@@ -455,6 +650,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
     if (sd->size)
         memcpy(buf->data, sd->data, sd->size);
+    data = buf->data;
+    }
 #if FF_API_SIDE_DATA_BUF
 FF_DISABLE_DEPRECATION_WARNINGS
     av_buffer_unref(&sd->buf);
@@ -464,7 +661,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
     av_buffer_unref(&sdp->buf);
     sdp->buf = buf;
 #endif
-    sd->data = buf->data;
+    av_refstruct_unref(&sdp->refstruct);
+    sdp->refstruct = obj;
+    sd->data = data;
 
     return 0;
 }
diff --git a/libavutil/side_data.h b/libavutil/side_data.h
index 5d25833882..5a3aeccab0 100644
--- a/libavutil/side_data.h
+++ b/libavutil/side_data.h
@@ -27,6 +27,9 @@ AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd,
                                                  enum AVFrameSideDataType type,
                                                  AVBufferRef *buf);
 
+AVFrameSideData *ff_frame_side_data_copy(AVFrameSideData ***sd, int *nb_sd,
+                                         const AVFrameSideData *src);
+
 void ff_mdm_get_defaults(void *obj);
 void ff_ave_get_defaults(void *obj);
 void ff_spherical_get_defaults(void *obj);
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (5 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 07/14] avutil/frame: add support for RefStruct as backing for side data James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-29 12:29   ` Andreas Rheinhardt
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 09/14] avutil/ambient_viewing_environment: deprecate av_ambient_viewing_environment_create_side_data() James Almer
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

Similar in purpose as the packet side data of the same name, but for encoders.

Signed-off-by: James Almer <jamrial@gmail.com>
---
An example of RefCount used for side data, including a copy and uninit callback
to handle allocations within the entry.

 libavutil/frame.h     | 14 ++++++++++++++
 libavutil/side_data.c | 23 +++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/libavutil/frame.h b/libavutil/frame.h
index 1feb11506a..c677407781 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -243,8 +243,22 @@ enum AVFrameSideDataType {
      * The data is an int storing the view ID.
      */
     AV_FRAME_DATA_VIEW_ID,
+
+    /**
+     * A side data used to signal an encoder that certain parameters changed.
+     * The payload is an AVParamChange struct.
+     */
+    AV_FRAME_DATA_PARAM_CHANGE,
 };
 
+typedef struct AVParamChange {
+    /**
+     * A dictionary filled with options to be passed to an already initialized
+     * encoder. May contain global and encoder private options.
+     */
+    AVDictionary *opts;
+} AVParamChange;
+
 enum AVActiveFormatDescription {
     AV_AFD_SAME         = 8,
     AV_AFD_4_3          = 9,
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index 597228baf1..c156d2bef8 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -63,6 +63,24 @@ typedef struct FFSideDataDescriptor {
     size_t size;
 } FFSideDataDescriptor;
 
+/* Type specific refstruct callbacks */
+
+static int copy_param_change(void *_dst, const void *_src)
+{
+    const AVParamChange *src = _src;
+    AVParamChange *dst = _dst;
+    int ret = av_dict_copy(&dst->opts, src->opts, 0);
+    if (ret < 0)
+        av_dict_free(&dst->opts);
+    return ret;
+}
+
+static void uninit_param_change(AVRefStructOpaque opaque, void *obj)
+{
+    AVParamChange *param = obj;
+    av_dict_free(&param->opts);
+}
+
 static const FFSideDataDescriptor sd_props[] = {
     [AV_FRAME_DATA_PANSCAN]                     = { .p = { "AVPanScan",                                    AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
                                                     .size = sizeof(AVPanScan) },
@@ -88,6 +106,11 @@ static const FFSideDataDescriptor sd_props[] = {
     [AV_FRAME_DATA_DOVI_METADATA]               = { .p = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
     [AV_FRAME_DATA_LCEVC]                       = { .p = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
     [AV_FRAME_DATA_VIEW_ID]                     = { .p = { "View ID" } },
+    [AV_FRAME_DATA_PARAM_CHANGE]                = { .p = { "Param Change",                                 AV_SIDE_DATA_PROP_STRUCT },
+                                                    .props = FF_SIDE_DATA_PROP_REFSTRUCT,
+                                                    .copy = copy_param_change,
+                                                    .uninit = uninit_param_change,
+                                                    .size = sizeof(AVParamChange) },
     [AV_FRAME_DATA_STEREO3D]                    = { .p = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
                                                     .size = sizeof(AVStereo3D) },
     [AV_FRAME_DATA_REPLAYGAIN]                  = { .p = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 09/14] avutil/ambient_viewing_environment: deprecate av_ambient_viewing_environment_create_side_data()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (6 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 10/14] avutil/downmix_info: deprecate av_downmix_info_update_side_data() James Almer
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

It's no longer needed after the addition of av_frame_side_data_new_struct()

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/ambient_viewing_environment.c | 2 ++
 libavutil/ambient_viewing_environment.h | 6 ++++++
 libavutil/version.h                     | 1 +
 3 files changed, 9 insertions(+)

diff --git a/libavutil/ambient_viewing_environment.c b/libavutil/ambient_viewing_environment.c
index ee2e9427cd..16858bf206 100644
--- a/libavutil/ambient_viewing_environment.c
+++ b/libavutil/ambient_viewing_environment.c
@@ -46,6 +46,7 @@ AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size)
     return env;
 }
 
+#if FF_API_CREATE_SIDE_DATA
 AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data =
@@ -60,3 +61,4 @@ AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVF
 
     return (AVAmbientViewingEnvironment *)side_data->data;
 }
+#endif
diff --git a/libavutil/ambient_viewing_environment.h b/libavutil/ambient_viewing_environment.h
index e5e4ac2173..08aac686f0 100644
--- a/libavutil/ambient_viewing_environment.h
+++ b/libavutil/ambient_viewing_environment.h
@@ -22,8 +22,10 @@
 #define AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H
 
 #include <stddef.h>
+#include "attributes.h"
 #include "frame.h"
 #include "rational.h"
+#include "version.h"
 
 /**
  * Ambient viewing environment metadata as defined by H.274. The values are
@@ -61,12 +63,16 @@ typedef struct AVAmbientViewingEnvironment {
  */
 AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size);
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Allocate and add an AVAmbientViewingEnvironment structure to an existing
  * AVFrame as side data.
  *
+ * @deprecated use @ref av_frame_side_data_new_struct()
  * @return the newly allocated struct, or NULL on failure
  */
+attribute_deprecated
 AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVFrame *frame);
+#endif
 
 #endif /* AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H */
diff --git a/libavutil/version.h b/libavutil/version.h
index e736484a1e..d4229178ab 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -118,6 +118,7 @@
 #define FF_API_OPT_INT_LIST             (LIBAVUTIL_VERSION_MAJOR < 60)
 #define FF_API_OPT_PTR                  (LIBAVUTIL_VERSION_MAJOR < 60)
 #define FF_API_SIDE_DATA_BUF            (LIBAVUTIL_VERSION_MAJOR < 60)
+#define FF_API_CREATE_SIDE_DATA         (LIBAVUTIL_VERSION_MAJOR < 60)
 
 /**
  * @}
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 10/14] avutil/downmix_info: deprecate av_downmix_info_update_side_data()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (7 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 09/14] avutil/ambient_viewing_environment: deprecate av_ambient_viewing_environment_create_side_data() James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 11/14] avutil/hdr_dynamic_metadata: deprecate av_dynamic_hdr_plus_create_side_data() James Almer
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

It's no longer needed after the addition of av_frame_side_data_new_struct()

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/downmix_info.c | 2 ++
 libavutil/downmix_info.h | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/libavutil/downmix_info.c b/libavutil/downmix_info.c
index c634c6a79f..73d0f6b261 100644
--- a/libavutil/downmix_info.c
+++ b/libavutil/downmix_info.c
@@ -21,6 +21,7 @@
 #include "downmix_info.h"
 #include "frame.h"
 
+#if FF_API_CREATE_SIDE_DATA
 AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data;
@@ -36,3 +37,4 @@ AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame)
 
     return (AVDownmixInfo*)side_data->data;
 }
+#endif
diff --git a/libavutil/downmix_info.h b/libavutil/downmix_info.h
index 221cf5bf9b..6580f8873e 100644
--- a/libavutil/downmix_info.h
+++ b/libavutil/downmix_info.h
@@ -21,7 +21,9 @@
 #ifndef AVUTIL_DOWNMIX_INFO_H
 #define AVUTIL_DOWNMIX_INFO_H
 
+#include "attributes.h"
 #include "frame.h"
+#include "version.h"
 
 /**
  * @file
@@ -92,6 +94,7 @@ typedef struct AVDownmixInfo {
     double lfe_mix_level;
 } AVDownmixInfo;
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing.
  *
@@ -99,10 +102,13 @@ typedef struct AVDownmixInfo {
  *
  * @param frame the frame for which the side data is to be obtained or created
  *
+ * @deprecated use @ref av_frame_side_data_new_struct() and @ref av_frame_side_data_get()
  * @return the AVDownmixInfo structure to be edited by the caller, or NULL if
  *         the structure cannot be allocated.
  */
+attribute_deprecated
 AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame);
+#endif
 
 /**
  * @}
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 11/14] avutil/hdr_dynamic_metadata: deprecate av_dynamic_hdr_plus_create_side_data()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (8 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 10/14] avutil/downmix_info: deprecate av_downmix_info_update_side_data() James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 12/14] avutil/hdr_dynamic_vivid_metadata: deprecate av_dynamic_hdr_vivid_create_side_data() James Almer
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

It's no longer needed after the addition of av_frame_side_data_new_struct()

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/hdr_dynamic_metadata.c | 2 ++
 libavutil/hdr_dynamic_metadata.h | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/libavutil/hdr_dynamic_metadata.c b/libavutil/hdr_dynamic_metadata.c
index 7033f060c0..25ea6544c1 100644
--- a/libavutil/hdr_dynamic_metadata.c
+++ b/libavutil/hdr_dynamic_metadata.c
@@ -45,6 +45,7 @@ AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size)
     return hdr_plus;
 }
 
+#if FF_API_CREATE_SIDE_DATA
 AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data = av_frame_new_side_data(frame,
@@ -57,6 +58,7 @@ AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame)
 
     return (AVDynamicHDRPlus *)side_data->data;
 }
+#endif
 
 int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data,
                                  size_t size)
diff --git a/libavutil/hdr_dynamic_metadata.h b/libavutil/hdr_dynamic_metadata.h
index 5100ed6f41..415b1b1fbd 100644
--- a/libavutil/hdr_dynamic_metadata.h
+++ b/libavutil/hdr_dynamic_metadata.h
@@ -21,8 +21,10 @@
 #ifndef AVUTIL_HDR_DYNAMIC_METADATA_H
 #define AVUTIL_HDR_DYNAMIC_METADATA_H
 
+#include "attributes.h"
 #include "frame.h"
 #include "rational.h"
+#include "version.h"
 
 /**
  * Option for overlapping elliptical pixel selectors in an image.
@@ -331,14 +333,18 @@ typedef struct AVDynamicHDRPlus {
  */
 AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size);
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Allocate a complete AVDynamicHDRPlus and add it to the frame.
  * @param frame The frame which side data is added to.
  *
+ * @deprecated use @ref av_frame_side_data_new_struct()
  * @return The AVDynamicHDRPlus structure to be filled by caller or NULL
  *         on failure.
  */
+attribute_deprecated
 AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame);
+#endif
 
 /**
  * Parse the user data registered ITU-T T.35 to AVbuffer (AVDynamicHDRPlus).
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 12/14] avutil/hdr_dynamic_vivid_metadata: deprecate av_dynamic_hdr_vivid_create_side_data()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (9 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 11/14] avutil/hdr_dynamic_metadata: deprecate av_dynamic_hdr_plus_create_side_data() James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 13/14] avutil/mastering_display_metadata: deprecate av_{content_light, mastering_display_metadata}_create_side_data() James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 14/14] avutil/stereo3d: deprecate av_stereo3d_create_side_data() James Almer
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

It's no longer needed after the addition of av_frame_side_data_new_struct()

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/hdr_dynamic_vivid_metadata.c | 2 ++
 libavutil/hdr_dynamic_vivid_metadata.h | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/libavutil/hdr_dynamic_vivid_metadata.c b/libavutil/hdr_dynamic_vivid_metadata.c
index 32da01f587..140a4df4c2 100644
--- a/libavutil/hdr_dynamic_vivid_metadata.c
+++ b/libavutil/hdr_dynamic_vivid_metadata.c
@@ -33,6 +33,7 @@ AVDynamicHDRVivid *av_dynamic_hdr_vivid_alloc(size_t *size)
     return hdr_vivid;
 }
 
+#if FF_API_CREATE_SIDE_DATA
 AVDynamicHDRVivid *av_dynamic_hdr_vivid_create_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data = av_frame_new_side_data(frame,
@@ -45,3 +46,4 @@ AVDynamicHDRVivid *av_dynamic_hdr_vivid_create_side_data(AVFrame *frame)
 
     return (AVDynamicHDRVivid *)side_data->data;
 }
+#endif
diff --git a/libavutil/hdr_dynamic_vivid_metadata.h b/libavutil/hdr_dynamic_vivid_metadata.h
index 4524a81557..0b42ccc7d0 100644
--- a/libavutil/hdr_dynamic_vivid_metadata.h
+++ b/libavutil/hdr_dynamic_vivid_metadata.h
@@ -21,8 +21,10 @@
 #ifndef AVUTIL_HDR_DYNAMIC_VIVID_METADATA_H
 #define AVUTIL_HDR_DYNAMIC_VIVID_METADATA_H
 
+#include "attributes.h"
 #include "frame.h"
 #include "rational.h"
+#include "version.h"
 
 /**
  * HDR Vivid three spline params.
@@ -334,13 +336,17 @@ typedef struct AVDynamicHDRVivid {
  */
 AVDynamicHDRVivid *av_dynamic_hdr_vivid_alloc(size_t *size);
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Allocate a complete AVDynamicHDRVivid and add it to the frame.
  * @param frame The frame which side data is added to.
  *
+ * @deprecated use @ref av_frame_side_data_new_struct()
  * @return The AVDynamicHDRVivid structure to be filled by caller or NULL
  *         on failure.
  */
+attribute_deprecated
 AVDynamicHDRVivid *av_dynamic_hdr_vivid_create_side_data(AVFrame *frame);
+#endif
 
 #endif /* AVUTIL_HDR_DYNAMIC_VIVID_METADATA_H */
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 13/14] avutil/mastering_display_metadata: deprecate av_{content_light, mastering_display_metadata}_create_side_data()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (10 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 12/14] avutil/hdr_dynamic_vivid_metadata: deprecate av_dynamic_hdr_vivid_create_side_data() James Almer
@ 2025-01-25 20:21 ` James Almer
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 14/14] avutil/stereo3d: deprecate av_stereo3d_create_side_data() James Almer
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

It's no longer needed after the addition of av_frame_side_data_new_struct()

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/mastering_display_metadata.c |  4 ++++
 libavutil/mastering_display_metadata.h | 10 ++++++++++
 2 files changed, 14 insertions(+)

diff --git a/libavutil/mastering_display_metadata.c b/libavutil/mastering_display_metadata.c
index 4948f30523..48d8b04cc8 100644
--- a/libavutil/mastering_display_metadata.c
+++ b/libavutil/mastering_display_metadata.c
@@ -58,6 +58,7 @@ AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *siz
     return mastering;
 }
 
+#if FF_API_CREATE_SIDE_DATA
 AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data = av_frame_new_side_data(frame,
@@ -71,6 +72,7 @@ AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFra
 
     return (AVMasteringDisplayMetadata *)side_data->data;
 }
+#endif
 
 AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size)
 {
@@ -82,6 +84,7 @@ AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size)
     return metadata;
 }
 
+#if FF_API_CREATE_SIDE_DATA
 AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data = av_frame_new_side_data(frame,
@@ -94,3 +97,4 @@ AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *fram
 
     return (AVContentLightMetadata *)side_data->data;
 }
+#endif
diff --git a/libavutil/mastering_display_metadata.h b/libavutil/mastering_display_metadata.h
index 52fcef9e37..60ca817eff 100644
--- a/libavutil/mastering_display_metadata.h
+++ b/libavutil/mastering_display_metadata.h
@@ -21,8 +21,10 @@
 #ifndef AVUTIL_MASTERING_DISPLAY_METADATA_H
 #define AVUTIL_MASTERING_DISPLAY_METADATA_H
 
+#include "attributes.h"
 #include "frame.h"
 #include "rational.h"
+#include "version.h"
 
 
 /**
@@ -86,14 +88,18 @@ AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void);
  */
 AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *size);
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Allocate a complete AVMasteringDisplayMetadata and add it to the frame.
  *
  * @param frame The frame which side data is added to.
  *
+ * @deprecated use @ref av_frame_side_data_new_struct()
  * @return The AVMasteringDisplayMetadata structure to be filled by caller.
  */
+attribute_deprecated
 AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame);
+#endif
 
 /**
  * Content light level needed by to transmit HDR over HDMI (CTA-861.3).
@@ -125,13 +131,17 @@ typedef struct AVContentLightMetadata {
  */
 AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size);
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Allocate a complete AVContentLightMetadata and add it to the frame.
  *
  * @param frame The frame which side data is added to.
  *
+ * @deprecated use @ref av_frame_side_data_new_struct()
  * @return The AVContentLightMetadata structure to be filled by caller.
  */
+attribute_deprecated
 AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame);
+#endif
 
 #endif /* AVUTIL_MASTERING_DISPLAY_METADATA_H */
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* [FFmpeg-devel] [PATCH 14/14] avutil/stereo3d: deprecate av_stereo3d_create_side_data()
  2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
                   ` (11 preceding siblings ...)
  2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 13/14] avutil/mastering_display_metadata: deprecate av_{content_light, mastering_display_metadata}_create_side_data() James Almer
@ 2025-01-25 20:21 ` James Almer
  12 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-25 20:21 UTC (permalink / raw)
  To: ffmpeg-devel

It's no longer needed after the addition of av_frame_side_data_new_struct()

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/stereo3d.c | 2 ++
 libavutil/stereo3d.h | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/libavutil/stereo3d.c b/libavutil/stereo3d.c
index d6de476532..8a21cfd407 100644
--- a/libavutil/stereo3d.c
+++ b/libavutil/stereo3d.c
@@ -51,6 +51,7 @@ AVStereo3D *av_stereo3d_alloc_size(size_t *size)
     return stereo;
 }
 
+#if FF_API_CREATE_SIDE_DATA
 AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame)
 {
     AVFrameSideData *side_data = av_frame_new_side_data(frame,
@@ -64,6 +65,7 @@ AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame)
 
     return (AVStereo3D *)side_data->data;
 }
+#endif
 
 static const char * const stereo3d_type_names[] = {
     [AV_STEREO3D_2D]                  = "2D",
diff --git a/libavutil/stereo3d.h b/libavutil/stereo3d.h
index c0a4ab3f2d..4f679b9bb1 100644
--- a/libavutil/stereo3d.h
+++ b/libavutil/stereo3d.h
@@ -29,7 +29,9 @@
 
 #include <stdint.h>
 
+#include "attributes.h"
 #include "frame.h"
+#include "version.h"
 
 /**
  * @defgroup lavu_video_stereo3d Stereo3D types and functions
@@ -255,14 +257,18 @@ AVStereo3D *av_stereo3d_alloc(void);
  */
 AVStereo3D *av_stereo3d_alloc_size(size_t *size);
 
+#if FF_API_CREATE_SIDE_DATA
 /**
  * Allocate a complete AVFrameSideData and add it to the frame.
  *
  * @param frame The frame which side data is added to.
  *
+ * @deprecated use @ref av_frame_side_data_new_struct()
  * @return The AVStereo3D structure to be filled by caller.
  */
+attribute_deprecated
 AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame);
+#endif
 
 /**
  * Provide a human-readable name of a given stereo3d type.
-- 
2.48.1

_______________________________________________
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] 16+ messages in thread

* Re: [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type
  2025-01-25 20:21 ` [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type James Almer
@ 2025-01-29 12:29   ` Andreas Rheinhardt
  2025-01-29 13:53     ` James Almer
  0 siblings, 1 reply; 16+ messages in thread
From: Andreas Rheinhardt @ 2025-01-29 12:29 UTC (permalink / raw)
  To: ffmpeg-devel

James Almer:
> Similar in purpose as the packet side data of the same name, but for encoders.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> An example of RefCount used for side data, including a copy and uninit callback
> to handle allocations within the entry.
> 
>  libavutil/frame.h     | 14 ++++++++++++++
>  libavutil/side_data.c | 23 +++++++++++++++++++++++
>  2 files changed, 37 insertions(+)
> 
> diff --git a/libavutil/frame.h b/libavutil/frame.h
> index 1feb11506a..c677407781 100644
> --- a/libavutil/frame.h
> +++ b/libavutil/frame.h
> @@ -243,8 +243,22 @@ enum AVFrameSideDataType {
>       * The data is an int storing the view ID.
>       */
>      AV_FRAME_DATA_VIEW_ID,
> +
> +    /**
> +     * A side data used to signal an encoder that certain parameters changed.
> +     * The payload is an AVParamChange struct.
> +     */
> +    AV_FRAME_DATA_PARAM_CHANGE,
>  };
>  
> +typedef struct AVParamChange {
> +    /**
> +     * A dictionary filled with options to be passed to an already initialized
> +     * encoder. May contain global and encoder private options.
> +     */
> +    AVDictionary *opts;
> +} AVParamChange;
> +
>  enum AVActiveFormatDescription {
>      AV_AFD_SAME         = 8,
>      AV_AFD_4_3          = 9,
> diff --git a/libavutil/side_data.c b/libavutil/side_data.c
> index 597228baf1..c156d2bef8 100644
> --- a/libavutil/side_data.c
> +++ b/libavutil/side_data.c
> @@ -63,6 +63,24 @@ typedef struct FFSideDataDescriptor {
>      size_t size;
>  } FFSideDataDescriptor;
>  
> +/* Type specific refstruct callbacks */
> +
> +static int copy_param_change(void *_dst, const void *_src)
> +{
> +    const AVParamChange *src = _src;
> +    AVParamChange *dst = _dst;
> +    int ret = av_dict_copy(&dst->opts, src->opts, 0);
> +    if (ret < 0)
> +        av_dict_free(&dst->opts);
> +    return ret;
> +}
> +
> +static void uninit_param_change(AVRefStructOpaque opaque, void *obj)
> +{
> +    AVParamChange *param = obj;
> +    av_dict_free(&param->opts);
> +}
> +
>  static const FFSideDataDescriptor sd_props[] = {
>      [AV_FRAME_DATA_PANSCAN]                     = { .p = { "AVPanScan",                                    AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
>                                                      .size = sizeof(AVPanScan) },
> @@ -88,6 +106,11 @@ static const FFSideDataDescriptor sd_props[] = {
>      [AV_FRAME_DATA_DOVI_METADATA]               = { .p = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
>      [AV_FRAME_DATA_LCEVC]                       = { .p = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
>      [AV_FRAME_DATA_VIEW_ID]                     = { .p = { "View ID" } },
> +    [AV_FRAME_DATA_PARAM_CHANGE]                = { .p = { "Param Change",                                 AV_SIDE_DATA_PROP_STRUCT },
> +                                                    .props = FF_SIDE_DATA_PROP_REFSTRUCT,
> +                                                    .copy = copy_param_change,
> +                                                    .uninit = uninit_param_change,
> +                                                    .size = sizeof(AVParamChange) },
>      [AV_FRAME_DATA_STEREO3D]                    = { .p = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
>                                                      .size = sizeof(AVStereo3D) },
>      [AV_FRAME_DATA_REPLAYGAIN]                  = { .p = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },

I dislike the whole approach: Frame side data is supposed to contain
side-data that applies to the frame; yet a lot of encoder options which
will ultimately be added to this side data (if it gets committed) are
not frame properties at all.

Furthermore, this approach necessitates checking every frame (even of
encoders that do not support parameter changes) for the existence of
said side-data, although this side data will not exist in the
overwhelming majority of cases. Why not add a new function for this
task? (This does not imply that I am in favor of the reconfiguration
approach at all. I'm still leaning towards "close+reopen".)

- Andreas

_______________________________________________
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] 16+ messages in thread

* Re: [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type
  2025-01-29 12:29   ` Andreas Rheinhardt
@ 2025-01-29 13:53     ` James Almer
  0 siblings, 0 replies; 16+ messages in thread
From: James Almer @ 2025-01-29 13:53 UTC (permalink / raw)
  To: ffmpeg-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 5420 bytes --]

On 1/29/2025 9:29 AM, Andreas Rheinhardt wrote:
> James Almer:
>> Similar in purpose as the packet side data of the same name, but for encoders.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>> An example of RefCount used for side data, including a copy and uninit callback
>> to handle allocations within the entry.
>>
>>   libavutil/frame.h     | 14 ++++++++++++++
>>   libavutil/side_data.c | 23 +++++++++++++++++++++++
>>   2 files changed, 37 insertions(+)
>>
>> diff --git a/libavutil/frame.h b/libavutil/frame.h
>> index 1feb11506a..c677407781 100644
>> --- a/libavutil/frame.h
>> +++ b/libavutil/frame.h
>> @@ -243,8 +243,22 @@ enum AVFrameSideDataType {
>>        * The data is an int storing the view ID.
>>        */
>>       AV_FRAME_DATA_VIEW_ID,
>> +
>> +    /**
>> +     * A side data used to signal an encoder that certain parameters changed.
>> +     * The payload is an AVParamChange struct.
>> +     */
>> +    AV_FRAME_DATA_PARAM_CHANGE,
>>   };
>>   
>> +typedef struct AVParamChange {
>> +    /**
>> +     * A dictionary filled with options to be passed to an already initialized
>> +     * encoder. May contain global and encoder private options.
>> +     */
>> +    AVDictionary *opts;
>> +} AVParamChange;
>> +
>>   enum AVActiveFormatDescription {
>>       AV_AFD_SAME         = 8,
>>       AV_AFD_4_3          = 9,
>> diff --git a/libavutil/side_data.c b/libavutil/side_data.c
>> index 597228baf1..c156d2bef8 100644
>> --- a/libavutil/side_data.c
>> +++ b/libavutil/side_data.c
>> @@ -63,6 +63,24 @@ typedef struct FFSideDataDescriptor {
>>       size_t size;
>>   } FFSideDataDescriptor;
>>   
>> +/* Type specific refstruct callbacks */
>> +
>> +static int copy_param_change(void *_dst, const void *_src)
>> +{
>> +    const AVParamChange *src = _src;
>> +    AVParamChange *dst = _dst;
>> +    int ret = av_dict_copy(&dst->opts, src->opts, 0);
>> +    if (ret < 0)
>> +        av_dict_free(&dst->opts);
>> +    return ret;
>> +}
>> +
>> +static void uninit_param_change(AVRefStructOpaque opaque, void *obj)
>> +{
>> +    AVParamChange *param = obj;
>> +    av_dict_free(&param->opts);
>> +}
>> +
>>   static const FFSideDataDescriptor sd_props[] = {
>>       [AV_FRAME_DATA_PANSCAN]                     = { .p = { "AVPanScan",                                    AV_SIDE_DATA_PROP_STRUCT | AV_SIDE_DATA_PROP_SIZE_DEPENDENT },
>>                                                       .size = sizeof(AVPanScan) },
>> @@ -88,6 +106,11 @@ static const FFSideDataDescriptor sd_props[] = {
>>       [AV_FRAME_DATA_DOVI_METADATA]               = { .p = { "Dolby Vision Metadata",                        AV_SIDE_DATA_PROP_COLOR_DEPENDENT } },
>>       [AV_FRAME_DATA_LCEVC]                       = { .p = { "LCEVC NAL data",                               AV_SIDE_DATA_PROP_SIZE_DEPENDENT } },
>>       [AV_FRAME_DATA_VIEW_ID]                     = { .p = { "View ID" } },
>> +    [AV_FRAME_DATA_PARAM_CHANGE]                = { .p = { "Param Change",                                 AV_SIDE_DATA_PROP_STRUCT },
>> +                                                    .props = FF_SIDE_DATA_PROP_REFSTRUCT,
>> +                                                    .copy = copy_param_change,
>> +                                                    .uninit = uninit_param_change,
>> +                                                    .size = sizeof(AVParamChange) },
>>       [AV_FRAME_DATA_STEREO3D]                    = { .p = { "Stereo 3D",                                    AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
>>                                                       .size = sizeof(AVStereo3D) },
>>       [AV_FRAME_DATA_REPLAYGAIN]                  = { .p = { "AVReplayGain",                                 AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_STRUCT },
> 
> I dislike the whole approach: Frame side data is supposed to contain
> side-data that applies to the frame; yet a lot of encoder options which
> will ultimately be added to this side data (if it gets committed) are
> not frame properties at all.

Fair enough.

> 
> Furthermore, this approach necessitates checking every frame (even of
> encoders that do not support parameter changes) for the existence of
> said side-data, although this side data will not exist in the

There's no need to check them. I just copied the check done for the 
packet side data of the same name, which aborts if it's present when it 
shouldn't. We can always just silently ignore it instead if the encoder 
doesn't care about it.

> overwhelming majority of cases. Why not add a new function for this
> task? (This does not imply that I am in favor of the reconfiguration
> approach at all. I'm still leaning towards "close+reopen".)
Like i said, there are some cases where it's better to do a graceful 
re-initialization for the sake of compression if you only care about 
changing a few values. If we can implement a way to do it that's not 
invasive, then it's IMO worth giving the option.
Right now, libx264 does it silently if it detects changes to the avctx 
or the private struct, which is not ok as it gives the user the 
impression it can be done for every encoder, when that's clearly not the 
case and can even result in crazy behavior for some.

I'll look into making it a function later.


[-- 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] 16+ messages in thread

end of thread, other threads:[~2025-01-29 13:53 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-25 20:21 [FFmpeg-devel] [PATCH 01/14] avutil/frame: move side data helpers to a new file James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 02/14] avutil/frame: allow the addition of internal fields to AVSideDataDescriptor James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 03/14] avutil/frame: allow the addition of internal fields to AVFrameSideData James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 04/14] avutil/frame: schedule making AVFrameSideData.buf internal James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 05/14] avutil/frame: add functions to check and ensure a side data entry is writable James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 06/14] avutil/frame: av_frame_side_data_new_struct() James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 07/14] avutil/frame: add support for RefStruct as backing for side data James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PoC][PATCH 08/14] avutil/frame: add a param change side data type James Almer
2025-01-29 12:29   ` Andreas Rheinhardt
2025-01-29 13:53     ` James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 09/14] avutil/ambient_viewing_environment: deprecate av_ambient_viewing_environment_create_side_data() James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 10/14] avutil/downmix_info: deprecate av_downmix_info_update_side_data() James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 11/14] avutil/hdr_dynamic_metadata: deprecate av_dynamic_hdr_plus_create_side_data() James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 12/14] avutil/hdr_dynamic_vivid_metadata: deprecate av_dynamic_hdr_vivid_create_side_data() James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 13/14] avutil/mastering_display_metadata: deprecate av_{content_light, mastering_display_metadata}_create_side_data() James Almer
2025-01-25 20:21 ` [FFmpeg-devel] [PATCH 14/14] avutil/stereo3d: deprecate av_stereo3d_create_side_data() 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