diff options
author | James Almer <jamrial@gmail.com> | 2024-03-28 13:01:47 -0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2024-04-11 09:18:19 -0300 |
commit | 55621f6fae766dd337b792a99ec0cae3a1e69cb9 (patch) | |
tree | cd4713c6255ad97b60f5a521904cd7621eb3d273 | |
parent | a16338089cfbf89d94465e9d678bfe1b875a8f5a (diff) | |
download | ffmpeg-55621f6fae766dd337b792a99ec0cae3a1e69cb9.tar.gz |
avutil/frame: add a flag to allow overwritting existing entries
Enable it only for side data types that don't allow more than one entry.
Signed-off-by: James Almer <jamrial@gmail.com>
-rw-r--r-- | libavutil/frame.c | 59 | ||||
-rw-r--r-- | libavutil/frame.h | 30 | ||||
-rw-r--r-- | libavutil/tests/side_data_array.c | 52 | ||||
-rw-r--r-- | tests/ref/fate/side_data_array | 22 |
4 files changed, 119 insertions, 44 deletions
diff --git a/libavutil/frame.c b/libavutil/frame.c index f77e1986bf..d37f1511e8 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -804,15 +804,36 @@ 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); + 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) @@ -831,6 +852,13 @@ AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, 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); + if (sd_dst) + *pbuf = NULL; + return sd_dst; + } sd_dst = add_side_data_from_buf(sd, nb_sd, type, buf); if (!sd_dst) @@ -843,6 +871,7 @@ AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, 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; @@ -850,13 +879,37 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, 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); - if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) - remove_side_data(sd, nb_sd, src->type); - sd_dst = add_side_data_from_buf_ext(sd, nb_sd, src->type, buf, src->data, src->size); if (!sd_dst) { diff --git a/libavutil/frame.h b/libavutil/frame.h index 8d16924432..4885600dce 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -1040,7 +1040,15 @@ const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType typ */ void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd); +/** + * Remove existing entries before adding new ones. + */ #define AV_FRAME_SIDE_DATA_FLAG_UNIQUE (1 << 0) +/** + * Don't add a new entry if another of the same type exists. + * Applies only for side data types without the AV_SIDE_DATA_PROP_MULTI prop. + */ +#define AV_FRAME_SIDE_DATA_FLAG_REPLACE (1 << 1) /** * Add new side data entry to an array. @@ -1053,10 +1061,12 @@ void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd); * @param size size of the side data * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. * - * @return newly added side data on success, NULL on error. In case of - * AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of matching - * AVFrameSideDataType will be removed before the addition is - * attempted. + * @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. */ AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, enum AVFrameSideDataType type, @@ -1080,6 +1090,8 @@ AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, * @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. * */ AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, @@ -1098,10 +1110,12 @@ AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, * for the buffer. * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. * - * @return negative error code on failure, >=0 on success. In case of - * AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of matching - * AVFrameSideDataType will be removed before the addition is - * attempted. + * @return negative error code on failure, >=0 on success. + * @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. */ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, const AVFrameSideData *src, unsigned int flags); diff --git a/libavutil/tests/side_data_array.c b/libavutil/tests/side_data_array.c index 793a62c009..633e9ee681 100644 --- a/libavutil/tests/side_data_array.c +++ b/libavutil/tests/side_data_array.c @@ -20,23 +20,22 @@ #include <stdio.h> #include "libavutil/frame.c" -#include "libavutil/mastering_display_metadata.h" +#include "libavutil/internal.h" -static void print_clls(const AVFrameSideData **sd, const int nb_sd) +static void print_entries(const AVFrameSideData **sd, const int nb_sd) { for (int i = 0; i < nb_sd; i++) { const AVFrameSideData *entry = sd[i]; - printf("sd %d, %s", - i, av_frame_side_data_name(entry->type)); + printf("sd %d (size %"SIZE_SPECIFIER"), %s", + i, entry->size, av_frame_side_data_name(entry->type)); - if (entry->type != AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) { + if (entry->type != AV_FRAME_DATA_SEI_UNREGISTERED) { putchar('\n'); continue; } - printf(": MaxCLL: %u\n", - ((AVContentLightMetadata *)entry->data)->MaxCLL); + printf(": %d\n", *(int32_t *)entry->data); } } @@ -51,51 +50,60 @@ int main(void) av_assert0( av_frame_side_data_new(&set.sd, &set.nb_sd, - AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT, - 0, 0)); + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(int64_t), 0)); + av_assert0( + av_frame_side_data_new(&set.sd, &set.nb_sd, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(int32_t), AV_FRAME_SIDE_DATA_FLAG_REPLACE)); // test entries in the middle for (int value = 1; value < 4; value++) { AVFrameSideData *sd = av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, - sizeof(AVContentLightMetadata), 0); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + sizeof(int32_t), 0); av_assert0(sd); - ((AVContentLightMetadata *)sd->data)->MaxCLL = value; + *(int32_t *)sd->data = value; } av_assert0( av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_SPHERICAL, 0, 0)); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SPHERICAL, + sizeof(int64_t), 0)); + + av_assert0( + av_frame_side_data_new( + &set.sd, &set.nb_sd, AV_FRAME_DATA_SPHERICAL, + sizeof(int32_t), AV_FRAME_SIDE_DATA_FLAG_REPLACE)); // test entries at the end for (int value = 1; value < 4; value++) { AVFrameSideData *sd = av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, - sizeof(AVContentLightMetadata), 0); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + sizeof(int32_t), 0); av_assert0(sd); - ((AVContentLightMetadata *)sd->data)->MaxCLL = value + 3; + *(int32_t *)sd->data = value + 3; } puts("Initial addition results with duplicates:"); - print_clls((const AVFrameSideData **)set.sd, set.nb_sd); + print_entries((const AVFrameSideData **)set.sd, set.nb_sd); { AVFrameSideData *sd = av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, - sizeof(AVContentLightMetadata), - AV_FRAME_SIDE_DATA_FLAG_UNIQUE); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + sizeof(int32_t), AV_FRAME_SIDE_DATA_FLAG_UNIQUE); av_assert0(sd); - ((AVContentLightMetadata *)sd->data)->MaxCLL = 1337; + *(int32_t *)sd->data = 1337; } puts("\nFinal state after a single 'no-duplicates' addition:"); - print_clls((const AVFrameSideData **)set.sd, set.nb_sd); + print_entries((const AVFrameSideData **)set.sd, set.nb_sd); av_frame_side_data_free(&set.sd, &set.nb_sd); diff --git a/tests/ref/fate/side_data_array b/tests/ref/fate/side_data_array index 7d8c684d8f..c1d77b0445 100644 --- a/tests/ref/fate/side_data_array +++ b/tests/ref/fate/side_data_array @@ -1,14 +1,14 @@ Initial addition results with duplicates: -sd 0, Ambient viewing environment -sd 1, Content light level metadata: MaxCLL: 1 -sd 2, Content light level metadata: MaxCLL: 2 -sd 3, Content light level metadata: MaxCLL: 3 -sd 4, Spherical Mapping -sd 5, Content light level metadata: MaxCLL: 4 -sd 6, Content light level metadata: MaxCLL: 5 -sd 7, Content light level metadata: MaxCLL: 6 +sd 0 (size 4), Content light level metadata +sd 1 (size 4), H.26[45] User Data Unregistered SEI message: 1 +sd 2 (size 4), H.26[45] User Data Unregistered SEI message: 2 +sd 3 (size 4), H.26[45] User Data Unregistered SEI message: 3 +sd 4 (size 4), Spherical Mapping +sd 5 (size 4), H.26[45] User Data Unregistered SEI message: 4 +sd 6 (size 4), H.26[45] User Data Unregistered SEI message: 5 +sd 7 (size 4), H.26[45] User Data Unregistered SEI message: 6 Final state after a single 'no-duplicates' addition: -sd 0, Ambient viewing environment -sd 1, Spherical Mapping -sd 2, Content light level metadata: MaxCLL: 1337 +sd 0 (size 4), Content light level metadata +sd 1 (size 4), Spherical Mapping +sd 2 (size 4), H.26[45] User Data Unregistered SEI message: 1337 |