* [FFmpeg-devel] [PATCH 02/29] lavu/opt: factor per-type dispatch out of av_opt_set()
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 03/29] libavutil/opt: rework figuring out option sizes Anton Khirnov
` (27 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
Will be useful in following commits.
---
libavutil/opt.c | 35 ++++++++++++++++++++++-------------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/libavutil/opt.c b/libavutil/opt.c
index dac00478ee..b372c76120 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -494,13 +494,11 @@ static int set_string_channel_layout(void *obj, const AVOption *o,
return av_channel_layout_from_string(channel_layout, val);
}
-int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
+static int opt_set_elem(void *obj, void *target_obj, const AVOption *o,
+ const char *val, void *dst)
{
- int ret = 0;
- void *dst, *target_obj;
- const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
- if (!o || !target_obj)
- return AVERROR_OPTION_NOT_FOUND;
+ int ret;
+
FF_DISABLE_DEPRECATION_WARNINGS
if (!val && (o->type != AV_OPT_TYPE_STRING &&
o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT &&
@@ -513,13 +511,6 @@ FF_DISABLE_DEPRECATION_WARNINGS
return AVERROR(EINVAL);
FF_ENABLE_DEPRECATION_WARNINGS
- if (o->flags & AV_OPT_FLAG_READONLY)
- return AVERROR(EINVAL);
-
- if (o->flags & AV_OPT_FLAG_DEPRECATED)
- av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help);
-
- dst = ((uint8_t *)target_obj) + o->offset;
switch (o->type) {
case AV_OPT_TYPE_BOOL:
return set_string_bool(obj, o, val, dst);
@@ -599,6 +590,24 @@ FF_ENABLE_DEPRECATION_WARNINGS
return AVERROR(EINVAL);
}
+int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
+{
+ void *dst, *target_obj;
+ const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
+ if (!o || !target_obj)
+ return AVERROR_OPTION_NOT_FOUND;
+
+ if (o->flags & AV_OPT_FLAG_READONLY)
+ return AVERROR(EINVAL);
+
+ if (o->flags & AV_OPT_FLAG_DEPRECATED)
+ av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help);
+
+ dst = ((uint8_t *)target_obj) + o->offset;
+
+ return opt_set_elem(obj, target_obj, o, val, dst);
+}
+
#define OPT_EVAL_NUMBER(name, opttype, vartype) \
int av_opt_eval_ ## name(void *obj, const AVOption *o, \
const char *val, vartype *name ## _out) \
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 03/29] libavutil/opt: rework figuring out option sizes
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 02/29] lavu/opt: factor per-type dispatch out of av_opt_set() Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 04/29] lavu/opt: factor per-type dispatch out of av_opt_copy() Anton Khirnov
` (26 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
Replace the opt_size() function, currently only called from
av_opt_copy(), with
* a constant array of element sizes
* a function that signals whether an option type is POD (i.e.
memcpyable) or not
Will be useful in following commits.
---
libavutil/opt.c | 100 +++++++++++++++++++++++++++---------------------
1 file changed, 56 insertions(+), 44 deletions(-)
diff --git a/libavutil/opt.c b/libavutil/opt.c
index b372c76120..051a121331 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -56,6 +56,56 @@ const AVOption *av_opt_next(const void *obj, const AVOption *last)
return NULL;
}
+static const size_t opt_elem_size[] = {
+ [AV_OPT_TYPE_FLAGS] = sizeof(unsigned),
+ [AV_OPT_TYPE_INT] = sizeof(int),
+ [AV_OPT_TYPE_INT64] = sizeof(int64_t),
+ [AV_OPT_TYPE_UINT64] = sizeof(uint64_t),
+ [AV_OPT_TYPE_DOUBLE] = sizeof(double),
+ [AV_OPT_TYPE_FLOAT] = sizeof(float),
+ [AV_OPT_TYPE_STRING] = sizeof(char *),
+ [AV_OPT_TYPE_RATIONAL] = sizeof(AVRational),
+ [AV_OPT_TYPE_BINARY] = sizeof(uint8_t *),
+ [AV_OPT_TYPE_DICT] = sizeof(AVDictionary *),
+ [AV_OPT_TYPE_IMAGE_SIZE] = sizeof(int[2]),
+ [AV_OPT_TYPE_VIDEO_RATE] = sizeof(AVRational),
+ [AV_OPT_TYPE_PIXEL_FMT] = sizeof(int),
+ [AV_OPT_TYPE_SAMPLE_FMT] = sizeof(int),
+ [AV_OPT_TYPE_DURATION] = sizeof(int64_t),
+ [AV_OPT_TYPE_COLOR] = sizeof(uint8_t[4]),
+#if FF_API_OLD_CHANNEL_LAYOUT
+ [AV_OPT_TYPE_CHANNEL_LAYOUT]= sizeof(uint64_t),
+#endif
+ [AV_OPT_TYPE_CHLAYOUT] = sizeof(AVChannelLayout),
+ [AV_OPT_TYPE_BOOL] = sizeof(int),
+};
+
+// option is plain old data
+static int opt_is_pod(enum AVOptionType type)
+{
+ switch (type) {
+ case AV_OPT_TYPE_FLAGS:
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_INT64:
+ case AV_OPT_TYPE_DOUBLE:
+ case AV_OPT_TYPE_FLOAT:
+ case AV_OPT_TYPE_RATIONAL:
+ case AV_OPT_TYPE_UINT64:
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ case AV_OPT_TYPE_PIXEL_FMT:
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ case AV_OPT_TYPE_VIDEO_RATE:
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_COLOR:
+#if FF_API_OLD_CHANNEL_LAYOUT
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+#endif
+ case AV_OPT_TYPE_BOOL:
+ return 1;
+ }
+ return 0;
+}
+
static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum)
{
switch (o->type) {
@@ -1850,45 +1900,6 @@ void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
return (uint8_t*)obj + opt->offset;
}
-static int opt_size(enum AVOptionType type)
-{
- switch(type) {
- case AV_OPT_TYPE_BOOL:
- case AV_OPT_TYPE_INT:
- case AV_OPT_TYPE_FLAGS:
- return sizeof(int);
- case AV_OPT_TYPE_DURATION:
-#if FF_API_OLD_CHANNEL_LAYOUT
-FF_DISABLE_DEPRECATION_WARNINGS
- case AV_OPT_TYPE_CHANNEL_LAYOUT:
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
- case AV_OPT_TYPE_INT64:
- case AV_OPT_TYPE_UINT64:
- return sizeof(int64_t);
- case AV_OPT_TYPE_DOUBLE:
- return sizeof(double);
- case AV_OPT_TYPE_FLOAT:
- return sizeof(float);
- case AV_OPT_TYPE_STRING:
- return sizeof(uint8_t*);
- case AV_OPT_TYPE_VIDEO_RATE:
- case AV_OPT_TYPE_RATIONAL:
- return sizeof(AVRational);
- case AV_OPT_TYPE_BINARY:
- return sizeof(uint8_t*) + sizeof(int);
- case AV_OPT_TYPE_IMAGE_SIZE:
- return sizeof(int[2]);
- case AV_OPT_TYPE_PIXEL_FMT:
- return sizeof(enum AVPixelFormat);
- case AV_OPT_TYPE_SAMPLE_FMT:
- return sizeof(enum AVSampleFormat);
- case AV_OPT_TYPE_COLOR:
- return 4;
- }
- return AVERROR(EINVAL);
-}
-
int av_opt_copy(void *dst, const void *src)
{
const AVOption *o = NULL;
@@ -1939,12 +1950,13 @@ int av_opt_copy(void *dst, const void *src)
} else if (o->type == AV_OPT_TYPE_CHLAYOUT) {
if (field_dst != field_src)
ret = av_channel_layout_copy(field_dst, field_src);
+ } else if (opt_is_pod(o->type)) {
+ size_t size = opt_elem_size[o->type];
+ memcpy(field_dst, field_src, size);
} else {
- int size = opt_size(o->type);
- if (size < 0)
- ret = size;
- else
- memcpy(field_dst, field_src, size);
+ av_log(dst, AV_LOG_ERROR, "Unhandled option type: %d\n",
+ o->type);
+ ret = AVERROR(EINVAL);
}
}
return ret;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 04/29] lavu/opt: factor per-type dispatch out of av_opt_copy()
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 02/29] lavu/opt: factor per-type dispatch out of av_opt_set() Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 03/29] libavutil/opt: rework figuring out option sizes Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields Anton Khirnov
` (25 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
Will be useful in following commits.
---
libavutil/opt.c | 89 ++++++++++++++++++++++++++-----------------------
1 file changed, 48 insertions(+), 41 deletions(-)
diff --git a/libavutil/opt.c b/libavutil/opt.c
index 051a121331..d18a1c63b7 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -1900,6 +1900,51 @@ void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
return (uint8_t*)obj + opt->offset;
}
+static int opt_copy_elem(void *logctx, enum AVOptionType type,
+ void *dst, const void *src)
+{
+ uint8_t **dst8 = (uint8_t **)dst;
+ const uint8_t **src8 = (const uint8_t **)src;
+
+ if (type == AV_OPT_TYPE_STRING) {
+ if (*dst8 != *src8)
+ av_freep(dst8);
+ *dst8 = av_strdup(*src8);
+ if (*src8 && !*dst8)
+ return AVERROR(ENOMEM);
+ } else if (type == AV_OPT_TYPE_BINARY) {
+ int len = *(const int *)(src8 + 1);
+ if (*dst8 != *src8)
+ av_freep(dst8);
+ *dst8 = av_memdup(*src8, len);
+ if (len && !*dst8) {
+ *(int *)(dst8 + 1) = 0;
+ return AVERROR(ENOMEM);
+ }
+ *(int *)(dst8 + 1) = len;
+ } else if (type == AV_OPT_TYPE_CONST) {
+ // do nothing
+ } else if (type == AV_OPT_TYPE_DICT) {
+ AVDictionary **sdict = (AVDictionary **)src;
+ AVDictionary **ddict = (AVDictionary **)dst;
+ if (*sdict != *ddict)
+ av_dict_free(ddict);
+ *ddict = NULL;
+ return av_dict_copy(ddict, *sdict, 0);
+ } else if (type == AV_OPT_TYPE_CHLAYOUT) {
+ if (dst != src)
+ return av_channel_layout_copy(dst, src);
+ } else if (opt_is_pod(type)) {
+ size_t size = opt_elem_size[type];
+ memcpy(dst, src, size);
+ } else {
+ av_log(logctx, AV_LOG_ERROR, "Unhandled option type: %d\n", type);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
int av_opt_copy(void *dst, const void *src)
{
const AVOption *o = NULL;
@@ -1916,48 +1961,10 @@ int av_opt_copy(void *dst, const void *src)
while ((o = av_opt_next(src, o))) {
void *field_dst = (uint8_t *)dst + o->offset;
void *field_src = (uint8_t *)src + o->offset;
- uint8_t **field_dst8 = (uint8_t **)field_dst;
- uint8_t **field_src8 = (uint8_t **)field_src;
- if (o->type == AV_OPT_TYPE_STRING) {
- if (*field_dst8 != *field_src8)
- av_freep(field_dst8);
- *field_dst8 = av_strdup(*field_src8);
- if (*field_src8 && !*field_dst8)
- ret = AVERROR(ENOMEM);
- } else if (o->type == AV_OPT_TYPE_BINARY) {
- int len = *(int *)(field_src8 + 1);
- if (*field_dst8 != *field_src8)
- av_freep(field_dst8);
- *field_dst8 = av_memdup(*field_src8, len);
- if (len && !*field_dst8) {
- ret = AVERROR(ENOMEM);
- len = 0;
- }
- *(int *)(field_dst8 + 1) = len;
- } else if (o->type == AV_OPT_TYPE_CONST) {
- // do nothing
- } else if (o->type == AV_OPT_TYPE_DICT) {
- AVDictionary **sdict = (AVDictionary **) field_src;
- AVDictionary **ddict = (AVDictionary **) field_dst;
- int ret2;
- if (*sdict != *ddict)
- av_dict_free(ddict);
- *ddict = NULL;
- ret2 = av_dict_copy(ddict, *sdict, 0);
- if (ret2 < 0)
- ret = ret2;
- } else if (o->type == AV_OPT_TYPE_CHLAYOUT) {
- if (field_dst != field_src)
- ret = av_channel_layout_copy(field_dst, field_src);
- } else if (opt_is_pod(o->type)) {
- size_t size = opt_elem_size[o->type];
- memcpy(field_dst, field_src, size);
- } else {
- av_log(dst, AV_LOG_ERROR, "Unhandled option type: %d\n",
- o->type);
- ret = AVERROR(EINVAL);
- }
+ int err = opt_copy_elem(dst, o->type, field_dst, field_src);
+ if (err < 0)
+ ret = err;
}
return ret;
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (2 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 04/29] lavu/opt: factor per-type dispatch out of av_opt_copy() Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 22:39 ` Marton Balint
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options Anton Khirnov
` (24 subsequent siblings)
28 siblings, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
Native access is from the code that declared the options, foreign access
is from code that is using the options. Forbid foreign access to
AVOption.offset/default_val, for which there is no good reason, and
which should allow us more freedom in extending their semantics in a
compatible way.
---
libavutil/opt.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/libavutil/opt.h b/libavutil/opt.h
index e34b8506f8..e402f6a0a0 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -43,6 +43,16 @@
* ("objects"). An option can have a help text, a type and a range of possible
* values. Options may then be enumerated, read and written to.
*
+ * There are two modes of access to members of AVOption and its child structs.
+ * One is called 'native access', and refers to access from the code that
+ * declares the AVOption in question. The other is 'foreign access', and refers
+ * to access from other code.
+ *
+ * Certain struct members in this header are documented as 'native access only'
+ * or similar - it means that only the code that declared the AVOption in
+ * question is allowed to access the field. This allows us to extend the
+ * semantics of those fields without breaking API compatibility.
+ *
* @section avoptions_implement Implementing AVOptions
* This section describes how to add AVOptions capabilities to a struct.
*
@@ -301,6 +311,8 @@ typedef struct AVOption {
const char *help;
/**
+ * Native access only.
+ *
* The offset relative to the context structure where the option
* value is stored. It should be 0 for named constants.
*/
@@ -308,6 +320,8 @@ typedef struct AVOption {
enum AVOptionType type;
/**
+ * Native access only.
+ *
* the default value for scalar options
*/
union {
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields Anton Khirnov
@ 2024-03-04 22:39 ` Marton Balint
2024-03-05 9:48 ` Anton Khirnov
2024-03-05 10:17 ` Diederick C. Niehorster
0 siblings, 2 replies; 57+ messages in thread
From: Marton Balint @ 2024-03-04 22:39 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Mon, 4 Mar 2024, Anton Khirnov wrote:
> Native access is from the code that declared the options, foreign access
> is from code that is using the options. Forbid foreign access to
> AVOption.offset/default_val, for which there is no good reason, and
> which should allow us more freedom in extending their semantics in a
> compatible way.
> ---
> libavutil/opt.h | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/libavutil/opt.h b/libavutil/opt.h
> index e34b8506f8..e402f6a0a0 100644
> --- a/libavutil/opt.h
> +++ b/libavutil/opt.h
> @@ -43,6 +43,16 @@
> * ("objects"). An option can have a help text, a type and a range of possible
> * values. Options may then be enumerated, read and written to.
> *
> + * There are two modes of access to members of AVOption and its child structs.
> + * One is called 'native access', and refers to access from the code that
> + * declares the AVOption in question. The other is 'foreign access', and refers
> + * to access from other code.
> + *
> + * Certain struct members in this header are documented as 'native access only'
> + * or similar - it means that only the code that declared the AVOption in
> + * question is allowed to access the field. This allows us to extend the
> + * semantics of those fields without breaking API compatibility.
> + *
Changing private/public status of existing fields retrospecitvely can be
considered an API break.
> * @section avoptions_implement Implementing AVOptions
> * This section describes how to add AVOptions capabilities to a struct.
> *
> @@ -301,6 +311,8 @@ typedef struct AVOption {
> const char *help;
>
> /**
> + * Native access only.
> + *
> * The offset relative to the context structure where the option
> * value is stored. It should be 0 for named constants.
I don't quite see the reason hiding this. I think it is pretty safe to
say that its semantics won't change, and getting the offset, adding it to
the object pointer and directly reading or writing the value is the most
efficient way to get or set the values. Also there is av_opt_ptr() which
implicitly returns this anyway. Or you want to fully disallow pointer
based member access? Some issues would be:
1) for a dictionary type you don't have a getter which does not copy
2) some types simply don't have a native typed getter/setter function
3) if you have multiple object of the same class, when using getters
there will always be a linear search for the attribute name each time you
get/set.
> */
> @@ -308,6 +320,8 @@ typedef struct AVOption {
> enum AVOptionType type;
>
> /**
> + * Native access only.
> + *
> * the default value for scalar options
> */
One could argue that it will be more difficult to get the default value of
an option (you'd have to create an object, call av_opt_set_defaults() and
finally do av_opt_get), but what I find more problematic is the
inconsistency. You are not allowed to access default_val, unless it is an
array type, in which case you might access it to get array settings, but -
oh well - not the default value.
In general, we should avoid having public API fields which are in fact
private. We have existing techniques to really hide those. Considering we
can always add new option types to define new semantics, I don't really
think that keeping the existing public API fields public is such a blow.
Regards,
Marton
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields
2024-03-04 22:39 ` Marton Balint
@ 2024-03-05 9:48 ` Anton Khirnov
2024-03-05 10:17 ` Diederick C. Niehorster
1 sibling, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 9:48 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Marton Balint (2024-03-04 23:39:19)
> On Mon, 4 Mar 2024, Anton Khirnov wrote:
> > Native access is from the code that declared the options, foreign access
> > is from code that is using the options. Forbid foreign access to
> > AVOption.offset/default_val, for which there is no good reason, and
> > which should allow us more freedom in extending their semantics in a
> > compatible way.
> > ---
> > libavutil/opt.h | 14 ++++++++++++++
> > 1 file changed, 14 insertions(+)
> >
> > diff --git a/libavutil/opt.h b/libavutil/opt.h
> > index e34b8506f8..e402f6a0a0 100644
> > --- a/libavutil/opt.h
> > +++ b/libavutil/opt.h
> > @@ -43,6 +43,16 @@
> > * ("objects"). An option can have a help text, a type and a range of possible
> > * values. Options may then be enumerated, read and written to.
> > *
> > + * There are two modes of access to members of AVOption and its child structs.
> > + * One is called 'native access', and refers to access from the code that
> > + * declares the AVOption in question. The other is 'foreign access', and refers
> > + * to access from other code.
> > + *
> > + * Certain struct members in this header are documented as 'native access only'
> > + * or similar - it means that only the code that declared the AVOption in
> > + * question is allowed to access the field. This allows us to extend the
> > + * semantics of those fields without breaking API compatibility.
> > + *
>
> Changing private/public status of existing fields retrospecitvely can be
> considered an API break.
I see this more as establishing/clarifying the status of those fields
rather than changing it.
While the idea that everything not explicitly forbidden is allowed is
nice in theory, I don't think it's viable for us, because so many
(especially older) APIs are barely documented, if at all. If we adhered
to it strictly, almost any extension of existing APIs could be
considered a break. E.g. consider that it is not publicly documented
what C type does any AVOption type map to, or even that we can add new
ones.
> > * @section avoptions_implement Implementing AVOptions
> > * This section describes how to add AVOptions capabilities to a struct.
> > *
> > @@ -301,6 +311,8 @@ typedef struct AVOption {
> > const char *help;
> >
> > /**
> > + * Native access only.
> > + *
> > * The offset relative to the context structure where the option
> > * value is stored. It should be 0 for named constants.
>
> I don't quite see the reason hiding this. I think it is pretty safe to
> say that its semantics won't change, and getting the offset, adding it to
> the object pointer and directly reading or writing the value is the most
> efficient way to get or set the values.
This is precisely what the callers have no business doing IMO, and what
the AVOption API is supposed to abstract away.
AVOptions are not supposed to be especially efficient currently, but if
some use case requires that we should add new API to make access more
efficient - e.g. that accepts AVOptions rather than string option names,
and flags that make setters take ownership rather than copy.
> Also there is av_opt_ptr() which implicitly returns this anyway. Or
> you want to fully disallow pointer based member access?
Yes I do, at least in this generic type-unsafe form. av_opt_ptr() has a
single caller in our codebase that I'd like to get rid of, and then
deprecate+remove the function itself.
Also note that the fact av_opt_ptr() exists at all supports my
interpretation that option users are not supposed to access offset.
> Some issues would be:
> 1) for a dictionary type you don't have a getter which does not copy
> 2) some types simply don't have a native typed getter/setter function
> 3) if you have multiple object of the same class, when using getters
> there will always be a linear search for the attribute name each time you
> get/set.
All of these can and should be solved with better getter/setter API.
>
> > */
> > @@ -308,6 +320,8 @@ typedef struct AVOption {
> > enum AVOptionType type;
> >
> > /**
> > + * Native access only.
> > + *
> > * the default value for scalar options
> > */
>
> One could argue that it will be more difficult to get the default value of
> an option (you'd have to create an object, call av_opt_set_defaults() and
> finally do av_opt_get), but what I find more problematic is the
> inconsistency. You are not allowed to access default_val, unless it is an
> array type, in which case you might access it to get array settings, but -
> oh well - not the default value.
I consistently forbid users to read the default value directly, they
have to read it from the object.
The only inconsistency is that default_val stores far more than just the
default value for array options, but that follows from the constraints
we are operating under. Recall the previous version of this patch where
I put those values elsewhere and you objected to it.
> In general, we should avoid having public API fields which are in fact
> private. We have existing techniques to really hide those.
For instance? The problem is those fields are not purely private, they
are public in some contexts (what I call 'native access'), and private
in others. That means they have to appear in the public header.
> Considering we can always add new option types to define new
> semantics, I don't really think that keeping the existing public API
> fields public is such a blow.
I would much prefer not to be forced to add gazillions of option types
for every minor semantics difference we might want to introduce.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields
2024-03-04 22:39 ` Marton Balint
2024-03-05 9:48 ` Anton Khirnov
@ 2024-03-05 10:17 ` Diederick C. Niehorster
1 sibling, 0 replies; 57+ messages in thread
From: Diederick C. Niehorster @ 2024-03-05 10:17 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Mon, Mar 4, 2024 at 11:39 PM Marton Balint <cus@passwd.hu> wrote:
> On Mon, 4 Mar 2024, Anton Khirnov wrote:
>
> > Native access is from the code that declared the options, foreign access
> > is from code that is using the options. Forbid foreign access to
> > AVOption.offset/default_val, for which there is no good reason, and
> > which should allow us more freedom in extending their semantics in a
> > compatible way.
> > ---
> > libavutil/opt.h | 14 ++++++++++++++
> > 1 file changed, 14 insertions(+)
> >
> > diff --git a/libavutil/opt.h b/libavutil/opt.h
> > index e34b8506f8..e402f6a0a0 100644
> > --- a/libavutil/opt.h
> > +++ b/libavutil/opt.h
> > @@ -43,6 +43,16 @@
> > * ("objects"). An option can have a help text, a type and a range of
> possible
> > * values. Options may then be enumerated, read and written to.
> > *
> > + * There are two modes of access to members of AVOption and its child
> structs.
> > + * One is called 'native access', and refers to access from the code
> that
> > + * declares the AVOption in question. The other is 'foreign access',
> and refers
> > + * to access from other code.
> > + *
> > + * Certain struct members in this header are documented as 'native
> access only'
> > + * or similar - it means that only the code that declared the AVOption
> in
> > + * question is allowed to access the field. This allows us to extend the
> > + * semantics of those fields without breaking API compatibility.
> > + *
>
> Changing private/public status of existing fields retrospecitvely can be
> considered an API break.
>
> > */
> > @@ -308,6 +320,8 @@ typedef struct AVOption {
> > enum AVOptionType type;
> >
> > /**
> > + * Native access only.
> > + *
> > * the default value for scalar options
> > */
>
> One could argue that it will be more difficult to get the default value of
> an option (you'd have to create an object, call av_opt_set_defaults() and
> finally do av_opt_get), but what I find more problematic is the
> inconsistency. You are not allowed to access default_val, unless it is an
> array type, in which case you might access it to get array settings, but -
> oh well - not the default value.
>
There is no helper function for getting the default value of an option. If
you disallow reading this field directly (as in one of your other patches),
please add such a helper function(s), since library users need it. It
should also work without instantiating the object, but directly on the
class definition
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (3 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 05/29] lavu/opt: distinguish between native and foreign access for AVOption fields Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:29 ` Andreas Rheinhardt
2024-03-04 21:32 ` [FFmpeg-devel] [PATCH " Marton Balint
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference Anton Khirnov
` (23 subsequent siblings)
28 siblings, 2 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
---
doc/APIchanges | 3 +
libavutil/opt.c | 362 +++++++++++++++++++++++++++++++++++++-----
libavutil/opt.h | 62 +++++++-
libavutil/tests/opt.c | 51 ++++++
tests/ref/fate/opt | 35 +++-
5 files changed, 468 insertions(+), 45 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index 7d46ebb006..3209614ed6 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
API changes, most recent first:
+2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
+ Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
+
2024-02-28 - xxxxxxxxxx - swr 4.14.100 - swresample.h
swr_convert() now accepts arrays of const pointers (to input and output).
diff --git a/libavutil/opt.c b/libavutil/opt.c
index d18a1c63b7..6a5e3c7174 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -43,6 +43,8 @@
#include <float.h>
+#define TYPE_BASE(type) ((type) & ~AV_OPT_TYPE_FLAG_ARRAY)
+
const AVOption *av_opt_next(const void *obj, const AVOption *last)
{
const AVClass *class;
@@ -106,6 +108,54 @@ static int opt_is_pod(enum AVOptionType type)
return 0;
}
+static uint8_t opt_array_sep(const AVOption *o)
+{
+ const AVOptionArrayDef *d = o->default_val.arr;
+ av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY);
+ return (d && d->sep) ? d->sep : ',';
+}
+
+static void *opt_array_pelem(const AVOption *o, void *array, unsigned idx)
+{
+ av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY);
+ return (uint8_t *)array + idx * opt_elem_size[TYPE_BASE(o->type)];
+}
+
+static unsigned *opt_array_pcount(const void *parray)
+{
+ return (unsigned *)((const void * const *)parray + 1);
+}
+
+static void opt_free_elem(const AVOption *o, void *ptr)
+{
+ switch (TYPE_BASE(o->type)) {
+ case AV_OPT_TYPE_STRING:
+ case AV_OPT_TYPE_BINARY:
+ av_freep(ptr);
+ break;
+
+ case AV_OPT_TYPE_DICT:
+ av_dict_free((AVDictionary **)ptr);
+ break;
+
+ case AV_OPT_TYPE_CHLAYOUT:
+ av_channel_layout_uninit((AVChannelLayout *)ptr);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void opt_free_array(const AVOption *o, void *parray, unsigned *count)
+{
+ for (unsigned i = 0; i < *count; i++)
+ opt_free_elem(o, opt_array_pelem(o, *(void **)parray, i));
+
+ av_freep(parray);
+ *count = 0;
+}
+
static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum)
{
switch (o->type) {
@@ -151,14 +201,16 @@ FF_ENABLE_DEPRECATION_WARNINGS
static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
{
- if (o->type != AV_OPT_TYPE_FLAGS &&
+ const enum AVOptionType type = TYPE_BASE(o->type);
+
+ if (type != AV_OPT_TYPE_FLAGS &&
(!den || o->max * den < num * intnum || o->min * den > num * intnum)) {
num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN);
av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",
num, o->name, o->min, o->max);
return AVERROR(ERANGE);
}
- if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (type == AV_OPT_TYPE_FLAGS) {
double d = num*intnum/den;
if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) {
av_log(obj, AV_LOG_ERROR,
@@ -168,7 +220,7 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int
}
}
- switch (o->type) {
+ switch (type) {
case AV_OPT_TYPE_PIXEL_FMT:
*(enum AVPixelFormat *)dst = llrint(num / den) * intnum;
break;
@@ -287,9 +339,10 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d
static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst)
{
+ const enum AVOptionType type = TYPE_BASE(o->type);
int ret = 0;
- if (o->type == AV_OPT_TYPE_RATIONAL || o->type == AV_OPT_TYPE_VIDEO_RATE) {
+ if (type == AV_OPT_TYPE_RATIONAL || type == AV_OPT_TYPE_VIDEO_RATE) {
int num, den;
char c;
if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) {
@@ -306,7 +359,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con
double d;
int64_t intnum = 1;
- if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (type == AV_OPT_TYPE_FLAGS) {
if (*val == '+' || *val == '-')
cmd = *(val++);
for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
@@ -362,7 +415,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con
}
}
}
- if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (type == AV_OPT_TYPE_FLAGS) {
intnum = *(unsigned int*)dst;
if (cmd == '+')
d = intnum | (int64_t)d;
@@ -547,21 +600,22 @@ static int set_string_channel_layout(void *obj, const AVOption *o,
static int opt_set_elem(void *obj, void *target_obj, const AVOption *o,
const char *val, void *dst)
{
+ const enum AVOptionType type = TYPE_BASE(o->type);
int ret;
FF_DISABLE_DEPRECATION_WARNINGS
- if (!val && (o->type != AV_OPT_TYPE_STRING &&
- o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT &&
- o->type != AV_OPT_TYPE_IMAGE_SIZE &&
- o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR &&
+ if (!val && (type != AV_OPT_TYPE_STRING &&
+ type != AV_OPT_TYPE_PIXEL_FMT && type != AV_OPT_TYPE_SAMPLE_FMT &&
+ type != AV_OPT_TYPE_IMAGE_SIZE &&
+ type != AV_OPT_TYPE_DURATION && type != AV_OPT_TYPE_COLOR &&
#if FF_API_OLD_CHANNEL_LAYOUT
- o->type != AV_OPT_TYPE_CHANNEL_LAYOUT &&
+ type != AV_OPT_TYPE_CHANNEL_LAYOUT &&
#endif
- o->type != AV_OPT_TYPE_BOOL))
+ type != AV_OPT_TYPE_BOOL))
return AVERROR(EINVAL);
FF_ENABLE_DEPRECATION_WARNINGS
- switch (o->type) {
+ switch (type) {
case AV_OPT_TYPE_BOOL:
return set_string_bool(obj, o, val, dst);
case AV_OPT_TYPE_STRING:
@@ -640,6 +694,85 @@ FF_ENABLE_DEPRECATION_WARNINGS
return AVERROR(EINVAL);
}
+static int opt_set_array(void *obj, void *target_obj, const AVOption *o,
+ const char *val, void *dst)
+{
+ const AVOptionArrayDef *arr = o->default_val.arr;
+ const size_t elem_size = opt_elem_size[TYPE_BASE(o->type)];
+ const uint8_t sep = opt_array_sep(o);
+ uint8_t *str = NULL;
+
+ void *elems = NULL;
+ unsigned nb_elems = 0;
+ int ret;
+
+ if (val && *val) {
+ str = av_malloc(strlen(val) + 1);
+ if (!str)
+ return AVERROR(ENOMEM);
+ }
+
+ // split and unescape the string
+ while (val && *val) {
+ uint8_t *p = str;
+ void *tmp;
+
+ if (arr && arr->size_max && nb_elems >= arr->size_max) {
+ av_log(obj, AV_LOG_ERROR,
+ "Cannot assign more than %u elements to array option %s\n",
+ arr->size_max, o->name);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ for (; *val; val++, p++) {
+ if (*val == '\\' && val[1])
+ val++;
+ else if (*val == sep) {
+ val++;
+ break;
+ }
+ *p = *val;
+ }
+ *p = 0;
+
+ tmp = av_realloc_array(elems, nb_elems + 1, elem_size);
+ if (!tmp) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ elems = tmp;
+
+ tmp = opt_array_pelem(o, elems, nb_elems);
+ memset(tmp, 0, elem_size);
+
+ ret = opt_set_elem(obj, target_obj, o, str, tmp);
+ if (ret < 0)
+ goto fail;
+ nb_elems++;
+ }
+ av_freep(&str);
+
+ opt_free_array(o, dst, opt_array_pcount(dst));
+
+ if (arr && nb_elems < arr->size_min) {
+ av_log(obj, AV_LOG_ERROR,
+ "Cannot assign fewer than %u elements to array option %s\n",
+ arr->size_min, o->name);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ *((void **)dst) = elems;
+ *opt_array_pcount(dst) = nb_elems;
+
+ return 0;
+fail:
+ av_freep(&str);
+ opt_free_array(o, &elems, &nb_elems);
+ return ret;
+}
+
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
void *dst, *target_obj;
@@ -655,7 +788,8 @@ int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
dst = ((uint8_t *)target_obj) + o->offset;
- return opt_set_elem(obj, target_obj, o, val, dst);
+ return ((o->type & AV_OPT_TYPE_FLAG_ARRAY) ?
+ opt_set_array : opt_set_elem)(obj, target_obj, o, val, dst);
}
#define OPT_EVAL_NUMBER(name, opttype, vartype) \
@@ -683,7 +817,7 @@ static int set_number(void *obj, const char *name, double num, int den, int64_t
if (!o || !target_obj)
return AVERROR_OPTION_NOT_FOUND;
- if (o->flags & AV_OPT_FLAG_READONLY)
+ if ((o->flags & AV_OPT_FLAG_READONLY) || (o->type & AV_OPT_TYPE_FLAG_ARRAY))
return AVERROR(EINVAL);
dst = ((uint8_t *)target_obj) + o->offset;
@@ -766,7 +900,8 @@ int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int searc
return AVERROR_OPTION_NOT_FOUND;
if (o->type != AV_OPT_TYPE_VIDEO_RATE) {
av_log(obj, AV_LOG_ERROR,
- "The value set by option '%s' is not a video rate.\n", o->name);
+ "The value set by option '%s' is not a video rate.\n",
+ o->name);
return AVERROR(EINVAL);
}
if (val.num <= 0 || val.den <= 0)
@@ -908,7 +1043,7 @@ static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len,
{
int ret;
- switch (o->type) {
+ switch (TYPE_BASE(o->type)) {
case AV_OPT_TYPE_BOOL:
ret = snprintf(*pbuf, buf_len, "%s", get_bool_name(*(int *)dst));
break;
@@ -1014,6 +1149,66 @@ FF_ENABLE_DEPRECATION_WARNINGS
return ret;
}
+static int opt_get_array(const AVOption *o, void *dst, uint8_t **out_val)
+{
+ const unsigned count = *opt_array_pcount(dst);
+ const uint8_t sep = opt_array_sep(o);
+
+ uint8_t *str = NULL;
+ size_t str_len = 0;
+ int ret;
+
+ *out_val = NULL;
+
+ for (unsigned i = 0; i < count; i++) {
+ uint8_t buf[128], *out = buf;
+ size_t out_len;
+
+ ret = opt_get_elem(o, &out, sizeof(buf),
+ opt_array_pelem(o, *(void **)dst, i), 0);
+ if (ret < 0)
+ goto fail;
+
+ out_len = strlen(out);
+ if (out_len > SIZE_MAX / 2 - !!i ||
+ !!i + out_len * 2 > SIZE_MAX - str_len - 1) {
+ ret = AVERROR(ERANGE);
+ goto fail;
+ }
+
+ // terminator escaping separator
+ // ↓ ↓ ↓
+ ret = av_reallocp(&str, str_len + 1 + out_len * 2 + !!i);
+ if (ret < 0)
+ goto fail;
+
+ // add separator if needed
+ if (i)
+ str[str_len++] = sep;
+
+ // escape the element
+ for (unsigned j = 0; j < out_len; j++) {
+ uint8_t val = out[j];
+ if (val == sep || val == '\\')
+ str[str_len++] = '\\';
+ str[str_len++] = val;
+ }
+ str[str_len] = 0;
+
+fail:
+ if (out != buf)
+ av_freep(&out);
+ if (ret < 0) {
+ av_freep(&str);
+ return ret;
+ }
+ }
+
+ *out_val = str;
+
+ return 0;
+}
+
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
{
void *dst, *target_obj;
@@ -1029,8 +1224,19 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
dst = (uint8_t *)target_obj + o->offset;
- buf[0] = 0;
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ ret = opt_get_array(o, dst, out_val);
+ if (ret < 0)
+ return ret;
+ if (!*out_val && !(search_flags & AV_OPT_ALLOW_NULL)) {
+ *out_val = av_strdup("");
+ if (!*out_val)
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+ }
+ buf[0] = 0;
out = buf;
ret = opt_get_elem(o, &out, sizeof(buf), dst, search_flags);
if (ret < 0)
@@ -1053,6 +1259,8 @@ static int get_number(void *obj, const char *name, double *num, int *den, int64_
const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
if (!o || !target_obj)
return AVERROR_OPTION_NOT_FOUND;
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY)
+ return AVERROR(EINVAL);
dst = ((uint8_t *)target_obj) + o->offset;
@@ -1110,7 +1318,7 @@ int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_
return AVERROR_OPTION_NOT_FOUND;
if (o->type != AV_OPT_TYPE_IMAGE_SIZE) {
av_log(obj, AV_LOG_ERROR,
- "The value for option '%s' is not an image size.\n", name);
+ "The value for option '%s' is not a image size.\n", name);
return AVERROR(EINVAL);
}
@@ -1174,7 +1382,7 @@ int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int
return AVERROR_OPTION_NOT_FOUND;
if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) {
av_log(obj, AV_LOG_ERROR,
- "The value for option '%s' is not a channel layout.\n", name);
+ "The value for option '%s' is not a scalar channel layout.\n", name);
return AVERROR(EINVAL);
}
@@ -1341,11 +1549,16 @@ static void log_type(void *av_log_obj, const AVOption *o,
[AV_OPT_TYPE_CHLAYOUT] = "<channel_layout>",
[AV_OPT_TYPE_BOOL] = "<boolean>",
};
+ const enum AVOptionType type = TYPE_BASE(o->type);
- if (o->type == AV_OPT_TYPE_CONST && parent_type == AV_OPT_TYPE_INT)
+ if (o->type == AV_OPT_TYPE_CONST && TYPE_BASE(parent_type) == AV_OPT_TYPE_INT)
av_log(av_log_obj, AV_LOG_INFO, "%-12"PRId64" ", o->default_val.i64);
- else if (o->type < FF_ARRAY_ELEMS(desc) && desc[o->type])
- av_log(av_log_obj, AV_LOG_INFO, "%-12s ", desc[o->type]);
+ else if (type < FF_ARRAY_ELEMS(desc) && desc[type]) {
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY)
+ av_log(av_log_obj, AV_LOG_INFO, "[%-10s]", desc[type]);
+ else
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", desc[type]);
+ }
else
av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "");
}
@@ -1363,6 +1576,13 @@ static void log_default(void *obj, void *av_log_obj, const AVOption *opt)
!opt->default_val.str)
return;
+ if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ const AVOptionArrayDef *arr = opt->default_val.arr;
+ if (arr && arr->def)
+ av_log(av_log_obj, AV_LOG_INFO, " (default %s)", arr->def);
+ return;
+ }
+
av_log(av_log_obj, AV_LOG_INFO, " (default ");
switch (opt->type) {
case AV_OPT_TYPE_BOOL:
@@ -1530,6 +1750,21 @@ void av_opt_set_defaults2(void *s, int mask, int flags)
if (opt->flags & AV_OPT_FLAG_READONLY)
continue;
+ if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ const AVOptionArrayDef *arr = opt->default_val.arr;
+ const char sep = opt_array_sep(opt);
+
+ av_assert0(sep && sep != '\\' &&
+ (sep < 'a' || sep > 'z') &&
+ (sep < 'A' || sep > 'Z') &&
+ (sep < '0' || sep > '9'));
+
+ if (arr && arr->def)
+ opt_set_array(s, s, opt, arr->def, dst);
+
+ continue;
+ }
+
switch (opt->type) {
case AV_OPT_TYPE_CONST:
/* Nothing to be done here */
@@ -1777,23 +2012,12 @@ void av_opt_free(void *obj)
{
const AVOption *o = NULL;
while ((o = av_opt_next(obj, o))) {
- switch (o->type) {
- case AV_OPT_TYPE_STRING:
- case AV_OPT_TYPE_BINARY:
- av_freep((uint8_t *)obj + o->offset);
- break;
+ void *pitem = (uint8_t *)obj + o->offset;
- case AV_OPT_TYPE_DICT:
- av_dict_free((AVDictionary **)(((uint8_t *)obj) + o->offset));
- break;
-
- case AV_OPT_TYPE_CHLAYOUT:
- av_channel_layout_uninit((AVChannelLayout *)(((uint8_t *)obj) + o->offset));
- break;
-
- default:
- break;
- }
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY)
+ opt_free_array(o, pitem, opt_array_pcount(pitem));
+ else
+ opt_free_elem(o, pitem);
}
}
@@ -1895,7 +2119,9 @@ const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter)
void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
{
const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL);
- if(!opt)
+
+ // no direct access to array-type options
+ if (!opt || (opt->type & AV_OPT_TYPE_FLAG_ARRAY))
return NULL;
return (uint8_t*)obj + opt->offset;
}
@@ -1945,6 +2171,40 @@ static int opt_copy_elem(void *logctx, enum AVOptionType type,
return 0;
}
+static int opt_copy_array(void *logctx, const AVOption *o,
+ void **pdst, const void * const *psrc)
+{
+ unsigned nb_elems = *opt_array_pcount(psrc);
+ void *dst = NULL;
+ int ret;
+
+ if (*pdst == *psrc) {
+ *pdst = NULL;
+ *opt_array_pcount(pdst) = 0;
+ }
+
+ opt_free_array(o, pdst, opt_array_pcount(pdst));
+
+ dst = av_calloc(nb_elems, opt_elem_size[TYPE_BASE(o->type)]);
+ if (!dst)
+ return AVERROR(ENOMEM);
+
+ for (unsigned i = 0; i < nb_elems; i++) {
+ ret = opt_copy_elem(logctx, TYPE_BASE(o->type),
+ opt_array_pelem(o, dst, i),
+ opt_array_pelem(o, *(void**)psrc, i));
+ if (ret < 0) {
+ opt_free_array(o, &dst, &nb_elems);
+ return ret;
+ }
+ }
+
+ *pdst = dst;
+ *opt_array_pcount(pdst) = nb_elems;
+
+ return 0;
+}
+
int av_opt_copy(void *dst, const void *src)
{
const AVOption *o = NULL;
@@ -1962,7 +2222,9 @@ int av_opt_copy(void *dst, const void *src)
void *field_dst = (uint8_t *)dst + o->offset;
void *field_src = (uint8_t *)src + o->offset;
- int err = opt_copy_elem(dst, o->type, field_dst, field_src);
+ int err = (o->type & AV_OPT_TYPE_FLAG_ARRAY) ?
+ opt_copy_array(dst, o, field_dst, field_src) :
+ opt_copy_elem (dst, o->type, field_dst, field_src);
if (err < 0)
ret = err;
}
@@ -2096,6 +2358,24 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o)
dst = ((uint8_t*)obj) + o->offset;
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ const char *def = o->default_val.arr ? o->default_val.arr->def : NULL;
+ uint8_t *val;
+
+ ret = opt_get_array(o, dst, &val);
+ if (ret < 0)
+ return ret;
+
+ if (!!val != !!def)
+ ret = 0;
+ else if (val)
+ ret = !strcmp(val, def);
+
+ av_freep(&val);
+
+ return ret;
+ }
+
switch (o->type) {
case AV_OPT_TYPE_CONST:
return 1;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index e402f6a0a0..77797b3fbe 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -253,6 +253,17 @@ enum AVOptionType{
#endif
AV_OPT_TYPE_BOOL,
AV_OPT_TYPE_CHLAYOUT,
+
+ /**
+ * May be combined with another regular option type to declare an array
+ * option.
+ *
+ * For array options, @ref AVOption.offset should refer to a pointer
+ * corresponding to the option type. The pointer should be immediately
+ * followed by an unsigned int that will store the number of elements in the
+ * array.
+ */
+ AV_OPT_TYPE_FLAG_ARRAY = (1 << 16),
};
/**
@@ -298,6 +309,46 @@ enum AVOptionType{
*/
#define AV_OPT_FLAG_CHILD_CONSTS (1 << 18)
+/**
+ * Must be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options.
+ */
+typedef struct AVOptionArrayDef {
+ /**
+ * Must be set to sizeof(AVOptionArrayDef), in order to allow extending this
+ * struct without breaking ABI.
+ */
+ size_t sizeof_self;
+
+ /**
+ * Native access only.
+ *
+ * Default value of the option, as would be serialized by av_opt_get() (i.e.
+ * using the value of sep as the separator).
+ */
+ const char *def;
+
+ /**
+ * Minimum number of elements in the array. When this field is non-zero, def
+ * must be non-NULL and contain at least this number of elements.
+ */
+ unsigned size_min;
+ /**
+ * Maximum number of elements in the array, 0 when unlimited.
+ */
+ unsigned size_max;
+
+ /**
+ * Separator between array elements in string representations of this
+ * option, used by av_opt_set() and av_opt_get(). It must be a printable
+ * ASCII character, excluding alphanumeric and the backslash. A comma is
+ * used when sep=0.
+ *
+ * The separator and the backslash must be backslash-escaped in order to
+ * appear in string representations of the option value.
+ */
+ uint8_t sep;
+} AVOptionArrayDef;
+
/**
* AVOption
*/
@@ -320,8 +371,7 @@ typedef struct AVOption {
enum AVOptionType type;
/**
- * Native access only.
- *
+ * Native access only, except when documented otherwise.
* the default value for scalar options
*/
union {
@@ -330,6 +380,14 @@ typedef struct AVOption {
const char *str;
/* TODO those are unused now */
AVRational q;
+
+ /**
+ * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL.
+ *
+ * Foreign access to some members allowed, as noted in AVOptionArrayDef
+ * documentation.
+ */
+ const AVOptionArrayDef *arr;
} default_val;
double min; ///< minimum valid value for the option
double max; ///< maximum valid value for the option
diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c
index e2582cc93d..37437320cf 100644
--- a/libavutil/tests/opt.c
+++ b/libavutil/tests/opt.c
@@ -57,6 +57,15 @@ typedef struct TestContext {
int bool3;
AVDictionary *dict1;
AVDictionary *dict2;
+
+ int **array_int;
+ unsigned nb_array_int;
+
+ char **array_str;
+ unsigned nb_array_str;
+
+ AVDictionary **array_dict;
+ unsigned nb_array_dict;
} TestContext;
#define OFFSET(x) offsetof(TestContext, x)
@@ -65,6 +74,17 @@ typedef struct TestContext {
#define TEST_FLAG_LAME 02
#define TEST_FLAG_MU 04
+static const AVOptionArrayDef array_str = {
+ .sizeof_self = sizeof(AVOptionArrayDef),
+ .sep = '|',
+ .def = "str0|str\\|1|str\\\\2",
+};
+
+static const AVOptionArrayDef array_dict = {
+ .sizeof_self = sizeof(AVOptionArrayDef),
+ .def = "k00=v\\\\\\\\00:k01=v\\,01,k10=v\\\\=1\\\\:0",
+};
+
static const AVOption test_options[]= {
{"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, 1 },
{"toggle", "set toggle", OFFSET(toggle), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, 1 },
@@ -93,6 +113,10 @@ static const AVOption test_options[]= {
{"bool3", "set boolean value", OFFSET(bool3), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, 1 },
{"dict1", "set dictionary value", OFFSET(dict1), AV_OPT_TYPE_DICT, { .str = NULL}, 0, 0, 1 },
{"dict2", "set dictionary value", OFFSET(dict2), AV_OPT_TYPE_DICT, { .str = "happy=':-)'"}, 0, 0, 1 },
+ {"array_int", "array of ints", OFFSET(array_int), AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = AV_OPT_FLAG_RUNTIME_PARAM },
+ {"array_str", "array of strings", OFFSET(array_str), AV_OPT_TYPE_STRING | AV_OPT_TYPE_FLAG_ARRAY, { .arr = &array_str }, .flags = AV_OPT_FLAG_RUNTIME_PARAM },
+ // there are three levels of escaping - C string, array option, dict - so 8 backslashes are needed to get a literal one inside a dict key/val
+ {"array_dict", "array of dicts", OFFSET(array_dict), AV_OPT_TYPE_DICT | AV_OPT_TYPE_FLAG_ARRAY, { .arr = &array_dict }, .flags = AV_OPT_FLAG_RUNTIME_PARAM },
{ NULL },
};
@@ -146,6 +170,17 @@ int main(void)
printf("flt=%.6f\n", test_ctx.flt);
printf("dbl=%.6f\n", test_ctx.dbl);
+ for (unsigned i = 0; i < test_ctx.nb_array_str; i++)
+ printf("array_str[%u]=%s\n", i, test_ctx.array_str[i]);
+
+ for (unsigned i = 0; i < test_ctx.nb_array_dict; i++) {
+ AVDictionary *d = test_ctx.array_dict[i];
+ const AVDictionaryEntry *e = NULL;
+
+ while ((e = av_dict_iterate(d, e)))
+ printf("array_dict[%u]: %s\t%s\n", i, e->key, e->value);
+ }
+
av_opt_show2(&test_ctx, NULL, -1, 0);
av_opt_free(&test_ctx);
@@ -177,6 +212,9 @@ int main(void)
TestContext test_ctx = { 0 };
TestContext test2_ctx = { 0 };
const AVOption *o = NULL;
+ char *val = NULL;
+ int ret;
+
test_ctx.class = &test_class;
test2_ctx.class = &test_class;
@@ -209,6 +247,17 @@ int main(void)
av_free(value1);
av_free(value2);
}
+
+ // av_opt_set(NULL) with an array option resets it
+ ret = av_opt_set(&test_ctx, "array_dict", NULL, 0);
+ printf("av_opt_set(\"array_dict\", NULL) -> %d\n", ret);
+ printf("array_dict=%sNULL; nb_array_dict=%u\n",
+ test_ctx.array_dict ? "non-" : "", test_ctx.nb_array_dict);
+
+ // av_opt_get() on an empty array should return a NULL string
+ ret = av_opt_get(&test_ctx, "array_dict", AV_OPT_ALLOW_NULL, (uint8_t**)&val);
+ printf("av_opt_get(\"array_dict\") -> %s\n", val ? val : "NULL");
+
av_opt_free(&test_ctx);
av_opt_free(&test2_ctx);
}
@@ -303,6 +352,8 @@ int main(void)
"bool1=true",
"bool2=auto",
"dict1='happy=\\:-):sad=\\:-('",
+ "array_int=0,32,2147483647",
+ "array_int=2147483648", // out of range, should fail
};
test_ctx.class = &test_class;
diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt
index 832f9cc8a9..f4fce1bd49 100644
--- a/tests/ref/fate/opt
+++ b/tests/ref/fate/opt
@@ -17,6 +17,12 @@ binary_size=4
num64=1
flt=0.333333
dbl=0.333333
+array_str[0]=str0
+array_str[1]=str|1
+array_str[2]=str\2
+array_dict[0]: k00 v\00
+array_dict[0]: k01 v,01
+array_dict[1]: k10 v=1:0
TestContext AVOptions:
-num <int> E.......... set num (from 0 to 100) (default 0)
-toggle <int> E.......... set toggle (from 0 to 1) (default 1)
@@ -45,6 +51,9 @@ TestContext AVOptions:
-bool3 <boolean> E.......... set boolean value (default false)
-dict1 <dictionary> E.......... set dictionary value
-dict2 <dictionary> E.......... set dictionary value (default "happy=':-)'")
+ -array_int [<int> ].........T. array of ints
+ -array_str [<string> ].........T. array of strings (default str0|str\|1|str\\2)
+ -array_dict [<dictionary>].........T. array of dicts (default k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0)
Testing av_opt_is_set_to_default()
name: num default:1 error:
@@ -74,6 +83,9 @@ name: bool2 default:0 error:
name: bool3 default:1 error:
name: dict1 default:1 error:
name: dict2 default:0 error:
+name: array_int default:0 error:
+name: array_str default:0 error:
+name:array_dict default:0 error:
name: num default:1 error:
name: toggle default:1 error:
name: rational default:1 error:
@@ -101,6 +113,9 @@ name: bool2 default:1 error:
name: bool3 default:1 error:
name: dict1 default:1 error:
name: dict2 default:1 error:
+name: array_int default:0 error:
+name: array_str default:1 error:
+name:array_dict default:1 error:
Testing av_opt_get/av_opt_set()
name: num get: 0 set: OK get: 0 OK
@@ -127,9 +142,15 @@ name: bool2 get: true set: OK get: true
name: bool3 get: false set: OK get: false OK
name: dict1 get: set: OK get: OK
name: dict2 get: happy=\:-) set: OK get: happy=\:-) OK
+name: array_int get: set: OK get: OK
+name: array_str get: str0|str\|1|str\\2 set: OK get: str0|str\|1|str\\2 OK
+name: array_dict get: k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0 set: OK get: k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0 OK
+av_opt_set("array_dict", NULL) -> 0
+array_dict=NULL; nb_array_dict=0
+av_opt_get("array_dict") -> NULL
Test av_opt_serialize()
-num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-)
+num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0
Setting entry with key 'num' to value '0'
Setting entry with key 'toggle' to value '1'
Setting entry with key 'rational' to value '1/1'
@@ -154,7 +175,10 @@ Setting entry with key 'bool2' to value 'true'
Setting entry with key 'bool3' to value 'false'
Setting entry with key 'dict1' to value ''
Setting entry with key 'dict2' to value 'happy=\:-)'
-num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-)
+Setting entry with key 'array_int' to value ''
+Setting entry with key 'array_str' to value 'str0|str\|1|str\\2'
+Setting entry with key 'array_dict' to value 'k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0'
+num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0
Testing av_set_options_string()
Setting options string ''
@@ -378,6 +402,13 @@ OK 'bool2=auto'
Setting options string 'dict1='happy=\:-):sad=\:-(''
Setting entry with key 'dict1' to value 'happy=\:-):sad=\:-('
OK 'dict1='happy=\:-):sad=\:-(''
+Setting options string 'array_int=0,32,2147483647'
+Setting entry with key 'array_int' to value '0,32,2147483647'
+OK 'array_int=0,32,2147483647'
+Setting options string 'array_int=2147483648'
+Setting entry with key 'array_int' to value '2147483648'
+Value 2147483648.000000 for parameter 'array_int' out of range [0 - 2.14748e+09]
+Error 'array_int=2147483648'
Testing av_opt_set_from_string()
Setting options string ''
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options Anton Khirnov
@ 2024-03-04 13:29 ` Andreas Rheinhardt
2024-03-04 21:00 ` Anton Khirnov
2024-03-07 14:50 ` Andreas Rheinhardt
2024-03-04 21:32 ` [FFmpeg-devel] [PATCH " Marton Balint
1 sibling, 2 replies; 57+ messages in thread
From: Andreas Rheinhardt @ 2024-03-04 13:29 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> ---
> doc/APIchanges | 3 +
> libavutil/opt.c | 362 +++++++++++++++++++++++++++++++++++++-----
> libavutil/opt.h | 62 +++++++-
> libavutil/tests/opt.c | 51 ++++++
> tests/ref/fate/opt | 35 +++-
> 5 files changed, 468 insertions(+), 45 deletions(-)
>
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 7d46ebb006..3209614ed6 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
>
> API changes, most recent first:
>
> +2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
> + Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
> +
> 2024-02-28 - xxxxxxxxxx - swr 4.14.100 - swresample.h
> swr_convert() now accepts arrays of const pointers (to input and output).
>
> diff --git a/libavutil/opt.h b/libavutil/opt.h
> index e402f6a0a0..77797b3fbe 100644
> --- a/libavutil/opt.h
> +++ b/libavutil/opt.h
> @@ -253,6 +253,17 @@ enum AVOptionType{
> #endif
> AV_OPT_TYPE_BOOL,
> AV_OPT_TYPE_CHLAYOUT,
> +
> + /**
> + * May be combined with another regular option type to declare an array
> + * option.
> + *
> + * For array options, @ref AVOption.offset should refer to a pointer
> + * corresponding to the option type. The pointer should be immediately
> + * followed by an unsigned int that will store the number of elements in the
> + * array.
How about we make this actually type-safe and use an actual struct for
this instead of relying on the compiler not adding padding between a
pointer and an unsigned int?
> + */
> + AV_OPT_TYPE_FLAG_ARRAY = (1 << 16),
> };
>
> /**
> @@ -298,6 +309,46 @@ enum AVOptionType{
> */
> #define AV_OPT_FLAG_CHILD_CONSTS (1 << 18)
>
> +/**
> + * Must be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options.
> + */
> +typedef struct AVOptionArrayDef {
> + /**
> + * Must be set to sizeof(AVOptionArrayDef), in order to allow extending this
> + * struct without breaking ABI.
> + */
> + size_t sizeof_self;
I do not really get the point of this field: It is not sufficient for
detecting whether a user used a version that set a certain field due to
trailing padding (i.e. an additional field need not increase
sizeof(AVOptionArrayDef); this is actually relevant for this structure,
because on x64 at least a new int/unsigned would fit into trailing padding).
Luckily we already have a way to know the user's lavu version, as it is
contained in the AVClass.
> +
> + /**
> + * Native access only.
> + *
> + * Default value of the option, as would be serialized by av_opt_get() (i.e.
> + * using the value of sep as the separator).
> + */
> + const char *def;
> +
> + /**
> + * Minimum number of elements in the array. When this field is non-zero, def
> + * must be non-NULL and contain at least this number of elements.
> + */
> + unsigned size_min;
> + /**
> + * Maximum number of elements in the array, 0 when unlimited.
> + */
> + unsigned size_max;
> +
> + /**
> + * Separator between array elements in string representations of this
> + * option, used by av_opt_set() and av_opt_get(). It must be a printable
> + * ASCII character, excluding alphanumeric and the backslash. A comma is
> + * used when sep=0.
> + *
> + * The separator and the backslash must be backslash-escaped in order to
> + * appear in string representations of the option value.
> + */
> + uint8_t sep;
If this is a printable ASCII character, then it should be a char.
> +} AVOptionArrayDef;
> +
> /**
> * AVOption
> */
> @@ -320,8 +371,7 @@ typedef struct AVOption {
> enum AVOptionType type;
>
> /**
> - * Native access only.
> - *
> + * Native access only, except when documented otherwise.
> * the default value for scalar options
> */
> union {
> @@ -330,6 +380,14 @@ typedef struct AVOption {
> const char *str;
> /* TODO those are unused now */
> AVRational q;
> +
> + /**
> + * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL.
> + *
> + * Foreign access to some members allowed, as noted in AVOptionArrayDef
> + * documentation.
> + */
> + const AVOptionArrayDef *arr;
> } default_val;
> double min; ///< minimum valid value for the option
> double max; ///< maximum valid value for the option
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 13:29 ` Andreas Rheinhardt
@ 2024-03-04 21:00 ` Anton Khirnov
2024-03-05 8:52 ` Andreas Rheinhardt
2024-03-07 14:50 ` Andreas Rheinhardt
1 sibling, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 21:00 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2024-03-04 14:29:59)
> Anton Khirnov:
> > ---
> > doc/APIchanges | 3 +
> > libavutil/opt.c | 362 +++++++++++++++++++++++++++++++++++++-----
> > libavutil/opt.h | 62 +++++++-
> > libavutil/tests/opt.c | 51 ++++++
> > tests/ref/fate/opt | 35 +++-
> > 5 files changed, 468 insertions(+), 45 deletions(-)
> >
> > diff --git a/doc/APIchanges b/doc/APIchanges
> > index 7d46ebb006..3209614ed6 100644
> > --- a/doc/APIchanges
> > +++ b/doc/APIchanges
> > @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
> >
> > API changes, most recent first:
> >
> > +2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
> > + Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
> > +
> > 2024-02-28 - xxxxxxxxxx - swr 4.14.100 - swresample.h
> > swr_convert() now accepts arrays of const pointers (to input and output).
> >
> > diff --git a/libavutil/opt.h b/libavutil/opt.h
> > index e402f6a0a0..77797b3fbe 100644
> > --- a/libavutil/opt.h
> > +++ b/libavutil/opt.h
> > @@ -253,6 +253,17 @@ enum AVOptionType{
> > #endif
> > AV_OPT_TYPE_BOOL,
> > AV_OPT_TYPE_CHLAYOUT,
> > +
> > + /**
> > + * May be combined with another regular option type to declare an array
> > + * option.
> > + *
> > + * For array options, @ref AVOption.offset should refer to a pointer
> > + * corresponding to the option type. The pointer should be immediately
> > + * followed by an unsigned int that will store the number of elements in the
> > + * array.
>
> How about we make this actually type-safe and use an actual struct for
> this instead of relying on the compiler not adding padding between a
> pointer and an unsigned int?
A struct containing what exactly?
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 21:00 ` Anton Khirnov
@ 2024-03-05 8:52 ` Andreas Rheinhardt
0 siblings, 0 replies; 57+ messages in thread
From: Andreas Rheinhardt @ 2024-03-05 8:52 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> Quoting Andreas Rheinhardt (2024-03-04 14:29:59)
>> Anton Khirnov:
>>> ---
>>> doc/APIchanges | 3 +
>>> libavutil/opt.c | 362 +++++++++++++++++++++++++++++++++++++-----
>>> libavutil/opt.h | 62 +++++++-
>>> libavutil/tests/opt.c | 51 ++++++
>>> tests/ref/fate/opt | 35 +++-
>>> 5 files changed, 468 insertions(+), 45 deletions(-)
>>>
>>> diff --git a/doc/APIchanges b/doc/APIchanges
>>> index 7d46ebb006..3209614ed6 100644
>>> --- a/doc/APIchanges
>>> +++ b/doc/APIchanges
>>> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
>>>
>>> API changes, most recent first:
>>>
>>> +2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
>>> + Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
>>> +
>>> 2024-02-28 - xxxxxxxxxx - swr 4.14.100 - swresample.h
>>> swr_convert() now accepts arrays of const pointers (to input and output).
>>>
>>> diff --git a/libavutil/opt.h b/libavutil/opt.h
>>> index e402f6a0a0..77797b3fbe 100644
>>> --- a/libavutil/opt.h
>>> +++ b/libavutil/opt.h
>>> @@ -253,6 +253,17 @@ enum AVOptionType{
>>> #endif
>>> AV_OPT_TYPE_BOOL,
>>> AV_OPT_TYPE_CHLAYOUT,
>>> +
>>> + /**
>>> + * May be combined with another regular option type to declare an array
>>> + * option.
>>> + *
>>> + * For array options, @ref AVOption.offset should refer to a pointer
>>> + * corresponding to the option type. The pointer should be immediately
>>> + * followed by an unsigned int that will store the number of elements in the
>>> + * array.
>>
>> How about we make this actually type-safe and use an actual struct for
>> this instead of relying on the compiler not adding padding between a
>> pointer and an unsigned int?
>
> A struct containing what exactly?
>
A pointer and a size field.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 13:29 ` Andreas Rheinhardt
2024-03-04 21:00 ` Anton Khirnov
@ 2024-03-07 14:50 ` Andreas Rheinhardt
2024-03-07 15:24 ` [FFmpeg-devel] [PATCH v2 " Anton Khirnov
1 sibling, 1 reply; 57+ messages in thread
From: Andreas Rheinhardt @ 2024-03-07 14:50 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> Anton Khirnov:
>> +/**
>> + * Must be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options.
>> + */
>> +typedef struct AVOptionArrayDef {
>> + /**
>> + * Must be set to sizeof(AVOptionArrayDef), in order to allow extending this
>> + * struct without breaking ABI.
>> + */
>> + size_t sizeof_self;
>
> I do not really get the point of this field: It is not sufficient for
> detecting whether a user used a version that set a certain field due to
> trailing padding (i.e. an additional field need not increase
> sizeof(AVOptionArrayDef); this is actually relevant for this structure,
> because on x64 at least a new int/unsigned would fit into trailing padding).
> Luckily we already have a way to know the user's lavu version, as it is
> contained in the AVClass.
>
I do not really see a reply to the above comment.
>> +
>> + /**
>> + * Native access only.
>> + *
>> + * Default value of the option, as would be serialized by av_opt_get() (i.e.
>> + * using the value of sep as the separator).
>> + */
>> + const char *def;
>> +
>> + /**
>> + * Minimum number of elements in the array. When this field is non-zero, def
>> + * must be non-NULL and contain at least this number of elements.
>> + */
>> + unsigned size_min;
>> + /**
>> + * Maximum number of elements in the array, 0 when unlimited.
>> + */
>> + unsigned size_max;
>> +
>> + /**
>> + * Separator between array elements in string representations of this
>> + * option, used by av_opt_set() and av_opt_get(). It must be a printable
>> + * ASCII character, excluding alphanumeric and the backslash. A comma is
>> + * used when sep=0.
>> + *
>> + * The separator and the backslash must be backslash-escaped in order to
>> + * appear in string representations of the option value.
>> + */
>> + uint8_t sep;
>
> If this is a printable ASCII character, then it should be a char.
>
>> +} AVOptionArrayDef;
>> +
>> /**
>> * AVOption
>> */
>> @@ -320,8 +371,7 @@ typedef struct AVOption {
>> enum AVOptionType type;
>>
>> /**
>> - * Native access only.
>> - *
>> + * Native access only, except when documented otherwise.
>> * the default value for scalar options
>> */
>> union {
>> @@ -330,6 +380,14 @@ typedef struct AVOption {
>> const char *str;
>> /* TODO those are unused now */
>> AVRational q;
>> +
>> + /**
>> + * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL.
>> + *
>> + * Foreign access to some members allowed, as noted in AVOptionArrayDef
>> + * documentation.
>> + */
>> + const AVOptionArrayDef *arr;
>> } default_val;
>> double min; ///< minimum valid value for the option
>> double max; ///< maximum valid value for the option
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH v2 06/29] lavu/opt: add array options
2024-03-07 14:50 ` Andreas Rheinhardt
@ 2024-03-07 15:24 ` Anton Khirnov
0 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-07 15:24 UTC (permalink / raw)
To: ffmpeg-devel
---
doc/APIchanges | 3 +
libavutil/opt.c | 360 +++++++++++++++++++++++++++++++++++++-----
libavutil/opt.h | 56 ++++++-
libavutil/tests/opt.c | 49 ++++++
tests/ref/fate/opt | 35 +++-
5 files changed, 458 insertions(+), 45 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index 4f7612e449..6e2c851e31 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07
API changes, most recent first:
+2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
+ Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
+
2024-03-06 - xxxxxxxxxx - lavf 60.25.100 - avformat.h
Deprecate av_fmt_ctx_get_duration_estimation_method().
The relevant field is public and needs no getter to access.
diff --git a/libavutil/opt.c b/libavutil/opt.c
index 06d3056a37..685206f416 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -43,6 +43,8 @@
#include <float.h>
+#define TYPE_BASE(type) ((type) & ~AV_OPT_TYPE_FLAG_ARRAY)
+
const AVOption *av_opt_next(const void *obj, const AVOption *last)
{
const AVClass *class;
@@ -100,6 +102,54 @@ static int opt_is_pod(enum AVOptionType type)
return 0;
}
+static uint8_t opt_array_sep(const AVOption *o)
+{
+ const AVOptionArrayDef *d = o->default_val.arr;
+ av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY);
+ return (d && d->sep) ? d->sep : ',';
+}
+
+static void *opt_array_pelem(const AVOption *o, void *array, unsigned idx)
+{
+ av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY);
+ return (uint8_t *)array + idx * opt_elem_size[TYPE_BASE(o->type)];
+}
+
+static unsigned *opt_array_pcount(const void *parray)
+{
+ return (unsigned *)((const void * const *)parray + 1);
+}
+
+static void opt_free_elem(const AVOption *o, void *ptr)
+{
+ switch (TYPE_BASE(o->type)) {
+ case AV_OPT_TYPE_STRING:
+ case AV_OPT_TYPE_BINARY:
+ av_freep(ptr);
+ break;
+
+ case AV_OPT_TYPE_DICT:
+ av_dict_free((AVDictionary **)ptr);
+ break;
+
+ case AV_OPT_TYPE_CHLAYOUT:
+ av_channel_layout_uninit((AVChannelLayout *)ptr);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void opt_free_array(const AVOption *o, void *parray, unsigned *count)
+{
+ for (unsigned i = 0; i < *count; i++)
+ opt_free_elem(o, opt_array_pelem(o, *(void **)parray, i));
+
+ av_freep(parray);
+ *count = 0;
+}
+
static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum)
{
switch (o->type) {
@@ -140,14 +190,16 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den
static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
{
- if (o->type != AV_OPT_TYPE_FLAGS &&
+ const enum AVOptionType type = TYPE_BASE(o->type);
+
+ if (type != AV_OPT_TYPE_FLAGS &&
(!den || o->max * den < num * intnum || o->min * den > num * intnum)) {
num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN);
av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",
num, o->name, o->min, o->max);
return AVERROR(ERANGE);
}
- if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (type == AV_OPT_TYPE_FLAGS) {
double d = num*intnum/den;
if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) {
av_log(obj, AV_LOG_ERROR,
@@ -157,7 +209,7 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int
}
}
- switch (o->type) {
+ switch (type) {
case AV_OPT_TYPE_PIXEL_FMT:
*(enum AVPixelFormat *)dst = llrint(num / den) * intnum;
break;
@@ -271,9 +323,10 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d
static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst)
{
+ const enum AVOptionType type = TYPE_BASE(o->type);
int ret = 0;
- if (o->type == AV_OPT_TYPE_RATIONAL || o->type == AV_OPT_TYPE_VIDEO_RATE) {
+ if (type == AV_OPT_TYPE_RATIONAL || type == AV_OPT_TYPE_VIDEO_RATE) {
int num, den;
char c;
if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) {
@@ -290,7 +343,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con
double d;
int64_t intnum = 1;
- if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (type == AV_OPT_TYPE_FLAGS) {
if (*val == '+' || *val == '-')
cmd = *(val++);
for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
@@ -346,7 +399,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con
}
}
}
- if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (type == AV_OPT_TYPE_FLAGS) {
intnum = *(unsigned int*)dst;
if (cmd == '+')
d = intnum | (int64_t)d;
@@ -531,18 +584,17 @@ static int set_string_channel_layout(void *obj, const AVOption *o,
static int opt_set_elem(void *obj, void *target_obj, const AVOption *o,
const char *val, void *dst)
{
+ const enum AVOptionType type = TYPE_BASE(o->type);
int ret;
-FF_DISABLE_DEPRECATION_WARNINGS
- if (!val && (o->type != AV_OPT_TYPE_STRING &&
- o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT &&
- o->type != AV_OPT_TYPE_IMAGE_SIZE &&
- o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR &&
- o->type != AV_OPT_TYPE_BOOL))
+ if (!val && (type != AV_OPT_TYPE_STRING &&
+ type != AV_OPT_TYPE_PIXEL_FMT && type != AV_OPT_TYPE_SAMPLE_FMT &&
+ type != AV_OPT_TYPE_IMAGE_SIZE &&
+ type != AV_OPT_TYPE_DURATION && type != AV_OPT_TYPE_COLOR &&
+ type != AV_OPT_TYPE_BOOL))
return AVERROR(EINVAL);
-FF_ENABLE_DEPRECATION_WARNINGS
- switch (o->type) {
+ switch (type) {
case AV_OPT_TYPE_BOOL:
return set_string_bool(obj, o, val, dst);
case AV_OPT_TYPE_STRING:
@@ -604,6 +656,85 @@ FF_ENABLE_DEPRECATION_WARNINGS
return AVERROR(EINVAL);
}
+static int opt_set_array(void *obj, void *target_obj, const AVOption *o,
+ const char *val, void *dst)
+{
+ const AVOptionArrayDef *arr = o->default_val.arr;
+ const size_t elem_size = opt_elem_size[TYPE_BASE(o->type)];
+ const uint8_t sep = opt_array_sep(o);
+ uint8_t *str = NULL;
+
+ void *elems = NULL;
+ unsigned nb_elems = 0;
+ int ret;
+
+ if (val && *val) {
+ str = av_malloc(strlen(val) + 1);
+ if (!str)
+ return AVERROR(ENOMEM);
+ }
+
+ // split and unescape the string
+ while (val && *val) {
+ uint8_t *p = str;
+ void *tmp;
+
+ if (arr && arr->size_max && nb_elems >= arr->size_max) {
+ av_log(obj, AV_LOG_ERROR,
+ "Cannot assign more than %u elements to array option %s\n",
+ arr->size_max, o->name);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ for (; *val; val++, p++) {
+ if (*val == '\\' && val[1])
+ val++;
+ else if (*val == sep) {
+ val++;
+ break;
+ }
+ *p = *val;
+ }
+ *p = 0;
+
+ tmp = av_realloc_array(elems, nb_elems + 1, elem_size);
+ if (!tmp) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ elems = tmp;
+
+ tmp = opt_array_pelem(o, elems, nb_elems);
+ memset(tmp, 0, elem_size);
+
+ ret = opt_set_elem(obj, target_obj, o, str, tmp);
+ if (ret < 0)
+ goto fail;
+ nb_elems++;
+ }
+ av_freep(&str);
+
+ opt_free_array(o, dst, opt_array_pcount(dst));
+
+ if (arr && nb_elems < arr->size_min) {
+ av_log(obj, AV_LOG_ERROR,
+ "Cannot assign fewer than %u elements to array option %s\n",
+ arr->size_min, o->name);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ *((void **)dst) = elems;
+ *opt_array_pcount(dst) = nb_elems;
+
+ return 0;
+fail:
+ av_freep(&str);
+ opt_free_array(o, &elems, &nb_elems);
+ return ret;
+}
+
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
void *dst, *target_obj;
@@ -619,7 +750,8 @@ int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
dst = ((uint8_t *)target_obj) + o->offset;
- return opt_set_elem(obj, target_obj, o, val, dst);
+ return ((o->type & AV_OPT_TYPE_FLAG_ARRAY) ?
+ opt_set_array : opt_set_elem)(obj, target_obj, o, val, dst);
}
#define OPT_EVAL_NUMBER(name, opttype, vartype) \
@@ -647,7 +779,7 @@ static int set_number(void *obj, const char *name, double num, int den, int64_t
if (!o || !target_obj)
return AVERROR_OPTION_NOT_FOUND;
- if (o->flags & AV_OPT_FLAG_READONLY)
+ if ((o->flags & AV_OPT_FLAG_READONLY) || (o->type & AV_OPT_TYPE_FLAG_ARRAY))
return AVERROR(EINVAL);
dst = ((uint8_t *)target_obj) + o->offset;
@@ -730,7 +862,8 @@ int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int searc
return AVERROR_OPTION_NOT_FOUND;
if (o->type != AV_OPT_TYPE_VIDEO_RATE) {
av_log(obj, AV_LOG_ERROR,
- "The value set by option '%s' is not a video rate.\n", o->name);
+ "The value set by option '%s' is not a video rate.\n",
+ o->name);
return AVERROR(EINVAL);
}
if (val.num <= 0 || val.den <= 0)
@@ -852,7 +985,7 @@ static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len,
{
int ret;
- switch (o->type) {
+ switch (TYPE_BASE(o->type)) {
case AV_OPT_TYPE_BOOL:
ret = snprintf(*pbuf, buf_len, "%s", get_bool_name(*(int *)dst));
break;
@@ -949,6 +1082,66 @@ static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len,
return ret;
}
+static int opt_get_array(const AVOption *o, void *dst, uint8_t **out_val)
+{
+ const unsigned count = *opt_array_pcount(dst);
+ const uint8_t sep = opt_array_sep(o);
+
+ uint8_t *str = NULL;
+ size_t str_len = 0;
+ int ret;
+
+ *out_val = NULL;
+
+ for (unsigned i = 0; i < count; i++) {
+ uint8_t buf[128], *out = buf;
+ size_t out_len;
+
+ ret = opt_get_elem(o, &out, sizeof(buf),
+ opt_array_pelem(o, *(void **)dst, i), 0);
+ if (ret < 0)
+ goto fail;
+
+ out_len = strlen(out);
+ if (out_len > SIZE_MAX / 2 - !!i ||
+ !!i + out_len * 2 > SIZE_MAX - str_len - 1) {
+ ret = AVERROR(ERANGE);
+ goto fail;
+ }
+
+ // terminator escaping separator
+ // ↓ ↓ ↓
+ ret = av_reallocp(&str, str_len + 1 + out_len * 2 + !!i);
+ if (ret < 0)
+ goto fail;
+
+ // add separator if needed
+ if (i)
+ str[str_len++] = sep;
+
+ // escape the element
+ for (unsigned j = 0; j < out_len; j++) {
+ uint8_t val = out[j];
+ if (val == sep || val == '\\')
+ str[str_len++] = '\\';
+ str[str_len++] = val;
+ }
+ str[str_len] = 0;
+
+fail:
+ if (out != buf)
+ av_freep(&out);
+ if (ret < 0) {
+ av_freep(&str);
+ return ret;
+ }
+ }
+
+ *out_val = str;
+
+ return 0;
+}
+
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
{
void *dst, *target_obj;
@@ -964,8 +1157,19 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
dst = (uint8_t *)target_obj + o->offset;
- buf[0] = 0;
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ ret = opt_get_array(o, dst, out_val);
+ if (ret < 0)
+ return ret;
+ if (!*out_val && !(search_flags & AV_OPT_ALLOW_NULL)) {
+ *out_val = av_strdup("");
+ if (!*out_val)
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+ }
+ buf[0] = 0;
out = buf;
ret = opt_get_elem(o, &out, sizeof(buf), dst, search_flags);
if (ret < 0)
@@ -988,6 +1192,8 @@ static int get_number(void *obj, const char *name, double *num, int *den, int64_
const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
if (!o || !target_obj)
return AVERROR_OPTION_NOT_FOUND;
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY)
+ return AVERROR(EINVAL);
dst = ((uint8_t *)target_obj) + o->offset;
@@ -1045,7 +1251,7 @@ int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_
return AVERROR_OPTION_NOT_FOUND;
if (o->type != AV_OPT_TYPE_IMAGE_SIZE) {
av_log(obj, AV_LOG_ERROR,
- "The value for option '%s' is not an image size.\n", name);
+ "The value for option '%s' is not a image size.\n", name);
return AVERROR(EINVAL);
}
@@ -1252,11 +1458,16 @@ static void log_type(void *av_log_obj, const AVOption *o,
[AV_OPT_TYPE_CHLAYOUT] = "<channel_layout>",
[AV_OPT_TYPE_BOOL] = "<boolean>",
};
+ const enum AVOptionType type = TYPE_BASE(o->type);
- if (o->type == AV_OPT_TYPE_CONST && parent_type == AV_OPT_TYPE_INT)
+ if (o->type == AV_OPT_TYPE_CONST && TYPE_BASE(parent_type) == AV_OPT_TYPE_INT)
av_log(av_log_obj, AV_LOG_INFO, "%-12"PRId64" ", o->default_val.i64);
- else if (o->type < FF_ARRAY_ELEMS(desc) && desc[o->type])
- av_log(av_log_obj, AV_LOG_INFO, "%-12s ", desc[o->type]);
+ else if (type < FF_ARRAY_ELEMS(desc) && desc[type]) {
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY)
+ av_log(av_log_obj, AV_LOG_INFO, "[%-10s]", desc[type]);
+ else
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", desc[type]);
+ }
else
av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "");
}
@@ -1274,6 +1485,13 @@ static void log_default(void *obj, void *av_log_obj, const AVOption *opt)
!opt->default_val.str)
return;
+ if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ const AVOptionArrayDef *arr = opt->default_val.arr;
+ if (arr && arr->def)
+ av_log(av_log_obj, AV_LOG_INFO, " (default %s)", arr->def);
+ return;
+ }
+
av_log(av_log_obj, AV_LOG_INFO, " (default ");
switch (opt->type) {
case AV_OPT_TYPE_BOOL:
@@ -1434,6 +1652,21 @@ void av_opt_set_defaults2(void *s, int mask, int flags)
if (opt->flags & AV_OPT_FLAG_READONLY)
continue;
+ if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ const AVOptionArrayDef *arr = opt->default_val.arr;
+ const char sep = opt_array_sep(opt);
+
+ av_assert0(sep && sep != '\\' &&
+ (sep < 'a' || sep > 'z') &&
+ (sep < 'A' || sep > 'Z') &&
+ (sep < '0' || sep > '9'));
+
+ if (arr && arr->def)
+ opt_set_array(s, s, opt, arr->def, dst);
+
+ continue;
+ }
+
switch (opt->type) {
case AV_OPT_TYPE_CONST:
/* Nothing to be done here */
@@ -1676,23 +1909,12 @@ void av_opt_free(void *obj)
{
const AVOption *o = NULL;
while ((o = av_opt_next(obj, o))) {
- switch (o->type) {
- case AV_OPT_TYPE_STRING:
- case AV_OPT_TYPE_BINARY:
- av_freep((uint8_t *)obj + o->offset);
- break;
+ void *pitem = (uint8_t *)obj + o->offset;
- case AV_OPT_TYPE_DICT:
- av_dict_free((AVDictionary **)(((uint8_t *)obj) + o->offset));
- break;
-
- case AV_OPT_TYPE_CHLAYOUT:
- av_channel_layout_uninit((AVChannelLayout *)(((uint8_t *)obj) + o->offset));
- break;
-
- default:
- break;
- }
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY)
+ opt_free_array(o, pitem, opt_array_pcount(pitem));
+ else
+ opt_free_elem(o, pitem);
}
}
@@ -1794,7 +2016,9 @@ const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter)
void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
{
const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL);
- if(!opt)
+
+ // no direct access to array-type options
+ if (!opt || (opt->type & AV_OPT_TYPE_FLAG_ARRAY))
return NULL;
return (uint8_t*)obj + opt->offset;
}
@@ -1844,6 +2068,40 @@ static int opt_copy_elem(void *logctx, enum AVOptionType type,
return 0;
}
+static int opt_copy_array(void *logctx, const AVOption *o,
+ void **pdst, const void * const *psrc)
+{
+ unsigned nb_elems = *opt_array_pcount(psrc);
+ void *dst = NULL;
+ int ret;
+
+ if (*pdst == *psrc) {
+ *pdst = NULL;
+ *opt_array_pcount(pdst) = 0;
+ }
+
+ opt_free_array(o, pdst, opt_array_pcount(pdst));
+
+ dst = av_calloc(nb_elems, opt_elem_size[TYPE_BASE(o->type)]);
+ if (!dst)
+ return AVERROR(ENOMEM);
+
+ for (unsigned i = 0; i < nb_elems; i++) {
+ ret = opt_copy_elem(logctx, TYPE_BASE(o->type),
+ opt_array_pelem(o, dst, i),
+ opt_array_pelem(o, *(void**)psrc, i));
+ if (ret < 0) {
+ opt_free_array(o, &dst, &nb_elems);
+ return ret;
+ }
+ }
+
+ *pdst = dst;
+ *opt_array_pcount(pdst) = nb_elems;
+
+ return 0;
+}
+
int av_opt_copy(void *dst, const void *src)
{
const AVOption *o = NULL;
@@ -1861,7 +2119,9 @@ int av_opt_copy(void *dst, const void *src)
void *field_dst = (uint8_t *)dst + o->offset;
void *field_src = (uint8_t *)src + o->offset;
- int err = opt_copy_elem(dst, o->type, field_dst, field_src);
+ int err = (o->type & AV_OPT_TYPE_FLAG_ARRAY) ?
+ opt_copy_array(dst, o, field_dst, field_src) :
+ opt_copy_elem (dst, o->type, field_dst, field_src);
if (err < 0)
ret = err;
}
@@ -1990,6 +2250,24 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o)
dst = ((uint8_t*)obj) + o->offset;
+ if (o->type & AV_OPT_TYPE_FLAG_ARRAY) {
+ const char *def = o->default_val.arr ? o->default_val.arr->def : NULL;
+ uint8_t *val;
+
+ ret = opt_get_array(o, dst, &val);
+ if (ret < 0)
+ return ret;
+
+ if (!!val != !!def)
+ ret = 0;
+ else if (val)
+ ret = !strcmp(val, def);
+
+ av_freep(&val);
+
+ return ret;
+ }
+
switch (o->type) {
case AV_OPT_TYPE_CONST:
return 1;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index 82bca920fb..e6013662f6 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -250,6 +250,17 @@ enum AVOptionType{
AV_OPT_TYPE_COLOR,
AV_OPT_TYPE_BOOL,
AV_OPT_TYPE_CHLAYOUT,
+
+ /**
+ * May be combined with another regular option type to declare an array
+ * option.
+ *
+ * For array options, @ref AVOption.offset should refer to a pointer
+ * corresponding to the option type. The pointer should be immediately
+ * followed by an unsigned int that will store the number of elements in the
+ * array.
+ */
+ AV_OPT_TYPE_FLAG_ARRAY = (1 << 16),
};
/**
@@ -295,6 +306,40 @@ enum AVOptionType{
*/
#define AV_OPT_FLAG_CHILD_CONSTS (1 << 18)
+/**
+ * May be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options.
+ */
+typedef struct AVOptionArrayDef {
+ /**
+ * Native access only.
+ *
+ * Default value of the option, as would be serialized by av_opt_get() (i.e.
+ * using the value of sep as the separator).
+ */
+ const char *def;
+
+ /**
+ * Minimum number of elements in the array. When this field is non-zero, def
+ * must be non-NULL and contain at least this number of elements.
+ */
+ unsigned size_min;
+ /**
+ * Maximum number of elements in the array, 0 when unlimited.
+ */
+ unsigned size_max;
+
+ /**
+ * Separator between array elements in string representations of this
+ * option, used by av_opt_set() and av_opt_get(). It must be a printable
+ * ASCII character, excluding alphanumeric and the backslash. A comma is
+ * used when sep=0.
+ *
+ * The separator and the backslash must be backslash-escaped in order to
+ * appear in string representations of the option value.
+ */
+ char sep;
+} AVOptionArrayDef;
+
/**
* AVOption
*/
@@ -317,8 +362,7 @@ typedef struct AVOption {
enum AVOptionType type;
/**
- * Native access only.
- *
+ * Native access only, except when documented otherwise.
* the default value for scalar options
*/
union {
@@ -327,6 +371,14 @@ typedef struct AVOption {
const char *str;
/* TODO those are unused now */
AVRational q;
+
+ /**
+ * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL.
+ *
+ * Foreign access to some members allowed, as noted in AVOptionArrayDef
+ * documentation.
+ */
+ const AVOptionArrayDef *arr;
} default_val;
double min; ///< minimum valid value for the option
double max; ///< maximum valid value for the option
diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c
index e2582cc93d..04b4901579 100644
--- a/libavutil/tests/opt.c
+++ b/libavutil/tests/opt.c
@@ -57,6 +57,15 @@ typedef struct TestContext {
int bool3;
AVDictionary *dict1;
AVDictionary *dict2;
+
+ int **array_int;
+ unsigned nb_array_int;
+
+ char **array_str;
+ unsigned nb_array_str;
+
+ AVDictionary **array_dict;
+ unsigned nb_array_dict;
} TestContext;
#define OFFSET(x) offsetof(TestContext, x)
@@ -65,6 +74,15 @@ typedef struct TestContext {
#define TEST_FLAG_LAME 02
#define TEST_FLAG_MU 04
+static const AVOptionArrayDef array_str = {
+ .sep = '|',
+ .def = "str0|str\\|1|str\\\\2",
+};
+
+static const AVOptionArrayDef array_dict = {
+ .def = "k00=v\\\\\\\\00:k01=v\\,01,k10=v\\\\=1\\\\:0",
+};
+
static const AVOption test_options[]= {
{"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, 1 },
{"toggle", "set toggle", OFFSET(toggle), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, 1 },
@@ -93,6 +111,10 @@ static const AVOption test_options[]= {
{"bool3", "set boolean value", OFFSET(bool3), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, 1 },
{"dict1", "set dictionary value", OFFSET(dict1), AV_OPT_TYPE_DICT, { .str = NULL}, 0, 0, 1 },
{"dict2", "set dictionary value", OFFSET(dict2), AV_OPT_TYPE_DICT, { .str = "happy=':-)'"}, 0, 0, 1 },
+ {"array_int", "array of ints", OFFSET(array_int), AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = AV_OPT_FLAG_RUNTIME_PARAM },
+ {"array_str", "array of strings", OFFSET(array_str), AV_OPT_TYPE_STRING | AV_OPT_TYPE_FLAG_ARRAY, { .arr = &array_str }, .flags = AV_OPT_FLAG_RUNTIME_PARAM },
+ // there are three levels of escaping - C string, array option, dict - so 8 backslashes are needed to get a literal one inside a dict key/val
+ {"array_dict", "array of dicts", OFFSET(array_dict), AV_OPT_TYPE_DICT | AV_OPT_TYPE_FLAG_ARRAY, { .arr = &array_dict }, .flags = AV_OPT_FLAG_RUNTIME_PARAM },
{ NULL },
};
@@ -146,6 +168,17 @@ int main(void)
printf("flt=%.6f\n", test_ctx.flt);
printf("dbl=%.6f\n", test_ctx.dbl);
+ for (unsigned i = 0; i < test_ctx.nb_array_str; i++)
+ printf("array_str[%u]=%s\n", i, test_ctx.array_str[i]);
+
+ for (unsigned i = 0; i < test_ctx.nb_array_dict; i++) {
+ AVDictionary *d = test_ctx.array_dict[i];
+ const AVDictionaryEntry *e = NULL;
+
+ while ((e = av_dict_iterate(d, e)))
+ printf("array_dict[%u]: %s\t%s\n", i, e->key, e->value);
+ }
+
av_opt_show2(&test_ctx, NULL, -1, 0);
av_opt_free(&test_ctx);
@@ -177,6 +210,9 @@ int main(void)
TestContext test_ctx = { 0 };
TestContext test2_ctx = { 0 };
const AVOption *o = NULL;
+ char *val = NULL;
+ int ret;
+
test_ctx.class = &test_class;
test2_ctx.class = &test_class;
@@ -209,6 +245,17 @@ int main(void)
av_free(value1);
av_free(value2);
}
+
+ // av_opt_set(NULL) with an array option resets it
+ ret = av_opt_set(&test_ctx, "array_dict", NULL, 0);
+ printf("av_opt_set(\"array_dict\", NULL) -> %d\n", ret);
+ printf("array_dict=%sNULL; nb_array_dict=%u\n",
+ test_ctx.array_dict ? "non-" : "", test_ctx.nb_array_dict);
+
+ // av_opt_get() on an empty array should return a NULL string
+ ret = av_opt_get(&test_ctx, "array_dict", AV_OPT_ALLOW_NULL, (uint8_t**)&val);
+ printf("av_opt_get(\"array_dict\") -> %s\n", val ? val : "NULL");
+
av_opt_free(&test_ctx);
av_opt_free(&test2_ctx);
}
@@ -303,6 +350,8 @@ int main(void)
"bool1=true",
"bool2=auto",
"dict1='happy=\\:-):sad=\\:-('",
+ "array_int=0,32,2147483647",
+ "array_int=2147483648", // out of range, should fail
};
test_ctx.class = &test_class;
diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt
index 832f9cc8a9..f4fce1bd49 100644
--- a/tests/ref/fate/opt
+++ b/tests/ref/fate/opt
@@ -17,6 +17,12 @@ binary_size=4
num64=1
flt=0.333333
dbl=0.333333
+array_str[0]=str0
+array_str[1]=str|1
+array_str[2]=str\2
+array_dict[0]: k00 v\00
+array_dict[0]: k01 v,01
+array_dict[1]: k10 v=1:0
TestContext AVOptions:
-num <int> E.......... set num (from 0 to 100) (default 0)
-toggle <int> E.......... set toggle (from 0 to 1) (default 1)
@@ -45,6 +51,9 @@ TestContext AVOptions:
-bool3 <boolean> E.......... set boolean value (default false)
-dict1 <dictionary> E.......... set dictionary value
-dict2 <dictionary> E.......... set dictionary value (default "happy=':-)'")
+ -array_int [<int> ].........T. array of ints
+ -array_str [<string> ].........T. array of strings (default str0|str\|1|str\\2)
+ -array_dict [<dictionary>].........T. array of dicts (default k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0)
Testing av_opt_is_set_to_default()
name: num default:1 error:
@@ -74,6 +83,9 @@ name: bool2 default:0 error:
name: bool3 default:1 error:
name: dict1 default:1 error:
name: dict2 default:0 error:
+name: array_int default:0 error:
+name: array_str default:0 error:
+name:array_dict default:0 error:
name: num default:1 error:
name: toggle default:1 error:
name: rational default:1 error:
@@ -101,6 +113,9 @@ name: bool2 default:1 error:
name: bool3 default:1 error:
name: dict1 default:1 error:
name: dict2 default:1 error:
+name: array_int default:0 error:
+name: array_str default:1 error:
+name:array_dict default:1 error:
Testing av_opt_get/av_opt_set()
name: num get: 0 set: OK get: 0 OK
@@ -127,9 +142,15 @@ name: bool2 get: true set: OK get: true
name: bool3 get: false set: OK get: false OK
name: dict1 get: set: OK get: OK
name: dict2 get: happy=\:-) set: OK get: happy=\:-) OK
+name: array_int get: set: OK get: OK
+name: array_str get: str0|str\|1|str\\2 set: OK get: str0|str\|1|str\\2 OK
+name: array_dict get: k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0 set: OK get: k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0 OK
+av_opt_set("array_dict", NULL) -> 0
+array_dict=NULL; nb_array_dict=0
+av_opt_get("array_dict") -> NULL
Test av_opt_serialize()
-num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-)
+num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0
Setting entry with key 'num' to value '0'
Setting entry with key 'toggle' to value '1'
Setting entry with key 'rational' to value '1/1'
@@ -154,7 +175,10 @@ Setting entry with key 'bool2' to value 'true'
Setting entry with key 'bool3' to value 'false'
Setting entry with key 'dict1' to value ''
Setting entry with key 'dict2' to value 'happy=\:-)'
-num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-)
+Setting entry with key 'array_int' to value ''
+Setting entry with key 'array_str' to value 'str0|str\|1|str\\2'
+Setting entry with key 'array_dict' to value 'k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0'
+num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0
Testing av_set_options_string()
Setting options string ''
@@ -378,6 +402,13 @@ OK 'bool2=auto'
Setting options string 'dict1='happy=\:-):sad=\:-(''
Setting entry with key 'dict1' to value 'happy=\:-):sad=\:-('
OK 'dict1='happy=\:-):sad=\:-(''
+Setting options string 'array_int=0,32,2147483647'
+Setting entry with key 'array_int' to value '0,32,2147483647'
+OK 'array_int=0,32,2147483647'
+Setting options string 'array_int=2147483648'
+Setting entry with key 'array_int' to value '2147483648'
+Value 2147483648.000000 for parameter 'array_int' out of range [0 - 2.14748e+09]
+Error 'array_int=2147483648'
Testing av_opt_set_from_string()
Setting options string ''
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options Anton Khirnov
2024-03-04 13:29 ` Andreas Rheinhardt
@ 2024-03-04 21:32 ` Marton Balint
2024-03-05 9:50 ` Anton Khirnov
1 sibling, 1 reply; 57+ messages in thread
From: Marton Balint @ 2024-03-04 21:32 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Mon, 4 Mar 2024, Anton Khirnov wrote:
> ---
> doc/APIchanges | 3 +
> libavutil/opt.c | 362 +++++++++++++++++++++++++++++++++++++-----
> libavutil/opt.h | 62 +++++++-
> libavutil/tests/opt.c | 51 ++++++
> tests/ref/fate/opt | 35 +++-
> 5 files changed, 468 insertions(+), 45 deletions(-)
>
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 7d46ebb006..3209614ed6 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
>
> API changes, most recent first:
>
> +2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
> + Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
> +
> 2024-02-28 - xxxxxxxxxx - swr 4.14.100 - swresample.h
> swr_convert() now accepts arrays of const pointers (to input and output).
[...]
> diff --git a/libavutil/opt.h b/libavutil/opt.h
> index e402f6a0a0..77797b3fbe 100644
> --- a/libavutil/opt.h
> +++ b/libavutil/opt.h
> @@ -253,6 +253,17 @@ enum AVOptionType{
> #endif
> AV_OPT_TYPE_BOOL,
> AV_OPT_TYPE_CHLAYOUT,
> +
> + /**
> + * May be combined with another regular option type to declare an array
> + * option.
> + *
> + * For array options, @ref AVOption.offset should refer to a pointer
> + * corresponding to the option type. The pointer should be immediately
> + * followed by an unsigned int that will store the number of elements in the
> + * array.
> + */
> + AV_OPT_TYPE_FLAG_ARRAY = (1 << 16),
> };
>
> /**
> @@ -298,6 +309,46 @@ enum AVOptionType{
> */
> #define AV_OPT_FLAG_CHILD_CONSTS (1 << 18)
>
> +/**
> + * Must be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options.
> + */
> +typedef struct AVOptionArrayDef {
> + /**
> + * Must be set to sizeof(AVOptionArrayDef), in order to allow extending this
> + * struct without breaking ABI.
> + */
> + size_t sizeof_self;
> +
> + /**
> + * Native access only.
> + *
> + * Default value of the option, as would be serialized by av_opt_get() (i.e.
> + * using the value of sep as the separator).
> + */
> + const char *def;
> +
> + /**
> + * Minimum number of elements in the array. When this field is non-zero, def
> + * must be non-NULL and contain at least this number of elements.
> + */
> + unsigned size_min;
> + /**
> + * Maximum number of elements in the array, 0 when unlimited.
> + */
> + unsigned size_max;
> +
> + /**
> + * Separator between array elements in string representations of this
> + * option, used by av_opt_set() and av_opt_get(). It must be a printable
> + * ASCII character, excluding alphanumeric and the backslash. A comma is
> + * used when sep=0.
> + *
> + * The separator and the backslash must be backslash-escaped in order to
> + * appear in string representations of the option value.
> + */
> + uint8_t sep;
> +} AVOptionArrayDef;
> +
> /**
> * AVOption
> */
> @@ -320,8 +371,7 @@ typedef struct AVOption {
> enum AVOptionType type;
>
> /**
> - * Native access only.
> - *
> + * Native access only, except when documented otherwise.
> * the default value for scalar options
> */
> union {
> @@ -330,6 +380,14 @@ typedef struct AVOption {
> const char *str;
> /* TODO those are unused now */
> AVRational q;
> +
> + /**
> + * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL.
This contradicts with the documentation of AVOptionArrayDef above, because
there you write that default_val MUST be set.
> + *
> + * Foreign access to some members allowed, as noted in AVOptionArrayDef
> + * documentation.
> + */
> + const AVOptionArrayDef *arr;
> } default_val;
Regards,
Marton
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options
2024-03-04 21:32 ` [FFmpeg-devel] [PATCH " Marton Balint
@ 2024-03-05 9:50 ` Anton Khirnov
0 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 9:50 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Marton Balint (2024-03-04 22:32:21)
> > @@ -330,6 +380,14 @@ typedef struct AVOption {
> > const char *str;
> > /* TODO those are unused now */
> > AVRational q;
> > +
> > + /**
> > + * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL.
>
> This contradicts with the documentation of AVOptionArrayDef above, because
> there you write that default_val MUST be set.
Changed 'must' to 'may' locally. It is optional, and one of the test
entries does not set it.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (4 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 06/29] lavu/opt: add array options Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 14:05 ` Derek Buitenhuis
` (2 more replies)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 08/29] avcodec: add internal side data wrappers Anton Khirnov
` (22 subsequent siblings)
28 siblings, 3 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
This and the following commits fix #10857
---
doc/APIchanges | 3 +++
libavcodec/avcodec.h | 20 ++++++++++++++++++++
libavcodec/decode.c | 36 ++++++++++++++++++++++++++++++++++++
libavcodec/options_table.h | 13 +++++++++++++
4 files changed, 72 insertions(+)
diff --git a/doc/APIchanges b/doc/APIchanges
index 3209614ed6..5d8585d8ba 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
API changes, most recent first:
+2024-02-xx - xxxxxxxxxx - lavc 60.xx.100 - avcodec.h
+ Add AVCodecContext.[nb_]side_data_prefer_global.
+
2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 43859251cc..307a3e99db 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2120,6 +2120,26 @@ typedef struct AVCodecContext {
* an error.
*/
int64_t frame_num;
+
+ /**
+ * Decoding only. May be set by the caller before avcodec_open2() to an
+ * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder
+ * afterwards.
+ *
+ * By default, when some side data type is present both in global
+ * user-supplied coded_side_data and inside the coded bitstream, avcodec
+ * will propagate the latter to the decoded frame.
+ *
+ * This array contains a list of AVPacketSideDataType for which this
+ * preference should be switched, i.e. avcodec will prefer global side data
+ * over those in stored in the bytestream. It may also contain a single -1,
+ * in which case the preference is switched for all side data types.
+ */
+ int *side_data_prefer_global;
+ /**
+ * Number of entries in side_data_prefer_global.
+ */
+ unsigned nb_side_data_prefer_global;
} AVCodecContext;
/**
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 7c67b18bc4..5c80ef9cd0 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -60,6 +60,12 @@ typedef struct DecodeContext {
* The caller has submitted a NULL packet on input.
*/
int draining_started;
+
+ /**
+ * Bitmask indicating for which side data types we prefer global
+ * side data over per-packet.
+ */
+ uint64_t side_data_pref_mask;
} DecodeContext;
static DecodeContext *decode_ctx(AVCodecInternal *avci)
@@ -1744,6 +1750,7 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
int ff_decode_preinit(AVCodecContext *avctx)
{
AVCodecInternal *avci = avctx->internal;
+ DecodeContext *dc = decode_ctx(avci);
int ret = 0;
/* if the decoder init function was already called previously,
@@ -1804,6 +1811,35 @@ int ff_decode_preinit(AVCodecContext *avctx)
avctx->export_side_data |= AV_CODEC_EXPORT_DATA_MVS;
}
+ if (avctx->nb_side_data_prefer_global == 1 &&
+ avctx->side_data_prefer_global[0] == -1)
+ dc->side_data_pref_mask = ~0ULL;
+ else {
+ for (unsigned i = 0; i < avctx->nb_side_data_prefer_global; i++) {
+ int val = avctx->side_data_prefer_global[i];
+
+ if (val < 0 || val >= AV_PKT_DATA_NB) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid side data type: %d\n", val);
+ return AVERROR(EINVAL);
+ }
+
+ for (unsigned j = 0; j < FF_ARRAY_ELEMS(sd_global_map); j++) {
+ if (sd_global_map[j].packet == val) {
+ val = sd_global_map[j].frame;
+
+ // this code will need to be changed when we have more than
+ // 64 frame side data types
+ if (val >= 64) {
+ av_log(avctx, AV_LOG_ERROR, "Side data type too big\n");
+ return AVERROR_BUG;
+ }
+
+ dc->side_data_pref_mask |= 1ULL << val;
+ }
+ }
+ }
+ }
+
avci->in_pkt = av_packet_alloc();
avci->last_pkt_props = av_packet_alloc();
if (!avci->in_pkt || !avci->last_pkt_props)
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index ac32d8928a..3ff03d1cf0 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -42,6 +42,8 @@
#define D AV_OPT_FLAG_DECODING_PARAM
#define CC AV_OPT_FLAG_CHILD_CONSTS
+#define AR AV_OPT_TYPE_FLAG_ARRAY
+
#define AV_CODEC_DEFAULT_BITRATE 200*1000
static const AVOption avcodec_options[] = {
@@ -405,6 +407,17 @@ static const AVOption avcodec_options[] = {
{"unsafe_output", "allow potentially unsafe hwaccel frame output that might require special care to process successfully", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_UNSAFE_OUTPUT }, INT_MIN, INT_MAX, V | D, .unit = "hwaccel_flags"},
{"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D },
{"discard_damaged_percentage", "Percentage of damaged samples to discard a frame", OFFSET(discard_damaged_percentage), AV_OPT_TYPE_INT, {.i64 = 95 }, 0, 100, V|D },
+{"side_data_prefer_global", "Comma-separated list of side data types for which global headers are preferred over frame-level data",
+ OFFSET(side_data_prefer_global), AV_OPT_TYPE_INT | AR, .min = -1, .max = INT_MAX, .flags = V|A|S|D, .unit = "side_data_pkt" },
+ {"replaygain", .default_val.i64 = AV_PKT_DATA_REPLAYGAIN, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"displaymatrix", .default_val.i64 = AV_PKT_DATA_DISPLAYMATRIX, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"spherical", .default_val.i64 = AV_PKT_DATA_SPHERICAL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"stereo3d", .default_val.i64 = AV_PKT_DATA_STEREO3D, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"audio_service_type", .default_val.i64 = AV_PKT_DATA_AUDIO_SERVICE_TYPE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"dynamic_hdr10_plus", .default_val.i64 = AV_PKT_DATA_DYNAMIC_HDR10_PLUS, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
{NULL},
};
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference Anton Khirnov
@ 2024-03-04 14:05 ` Derek Buitenhuis
2024-03-05 9:57 ` Anton Khirnov
2024-03-05 12:30 ` James Almer
2024-03-06 13:58 ` [FFmpeg-devel] [PATCH v2 " Anton Khirnov
2 siblings, 1 reply; 57+ messages in thread
From: Derek Buitenhuis @ 2024-03-04 14:05 UTC (permalink / raw)
To: ffmpeg-devel
On 3/4/2024 1:06 PM, Anton Khirnov wrote:
> + /**
> + * Decoding only. May be set by the caller before avcodec_open2() to an
> + * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder
> + * afterwards.
> + *
> + * By default, when some side data type is present both in global
> + * user-supplied coded_side_data and inside the coded bitstream, avcodec
> + * will propagate the latter to the decoded frame.
> + *
> + * This array contains a list of AVPacketSideDataType for which this
> + * preference should be switched, i.e. avcodec will prefer global side data
> + * over those in stored in the bytestream. It may also contain a single -1,
> + * in which case the preference is switched for all side data types.
> + */
> + int *side_data_prefer_global;
My only comment is that it would be nice to include some text about what the practical
application of this option is, rather than just technical details. Something like:
This can be useful, when, for example, input contains data in both the container
and bitstream.
- Derek
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-04 14:05 ` Derek Buitenhuis
@ 2024-03-05 9:57 ` Anton Khirnov
0 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 9:57 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Derek Buitenhuis (2024-03-04 15:05:29)
> On 3/4/2024 1:06 PM, Anton Khirnov wrote:
> > + /**
> > + * Decoding only. May be set by the caller before avcodec_open2() to an
> > + * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder
> > + * afterwards.
> > + *
> > + * By default, when some side data type is present both in global
> > + * user-supplied coded_side_data and inside the coded bitstream, avcodec
> > + * will propagate the latter to the decoded frame.
> > + *
> > + * This array contains a list of AVPacketSideDataType for which this
> > + * preference should be switched, i.e. avcodec will prefer global side data
> > + * over those in stored in the bytestream. It may also contain a single -1,
> > + * in which case the preference is switched for all side data types.
> > + */
> > + int *side_data_prefer_global;
>
> My only comment is that it would be nice to include some text about what the practical
> application of this option is, rather than just technical details. Something like:
>
> This can be useful, when, for example, input contains data in both the container
> and bitstream.
Added text to that effect locally.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference Anton Khirnov
2024-03-04 14:05 ` Derek Buitenhuis
@ 2024-03-05 12:30 ` James Almer
2024-03-05 14:29 ` Anton Khirnov
2024-03-06 13:58 ` [FFmpeg-devel] [PATCH v2 " Anton Khirnov
2 siblings, 1 reply; 57+ messages in thread
From: James Almer @ 2024-03-05 12:30 UTC (permalink / raw)
To: ffmpeg-devel
On 3/4/2024 10:06 AM, Anton Khirnov wrote:
> This and the following commits fix #10857
> ---
> doc/APIchanges | 3 +++
> libavcodec/avcodec.h | 20 ++++++++++++++++++++
> libavcodec/decode.c | 36 ++++++++++++++++++++++++++++++++++++
> libavcodec/options_table.h | 13 +++++++++++++
> 4 files changed, 72 insertions(+)
>
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 3209614ed6..5d8585d8ba 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
>
> API changes, most recent first:
>
> +2024-02-xx - xxxxxxxxxx - lavc 60.xx.100 - avcodec.h
> + Add AVCodecContext.[nb_]side_data_prefer_global.
> +
> 2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
> Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 43859251cc..307a3e99db 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -2120,6 +2120,26 @@ typedef struct AVCodecContext {
> * an error.
> */
> int64_t frame_num;
> +
> + /**
> + * Decoding only. May be set by the caller before avcodec_open2() to an
> + * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder
> + * afterwards.
> + *
> + * By default, when some side data type is present both in global
> + * user-supplied coded_side_data and inside the coded bitstream, avcodec
> + * will propagate the latter to the decoded frame.
> + *
> + * This array contains a list of AVPacketSideDataType for which this
> + * preference should be switched, i.e. avcodec will prefer global side data
> + * over those in stored in the bytestream. It may also contain a single -1,
> + * in which case the preference is switched for all side data types.
> + */
> + int *side_data_prefer_global;
> + /**
> + * Number of entries in side_data_prefer_global.
> + */
> + unsigned nb_side_data_prefer_global;
> } AVCodecContext;
>
> /**
> diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> index 7c67b18bc4..5c80ef9cd0 100644
> --- a/libavcodec/decode.c
> +++ b/libavcodec/decode.c
> @@ -60,6 +60,12 @@ typedef struct DecodeContext {
> * The caller has submitted a NULL packet on input.
> */
> int draining_started;
> +
> + /**
> + * Bitmask indicating for which side data types we prefer global
> + * side data over per-packet.
> + */
> + uint64_t side_data_pref_mask;
> } DecodeContext;
>
> static DecodeContext *decode_ctx(AVCodecInternal *avci)
> @@ -1744,6 +1750,7 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
> int ff_decode_preinit(AVCodecContext *avctx)
> {
> AVCodecInternal *avci = avctx->internal;
> + DecodeContext *dc = decode_ctx(avci);
> int ret = 0;
>
> /* if the decoder init function was already called previously,
> @@ -1804,6 +1811,35 @@ int ff_decode_preinit(AVCodecContext *avctx)
> avctx->export_side_data |= AV_CODEC_EXPORT_DATA_MVS;
> }
>
> + if (avctx->nb_side_data_prefer_global == 1 &&
> + avctx->side_data_prefer_global[0] == -1)
> + dc->side_data_pref_mask = ~0ULL;
> + else {
> + for (unsigned i = 0; i < avctx->nb_side_data_prefer_global; i++) {
> + int val = avctx->side_data_prefer_global[i];
> +
> + if (val < 0 || val >= AV_PKT_DATA_NB) {
> + av_log(avctx, AV_LOG_ERROR, "Invalid side data type: %d\n", val);
> + return AVERROR(EINVAL);
> + }
> +
> + for (unsigned j = 0; j < FF_ARRAY_ELEMS(sd_global_map); j++) {
> + if (sd_global_map[j].packet == val) {
> + val = sd_global_map[j].frame;
> +
> + // this code will need to be changed when we have more than
> + // 64 frame side data types
> + if (val >= 64) {
> + av_log(avctx, AV_LOG_ERROR, "Side data type too big\n");
> + return AVERROR_BUG;
> + }
> +
> + dc->side_data_pref_mask |= 1ULL << val;
> + }
> + }
> + }
> + }
> +
> avci->in_pkt = av_packet_alloc();
> avci->last_pkt_props = av_packet_alloc();
> if (!avci->in_pkt || !avci->last_pkt_props)
> diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
> index ac32d8928a..3ff03d1cf0 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -42,6 +42,8 @@
> #define D AV_OPT_FLAG_DECODING_PARAM
> #define CC AV_OPT_FLAG_CHILD_CONSTS
>
> +#define AR AV_OPT_TYPE_FLAG_ARRAY
> +
> #define AV_CODEC_DEFAULT_BITRATE 200*1000
>
> static const AVOption avcodec_options[] = {
> @@ -405,6 +407,17 @@ static const AVOption avcodec_options[] = {
> {"unsafe_output", "allow potentially unsafe hwaccel frame output that might require special care to process successfully", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_UNSAFE_OUTPUT }, INT_MIN, INT_MAX, V | D, .unit = "hwaccel_flags"},
> {"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D },
> {"discard_damaged_percentage", "Percentage of damaged samples to discard a frame", OFFSET(discard_damaged_percentage), AV_OPT_TYPE_INT, {.i64 = 95 }, 0, 100, V|D },
> +{"side_data_prefer_global", "Comma-separated list of side data types for which global headers are preferred over frame-level data",
> + OFFSET(side_data_prefer_global), AV_OPT_TYPE_INT | AR, .min = -1, .max = INT_MAX, .flags = V|A|S|D, .unit = "side_data_pkt" },
> + {"replaygain", .default_val.i64 = AV_PKT_DATA_REPLAYGAIN, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"displaymatrix", .default_val.i64 = AV_PKT_DATA_DISPLAYMATRIX, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"spherical", .default_val.i64 = AV_PKT_DATA_SPHERICAL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"stereo3d", .default_val.i64 = AV_PKT_DATA_STEREO3D, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"audio_service_type", .default_val.i64 = AV_PKT_DATA_AUDIO_SERVICE_TYPE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> + {"dynamic_hdr10_plus", .default_val.i64 = AV_PKT_DATA_DYNAMIC_HDR10_PLUS, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
This one packet/frame level only, not global. Is this option meant to
also choose which one of those to use?
> {NULL},
> };
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-05 12:30 ` James Almer
@ 2024-03-05 14:29 ` Anton Khirnov
2024-03-05 14:35 ` James Almer
0 siblings, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 14:29 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting James Almer (2024-03-05 13:30:58)
> > + {"dynamic_hdr10_plus", .default_val.i64 = AV_PKT_DATA_DYNAMIC_HDR10_PLUS, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
>
> This one packet/frame level only, not global.
It is in sd_global_map
> Is this option meant to also choose which one of those to use?
???
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-05 14:29 ` Anton Khirnov
@ 2024-03-05 14:35 ` James Almer
2024-03-05 14:54 ` Anton Khirnov
0 siblings, 1 reply; 57+ messages in thread
From: James Almer @ 2024-03-05 14:35 UTC (permalink / raw)
To: ffmpeg-devel
On 3/5/2024 11:29 AM, Anton Khirnov wrote:
> Quoting James Almer (2024-03-05 13:30:58)
>>> + {"dynamic_hdr10_plus", .default_val.i64 = AV_PKT_DATA_DYNAMIC_HDR10_PLUS, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
>>
>> This one packet/frame level only, not global.
>
> It is in sd_global_map
Then that's a mistake, and I'm probably he culprit. HDR10+ is per frame
metadata. Static HDR metadata are mastering_display and ccl.
>
>> Is this option meant to also choose which one of those to use?
>
> ???
You can have packet side data at the container level that corresponds to
the same thinga per frame side data at the bitstream level does. In
HDR10+ case, Matroska may have it in block additional, and then afaik it
could be present in the hevc bitstream.
One of them should have priority, or the user could be given the choice.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-05 14:35 ` James Almer
@ 2024-03-05 14:54 ` Anton Khirnov
2024-03-05 15:07 ` James Almer
0 siblings, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 14:54 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting James Almer (2024-03-05 15:35:02)
> On 3/5/2024 11:29 AM, Anton Khirnov wrote:
> > Quoting James Almer (2024-03-05 13:30:58)
> >>> + {"dynamic_hdr10_plus", .default_val.i64 = AV_PKT_DATA_DYNAMIC_HDR10_PLUS, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
> >>
> >> This one packet/frame level only, not global.
> >
> > It is in sd_global_map
>
> Then that's a mistake, and I'm probably he culprit. HDR10+ is per frame
> metadata. Static HDR metadata are mastering_display and ccl.
Ok, dropped from the options table locally.
>
> >
> >> Is this option meant to also choose which one of those to use?
> >
> > ???
>
> You can have packet side data at the container level that corresponds to
> the same thinga per frame side data at the bitstream level does. In
> HDR10+ case, Matroska may have it in block additional, and then afaik it
> could be present in the hevc bitstream.
> One of them should have priority, or the user could be given the choice.
Right, I've thought about this a bit, but then couldn't find any side
data types that some container could export per-packet AND could also be
present in the bitstream.
One possible solution is to rename the option to something like
side_data_prefer_external (better names welcome), and have it switch
between user-supplied (i.e. global or per-packet) and in-bitstream side
data.
This adds an ambiguity for the hypothetical case where some side data
exists as global and per-packet - then I'd say lavc should default to
per-packet and leave the other case to the caller (should be very rare,
possibly could be handled with a bitstream filter).
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-05 14:54 ` Anton Khirnov
@ 2024-03-05 15:07 ` James Almer
2024-03-05 15:19 ` Anton Khirnov
0 siblings, 1 reply; 57+ messages in thread
From: James Almer @ 2024-03-05 15:07 UTC (permalink / raw)
To: ffmpeg-devel
On 3/5/2024 11:54 AM, Anton Khirnov wrote:
> Quoting James Almer (2024-03-05 15:35:02)
>> On 3/5/2024 11:29 AM, Anton Khirnov wrote:
>>> Quoting James Almer (2024-03-05 13:30:58)
>>>>> + {"dynamic_hdr10_plus", .default_val.i64 = AV_PKT_DATA_DYNAMIC_HDR10_PLUS, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
>>>>
>>>> This one packet/frame level only, not global.
>>>
>>> It is in sd_global_map
>>
>> Then that's a mistake, and I'm probably he culprit. HDR10+ is per frame
>> metadata. Static HDR metadata are mastering_display and ccl.
>
> Ok, dropped from the options table locally.
>
>>
>>>
>>>> Is this option meant to also choose which one of those to use?
>>>
>>> ???
>>
>> You can have packet side data at the container level that corresponds to
>> the same thinga per frame side data at the bitstream level does. In
>> HDR10+ case, Matroska may have it in block additional, and then afaik it
>> could be present in the hevc bitstream.
>> One of them should have priority, or the user could be given the choice.
>
> Right, I've thought about this a bit, but then couldn't find any side
> data types that some container could export per-packet AND could also be
> present in the bitstream.
Aside from HDR10+, I'm sure this scenario can also happen with closed
captions.
>
> One possible solution is to rename the option to something like
> side_data_prefer_external (better names welcome), and have it switch
> between user-supplied (i.e. global or per-packet) and in-bitstream side
> data.
>
> This adds an ambiguity for the hypothetical case where some side data
> exists as global and per-packet - then I'd say lavc should default to
> per-packet and leave the other case to the caller (should be very rare,
> possibly could be handled with a bitstream filter).
If a given side data type at the container level were to be duplicated
in the header (global) and per packet, then IMO the packet must have
priority, given it's the container overriding its own parameters.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference
2024-03-05 15:07 ` James Almer
@ 2024-03-05 15:19 ` Anton Khirnov
0 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 15:19 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting James Almer (2024-03-05 16:07:05)
> >
> > One possible solution is to rename the option to something like
> > side_data_prefer_external (better names welcome), and have it switch
> > between user-supplied (i.e. global or per-packet) and in-bitstream side
> > data.
> >
> > This adds an ambiguity for the hypothetical case where some side data
> > exists as global and per-packet - then I'd say lavc should default to
> > per-packet and leave the other case to the caller (should be very rare,
> > possibly could be handled with a bitstream filter).
>
> If a given side data type at the container level were to be duplicated
> in the header (global) and per packet, then IMO the packet must have
> priority, given it's the container overriding its own parameters.
I'd be careful with 'must' - in a sane world that's what would be
reasonable, but I can definitely imagine a situation where you'd want
the reverse. But I do agree that it's not something lavc needs to
handle.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH v2 07/29] lavc: add a decoder option for configuring side data preference
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference Anton Khirnov
2024-03-04 14:05 ` Derek Buitenhuis
2024-03-05 12:30 ` James Almer
@ 2024-03-06 13:58 ` Anton Khirnov
2 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-06 13:58 UTC (permalink / raw)
To: ffmpeg-devel
This and the following commits fix #10857
---
Renamed the option to 'side_data_prefer_packet', as preferred by James
and Derek on IRC.
---
doc/APIchanges | 3 +++
libavcodec/avcodec.h | 31 +++++++++++++++++++++++++++++++
libavcodec/decode.c | 36 ++++++++++++++++++++++++++++++++++++
libavcodec/options_table.h | 12 ++++++++++++
4 files changed, 82 insertions(+)
diff --git a/doc/APIchanges b/doc/APIchanges
index a0898dd701..83b24e5b37 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
API changes, most recent first:
+2024-02-xx - xxxxxxxxxx - lavc 60.xx.100 - avcodec.h
+ Add AVCodecContext.[nb_]side_data_prefer_packet.
+
2024-02-xx - xxxxxxxxxx - lavu 58.xx.100 - opt.h
Add AV_OPT_TYPE_FLAG_ARRAY and AVOptionArrayDef.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 8aa1356b8c..2e61bef19b 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2120,6 +2120,37 @@ typedef struct AVCodecContext {
* an error.
*/
int64_t frame_num;
+
+ /**
+ * Decoding only. May be set by the caller before avcodec_open2() to an
+ * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder
+ * afterwards.
+ *
+ * Side data attached to decoded frames may come from several sources:
+ * - coded_side_data, which the decoder will for certain types translate
+ * from packet-type to frame-type and attach to frames;
+ * - user-supplied side data attached to an AVPacket sent for decoding (same
+ * considerations as above);
+ * - extracted from the coded bytestream.
+ * The first two cases are supplied by the caller and typically come from a
+ * container.
+ *
+ * This array configures decoder behaviour in case when some side data type
+ * is present both in the coded bytestream and in the user-supplied side
+ * data. In all cases, at most one instance of each side data type will be
+ * attached to output frames. By default it will be the bytestream side
+ * data. Adding a AVPacketSideDataType value to this array will flip the
+ * preference for this type, thus making the decoder prefer user-supplied
+ * side data over bytestream.
+ *
+ * The array may also contain a single -1, in which case the preference is
+ * switched for all side data types.
+ */
+ int *side_data_prefer_packet;
+ /**
+ * Number of entries in side_data_prefer_packet.
+ */
+ unsigned nb_side_data_prefer_packet;
} AVCodecContext;
/**
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index cd483528c5..29fe840db7 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -60,6 +60,12 @@ typedef struct DecodeContext {
* The caller has submitted a NULL packet on input.
*/
int draining_started;
+
+ /**
+ * Bitmask indicating for which side data types we prefer user-supplied
+ * (global or attached to packets) side data over bytestream.
+ */
+ uint64_t side_data_pref_mask;
} DecodeContext;
static DecodeContext *decode_ctx(AVCodecInternal *avci)
@@ -1744,6 +1750,7 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
int ff_decode_preinit(AVCodecContext *avctx)
{
AVCodecInternal *avci = avctx->internal;
+ DecodeContext *dc = decode_ctx(avci);
int ret = 0;
/* if the decoder init function was already called previously,
@@ -1804,6 +1811,35 @@ int ff_decode_preinit(AVCodecContext *avctx)
avctx->export_side_data |= AV_CODEC_EXPORT_DATA_MVS;
}
+ if (avctx->nb_side_data_prefer_packet == 1 &&
+ avctx->side_data_prefer_packet[0] == -1)
+ dc->side_data_pref_mask = ~0ULL;
+ else {
+ for (unsigned i = 0; i < avctx->nb_side_data_prefer_packet; i++) {
+ int val = avctx->side_data_prefer_packet[i];
+
+ if (val < 0 || val >= AV_PKT_DATA_NB) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid side data type: %d\n", val);
+ return AVERROR(EINVAL);
+ }
+
+ for (unsigned j = 0; j < FF_ARRAY_ELEMS(sd_global_map); j++) {
+ if (sd_global_map[j].packet == val) {
+ val = sd_global_map[j].frame;
+
+ // this code will need to be changed when we have more than
+ // 64 frame side data types
+ if (val >= 64) {
+ av_log(avctx, AV_LOG_ERROR, "Side data type too big\n");
+ return AVERROR_BUG;
+ }
+
+ dc->side_data_pref_mask |= 1ULL << val;
+ }
+ }
+ }
+ }
+
avci->in_pkt = av_packet_alloc();
avci->last_pkt_props = av_packet_alloc();
if (!avci->in_pkt || !avci->last_pkt_props)
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index ac32d8928a..55088bd2e4 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -42,6 +42,8 @@
#define D AV_OPT_FLAG_DECODING_PARAM
#define CC AV_OPT_FLAG_CHILD_CONSTS
+#define AR AV_OPT_TYPE_FLAG_ARRAY
+
#define AV_CODEC_DEFAULT_BITRATE 200*1000
static const AVOption avcodec_options[] = {
@@ -405,6 +407,16 @@ static const AVOption avcodec_options[] = {
{"unsafe_output", "allow potentially unsafe hwaccel frame output that might require special care to process successfully", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_UNSAFE_OUTPUT }, INT_MIN, INT_MAX, V | D, .unit = "hwaccel_flags"},
{"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D },
{"discard_damaged_percentage", "Percentage of damaged samples to discard a frame", OFFSET(discard_damaged_percentage), AV_OPT_TYPE_INT, {.i64 = 95 }, 0, 100, V|D },
+{"side_data_prefer_packet", "Comma-separated list of side data types for which user-supplied (container) data is preferred over coded bytestream",
+ OFFSET(side_data_prefer_packet), AV_OPT_TYPE_INT | AR, .min = -1, .max = INT_MAX, .flags = V|A|S|D, .unit = "side_data_pkt" },
+ {"replaygain", .default_val.i64 = AV_PKT_DATA_REPLAYGAIN, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"displaymatrix", .default_val.i64 = AV_PKT_DATA_DISPLAYMATRIX, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"spherical", .default_val.i64 = AV_PKT_DATA_SPHERICAL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"stereo3d", .default_val.i64 = AV_PKT_DATA_STEREO3D, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"audio_service_type", .default_val.i64 = AV_PKT_DATA_AUDIO_SERVICE_TYPE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"mastering_display_metadata", .default_val.i64 = AV_PKT_DATA_MASTERING_DISPLAY_METADATA, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"content_light_level", .default_val.i64 = AV_PKT_DATA_CONTENT_LIGHT_LEVEL, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
+ {"icc_profile", .default_val.i64 = AV_PKT_DATA_ICC_PROFILE, .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = "side_data_pkt" },
{NULL},
};
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 08/29] avcodec: add internal side data wrappers
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (5 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 07/29] lavc: add a decoder option for configuring side data preference Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 09/29] lavc: add content light/mastering display " Anton Khirnov
` (21 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
The signature of these wrappers is more complicated due to a need to
distinguish between "failed allocating side data" and "side data was
already present".
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/decode.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
libavcodec/decode.h | 20 ++++++++++++++
2 files changed, 86 insertions(+)
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 5c80ef9cd0..f3e8b72be7 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1857,6 +1857,72 @@ int ff_decode_preinit(AVCodecContext *avctx)
return 0;
}
+/**
+ * Check side data preference and clear existing side data from frame
+ * if needed.
+ *
+ * @retval 0 side data of this type can be added to frame
+ * @retval 1 side data of this type should not be added to frame
+ */
+static int side_data_pref(const AVCodecContext *avctx, AVFrame *frame,
+ enum AVFrameSideDataType type)
+{
+ DecodeContext *dc = decode_ctx(avctx->internal);
+
+ // Note: could be skipped for `type` without corresponding packet sd
+ if (av_frame_get_side_data(frame, type)) {
+ if (dc->side_data_pref_mask & (1ULL << type))
+ return 1;
+ av_frame_remove_side_data(frame, type);
+ }
+
+ return 0;
+}
+
+
+int ff_frame_new_side_data(const AVCodecContext *avctx, AVFrame *frame,
+ enum AVFrameSideDataType type, size_t size,
+ AVFrameSideData **psd)
+{
+ AVFrameSideData *sd;
+
+ if (side_data_pref(avctx, frame, type)) {
+ if (psd)
+ *psd = NULL;
+ return 0;
+ }
+
+ sd = av_frame_new_side_data(frame, type, size);
+ if (psd)
+ *psd = sd;
+
+ return sd ? 0 : AVERROR(ENOMEM);
+}
+
+int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx,
+ AVFrame *frame, enum AVFrameSideDataType type,
+ AVBufferRef **buf, AVFrameSideData **psd)
+{
+ AVFrameSideData *sd = NULL;
+ int ret = 0;
+
+ if (side_data_pref(avctx, frame, type))
+ goto finish;
+
+ sd = av_frame_new_side_data_from_buf(frame, type, *buf);
+ if (sd)
+ *buf = NULL;
+ else
+ ret = AVERROR(ENOMEM);
+
+finish:
+ av_buffer_unref(buf);
+ if (psd)
+ *psd = sd;
+
+ return ret;
+}
+
int ff_copy_palette(void *dst, const AVPacket *src, void *logctx)
{
size_t size;
diff --git a/libavcodec/decode.h b/libavcodec/decode.h
index daf1a67444..b269b5a43b 100644
--- a/libavcodec/decode.h
+++ b/libavcodec/decode.h
@@ -155,4 +155,24 @@ int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void **hwaccel_picture_pr
const AVPacketSideData *ff_get_coded_side_data(const AVCodecContext *avctx,
enum AVPacketSideDataType type);
+/**
+ * Wrapper around av_frame_new_side_data, which rejects side data overridden by
+ * the demuxer. Returns 0 on success, and a negative error code otherwise.
+ * If successful and sd is not NULL, *sd may either contain a pointer to the new
+ * side data, or NULL in case the side data was already present.
+ */
+int ff_frame_new_side_data(const AVCodecContext *avctx, AVFrame *frame,
+ enum AVFrameSideDataType type, size_t size,
+ AVFrameSideData **sd);
+
+/**
+ * Similar to `ff_frame_new_side_data`, but using an existing buffer ref.
+ *
+ * *buf is ALWAYS consumed by this function and NULL written in its place, even
+ * on failure.
+ */
+int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx,
+ AVFrame *frame, enum AVFrameSideDataType type,
+ AVBufferRef **buf, AVFrameSideData **sd);
+
#endif /* AVCODEC_DECODE_H */
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 09/29] lavc: add content light/mastering display side data wrappers
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (6 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 08/29] avcodec: add internal side data wrappers Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 10/29] avcodec/av1dec: respect side data preference Anton Khirnov
` (20 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
---
libavcodec/decode.c | 25 +++++++++++++++++++++++++
libavcodec/decode.h | 21 +++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index f3e8b72be7..105c9c5c39 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -35,6 +35,7 @@
#include "libavutil/hwcontext.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
+#include "libavutil/mastering_display_metadata.h"
#include "avcodec.h"
#include "avcodec_internal.h"
@@ -1923,6 +1924,30 @@ finish:
return ret;
}
+int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame,
+ AVMasteringDisplayMetadata **mdm)
+{
+ if (side_data_pref(avctx, frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)) {
+ *mdm = NULL;
+ return 0;
+ }
+
+ *mdm = av_mastering_display_metadata_create_side_data(frame);
+ return *mdm ? 0 : AVERROR(ENOMEM);
+}
+
+int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame,
+ AVContentLightMetadata **clm)
+{
+ if (side_data_pref(avctx, frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL)) {
+ *clm = NULL;
+ return 0;
+ }
+
+ *clm = av_content_light_metadata_create_side_data(frame);
+ return *clm ? 0 : AVERROR(ENOMEM);
+}
+
int ff_copy_palette(void *dst, const AVPacket *src, void *logctx)
{
size_t size;
diff --git a/libavcodec/decode.h b/libavcodec/decode.h
index b269b5a43b..4ffbd9db8e 100644
--- a/libavcodec/decode.h
+++ b/libavcodec/decode.h
@@ -175,4 +175,25 @@ int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx,
AVFrame *frame, enum AVFrameSideDataType type,
AVBufferRef **buf, AVFrameSideData **sd);
+struct AVMasteringDisplayMetadata;
+struct AVContentLightMetadata;
+
+/**
+ * Wrapper around av_mastering_display_metadata_create_side_data(), which
+ * rejects side data overridden by the demuxer. Returns 0 on success, and a
+ * negative error code otherwise. If successful, *mdm may either be a pointer to
+ * the new side data, or NULL in case the side data was already present.
+ */
+int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame,
+ struct AVMasteringDisplayMetadata **mdm);
+
+/**
+ * Wrapper around av_content_light_metadata_create_side_data(), which
+ * rejects side data overridden by the demuxer. Returns 0 on success, and a
+ * negative error code otherwise. If successful, *clm may either be a pointer to
+ * the new side data, or NULL in case the side data was already present.
+ */
+int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame,
+ struct AVContentLightMetadata **clm);
+
#endif /* AVCODEC_DECODE_H */
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 10/29] avcodec/av1dec: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (7 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 09/29] lavc: add content light/mastering display " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 11/29] avcodec/cri: " Anton Khirnov
` (19 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
---
libavcodec/av1dec.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 704b9d6298..af80ee0b17 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -954,8 +954,9 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame,
if (!ret)
break;
- if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_A53_CC, buf))
- av_buffer_unref(&buf);
+ ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_A53_CC, &buf, NULL);
+ if (ret < 0)
+ return ret;
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
break;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 11/29] avcodec/cri: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (8 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 10/29] avcodec/av1dec: respect side data preference Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 12/29] avcodec/h264_slice: " Anton Khirnov
` (18 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
This function was already ignoring OOM errors.
---
libavcodec/cri.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libavcodec/cri.c b/libavcodec/cri.c
index c4eb468610..990e52ac99 100644
--- a/libavcodec/cri.c
+++ b/libavcodec/cri.c
@@ -398,8 +398,8 @@ skip:
}
if (hflip || vflip) {
- rotation = av_frame_new_side_data(p, AV_FRAME_DATA_DISPLAYMATRIX,
- sizeof(int32_t) * 9);
+ ff_frame_new_side_data(avctx, p, AV_FRAME_DATA_DISPLAYMATRIX,
+ sizeof(int32_t) * 9, &rotation);
if (rotation) {
av_display_rotation_set((int32_t *)rotation->data, 0.f);
av_display_matrix_flip((int32_t *)rotation->data, hflip, vflip);
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 12/29] avcodec/h264_slice: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (9 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 11/29] avcodec/cri: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 13/29] lavc/hevcdec: pass an actual codec context to ff_h2645_sei_to_frame() Anton Khirnov
` (17 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
If the time code side data is overridden by the packet level, we also
make sure not to update `out->metadata` to a mismatched timecode.
---
libavcodec/h264_slice.c | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 8464a0b34c..f30ff33188 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -1257,26 +1257,27 @@ static int h264_export_frame_props(H264Context *h)
if (h->sei.picture_timing.timecode_cnt > 0) {
uint32_t *tc_sd;
char tcbuf[AV_TIMECODE_STR_SIZE];
+ AVFrameSideData *tcside;
+ ret = ff_frame_new_side_data(h->avctx, out, AV_FRAME_DATA_S12M_TIMECODE,
+ sizeof(uint32_t)*4, &tcside);
+ if (ret < 0)
+ return ret;
- AVFrameSideData *tcside = av_frame_new_side_data(out,
- AV_FRAME_DATA_S12M_TIMECODE,
- sizeof(uint32_t)*4);
- if (!tcside)
- return AVERROR(ENOMEM);
+ if (tcside) {
+ tc_sd = (uint32_t*)tcside->data;
+ tc_sd[0] = h->sei.picture_timing.timecode_cnt;
- tc_sd = (uint32_t*)tcside->data;
- tc_sd[0] = h->sei.picture_timing.timecode_cnt;
+ for (int i = 0; i < tc_sd[0]; i++) {
+ int drop = h->sei.picture_timing.timecode[i].dropframe;
+ int hh = h->sei.picture_timing.timecode[i].hours;
+ int mm = h->sei.picture_timing.timecode[i].minutes;
+ int ss = h->sei.picture_timing.timecode[i].seconds;
+ int ff = h->sei.picture_timing.timecode[i].frame;
- for (int i = 0; i < tc_sd[0]; i++) {
- int drop = h->sei.picture_timing.timecode[i].dropframe;
- int hh = h->sei.picture_timing.timecode[i].hours;
- int mm = h->sei.picture_timing.timecode[i].minutes;
- int ss = h->sei.picture_timing.timecode[i].seconds;
- int ff = h->sei.picture_timing.timecode[i].frame;
-
- tc_sd[i + 1] = av_timecode_get_smpte(h->avctx->framerate, drop, hh, mm, ss, ff);
- av_timecode_make_smpte_tc_string2(tcbuf, h->avctx->framerate, tc_sd[i + 1], 0, 0);
- av_dict_set(&out->metadata, "timecode", tcbuf, 0);
+ tc_sd[i + 1] = av_timecode_get_smpte(h->avctx->framerate, drop, hh, mm, ss, ff);
+ av_timecode_make_smpte_tc_string2(tcbuf, h->avctx->framerate, tc_sd[i + 1], 0, 0);
+ av_dict_set(&out->metadata, "timecode", tcbuf, 0);
+ }
}
h->sei.picture_timing.timecode_cnt = 0;
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 13/29] lavc/hevcdec: pass an actual codec context to ff_h2645_sei_to_frame()
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (10 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 12/29] avcodec/h264_slice: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 14/29] avcodec/hevcdec: respect side data preference Anton Khirnov
` (16 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
Needed by following commit.
---
libavcodec/hevcdec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index b5311ae510..17c6a9212f 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -2778,7 +2778,7 @@ static int set_side_data(HEVCContext *s)
s->sei.common.content_light.present--;
}
- ret = ff_h2645_sei_to_frame(out, &s->sei.common, AV_CODEC_ID_HEVC, NULL,
+ ret = ff_h2645_sei_to_frame(out, &s->sei.common, AV_CODEC_ID_HEVC, s->avctx,
&s->ps.sps->vui.common,
s->ps.sps->bit_depth, s->ps.sps->bit_depth_chroma,
s->ref->poc /* no poc_offset in HEVC */);
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 14/29] avcodec/hevcdec: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (11 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 13/29] lavc/hevcdec: pass an actual codec context to ff_h2645_sei_to_frame() Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 15/29] avcodec/libjxldec: " Anton Khirnov
` (15 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
If the time code side data is overridden by the packet level, we also
make sure not to update `out->metadata` to a mismatched timecode.
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/hevcdec.c | 40 +++++++++++++++++++++-------------------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 17c6a9212f..76aa6b4588 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -2788,24 +2788,27 @@ static int set_side_data(HEVCContext *s)
if (s->sei.timecode.present) {
uint32_t *tc_sd;
char tcbuf[AV_TIMECODE_STR_SIZE];
- AVFrameSideData *tcside = av_frame_new_side_data(out, AV_FRAME_DATA_S12M_TIMECODE,
- sizeof(uint32_t) * 4);
- if (!tcside)
- return AVERROR(ENOMEM);
+ AVFrameSideData *tcside;
+ ret = ff_frame_new_side_data(s->avctx, out, AV_FRAME_DATA_S12M_TIMECODE,
+ sizeof(uint32_t) * 4, &tcside);
+ if (ret < 0)
+ return ret;
- tc_sd = (uint32_t*)tcside->data;
- tc_sd[0] = s->sei.timecode.num_clock_ts;
+ if (tcside) {
+ tc_sd = (uint32_t*)tcside->data;
+ tc_sd[0] = s->sei.timecode.num_clock_ts;
- for (int i = 0; i < tc_sd[0]; i++) {
- int drop = s->sei.timecode.cnt_dropped_flag[i];
- int hh = s->sei.timecode.hours_value[i];
- int mm = s->sei.timecode.minutes_value[i];
- int ss = s->sei.timecode.seconds_value[i];
- int ff = s->sei.timecode.n_frames[i];
+ for (int i = 0; i < tc_sd[0]; i++) {
+ int drop = s->sei.timecode.cnt_dropped_flag[i];
+ int hh = s->sei.timecode.hours_value[i];
+ int mm = s->sei.timecode.minutes_value[i];
+ int ss = s->sei.timecode.seconds_value[i];
+ int ff = s->sei.timecode.n_frames[i];
- tc_sd[i + 1] = av_timecode_get_smpte(s->avctx->framerate, drop, hh, mm, ss, ff);
- av_timecode_make_smpte_tc_string2(tcbuf, s->avctx->framerate, tc_sd[i + 1], 0, 0);
- av_dict_set(&out->metadata, "timecode", tcbuf, 0);
+ tc_sd[i + 1] = av_timecode_get_smpte(s->avctx->framerate, drop, hh, mm, ss, ff);
+ av_timecode_make_smpte_tc_string2(tcbuf, s->avctx->framerate, tc_sd[i + 1], 0, 0);
+ av_dict_set(&out->metadata, "timecode", tcbuf, 0);
+ }
}
s->sei.timecode.num_clock_ts = 0;
@@ -2816,10 +2819,9 @@ static int set_side_data(HEVCContext *s)
if (!info_ref)
return AVERROR(ENOMEM);
- if (!av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_DYNAMIC_HDR_PLUS, info_ref)) {
- av_buffer_unref(&info_ref);
- return AVERROR(ENOMEM);
- }
+ ret = ff_frame_new_side_data_from_buf(s->avctx, out, AV_FRAME_DATA_DYNAMIC_HDR_PLUS, &info_ref, NULL);
+ if (ret < 0)
+ return ret;
}
if (s->rpu_buf) {
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 15/29] avcodec/libjxldec: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (12 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 14/29] avcodec/hevcdec: respect side data preference Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 16/29] avcodec/mjpegdec: " Anton Khirnov
` (14 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
Also fixes a memory leak where the side data was previously not properly
cleaned up on OOM.
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/libjxldec.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c
index b830eee784..d57a27418f 100644
--- a/libavcodec/libjxldec.c
+++ b/libavcodec/libjxldec.c
@@ -483,11 +483,9 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame)
/* full image is one frame, even if animated */
av_log(avctx, AV_LOG_DEBUG, "FULL_IMAGE event emitted\n");
if (ctx->iccp) {
- AVFrameSideData *sd = av_frame_new_side_data_from_buf(ctx->frame, AV_FRAME_DATA_ICC_PROFILE, ctx->iccp);
- if (!sd)
- return AVERROR(ENOMEM);
- /* ownership is transfered, and it is not ref-ed */
- ctx->iccp = NULL;
+ ret = ff_frame_new_side_data_from_buf(avctx, ctx->frame, AV_FRAME_DATA_ICC_PROFILE, &ctx->iccp, NULL);
+ if (ret < 0)
+ return ret;
}
if (ctx->basic_info.have_animation) {
ctx->frame->pts = av_rescale_q(ctx->accumulated_pts, ctx->anim_timebase, avctx->pkt_timebase);
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 16/29] avcodec/mjpegdec: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (13 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 15/29] avcodec/libjxldec: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 17/29] avcodec/mpeg12dec: " Anton Khirnov
` (13 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
---
libavcodec/mjpegdec.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 81f724d230..43b36d0a8f 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -2840,16 +2840,18 @@ the_end:
for (i = 0; i < s->iccnum; i++)
total_size += s->iccentries[i].length;
- sd = av_frame_new_side_data(frame, AV_FRAME_DATA_ICC_PROFILE, total_size);
- if (!sd) {
+ ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_ICC_PROFILE, total_size, &sd);
+ if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate frame side data\n");
- return AVERROR(ENOMEM);
+ return ret;
}
- /* Reassemble the parts, which are now in-order. */
- for (i = 0; i < s->iccnum; i++) {
- memcpy(sd->data + offset, s->iccentries[i].data, s->iccentries[i].length);
- offset += s->iccentries[i].length;
+ if (sd) {
+ /* Reassemble the parts, which are now in-order. */
+ for (i = 0; i < s->iccnum; i++) {
+ memcpy(sd->data + offset, s->iccentries[i].data, s->iccentries[i].length);
+ offset += s->iccentries[i].length;
+ }
}
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 17/29] avcodec/mpeg12dec: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (14 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 16/29] avcodec/mjpegdec: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 18/29] avcodec/pngdec: " Anton Khirnov
` (12 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
We only need to consider side data types that may possibly come from the
packet.
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/mpeg12dec.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index d07eed8744..3a2f17e508 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -1306,20 +1306,20 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
}
}
- pan_scan = av_frame_new_side_data(s->current_picture_ptr->f,
- AV_FRAME_DATA_PANSCAN,
- sizeof(s1->pan_scan));
- if (!pan_scan)
- return AVERROR(ENOMEM);
- memcpy(pan_scan->data, &s1->pan_scan, sizeof(s1->pan_scan));
+ ret = ff_frame_new_side_data(s->avctx, s->current_picture_ptr->f,
+ AV_FRAME_DATA_PANSCAN, sizeof(s1->pan_scan),
+ &pan_scan);
+ if (ret < 0)
+ return ret;
+ if (pan_scan)
+ memcpy(pan_scan->data, &s1->pan_scan, sizeof(s1->pan_scan));
if (s1->a53_buf_ref) {
- AVFrameSideData *sd = av_frame_new_side_data_from_buf(
- s->current_picture_ptr->f, AV_FRAME_DATA_A53_CC,
- s1->a53_buf_ref);
- if (!sd)
- av_buffer_unref(&s1->a53_buf_ref);
- s1->a53_buf_ref = NULL;
+ ret = ff_frame_new_side_data_from_buf(
+ s->avctx, s->current_picture_ptr->f, AV_FRAME_DATA_A53_CC,
+ &s1->a53_buf_ref, NULL);
+ if (ret < 0)
+ return ret;
}
if (s1->has_stereo3d) {
@@ -1332,13 +1332,13 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
}
if (s1->has_afd) {
- AVFrameSideData *sd =
- av_frame_new_side_data(s->current_picture_ptr->f,
- AV_FRAME_DATA_AFD, 1);
- if (!sd)
- return AVERROR(ENOMEM);
-
- *sd->data = s1->afd;
+ AVFrameSideData *sd;
+ ret = ff_frame_new_side_data(s->avctx, s->current_picture_ptr->f,
+ AV_FRAME_DATA_AFD, 1, &sd);
+ if (ret < 0)
+ return ret;
+ if (sd)
+ *sd->data = s1->afd;
s1->has_afd = 0;
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 18/29] avcodec/pngdec: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (15 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 17/29] avcodec/mpeg12dec: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 19/29] avcodec/tiff: " Anton Khirnov
` (11 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
---
libavcodec/pngdec.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 026da30c25..8f409c74b8 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -660,6 +660,7 @@ static int decode_phys_chunk(AVCodecContext *avctx, PNGDecContext *s,
static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame)
{
PNGDecContext *s = avctx->priv_data;
+ int ret;
if (s->have_cicp) {
if (s->cicp_primaries >= AVCOL_PRI_NB)
@@ -678,11 +679,15 @@ static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame)
avctx->color_range = frame->color_range = AVCOL_RANGE_UNSPECIFIED;
}
} else if (s->iccp_data) {
- AVFrameSideData *sd = av_frame_new_side_data(frame, AV_FRAME_DATA_ICC_PROFILE, s->iccp_data_len);
- if (!sd)
- return AVERROR(ENOMEM);
- memcpy(sd->data, s->iccp_data, s->iccp_data_len);
- av_dict_set(&sd->metadata, "name", s->iccp_name, 0);
+ AVFrameSideData *sd;
+ ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_ICC_PROFILE,
+ s->iccp_data_len, &sd);
+ if (ret < 0)
+ return ret;
+ if (sd) {
+ memcpy(sd->data, s->iccp_data, s->iccp_data_len);
+ av_dict_set(&sd->metadata, "name", s->iccp_name, 0);
+ }
} else if (s->have_srgb) {
avctx->color_primaries = frame->color_primaries = AVCOL_PRI_BT709;
avctx->color_trc = frame->color_trc = AVCOL_TRC_IEC61966_2_1;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 19/29] avcodec/tiff: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (16 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 18/29] avcodec/pngdec: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 20/29] avcodec/webp: " Anton Khirnov
` (10 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
---
libavcodec/tiff.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
index 71cb703821..cb4d378753 100644
--- a/libavcodec/tiff.c
+++ b/libavcodec/tiff.c
@@ -1706,11 +1706,11 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
if (bytestream2_get_bytes_left(&gb_temp) < count)
return AVERROR_INVALIDDATA;
- sd = av_frame_new_side_data(frame, AV_FRAME_DATA_ICC_PROFILE, count);
- if (!sd)
- return AVERROR(ENOMEM);
-
- bytestream2_get_bufferu(&gb_temp, sd->data, count);
+ ret = ff_frame_new_side_data(s->avctx, frame, AV_FRAME_DATA_ICC_PROFILE, count, &sd);
+ if (ret < 0)
+ return ret;
+ if (sd)
+ bytestream2_get_bufferu(&gb_temp, sd->data, count);
break;
case TIFF_ARTIST:
ADD_METADATA(count, "artist", NULL);
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 20/29] avcodec/webp: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (17 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 19/29] avcodec/tiff: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 21/29] avcodec/libdav1d: " Anton Khirnov
` (9 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
---
libavcodec/webp.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 54b3fde6dc..9308ea2b69 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -1500,11 +1500,16 @@ exif_end:
"VP8X header\n");
s->has_iccp = 1;
- sd = av_frame_new_side_data(p, AV_FRAME_DATA_ICC_PROFILE, chunk_size);
- if (!sd)
- return AVERROR(ENOMEM);
- bytestream2_get_buffer(&gb, sd->data, chunk_size);
+ ret = ff_frame_new_side_data(avctx, p, AV_FRAME_DATA_ICC_PROFILE, chunk_size, &sd);
+ if (ret < 0)
+ return ret;
+
+ if (sd) {
+ bytestream2_get_buffer(&gb, sd->data, chunk_size);
+ } else {
+ bytestream2_skip(&gb, chunk_size);
+ }
break;
}
case MKTAG('A', 'N', 'I', 'M'):
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 21/29] avcodec/libdav1d: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (18 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 20/29] avcodec/webp: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 22/29] avcodec/dpx: " Anton Khirnov
` (8 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/libdav1d.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 78a5c63bf4..3714137ed0 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -561,8 +561,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (!res)
break;
- if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_A53_CC, buf))
- av_buffer_unref(&buf);
+ res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf, NULL);
+ if (res < 0)
+ goto fail;
c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
break;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 22/29] avcodec/dpx: respect side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (19 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 21/29] avcodec/libdav1d: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data Anton Khirnov
` (7 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
If the time code side data is overridden by the packet level, we also
make sure not to update `p->metadata` to a mismatched timecode.
---
libavcodec/dpx.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/libavcodec/dpx.c b/libavcodec/dpx.c
index 31e4a3f82c..80616d98a2 100644
--- a/libavcodec/dpx.c
+++ b/libavcodec/dpx.c
@@ -287,19 +287,21 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
tc = av_bswap32(read32(&buf, endian));
if (i != 0xFFFFFFFF) {
- AVFrameSideData *tcside =
- av_frame_new_side_data(p, AV_FRAME_DATA_S12M_TIMECODE,
- sizeof(uint32_t) * 4);
- if (!tcside)
- return AVERROR(ENOMEM);
+ AVFrameSideData *tcside;
+ ret = ff_frame_new_side_data(avctx, p, AV_FRAME_DATA_S12M_TIMECODE,
+ sizeof(uint32_t) * 4, &tcside);
+ if (ret < 0)
+ return ret;
- tc_sd = (uint32_t*)tcside->data;
- tc_sd[0] = 1;
- tc_sd[1] = tc;
+ if (tcside) {
+ tc_sd = (uint32_t*)tcside->data;
+ tc_sd[0] = 1;
+ tc_sd[1] = tc;
- av_timecode_make_smpte_tc_string2(tcbuf, avctx->framerate,
- tc_sd[1], 0, 0);
- av_dict_set(&p->metadata, "timecode", tcbuf, 0);
+ av_timecode_make_smpte_tc_string2(tcbuf, avctx->framerate,
+ tc_sd[1], 0, 0);
+ av_dict_set(&p->metadata, "timecode", tcbuf, 0);
+ }
}
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (20 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 22/29] avcodec/dpx: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:36 ` Andreas Rheinhardt
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 24/29] avcodec/h2645_sei: use ff_frame_new_side_data_from_buf Anton Khirnov
` (6 subsequent siblings)
28 siblings, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
For consistency, even though this cannot be overriden at the packet
level.
---
libavcodec/mpeg12dec.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index 3a2f17e508..aa116336dd 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -2531,15 +2531,17 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture,
if (s->timecode_frame_start != -1 && *got_output) {
char tcbuf[AV_TIMECODE_STR_SIZE];
- AVFrameSideData *tcside = av_frame_new_side_data(picture,
- AV_FRAME_DATA_GOP_TIMECODE,
- sizeof(int64_t));
- if (!tcside)
- return AVERROR(ENOMEM);
- memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
+ AVFrameSideData *tcside;
+ ret = ff_frame_new_side_data(avctx, picture, AV_FRAME_DATA_GOP_TIMECODE,
+ sizeof(int64_t), &tcside);
+ if (ret < 0)
+ return ret;
+ if (tcside) {
+ memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
- av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
- av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
+ av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
+ av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
+ }
s->timecode_frame_start = -1;
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data Anton Khirnov
@ 2024-03-04 13:36 ` Andreas Rheinhardt
2024-03-05 10:00 ` Anton Khirnov
0 siblings, 1 reply; 57+ messages in thread
From: Andreas Rheinhardt @ 2024-03-04 13:36 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> From: Niklas Haas <git@haasn.dev>
>
> For consistency, even though this cannot be overriden at the packet
> level.
> ---
> libavcodec/mpeg12dec.c | 18 ++++++++++--------
> 1 file changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
> index 3a2f17e508..aa116336dd 100644
> --- a/libavcodec/mpeg12dec.c
> +++ b/libavcodec/mpeg12dec.c
> @@ -2531,15 +2531,17 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture,
>
> if (s->timecode_frame_start != -1 && *got_output) {
> char tcbuf[AV_TIMECODE_STR_SIZE];
> - AVFrameSideData *tcside = av_frame_new_side_data(picture,
> - AV_FRAME_DATA_GOP_TIMECODE,
> - sizeof(int64_t));
> - if (!tcside)
> - return AVERROR(ENOMEM);
> - memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
> + AVFrameSideData *tcside;
> + ret = ff_frame_new_side_data(avctx, picture, AV_FRAME_DATA_GOP_TIMECODE,
> + sizeof(int64_t), &tcside);
> + if (ret < 0)
> + return ret;
> + if (tcside) {
> + memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
>
> - av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
> - av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
> + av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
> + av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
> + }
>
> s->timecode_frame_start = -1;
> }
-1 to everything that is only done for consistency.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-04 13:36 ` Andreas Rheinhardt
@ 2024-03-05 10:00 ` Anton Khirnov
2024-03-07 11:19 ` Andreas Rheinhardt
2024-03-07 20:05 ` Niklas Haas
0 siblings, 2 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-05 10:00 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2024-03-04 14:36:09)
> Anton Khirnov:
> > From: Niklas Haas <git@haasn.dev>
> >
> > For consistency, even though this cannot be overriden at the packet
> > level.
> > ---
> > libavcodec/mpeg12dec.c | 18 ++++++++++--------
> > 1 file changed, 10 insertions(+), 8 deletions(-)
> >
> > diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
> > index 3a2f17e508..aa116336dd 100644
> > --- a/libavcodec/mpeg12dec.c
> > +++ b/libavcodec/mpeg12dec.c
> > @@ -2531,15 +2531,17 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture,
> >
> > if (s->timecode_frame_start != -1 && *got_output) {
> > char tcbuf[AV_TIMECODE_STR_SIZE];
> > - AVFrameSideData *tcside = av_frame_new_side_data(picture,
> > - AV_FRAME_DATA_GOP_TIMECODE,
> > - sizeof(int64_t));
> > - if (!tcside)
> > - return AVERROR(ENOMEM);
> > - memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
> > + AVFrameSideData *tcside;
> > + ret = ff_frame_new_side_data(avctx, picture, AV_FRAME_DATA_GOP_TIMECODE,
> > + sizeof(int64_t), &tcside);
> > + if (ret < 0)
> > + return ret;
> > + if (tcside) {
> > + memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
> >
> > - av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
> > - av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
> > + av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
> > + av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
> > + }
> >
> > s->timecode_frame_start = -1;
> > }
>
> -1 to everything that is only done for consistency.
I prefer consistency here, otherwise the decoder authors have to choose
which function to use, and they are often not aware of the precise
implications of thise choice. Better to always use just one function.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-05 10:00 ` Anton Khirnov
@ 2024-03-07 11:19 ` Andreas Rheinhardt
2024-03-07 12:18 ` Anton Khirnov
2024-03-07 20:05 ` Niklas Haas
1 sibling, 1 reply; 57+ messages in thread
From: Andreas Rheinhardt @ 2024-03-07 11:19 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> Quoting Andreas Rheinhardt (2024-03-04 14:36:09)
>> Anton Khirnov:
>>> From: Niklas Haas <git@haasn.dev>
>>>
>>> For consistency, even though this cannot be overriden at the packet
>>> level.
>>> ---
>>> libavcodec/mpeg12dec.c | 18 ++++++++++--------
>>> 1 file changed, 10 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
>>> index 3a2f17e508..aa116336dd 100644
>>> --- a/libavcodec/mpeg12dec.c
>>> +++ b/libavcodec/mpeg12dec.c
>>> @@ -2531,15 +2531,17 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture,
>>>
>>> if (s->timecode_frame_start != -1 && *got_output) {
>>> char tcbuf[AV_TIMECODE_STR_SIZE];
>>> - AVFrameSideData *tcside = av_frame_new_side_data(picture,
>>> - AV_FRAME_DATA_GOP_TIMECODE,
>>> - sizeof(int64_t));
>>> - if (!tcside)
>>> - return AVERROR(ENOMEM);
>>> - memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
>>> + AVFrameSideData *tcside;
>>> + ret = ff_frame_new_side_data(avctx, picture, AV_FRAME_DATA_GOP_TIMECODE,
>>> + sizeof(int64_t), &tcside);
>>> + if (ret < 0)
>>> + return ret;
>>> + if (tcside) {
>>> + memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
>>>
>>> - av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
>>> - av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
>>> + av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
>>> + av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
>>> + }
>>>
>>> s->timecode_frame_start = -1;
>>> }
>>
>> -1 to everything that is only done for consistency.
>
> I prefer consistency here, otherwise the decoder authors have to choose
> which function to use, and they are often not aware of the precise
> implications of thise choice. Better to always use just one function.
>
It adds unnecessary checks and given that internal API is updated more
frequently it is likely to lead to unnecessary further changes lateron.
Furthermore, mjpeg still emits an allocation failure error message
without knowing whether it was really allocation failure.
Finally, if we really believed decoder authors to be that uninformed, we
should remove ff_get_buffer() from decoders altogether and only use the
ff_thread_get_buffer() wrapper. Somehow I don't remember this difference
to ever be a problem.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-07 11:19 ` Andreas Rheinhardt
@ 2024-03-07 12:18 ` Anton Khirnov
2024-03-07 12:25 ` James Almer
0 siblings, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-07 12:18 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2024-03-07 12:19:28)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2024-03-04 14:36:09)
> >> Anton Khirnov:
> >>> From: Niklas Haas <git@haasn.dev>
> >>>
> >>> For consistency, even though this cannot be overriden at the packet
> >>> level.
> >>> ---
> >>> libavcodec/mpeg12dec.c | 18 ++++++++++--------
> >>> 1 file changed, 10 insertions(+), 8 deletions(-)
> >>>
> >>> diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
> >>> index 3a2f17e508..aa116336dd 100644
> >>> --- a/libavcodec/mpeg12dec.c
> >>> +++ b/libavcodec/mpeg12dec.c
> >>> @@ -2531,15 +2531,17 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture,
> >>>
> >>> if (s->timecode_frame_start != -1 && *got_output) {
> >>> char tcbuf[AV_TIMECODE_STR_SIZE];
> >>> - AVFrameSideData *tcside = av_frame_new_side_data(picture,
> >>> - AV_FRAME_DATA_GOP_TIMECODE,
> >>> - sizeof(int64_t));
> >>> - if (!tcside)
> >>> - return AVERROR(ENOMEM);
> >>> - memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
> >>> + AVFrameSideData *tcside;
> >>> + ret = ff_frame_new_side_data(avctx, picture, AV_FRAME_DATA_GOP_TIMECODE,
> >>> + sizeof(int64_t), &tcside);
> >>> + if (ret < 0)
> >>> + return ret;
> >>> + if (tcside) {
> >>> + memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
> >>>
> >>> - av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
> >>> - av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
> >>> + av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
> >>> + av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
> >>> + }
> >>>
> >>> s->timecode_frame_start = -1;
> >>> }
> >>
> >> -1 to everything that is only done for consistency.
> >
> > I prefer consistency here, otherwise the decoder authors have to choose
> > which function to use, and they are often not aware of the precise
> > implications of thise choice. Better to always use just one function.
> >
>
> It adds unnecessary checks and given that internal API is updated more
> frequently it is likely to lead to unnecessary further changes lateron.
> Furthermore, mjpeg still emits an allocation failure error message
> without knowing whether it was really allocation failure.
"Could not allocate frame side data" seems appropriate to me, it really
is what happened, whatever the actual reason is.
> Finally, if we really believed decoder authors to be that uninformed, we
> should remove ff_get_buffer() from decoders altogether and only use the
> ff_thread_get_buffer() wrapper.
I'd be in favor, fewer functions is better.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-07 12:18 ` Anton Khirnov
@ 2024-03-07 12:25 ` James Almer
2024-03-07 12:37 ` Anton Khirnov
0 siblings, 1 reply; 57+ messages in thread
From: James Almer @ 2024-03-07 12:25 UTC (permalink / raw)
To: ffmpeg-devel
On 3/7/2024 9:18 AM, Anton Khirnov wrote:
> Quoting Andreas Rheinhardt (2024-03-07 12:19:28)
>> Anton Khirnov:
>>> Quoting Andreas Rheinhardt (2024-03-04 14:36:09)
>>>> Anton Khirnov:
>>>>> From: Niklas Haas <git@haasn.dev>
>>>>>
>>>>> For consistency, even though this cannot be overriden at the packet
>>>>> level.
>>>>> ---
>>>>> libavcodec/mpeg12dec.c | 18 ++++++++++--------
>>>>> 1 file changed, 10 insertions(+), 8 deletions(-)
>>>>>
>>>>> diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
>>>>> index 3a2f17e508..aa116336dd 100644
>>>>> --- a/libavcodec/mpeg12dec.c
>>>>> +++ b/libavcodec/mpeg12dec.c
>>>>> @@ -2531,15 +2531,17 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture,
>>>>>
>>>>> if (s->timecode_frame_start != -1 && *got_output) {
>>>>> char tcbuf[AV_TIMECODE_STR_SIZE];
>>>>> - AVFrameSideData *tcside = av_frame_new_side_data(picture,
>>>>> - AV_FRAME_DATA_GOP_TIMECODE,
>>>>> - sizeof(int64_t));
>>>>> - if (!tcside)
>>>>> - return AVERROR(ENOMEM);
>>>>> - memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
>>>>> + AVFrameSideData *tcside;
>>>>> + ret = ff_frame_new_side_data(avctx, picture, AV_FRAME_DATA_GOP_TIMECODE,
>>>>> + sizeof(int64_t), &tcside);
>>>>> + if (ret < 0)
>>>>> + return ret;
>>>>> + if (tcside) {
>>>>> + memcpy(tcside->data, &s->timecode_frame_start, sizeof(int64_t));
>>>>>
>>>>> - av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
>>>>> - av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
>>>>> + av_timecode_make_mpeg_tc_string(tcbuf, s->timecode_frame_start);
>>>>> + av_dict_set(&picture->metadata, "timecode", tcbuf, 0);
>>>>> + }
>>>>>
>>>>> s->timecode_frame_start = -1;
>>>>> }
>>>>
>>>> -1 to everything that is only done for consistency.
>>>
>>> I prefer consistency here, otherwise the decoder authors have to choose
>>> which function to use, and they are often not aware of the precise
>>> implications of thise choice. Better to always use just one function.
>>>
>>
>> It adds unnecessary checks and given that internal API is updated more
>> frequently it is likely to lead to unnecessary further changes lateron.
>> Furthermore, mjpeg still emits an allocation failure error message
>> without knowing whether it was really allocation failure.
>
> "Could not allocate frame side data" seems appropriate to me, it really
> is what happened, whatever the actual reason is.
>
>> Finally, if we really believed decoder authors to be that uninformed, we
>> should remove ff_get_buffer() from decoders altogether and only use the
>> ff_thread_get_buffer() wrapper.
>
> I'd be in favor, fewer functions is better.
I wouldn't. It adds an extra layer of abstraction for no real gain. And
the name in this case is very specific and self explanatory in how it's
different from the alternative.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-07 12:25 ` James Almer
@ 2024-03-07 12:37 ` Anton Khirnov
0 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-07 12:37 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting James Almer (2024-03-07 13:25:07)
> I wouldn't. It adds an extra layer of abstraction for no real gain.
The gain is simpler API. What's the gain in forcing decoder authors to
call a different function to accomplish the same task, just because
frame threading happens to be used.
> And the name in this case is very specific and self explanatory in how
> it's different from the alternative.
From decoder POV it's not different at all, it does exactly the same
thing.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data
2024-03-05 10:00 ` Anton Khirnov
2024-03-07 11:19 ` Andreas Rheinhardt
@ 2024-03-07 20:05 ` Niklas Haas
1 sibling, 0 replies; 57+ messages in thread
From: Niklas Haas @ 2024-03-07 20:05 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Tue, 05 Mar 2024 11:00:02 +0100 Anton Khirnov <anton@khirnov.net> wrote:
> I prefer consistency here, otherwise the decoder authors have to choose
> which function to use, and they are often not aware of the precise
> implications of thise choice. Better to always use just one function.
Regardless of my personal preference, these (consistency) patches are
strictly optional and do not gain us any functionality. Given that this
is blocking the (by now fairly urgent) 7.0 release, I am in favor of
dropping them if that helps speed the process along by avoiding
unnecessary discussion where it is not of high priority.
> --
> Anton Khirnov
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 24/29] avcodec/h2645_sei: use ff_frame_new_side_data_from_buf
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (21 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 23/29] avcodec/mpeg12dec: use ff_frame_new_side_data Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 25/29] avcodec/snowdec: use ff_frame_new_side_data Anton Khirnov
` (5 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
For consistency, even though this cannot be overriden at the packet
level.
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/h2645_sei.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c
index cb6be0594b..56539608cd 100644
--- a/libavcodec/h2645_sei.c
+++ b/libavcodec/h2645_sei.c
@@ -35,6 +35,7 @@
#include "atsc_a53.h"
#include "avcodec.h"
+#include "decode.h"
#include "dynamic_hdr_vivid.h"
#include "get_bits.h"
#include "golomb.h"
@@ -607,12 +608,11 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei,
H2645SEIUnregistered *unreg = &sei->unregistered;
if (unreg->buf_ref[i]) {
- AVFrameSideData *sd = av_frame_new_side_data_from_buf(frame,
+ int ret = ff_frame_new_side_data_from_buf(avctx, frame,
AV_FRAME_DATA_SEI_UNREGISTERED,
- unreg->buf_ref[i]);
- if (!sd)
- av_buffer_unref(&unreg->buf_ref[i]);
- unreg->buf_ref[i] = NULL;
+ &unreg->buf_ref[i], NULL);
+ if (ret < 0)
+ return ret;
}
}
sei->unregistered.nb_buf_ref = 0;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 25/29] avcodec/snowdec: use ff_frame_new_side_data
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (22 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 24/29] avcodec/h2645_sei: use ff_frame_new_side_data_from_buf Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 26/29] avcodec/mjpegdec: " Anton Khirnov
` (4 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
For consistency, even though this cannot be overriden at the packet
level.
---
libavcodec/snowdec.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c
index 70fbab9a49..97aea748b6 100644
--- a/libavcodec/snowdec.c
+++ b/libavcodec/snowdec.c
@@ -787,11 +787,10 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture,
res = av_frame_ref(picture, s->mconly_picture);
if (res >= 0 && s->avmv_index) {
AVFrameSideData *sd;
-
- sd = av_frame_new_side_data(picture, AV_FRAME_DATA_MOTION_VECTORS, s->avmv_index * sizeof(AVMotionVector));
- if (!sd)
- return AVERROR(ENOMEM);
- memcpy(sd->data, s->avmv, s->avmv_index * sizeof(AVMotionVector));
+ res = ff_frame_new_side_data(s->avctx, picture, AV_FRAME_DATA_MOTION_VECTORS,
+ s->avmv_index * sizeof(AVMotionVector), &sd);
+ if (sd)
+ memcpy(sd->data, s->avmv, s->avmv_index * sizeof(AVMotionVector));
}
if (res < 0)
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 26/29] avcodec/mjpegdec: use ff_frame_new_side_data
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (23 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 25/29] avcodec/snowdec: use ff_frame_new_side_data Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 27/29] avcodec/hevcdec: switch to ff_frame_new_side_data_from_buf Anton Khirnov
` (3 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
For consistency, even though this can't (yet) be overriden at the packet
level.
---
libavcodec/mjpegdec.c | 66 ++++++++++++++++++++++---------------------
1 file changed, 34 insertions(+), 32 deletions(-)
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 43b36d0a8f..4ef565fe2d 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -2865,42 +2865,44 @@ the_end:
if (orientation >= 2 && orientation <= 8) {
int32_t *matrix;
- sd = av_frame_new_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9);
- if (!sd) {
+ ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9, &sd);
+ if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate frame side data\n");
- return AVERROR(ENOMEM);
+ return ret;
}
- matrix = (int32_t *)sd->data;
+ if (sd) {
+ matrix = (int32_t *)sd->data;
- switch (orientation) {
- case 2:
- av_display_rotation_set(matrix, 0.0);
- av_display_matrix_flip(matrix, 1, 0);
- break;
- case 3:
- av_display_rotation_set(matrix, 180.0);
- break;
- case 4:
- av_display_rotation_set(matrix, 180.0);
- av_display_matrix_flip(matrix, 1, 0);
- break;
- case 5:
- av_display_rotation_set(matrix, 90.0);
- av_display_matrix_flip(matrix, 1, 0);
- break;
- case 6:
- av_display_rotation_set(matrix, 90.0);
- break;
- case 7:
- av_display_rotation_set(matrix, -90.0);
- av_display_matrix_flip(matrix, 1, 0);
- break;
- case 8:
- av_display_rotation_set(matrix, -90.0);
- break;
- default:
- av_assert0(0);
+ switch (orientation) {
+ case 2:
+ av_display_rotation_set(matrix, 0.0);
+ av_display_matrix_flip(matrix, 1, 0);
+ break;
+ case 3:
+ av_display_rotation_set(matrix, 180.0);
+ break;
+ case 4:
+ av_display_rotation_set(matrix, 180.0);
+ av_display_matrix_flip(matrix, 1, 0);
+ break;
+ case 5:
+ av_display_rotation_set(matrix, 90.0);
+ av_display_matrix_flip(matrix, 1, 0);
+ break;
+ case 6:
+ av_display_rotation_set(matrix, 90.0);
+ break;
+ case 7:
+ av_display_rotation_set(matrix, -90.0);
+ av_display_matrix_flip(matrix, 1, 0);
+ break;
+ case 8:
+ av_display_rotation_set(matrix, -90.0);
+ break;
+ default:
+ av_assert0(0);
+ }
}
}
}
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 27/29] avcodec/hevcdec: switch to ff_frame_new_side_data_from_buf
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (24 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 26/29] avcodec/mjpegdec: " Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 28/29] lavc/*dec: use side data preference for mastering display/content light metadata Anton Khirnov
` (2 subsequent siblings)
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
From: Niklas Haas <git@haasn.dev>
For consistency, even though this cannot be overriden at the packet
level.
Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
libavcodec/hevcdec.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 76aa6b4588..a6b124dd2a 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -2825,11 +2825,9 @@ static int set_side_data(HEVCContext *s)
}
if (s->rpu_buf) {
- AVFrameSideData *rpu = av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_DOVI_RPU_BUFFER, s->rpu_buf);
- if (!rpu)
- return AVERROR(ENOMEM);
-
- s->rpu_buf = NULL;
+ ret = ff_frame_new_side_data_from_buf(s->avctx, out, AV_FRAME_DATA_DOVI_RPU_BUFFER, &s->rpu_buf, NULL);
+ if (ret < 0)
+ return ret;
}
if ((ret = ff_dovi_attach_side_data(&s->dovi_ctx, out)) < 0)
@@ -2840,10 +2838,9 @@ static int set_side_data(HEVCContext *s)
if (!info_ref)
return AVERROR(ENOMEM);
- if (!av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_DYNAMIC_HDR_VIVID, info_ref)) {
- av_buffer_unref(&info_ref);
- return AVERROR(ENOMEM);
- }
+ ret = ff_frame_new_side_data_from_buf(s->avctx, out, AV_FRAME_DATA_DYNAMIC_HDR_VIVID, &info_ref, NULL);
+ if (ret < 0)
+ return ret;
}
return 0;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 28/29] lavc/*dec: use side data preference for mastering display/content light metadata
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (25 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 27/29] avcodec/hevcdec: switch to ff_frame_new_side_data_from_buf Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 29/29] tests/fate/matroska: add tests for side data preference Anton Khirnov
2024-03-07 9:30 ` [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
---
libavcodec/av1dec.c | 46 +++++++++++---------
libavcodec/h2645_sei.c | 96 +++++++++++++++++++++++-------------------
libavcodec/libdav1d.c | 47 ++++++++++++---------
libavcodec/pngdec.c | 54 ++++++++++++++----------
libavcodec/qsvdec.c | 50 +++++++++++++---------
5 files changed, 165 insertions(+), 128 deletions(-)
diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index af80ee0b17..bbb5634773 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -999,31 +999,39 @@ static int export_metadata(AVCodecContext *avctx, AVFrame *frame)
int ret = 0;
if (s->mdcv) {
- AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame);
- if (!mastering)
- return AVERROR(ENOMEM);
+ AVMasteringDisplayMetadata *mastering;
- for (int i = 0; i < 3; i++) {
- mastering->display_primaries[i][0] = av_make_q(s->mdcv->primary_chromaticity_x[i], 1 << 16);
- mastering->display_primaries[i][1] = av_make_q(s->mdcv->primary_chromaticity_y[i], 1 << 16);
+ ret = ff_decode_mastering_display_new(avctx, frame, &mastering);
+ if (ret < 0)
+ return ret;
+
+ if (mastering) {
+ for (int i = 0; i < 3; i++) {
+ mastering->display_primaries[i][0] = av_make_q(s->mdcv->primary_chromaticity_x[i], 1 << 16);
+ mastering->display_primaries[i][1] = av_make_q(s->mdcv->primary_chromaticity_y[i], 1 << 16);
+ }
+ mastering->white_point[0] = av_make_q(s->mdcv->white_point_chromaticity_x, 1 << 16);
+ mastering->white_point[1] = av_make_q(s->mdcv->white_point_chromaticity_y, 1 << 16);
+
+ mastering->max_luminance = av_make_q(s->mdcv->luminance_max, 1 << 8);
+ mastering->min_luminance = av_make_q(s->mdcv->luminance_min, 1 << 14);
+
+ mastering->has_primaries = 1;
+ mastering->has_luminance = 1;
}
- mastering->white_point[0] = av_make_q(s->mdcv->white_point_chromaticity_x, 1 << 16);
- mastering->white_point[1] = av_make_q(s->mdcv->white_point_chromaticity_y, 1 << 16);
-
- mastering->max_luminance = av_make_q(s->mdcv->luminance_max, 1 << 8);
- mastering->min_luminance = av_make_q(s->mdcv->luminance_min, 1 << 14);
-
- mastering->has_primaries = 1;
- mastering->has_luminance = 1;
}
if (s->cll) {
- AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame);
- if (!light)
- return AVERROR(ENOMEM);
+ AVContentLightMetadata *light;
- light->MaxCLL = s->cll->max_cll;
- light->MaxFALL = s->cll->max_fall;
+ ret = ff_decode_content_light_new(avctx, frame, &light);
+ if (ret < 0)
+ return ret;
+
+ if (light) {
+ light->MaxCLL = s->cll->max_cll;
+ light->MaxFALL = s->cll->max_fall;
+ }
}
while (av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0) {
diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c
index 56539608cd..a9d17cc9fd 100644
--- a/libavcodec/h2645_sei.c
+++ b/libavcodec/h2645_sei.c
@@ -516,6 +516,7 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei,
int seed)
{
H2645SEIFramePacking *fp = &sei->frame_packing;
+ int ret;
if (fp->present &&
is_frame_packing_type_valid(fp->arrangement_type, codec_id) &&
@@ -710,56 +711,63 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei,
const int chroma_den = 50000;
const int luma_den = 10000;
int i;
- AVMasteringDisplayMetadata *metadata =
- av_mastering_display_metadata_create_side_data(frame);
- if (!metadata)
- return AVERROR(ENOMEM);
+ AVMasteringDisplayMetadata *metadata;
- for (i = 0; i < 3; i++) {
- const int j = mapping[i];
- metadata->display_primaries[i][0].num = sei->mastering_display.display_primaries[j][0];
- metadata->display_primaries[i][0].den = chroma_den;
- metadata->display_primaries[i][1].num = sei->mastering_display.display_primaries[j][1];
- metadata->display_primaries[i][1].den = chroma_den;
+ ret = ff_decode_mastering_display_new(avctx, frame, &metadata);
+ if (ret < 0)
+ return ret;
+
+ if (metadata) {
+ for (i = 0; i < 3; i++) {
+ const int j = mapping[i];
+ metadata->display_primaries[i][0].num = sei->mastering_display.display_primaries[j][0];
+ metadata->display_primaries[i][0].den = chroma_den;
+ metadata->display_primaries[i][1].num = sei->mastering_display.display_primaries[j][1];
+ metadata->display_primaries[i][1].den = chroma_den;
+ }
+ metadata->white_point[0].num = sei->mastering_display.white_point[0];
+ metadata->white_point[0].den = chroma_den;
+ metadata->white_point[1].num = sei->mastering_display.white_point[1];
+ metadata->white_point[1].den = chroma_den;
+
+ metadata->max_luminance.num = sei->mastering_display.max_luminance;
+ metadata->max_luminance.den = luma_den;
+ metadata->min_luminance.num = sei->mastering_display.min_luminance;
+ metadata->min_luminance.den = luma_den;
+ metadata->has_luminance = 1;
+ metadata->has_primaries = 1;
+
+ av_log(avctx, AV_LOG_DEBUG, "Mastering Display Metadata:\n");
+ av_log(avctx, AV_LOG_DEBUG,
+ "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f)\n",
+ av_q2d(metadata->display_primaries[0][0]),
+ av_q2d(metadata->display_primaries[0][1]),
+ av_q2d(metadata->display_primaries[1][0]),
+ av_q2d(metadata->display_primaries[1][1]),
+ av_q2d(metadata->display_primaries[2][0]),
+ av_q2d(metadata->display_primaries[2][1]),
+ av_q2d(metadata->white_point[0]), av_q2d(metadata->white_point[1]));
+ av_log(avctx, AV_LOG_DEBUG,
+ "min_luminance=%f, max_luminance=%f\n",
+ av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance));
}
- metadata->white_point[0].num = sei->mastering_display.white_point[0];
- metadata->white_point[0].den = chroma_den;
- metadata->white_point[1].num = sei->mastering_display.white_point[1];
- metadata->white_point[1].den = chroma_den;
-
- metadata->max_luminance.num = sei->mastering_display.max_luminance;
- metadata->max_luminance.den = luma_den;
- metadata->min_luminance.num = sei->mastering_display.min_luminance;
- metadata->min_luminance.den = luma_den;
- metadata->has_luminance = 1;
- metadata->has_primaries = 1;
-
- av_log(avctx, AV_LOG_DEBUG, "Mastering Display Metadata:\n");
- av_log(avctx, AV_LOG_DEBUG,
- "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f)\n",
- av_q2d(metadata->display_primaries[0][0]),
- av_q2d(metadata->display_primaries[0][1]),
- av_q2d(metadata->display_primaries[1][0]),
- av_q2d(metadata->display_primaries[1][1]),
- av_q2d(metadata->display_primaries[2][0]),
- av_q2d(metadata->display_primaries[2][1]),
- av_q2d(metadata->white_point[0]), av_q2d(metadata->white_point[1]));
- av_log(avctx, AV_LOG_DEBUG,
- "min_luminance=%f, max_luminance=%f\n",
- av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance));
}
if (sei->content_light.present) {
- AVContentLightMetadata *metadata =
- av_content_light_metadata_create_side_data(frame);
- if (!metadata)
- return AVERROR(ENOMEM);
- metadata->MaxCLL = sei->content_light.max_content_light_level;
- metadata->MaxFALL = sei->content_light.max_pic_average_light_level;
+ AVContentLightMetadata *metadata;
- av_log(avctx, AV_LOG_DEBUG, "Content Light Level Metadata:\n");
- av_log(avctx, AV_LOG_DEBUG, "MaxCLL=%d, MaxFALL=%d\n",
- metadata->MaxCLL, metadata->MaxFALL);
+ ret = ff_decode_content_light_new(avctx, frame, &metadata);
+ if (ret < 0)
+ return ret;
+
+ if (metadata) {
+ metadata->MaxCLL = sei->content_light.max_content_light_level;
+ metadata->MaxFALL = sei->content_light.max_pic_average_light_level;
+
+ av_log(avctx, AV_LOG_DEBUG, "Content Light Level Metadata:\n");
+ av_log(avctx, AV_LOG_DEBUG, "MaxCLL=%d, MaxFALL=%d\n",
+ metadata->MaxCLL, metadata->MaxFALL);
+ }
}
return 0;
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 3714137ed0..42d3ef00de 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -507,33 +507,38 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
if (p->mastering_display) {
- AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame);
- if (!mastering) {
- res = AVERROR(ENOMEM);
+ AVMasteringDisplayMetadata *mastering;
+
+ res = ff_decode_mastering_display_new(c, frame, &mastering);
+ if (res < 0)
goto fail;
+
+ if (mastering) {
+ for (int i = 0; i < 3; i++) {
+ mastering->display_primaries[i][0] = av_make_q(p->mastering_display->primaries[i][0], 1 << 16);
+ mastering->display_primaries[i][1] = av_make_q(p->mastering_display->primaries[i][1], 1 << 16);
+ }
+ mastering->white_point[0] = av_make_q(p->mastering_display->white_point[0], 1 << 16);
+ mastering->white_point[1] = av_make_q(p->mastering_display->white_point[1], 1 << 16);
+
+ mastering->max_luminance = av_make_q(p->mastering_display->max_luminance, 1 << 8);
+ mastering->min_luminance = av_make_q(p->mastering_display->min_luminance, 1 << 14);
+
+ mastering->has_primaries = 1;
+ mastering->has_luminance = 1;
}
-
- for (int i = 0; i < 3; i++) {
- mastering->display_primaries[i][0] = av_make_q(p->mastering_display->primaries[i][0], 1 << 16);
- mastering->display_primaries[i][1] = av_make_q(p->mastering_display->primaries[i][1], 1 << 16);
- }
- mastering->white_point[0] = av_make_q(p->mastering_display->white_point[0], 1 << 16);
- mastering->white_point[1] = av_make_q(p->mastering_display->white_point[1], 1 << 16);
-
- mastering->max_luminance = av_make_q(p->mastering_display->max_luminance, 1 << 8);
- mastering->min_luminance = av_make_q(p->mastering_display->min_luminance, 1 << 14);
-
- mastering->has_primaries = 1;
- mastering->has_luminance = 1;
}
if (p->content_light) {
- AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame);
- if (!light) {
- res = AVERROR(ENOMEM);
+ AVContentLightMetadata *light;
+
+ res = ff_decode_content_light_new(c, frame, &light);
+ if (res < 0)
goto fail;
+
+ if (light) {
+ light->MaxCLL = p->content_light->max_content_light_level;
+ light->MaxFALL = p->content_light->max_frame_average_light_level;
}
- light->MaxCLL = p->content_light->max_content_light_level;
- light->MaxFALL = p->content_light->max_frame_average_light_level;
}
if (p->itut_t35) {
#if FF_DAV1D_VERSION_AT_LEAST(6,9)
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 8f409c74b8..de50e6a5b6 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -746,33 +746,41 @@ static int populate_avctx_color_fields(AVCodecContext *avctx, AVFrame *frame)
avctx->bits_per_raw_sample = s->significant_bits;
if (s->have_clli) {
- AVContentLightMetadata *clli =
- av_content_light_metadata_create_side_data(frame);
- if (!clli)
- return AVERROR(ENOMEM);
- /*
- * 0.0001 divisor value
- * see: https://www.w3.org/TR/png-3/#cLLi-chunk
- */
- clli->MaxCLL = s->clli_max / 10000;
- clli->MaxFALL = s->clli_avg / 10000;
+ AVContentLightMetadata *clli;
+
+ ret = ff_decode_content_light_new(avctx, frame, &clli);
+ if (ret < 0)
+ return ret;
+
+ if (clli) {
+ /*
+ * 0.0001 divisor value
+ * see: https://www.w3.org/TR/png-3/#cLLi-chunk
+ */
+ clli->MaxCLL = s->clli_max / 10000;
+ clli->MaxFALL = s->clli_avg / 10000;
+ }
}
if (s->have_mdvc) {
- AVMasteringDisplayMetadata *mdvc =
- av_mastering_display_metadata_create_side_data(frame);
- if (!mdvc)
- return AVERROR(ENOMEM);
- mdvc->has_primaries = 1;
- for (int i = 0; i < 3; i++) {
- mdvc->display_primaries[i][0] = av_make_q(s->mdvc_primaries[i][0], 50000);
- mdvc->display_primaries[i][1] = av_make_q(s->mdvc_primaries[i][1], 50000);
+ AVMasteringDisplayMetadata *mdvc;
+
+ ret = ff_decode_mastering_display_new(avctx, frame, &mdvc);
+ if (ret < 0)
+ return ret;
+
+ if (mdvc) {
+ mdvc->has_primaries = 1;
+ for (int i = 0; i < 3; i++) {
+ mdvc->display_primaries[i][0] = av_make_q(s->mdvc_primaries[i][0], 50000);
+ mdvc->display_primaries[i][1] = av_make_q(s->mdvc_primaries[i][1], 50000);
+ }
+ mdvc->white_point[0] = av_make_q(s->mdvc_white_point[0], 50000);
+ mdvc->white_point[1] = av_make_q(s->mdvc_white_point[1], 50000);
+ mdvc->has_luminance = 1;
+ mdvc->max_luminance = av_make_q(s->mdvc_max_lum, 10000);
+ mdvc->min_luminance = av_make_q(s->mdvc_min_lum, 10000);
}
- mdvc->white_point[0] = av_make_q(s->mdvc_white_point[0], 50000);
- mdvc->white_point[1] = av_make_q(s->mdvc_white_point[1], 50000);
- mdvc->has_luminance = 1;
- mdvc->max_luminance = av_make_q(s->mdvc_max_lum, 10000);
- mdvc->min_luminance = av_make_q(s->mdvc_min_lum, 10000);
}
return 0;
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index d688a17c41..4f39f6942a 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -651,42 +651,50 @@ static int qsv_export_film_grain(AVCodecContext *avctx, mfxExtAV1FilmGrainParam
static int qsv_export_hdr_side_data(AVCodecContext *avctx, mfxExtMasteringDisplayColourVolume *mdcv,
mfxExtContentLightLevelInfo *clli, AVFrame *frame)
{
+ int ret;
+
// The SDK re-uses this flag for HDR SEI parsing
if (mdcv->InsertPayloadToggle) {
- AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame);
+ AVMasteringDisplayMetadata *mastering;
const int mapping[3] = {2, 0, 1};
const int chroma_den = 50000;
const int luma_den = 10000;
int i;
- if (!mastering)
- return AVERROR(ENOMEM);
+ ret = ff_decode_mastering_display_new(avctx, frame, &mastering);
+ if (ret < 0)
+ return ret;
- for (i = 0; i < 3; i++) {
- const int j = mapping[i];
- mastering->display_primaries[i][0] = av_make_q(mdcv->DisplayPrimariesX[j], chroma_den);
- mastering->display_primaries[i][1] = av_make_q(mdcv->DisplayPrimariesY[j], chroma_den);
+ if (mastering) {
+ for (i = 0; i < 3; i++) {
+ const int j = mapping[i];
+ mastering->display_primaries[i][0] = av_make_q(mdcv->DisplayPrimariesX[j], chroma_den);
+ mastering->display_primaries[i][1] = av_make_q(mdcv->DisplayPrimariesY[j], chroma_den);
+ }
+
+ mastering->white_point[0] = av_make_q(mdcv->WhitePointX, chroma_den);
+ mastering->white_point[1] = av_make_q(mdcv->WhitePointY, chroma_den);
+
+ mastering->max_luminance = av_make_q(mdcv->MaxDisplayMasteringLuminance, luma_den);
+ mastering->min_luminance = av_make_q(mdcv->MinDisplayMasteringLuminance, luma_den);
+
+ mastering->has_luminance = 1;
+ mastering->has_primaries = 1;
}
-
- mastering->white_point[0] = av_make_q(mdcv->WhitePointX, chroma_den);
- mastering->white_point[1] = av_make_q(mdcv->WhitePointY, chroma_den);
-
- mastering->max_luminance = av_make_q(mdcv->MaxDisplayMasteringLuminance, luma_den);
- mastering->min_luminance = av_make_q(mdcv->MinDisplayMasteringLuminance, luma_den);
-
- mastering->has_luminance = 1;
- mastering->has_primaries = 1;
}
// The SDK re-uses this flag for HDR SEI parsing
if (clli->InsertPayloadToggle) {
- AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame);
+ AVContentLightMetadata *light;
- if (!light)
- return AVERROR(ENOMEM);
+ ret = ff_decode_content_light_new(avctx, frame, &light);
+ if (ret < 0)
+ return ret;
- light->MaxCLL = clli->MaxContentLightLevel;
- light->MaxFALL = clli->MaxPicAverageLightLevel;
+ if (light) {
+ light->MaxCLL = clli->MaxContentLightLevel;
+ light->MaxFALL = clli->MaxPicAverageLightLevel;
+ }
}
return 0;
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 29/29] tests/fate/matroska: add tests for side data preference
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (26 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 28/29] lavc/*dec: use side data preference for mastering display/content light metadata Anton Khirnov
@ 2024-03-04 13:06 ` Anton Khirnov
2024-03-07 23:42 ` Andreas Rheinhardt
2024-03-07 9:30 ` [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
28 siblings, 1 reply; 57+ messages in thread
From: Anton Khirnov @ 2024-03-04 13:06 UTC (permalink / raw)
To: ffmpeg-devel
Cf. #10857
---
tests/fate/matroska.mak | 6 +
tests/ref/fate/matroska-side-data-pref-codec | 255 ++++++++++++++++++
tests/ref/fate/matroska-side-data-pref-global | 255 ++++++++++++++++++
3 files changed, 516 insertions(+)
create mode 100644 tests/ref/fate/matroska-side-data-pref-codec
create mode 100644 tests/ref/fate/matroska-side-data-pref-global
diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak
index 9ab747184a..e9433ce730 100644
--- a/tests/fate/matroska.mak
+++ b/tests/fate/matroska.mak
@@ -264,6 +264,12 @@ FATE_MATROSKA_FFMPEG_FFPROBE-$(call REMUX, MATROSKA, VP9_PARSER) \
+= fate-matroska-hdr10-plus-remux
fate-matroska-hdr10-plus-remux: CMD = transcode webm $(TARGET_SAMPLES)/mkv/hdr10_plus_vp9_sample.webm matroska "-map 0 -c:v copy" "-map 0 -c:v copy" "-show_packets"
+fate-matroska-side-data-pref-codec: CMD = run ffprobe$(PROGSSUF)$(EXESUF) $(TARGET_SAMPLES)/mkv/hdr10tags-both.mkv \
+ -show_streams -show_frames -show_entries stream=stream_side_data:frame=frame_side_data_list
+fate-matroska-side-data-pref-global: CMD = run ffprobe$(PROGSSUF)$(EXESUF) $(TARGET_SAMPLES)/mkv/hdr10tags-both.mkv \
+ -show_streams -show_frames -show_entries stream=stream_side_data:frame=frame_side_data_list -side_data_prefer_global mastering_display_metadata,content_light_level
+FATE_MATROSKA_FFPROBE-$(call ALLYES MATROSKA_DEMUXER HEVC_DECODER) += fate-matroska-side-data-pref-codec fate-matroska-side-data-pref-global
+
FATE_SAMPLES_AVCONV += $(FATE_MATROSKA-yes)
FATE_SAMPLES_FFPROBE += $(FATE_MATROSKA_FFPROBE-yes)
FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_MATROSKA_FFMPEG_FFPROBE-yes)
diff --git a/tests/ref/fate/matroska-side-data-pref-codec b/tests/ref/fate/matroska-side-data-pref-codec
new file mode 100644
index 0000000000..d27134d0c9
--- /dev/null
+++ b/tests/ref/fate/matroska-side-data-pref-codec
@@ -0,0 +1,255 @@
+[FRAME]
+[SIDE_DATA]
+side_data_type=H.26[45] User Data Unregistered SEI message
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[STREAM]
+DISPOSITION:default=1
+DISPOSITION:dub=0
+DISPOSITION:original=0
+DISPOSITION:comment=0
+DISPOSITION:lyrics=0
+DISPOSITION:karaoke=0
+DISPOSITION:forced=0
+DISPOSITION:hearing_impaired=0
+DISPOSITION:visual_impaired=0
+DISPOSITION:clean_effects=0
+DISPOSITION:attached_pic=0
+DISPOSITION:timed_thumbnails=0
+DISPOSITION:non_diegetic=0
+DISPOSITION:captions=0
+DISPOSITION:descriptions=0
+DISPOSITION:metadata=0
+DISPOSITION:dependent=0
+DISPOSITION:still_image=0
+TAG:BPS=216040
+TAG:BPS-eng=216040
+TAG:DURATION=00:00:00.400000000
+TAG:DURATION-eng=00:00:00.400000000
+TAG:NUMBER_OF_FRAMES=10
+TAG:NUMBER_OF_FRAMES-eng=10
+TAG:NUMBER_OF_BYTES=10802
+TAG:NUMBER_OF_BYTES-eng=10802
+TAG:_STATISTICS_WRITING_APP=mkvmerge v9.0.1 ('Mask Machine') 64bit
+TAG:_STATISTICS_WRITING_APP-eng=mkvmerge v9.0.1 ('Mask Machine') 64bit
+TAG:_STATISTICS_WRITING_DATE_UTC=2019-02-14 12:53:10
+TAG:_STATISTICS_WRITING_DATE_UTC-eng=2019-02-14 12:53:10
+TAG:_STATISTICS_TAGS=BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
+TAG:_STATISTICS_TAGS-eng=BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[/STREAM]
diff --git a/tests/ref/fate/matroska-side-data-pref-global b/tests/ref/fate/matroska-side-data-pref-global
new file mode 100644
index 0000000000..4ff0c2d9db
--- /dev/null
+++ b/tests/ref/fate/matroska-side-data-pref-global
@@ -0,0 +1,255 @@
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=H.26[45] User Data Unregistered SEI message
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[STREAM]
+DISPOSITION:default=1
+DISPOSITION:dub=0
+DISPOSITION:original=0
+DISPOSITION:comment=0
+DISPOSITION:lyrics=0
+DISPOSITION:karaoke=0
+DISPOSITION:forced=0
+DISPOSITION:hearing_impaired=0
+DISPOSITION:visual_impaired=0
+DISPOSITION:clean_effects=0
+DISPOSITION:attached_pic=0
+DISPOSITION:timed_thumbnails=0
+DISPOSITION:non_diegetic=0
+DISPOSITION:captions=0
+DISPOSITION:descriptions=0
+DISPOSITION:metadata=0
+DISPOSITION:dependent=0
+DISPOSITION:still_image=0
+TAG:BPS=216040
+TAG:BPS-eng=216040
+TAG:DURATION=00:00:00.400000000
+TAG:DURATION-eng=00:00:00.400000000
+TAG:NUMBER_OF_FRAMES=10
+TAG:NUMBER_OF_FRAMES-eng=10
+TAG:NUMBER_OF_BYTES=10802
+TAG:NUMBER_OF_BYTES-eng=10802
+TAG:_STATISTICS_WRITING_APP=mkvmerge v9.0.1 ('Mask Machine') 64bit
+TAG:_STATISTICS_WRITING_APP-eng=mkvmerge v9.0.1 ('Mask Machine') 64bit
+TAG:_STATISTICS_WRITING_DATE_UTC=2019-02-14 12:53:10
+TAG:_STATISTICS_WRITING_DATE_UTC-eng=2019-02-14 12:53:10
+TAG:_STATISTICS_TAGS=BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
+TAG:_STATISTICS_TAGS-eng=BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[/STREAM]
--
2.43.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* [FFmpeg-devel] [PATCH 29/29] tests/fate/matroska: add tests for side data preference
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 29/29] tests/fate/matroska: add tests for side data preference Anton Khirnov
@ 2024-03-07 23:42 ` Andreas Rheinhardt
0 siblings, 0 replies; 57+ messages in thread
From: Andreas Rheinhardt @ 2024-03-07 23:42 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Anton Khirnov
From: Anton Khirnov <anton@khirnov.net>
Cf. #10857
---
Updated in light of the updated sample.
tests/fate/matroska.mak | 6 +
tests/ref/fate/matroska-side-data-pref-codec | 348 ++++++++++++++++++
tests/ref/fate/matroska-side-data-pref-global | 348 ++++++++++++++++++
3 files changed, 702 insertions(+)
create mode 100644 tests/ref/fate/matroska-side-data-pref-codec
create mode 100644 tests/ref/fate/matroska-side-data-pref-global
diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak
index 9ab747184a..751ab55fe1 100644
--- a/tests/fate/matroska.mak
+++ b/tests/fate/matroska.mak
@@ -264,6 +264,12 @@ FATE_MATROSKA_FFMPEG_FFPROBE-$(call REMUX, MATROSKA, VP9_PARSER) \
+= fate-matroska-hdr10-plus-remux
fate-matroska-hdr10-plus-remux: CMD = transcode webm $(TARGET_SAMPLES)/mkv/hdr10_plus_vp9_sample.webm matroska "-map 0 -c:v copy" "-map 0 -c:v copy" "-show_packets"
+fate-matroska-side-data-pref-codec: CMD = run ffprobe$(PROGSSUF)$(EXESUF) $(TARGET_SAMPLES)/mkv/hdr10tags-both.mkv \
+ -select_streams v:0 -show_streams -show_frames -show_entries stream=stream_side_data:frame=frame_side_data_list
+fate-matroska-side-data-pref-global: CMD = run ffprobe$(PROGSSUF)$(EXESUF) $(TARGET_SAMPLES)/mkv/hdr10tags-both.mkv \
+ -select_streams v:0 -show_streams -show_frames -show_entries stream=stream_side_data:frame=frame_side_data_list -side_data_prefer_global mastering_display_metadata,content_light_level
+FATE_MATROSKA_FFPROBE-$(call ALLYES MATROSKA_DEMUXER HEVC_DECODER) += fate-matroska-side-data-pref-codec fate-matroska-side-data-pref-global
+
FATE_SAMPLES_AVCONV += $(FATE_MATROSKA-yes)
FATE_SAMPLES_FFPROBE += $(FATE_MATROSKA_FFPROBE-yes)
FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_MATROSKA_FFMPEG_FFPROBE-yes)
diff --git a/tests/ref/fate/matroska-side-data-pref-codec b/tests/ref/fate/matroska-side-data-pref-codec
new file mode 100644
index 0000000000..128ecdd423
--- /dev/null
+++ b/tests/ref/fate/matroska-side-data-pref-codec
@@ -0,0 +1,348 @@
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=H.26[45] User Data Unregistered SEI message
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=35400/50000
+red_y=14599/50000
+green_x=8500/50000
+green_y=39850/50000
+blue_x=6550/50000
+blue_y=2300/50000
+white_point_x=15634/50000
+white_point_y=16450/50000
+min_luminance=10/10000
+max_luminance=10000000/10000
+[/SIDE_DATA]
+[/FRAME]
+[STREAM]
+DISPOSITION:default=1
+DISPOSITION:dub=0
+DISPOSITION:original=0
+DISPOSITION:comment=0
+DISPOSITION:lyrics=0
+DISPOSITION:karaoke=0
+DISPOSITION:forced=0
+DISPOSITION:hearing_impaired=0
+DISPOSITION:visual_impaired=0
+DISPOSITION:clean_effects=0
+DISPOSITION:attached_pic=0
+DISPOSITION:timed_thumbnails=0
+DISPOSITION:non_diegetic=0
+DISPOSITION:captions=0
+DISPOSITION:descriptions=0
+DISPOSITION:metadata=0
+DISPOSITION:dependent=0
+DISPOSITION:still_image=0
+TAG:language=spa
+TAG:BPS-eng=216040
+TAG:DURATION-eng=00:00:00.400000000
+TAG:NUMBER_OF_FRAMES-eng=10
+TAG:NUMBER_OF_BYTES-eng=10802
+TAG:_STATISTICS_WRITING_APP-eng=mkvmerge v9.0.1 ('Mask Machine') 64bit
+TAG:_STATISTICS_WRITING_DATE_UTC-eng=2019-02-14 12:53:10
+TAG:_STATISTICS_TAGS-eng=BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Display Matrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[/STREAM]
diff --git a/tests/ref/fate/matroska-side-data-pref-global b/tests/ref/fate/matroska-side-data-pref-global
new file mode 100644
index 0000000000..a433ece6f4
--- /dev/null
+++ b/tests/ref/fate/matroska-side-data-pref-global
@@ -0,0 +1,348 @@
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=H.26[45] User Data Unregistered SEI message
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[FRAME]
+[SIDE_DATA]
+side_data_type=3x3 displaymatrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[/FRAME]
+[STREAM]
+DISPOSITION:default=1
+DISPOSITION:dub=0
+DISPOSITION:original=0
+DISPOSITION:comment=0
+DISPOSITION:lyrics=0
+DISPOSITION:karaoke=0
+DISPOSITION:forced=0
+DISPOSITION:hearing_impaired=0
+DISPOSITION:visual_impaired=0
+DISPOSITION:clean_effects=0
+DISPOSITION:attached_pic=0
+DISPOSITION:timed_thumbnails=0
+DISPOSITION:non_diegetic=0
+DISPOSITION:captions=0
+DISPOSITION:descriptions=0
+DISPOSITION:metadata=0
+DISPOSITION:dependent=0
+DISPOSITION:still_image=0
+TAG:language=spa
+TAG:BPS-eng=216040
+TAG:DURATION-eng=00:00:00.400000000
+TAG:NUMBER_OF_FRAMES-eng=10
+TAG:NUMBER_OF_BYTES-eng=10802
+TAG:_STATISTICS_WRITING_APP-eng=mkvmerge v9.0.1 ('Mask Machine') 64bit
+TAG:_STATISTICS_WRITING_DATE_UTC-eng=2019-02-14 12:53:10
+TAG:_STATISTICS_TAGS-eng=BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
+[SIDE_DATA]
+side_data_type=Content light level metadata
+max_content=1000
+max_average=300
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Mastering display metadata
+red_x=11408507/16777216
+red_y=5368709/16777216
+green_x=2222981/8388608
+green_y=11576279/16777216
+blue_x=5033165/33554432
+blue_y=16106127/268435456
+white_point_x=10492471/33554432
+white_point_y=689963/2097152
+min_luminance=5368709/536870912
+max_luminance=1000/1
+[/SIDE_DATA]
+[SIDE_DATA]
+side_data_type=Display Matrix
+displaymatrix=
+00000000: 0 65536 0
+00000001: 65536 0 0
+00000002: 0 0 1073741824
+
+rotation=-90
+[/SIDE_DATA]
+[/STREAM]
--
2.40.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get()
2024-03-04 13:06 [FFmpeg-devel] [PATCH 01/29] lavu/opt: factor per-type dispatch out of av_opt_get() Anton Khirnov
` (27 preceding siblings ...)
2024-03-04 13:06 ` [FFmpeg-devel] [PATCH 29/29] tests/fate/matroska: add tests for side data preference Anton Khirnov
@ 2024-03-07 9:30 ` Anton Khirnov
28 siblings, 0 replies; 57+ messages in thread
From: Anton Khirnov @ 2024-03-07 9:30 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Will push the set tomorrow if nobody has further objections.
--
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 57+ messages in thread