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, \
