diff mbox series

[FFmpeg-devel,02/10] avutil/frame: add helper for adding side data w/ AVBufferRef to array

Message ID 20240327191648.5017-1-jamrial@gmail.com
State New
Headers show
Series None | expand

Commit Message

James Almer March 27, 2024, 7:16 p.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/frame.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/frame.h | 34 ++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)
diff mbox series

Patch

diff --git a/libavutil/frame.c b/libavutil/frame.c
index 2e40018b83..08b6475cc2 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -834,6 +834,59 @@  AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
     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;
+
+    if (!sd || !pbuf || *pbuf || !nb_sd || (*nb_sd && !*sd))
+        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)) {
+        for (int i = 0; i < *nb_sd; i++) {
+            AVFrameSideData *entry = ((*sd)[i]);
+
+            if (entry->type != type)
+                continue;
+            if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE))
+                return NULL;
+
+            buf = *pbuf;
+            if (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF) {
+                int ret = av_buffer_replace(&entry->buf, buf);
+                if (ret < 0)
+                    return NULL;
+            } else
+                *pbuf = NULL;
+
+            av_dict_free(&entry->metadata);
+            entry->data = buf->data;
+            entry->size = buf->size;
+            return 0;
+        }
+    }
+
+    buf = (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF) ?
+           av_buffer_ref(*pbuf) : *pbuf;
+
+    sd_dst = add_side_data_from_buf(sd, nb_sd, type, buf);
+    if (!sd_dst) {
+        if (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF)
+            av_buffer_unref(&buf);
+        return NULL;
+    }
+
+    if (!(flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF))
+        *pbuf = NULL;
+
+    return sd_dst;
+}
+
 int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
                              const AVFrameSideData *src, unsigned int flags)
 {
diff --git a/libavutil/frame.h b/libavutil/frame.h
index 2ea129888e..3e5d170a5b 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -1048,6 +1048,10 @@  void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd);
  * Don't add a new entry if another of the same type exists.
  */
 #define AV_FRAME_SIDE_DATA_FLAG_REPLACE (1 << 1)
+/**
+ * Create a new reference instead of taking ownership of the passed in one.
+ */
+#define AV_FRAME_SIDE_DATA_FLAG_NEW_REF (1 << 2)
 
 /**
  * Add new side data entry to an array.
@@ -1066,11 +1070,40 @@  void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd);
  *       is attempted.
  * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an
  *       entry of the same type already exists, it will be replaced instead.
+ * @note AV_FRAME_SIDE_DATA_FLAG_NEW_REF has no effect in this function.
  */
 AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
                                         enum AVFrameSideDataType type,
                                         size_t size, unsigned int flags);
 
+/**
+ * Add a new side data entry to an array from an existing AVBufferRef.
+ *
+ * @param sd    pointer to array of side data to which to add another entry,
+ *              or to NULL in order to start a new array.
+ * @param nb_sd pointer to an integer containing the number of entries in
+ *              the array.
+ * @param type  type of the added side data
+ * @param buf   Pointer to AVBufferRef to add to the array. On success,
+ *              the function takes ownership of the AVBufferRef and *buf is
+ *              set to NULL, unless AV_FRAME_SIDE_DATA_FLAG_NEW_REF is set
+ *              in which case the ownership will remain with the caller.
+ * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0.
+ *
+ * @return newly added side data on success, NULL on error.
+ * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of
+ *       matching AVFrameSideDataType will be removed before the addition
+ *       is attempted.
+ * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an
+ *       entry of the same type already exists, it will be replaced instead.
+ * @note In case of AV_FRAME_SIDE_DATA_FLAG_NEW_REF being set, the ownership
+ *       of *buf will remain with the caller.
+ *
+ */
+AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd,
+                                        enum AVFrameSideDataType type,
+                                        AVBufferRef **buf, unsigned int flags);
+
 /**
  * Add a new side data entry to an array based on existing side data, taking
  * a reference towards the contained AVBufferRef.
@@ -1089,6 +1122,7 @@  AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
  *       is attempted.
  * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an
  *       entry of the same type already exists, it will be replaced instead.
+ * @note AV_FRAME_SIDE_DATA_FLAG_NEW_REF has no effect in this function.
  */
 int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd,
                              const AVFrameSideData *src, unsigned int flags);