@@ -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)
{
@@ -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);
Signed-off-by: James Almer <jamrial@gmail.com> --- libavutil/frame.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ libavutil/frame.h | 34 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+)