diff mbox series

[FFmpeg-devel,v2,23/33] avutil/opt: add av_opt_print_num

Message ID 20210611203104.1692-24-dcnieho@gmail.com
State Superseded, archived
Headers show
Series avdevice (mostly dshow) enhancements | expand

Checks

Context Check Description
andriy/x86_make_warn warning New warnings during build
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Diederick C. Niehorster June 11, 2021, 8:30 p.m. UTC
This function allows formatting an option value stored in a double (such
as the min and max fields of an AVOption, or min_value and max_value of
an AVOptionRange) properly, e.g. 1 for a AV_OPT_TYPE_PIXEL_FMT -> yuyv422.

Useful when printing more info about an option than just its value.
Usage will be shown in upcoming device_get_capabilities example.

av_opt_get (body changed) still passes FATE.

Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
 libavutil/opt.c     | 81 +++++++++++++++++++++++++++++++++++++--------
 libavutil/opt.h     | 17 +++++++++-
 libavutil/version.h |  2 +-
 3 files changed, 85 insertions(+), 15 deletions(-)

Comments

Diederick C. Niehorster June 11, 2021, 8:57 p.m. UTC | #1
On Fri, Jun 11, 2021 at 10:38 PM Diederick Niehorster <dcnieho@gmail.com> wrote:
>
> This function allows formatting an option value stored in a double (such
> as the min and max fields of an AVOption, or min_value and max_value of
> an AVOptionRange) properly, e.g. 1 for a AV_OPT_TYPE_PIXEL_FMT -> yuyv422.
>
> Useful when printing more info about an option than just its value.
> Usage will be shown in upcoming device_get_capabilities example.

This solution is not perfect, since multiple of the options returned
are not formatted properly now:
- "codec", which is just printed as int since there is no
AV_OPT_TYPE_CODEC or something like that
- "frame_size"/"window_size": these are reported as three components:
"pixel_count", "width", "height", none of which have a known type (and
thus we default to printing the provided double.

The other solution which enables handling this is to add a new
function avdevice_capabilities_print, which you pass a single
AVOptionRange* (not AVOptionRanges** as that would create many lines
of output) and it returns a formatted string. In the implementation of
that function, since we know all the options (and related components),
we can special-case the formatting where needed so that it all comes
out right.

Cheers,
Dee
diff mbox series

Patch

diff --git a/libavutil/opt.c b/libavutil/opt.c
index edb2c2ca41..108e9baf3b 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -776,24 +776,14 @@  static void format_duration(char *buf, size_t size, int64_t d)
         *(--e) = 0;
 }
 
-int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
+static int print_option(void *dst, enum AVOptionType type, int search_flags, AVOption *o, uint8_t **out_val)
 {
-    void *dst, *target_obj;
-    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
     uint8_t *bin, buf[128];
     int len, i, ret;
     int64_t i64;
 
-    if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST))
-        return AVERROR_OPTION_NOT_FOUND;
-
-    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;
-
     buf[0] = 0;
-    switch (o->type) {
+    switch (type) {
     case AV_OPT_TYPE_BOOL:
         ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(get_bool_name(*(int *)dst), "invalid"));
         break;
@@ -820,7 +810,8 @@  int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
         ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den);
         break;
     case AV_OPT_TYPE_CONST:
-        ret = snprintf(buf, sizeof(buf), "%f", o->default_val.dbl);
+        if (o)
+            ret = snprintf(buf, sizeof(buf), "%f", o->default_val.dbl);
         break;
     case AV_OPT_TYPE_STRING:
         if (*(uint8_t **)dst) {
@@ -889,6 +880,70 @@  int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
     return *out_val ? 0 : AVERROR(ENOMEM);
 }
 
+int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
+{
+    void *dst, *target_obj;
+    const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
+
+    if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST))
+        return AVERROR_OPTION_NOT_FOUND;
+
+    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 print_option(dst, o->type, search_flags, o, out_val);
+}
+
+int av_opt_print_num(enum AVOptionType type, double val, uint8_t **out_val)
+{
+    *out_val = NULL;
+
+    switch (type) {
+    case AV_OPT_TYPE_FLAGS:
+    case AV_OPT_TYPE_BOOL:
+    case AV_OPT_TYPE_INT:
+    case AV_OPT_TYPE_PIXEL_FMT:
+    case AV_OPT_TYPE_SAMPLE_FMT:
+    {
+        int temp = lrint(val);
+        return print_option(&temp, type, 0, NULL, out_val);
+    }
+    case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_DURATION:
+    case AV_OPT_TYPE_CHANNEL_LAYOUT:
+    {
+        int64_t temp = llrint(val);
+        return print_option(&temp, type, 0, NULL, out_val);
+    }
+    case AV_OPT_TYPE_UINT64:
+    {
+        uint64_t temp = llrint(val);
+        return print_option(&temp, type, 0, NULL, out_val);
+    }
+    case AV_OPT_TYPE_FLOAT:
+    {
+        float temp = (float)val;
+        return print_option(&temp, type, 0, NULL, out_val);
+    }
+    case AV_OPT_TYPE_DOUBLE:
+        return print_option(&val, type, 0, NULL, out_val);
+
+    default:
+        // AV_OPT_TYPE_DICT,
+        // AV_OPT_TYPE_COLOR,
+        // AV_OPT_TYPE_BINARY,
+        // AV_OPT_TYPE_STRING,
+        // AV_OPT_TYPE_RATIONAL,
+        // AV_OPT_TYPE_IMAGE_SIZE,
+        // AV_OPT_TYPE_VIDEO_RATE,
+        // AV_OPT_TYPE_CONST
+        // cannot be stored in a single double, and are thus not a valid input
+        return AVERROR(EINVAL);
+    }
+}
+
 static int get_number(void *obj, const char *name, const AVOption **o_out, double *num, int *den, int64_t *intnum,
                       int search_flags)
 {
diff --git a/libavutil/opt.h b/libavutil/opt.h
index 3c64e8d3a5..f9da141588 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -361,7 +361,7 @@  typedef struct AVOptionRanges {
      * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) {
      *     for (component_index = 0; component_index < ranges->nb_components; component_index++)
      *         range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index];
-     *     //do something with range here.
+     *     //do something with range here. For printing the value, av_opt_print_num() may be of use.
      * }
      * av_opt_freep_ranges(&ranges);
      * @endcode
@@ -760,6 +760,21 @@  int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int
  * be freed with av_dict_free() by the caller
  */
 int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val);
+
+/**
+ * Format option value and output to string.
+ * @param[in]  type Type of the option.
+ * @param[in]  val An option value that can be represented as a double
+               (e.g. min or max fields of AVOption, or min_value and
+               max_value of AVOptionRange)
+ * @param[out] out_val Value of the option will be written as a string here
+ * 
+ * @return >=0 on success, a negative error code otherwise
+ * 
+ * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller
+ */
+int av_opt_print_num(enum AVOptionType type, double val, uint8_t **out_val);
+
 /**
  * @}
  */
diff --git a/libavutil/version.h b/libavutil/version.h
index e11eaa20d0..34b83112de 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@ 
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  57
-#define LIBAVUTIL_VERSION_MINOR   0
+#define LIBAVUTIL_VERSION_MINOR   1
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \