[FFmpeg-devel] [PATCH 07/14] avutil/frame: add support for RefStruct as backing for side data

James Almer jamrial at gmail.com
Sat Jan 25 22:21:35 EET 2025


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

Signed-off-by: James Almer <jamrial at 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



More information about the ffmpeg-devel mailing list