diff mbox series

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

Message ID 20240325200602.63020-2-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel,1/6,v2] avutil/frame: add a flag to not create duplicate entries in a side data array | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

James Almer March 25, 2024, 8:05 p.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/frame.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 libavutil/frame.h | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)
diff mbox series

Patch

diff --git a/libavutil/frame.c b/libavutil/frame.c
index a780e62fd0..33c077998a 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -789,6 +789,49 @@  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)
+{
+    AVFrameSideData *sd_dst  = NULL;
+    AVBufferRef *buf;
+
+    if (!sd || !pbuf || !nb_sd || (*nb_sd && !*sd))
+        return NULL;
+
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE)
+        remove_side_data(sd, nb_sd, type);
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_DONT_APPEND) {
+        for (int i = 0; i < *nb_sd; i++) {
+            AVFrameSideData *entry = ((*sd)[i]);
+            if (entry->type == type) {
+                if (!(flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF))
+                    av_buffer_unref(pbuf);
+                return entry;
+            }
+        }
+    }
+
+    if (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF)
+        buf = av_buffer_ref(*pbuf);
+    else
+        buf = *pbuf;
+    if (!buf)
+        return NULL;
+
+    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 7cc55a455e..e03ce39af7 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -1011,6 +1011,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_DONT_APPEND (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.
@@ -1029,11 +1033,41 @@  void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd);
  *       is attempted.
  * @note In case of AV_FRAME_SIDE_DATA_FLAG_DONT_APPEND being set, if an
  *       entry of the same type already exists, it will be returned 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_DONT_APPEND being set, if an
+ *       entry of the same type already exists, it will be returned instead
+ *       and the array will be unchanged.
+ * @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.
@@ -1053,6 +1087,7 @@  AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd,
  * @note In case of AV_FRAME_SIDE_DATA_FLAG_DONT_APPEND being set, if an
  *       entry of the same type as the one from src already exists, this
  *       function will be a no-op.
+ * @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);