diff --git a/command.c b/command.c
index 3402380172..b5b101ce79 100644
--- a/command.c
+++ b/command.c
@@ -71,6 +71,16 @@
 #include "mp_fifo.h"
 #include "libavutil/avstring.h"
 
+static char *format_bitrate(int rate)
+{
+    return talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000);
+}
+
+static char *format_delay(double time)
+{
+    return talloc_asprintf(NULL, "%d ms", ROUND(time * 1000));
+}
+
 static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy,
                                       double *dx, double *dy)
 {
@@ -249,7 +259,7 @@ static int mp_property_stream_time_pos(m_option_t *prop, int action,
     if (pts == MP_NOPTS_VALUE)
         return M_PROPERTY_UNAVAILABLE;
 
-    return m_property_time_ro(prop, action, arg, pts);
+    return m_property_double_ro(prop, action, arg, pts);
 }
 
 
@@ -262,7 +272,7 @@ static int mp_property_length(m_option_t *prop, int action, void *arg,
     if (!(int) (len = get_time_length(mpctx)))
         return M_PROPERTY_UNAVAILABLE;
 
-    return m_property_time_ro(prop, action, arg, len);
+    return m_property_double_ro(prop, action, arg, len);
 }
 
 /// Current position in percent (RW)
@@ -300,7 +310,7 @@ static int mp_property_time_pos(m_option_t *prop, int action,
         queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0);
         return M_PROPERTY_OK;
     }
-    return m_property_time_ro(prop, action, arg, get_current_time(mpctx));
+    return m_property_double_ro(prop, action, arg, get_current_time(mpctx));
 }
 
 /// Current chapter (RW)
@@ -594,10 +604,13 @@ static int mp_property_audio_delay(m_option_t *prop, int action,
     if (!(mpctx->sh_audio && mpctx->sh_video))
         return M_PROPERTY_UNAVAILABLE;
     switch (action) {
+    case M_PROPERTY_PRINT:
+        *(char **)arg = format_delay(audio_delay);
+        return M_PROPERTY_OK;
     case M_PROPERTY_SET: {
         int ret;
         float delay = audio_delay;
-        ret = m_property_delay(prop, action, arg, &audio_delay);
+        ret = m_property_float_range(prop, action, arg, &audio_delay);
         if (ret != M_PROPERTY_OK)
             return ret;
         if (mpctx->sh_audio)
@@ -605,7 +618,7 @@ static int mp_property_audio_delay(m_option_t *prop, int action,
     }
         return M_PROPERTY_OK;
     default:
-        return m_property_delay(prop, action, arg, &audio_delay);
+        return m_property_float_range(prop, action, arg, &audio_delay);
     }
 }
 
@@ -634,7 +647,12 @@ static int mp_property_audio_bitrate(m_option_t *prop, int action,
 {
     if (!mpctx->sh_audio)
         return M_PROPERTY_UNAVAILABLE;
-    return m_property_bitrate(prop, action, arg, mpctx->sh_audio->i_bps);
+    switch (action) {
+    case M_PROPERTY_PRINT:
+        *(char **)arg = format_bitrate(mpctx->sh_audio->i_bps);
+        return M_PROPERTY_OK;
+    }
+    return m_property_int_ro(prop, action, arg, mpctx->sh_audio->i_bps);
 }
 
 /// Samplerate (RO)
@@ -1148,7 +1166,12 @@ static int mp_property_video_bitrate(m_option_t *prop, int action,
 {
     if (!mpctx->sh_video)
         return M_PROPERTY_UNAVAILABLE;
-    return m_property_bitrate(prop, action, arg, mpctx->sh_video->i_bps);
+    switch (action) {
+    case M_PROPERTY_PRINT:
+        *(char **)arg = format_bitrate(mpctx->sh_video->i_bps);
+        return M_PROPERTY_OK;
+    }
+    return m_property_int_ro(prop, action, arg, mpctx->sh_video->i_bps);
 }
 
 /// Video display width (RO)
@@ -1213,7 +1236,12 @@ static int mp_property_sub_delay(m_option_t *prop, int action, void *arg,
 {
     if (!mpctx->sh_video)
         return M_PROPERTY_UNAVAILABLE;
-    return m_property_delay(prop, action, arg, &sub_delay);
+    switch (action) {
+    case M_PROPERTY_PRINT:
+        *(char **)arg = format_delay(sub_delay);
+        return M_PROPERTY_OK;
+    }
+    return m_property_float_range(prop, action, arg, &sub_delay);
 }
 
 /// Subtitle visibility (RW)
@@ -1298,7 +1326,8 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg,
         M_PROPERTY_CLAMP(prop, *(float *) arg);
         if (opts->ass_enabled)
             opts->ass_font_scale = *(float *) arg;
-        text_font_scale_factor = *(float *) arg;
+        else
+            text_font_scale_factor = *(float *) arg;
         vo_osd_resized();
         return M_PROPERTY_OK;
     default:
diff --git a/m_option.c b/m_option.c
index 14a1a0a3d7..62887f4c48 100644
--- a/m_option.c
+++ b/m_option.c
@@ -489,10 +489,14 @@ static int parse_double(const m_option_t *opt, struct bstr name,
 
 static char *print_double(const m_option_t *opt, const void *val)
 {
-    opt = NULL;
     return talloc_asprintf(NULL, "%f", VAL(val));
 }
 
+static char *print_double_f2(const m_option_t *opt, const void *val)
+{
+    return talloc_asprintf(NULL, "%.2f", VAL(val));
+}
+
 static void add_double(const m_option_t *opt, void *val, double add, bool wrap)
 {
     double v = VAL(val);
@@ -516,6 +520,7 @@ const m_option_type_t m_option_type_double = {
     .size  = sizeof(double),
     .parse = parse_double,
     .print = print_double,
+    .pretty_print = print_double_f2,
     .copy  = copy_opt,
 };
 
@@ -534,10 +539,14 @@ static int parse_float(const m_option_t *opt, struct bstr name,
 
 static char *print_float(const m_option_t *opt, const void *val)
 {
-    opt = NULL;
     return talloc_asprintf(NULL, "%f", VAL(val));
 }
 
+static char *print_float_f2(const m_option_t *opt, const void *val)
+{
+    return talloc_asprintf(NULL, "%.2f", VAL(val));
+}
+
 static void add_float(const m_option_t *opt, void *val, double add, bool wrap)
 {
     double tmp = VAL(val);
@@ -551,6 +560,7 @@ const m_option_type_t m_option_type_float = {
     .size  = sizeof(float),
     .parse = parse_float,
     .print = print_float,
+    .pretty_print = print_float_f2,
     .copy  = copy_opt,
     .add = add_float,
 };
@@ -1135,11 +1145,17 @@ static int parse_time(const m_option_t *opt, struct bstr name,
     return 1;
 }
 
+static char *pretty_print_time(const m_option_t *opt, const void *val)
+{
+    return mp_format_time(*(double *)val, false);
+}
+
 const m_option_type_t m_option_type_time = {
     .name  = "Time",
     .size  = sizeof(double),
     .parse = parse_time,
     .print = print_double,
+    .pretty_print = pretty_print_time,
     .copy  = copy_opt,
     .add = add_double,
 };
diff --git a/m_option.h b/m_option.h
index 75f9ee5925..acbbb3fd9f 100644
--- a/m_option.h
+++ b/m_option.h
@@ -209,6 +209,11 @@ struct m_option_type {
      */
     char *(*print)(const m_option_t *opt, const void *val);
 
+    // Print the value in a human readable form. Unlike print(), it doesn't
+    // necessarily return the exact value, and is generally not parseable with
+    // parse().
+    char *(*pretty_print)(const m_option_t *opt, const void *val);
+
     // Copy data between two locations. Deep copy if the data has pointers.
     /** \param opt The option to copy.
      *  \param dst Pointer to the destination memory.
@@ -413,6 +418,15 @@ static inline char *m_option_print(const m_option_t *opt, const void *val_ptr)
         return NULL;
 }
 
+static inline char *m_option_pretty_print(const m_option_t *opt,
+                                          const void *val_ptr)
+{
+    if (opt->type->pretty_print)
+        return opt->type->pretty_print(opt, val_ptr);
+    else
+        return m_option_print(opt, val_ptr);
+}
+
 // Helper around \ref m_option_type::copy.
 static inline void m_option_copy(const m_option_t *opt, void *dst,
                                  const void *src)
diff --git a/m_property.c b/m_property.c
index 3f2468e53c..d7ae0c93fc 100644
--- a/m_property.c
+++ b/m_property.c
@@ -69,12 +69,24 @@ int m_property_do(const m_option_t *prop_list, const char *name,
     const m_option_t *opt;
     void *val;
     int r;
+    char *str;
 
     switch (action) {
     case M_PROPERTY_PRINT:
         if ((r = do_action(prop_list, name, M_PROPERTY_PRINT, arg, ctx)) >= 0)
             return r;
-    // fallback on the default print for this type
+        if ((r =
+             do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
+            return r;
+        val = calloc(1, opt->type->size);
+        if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) {
+            free(val);
+            return r;
+        }
+        str = m_option_pretty_print(opt, val);
+        free(val);
+        *(char **)arg = str;
+        return str != NULL;
     case M_PROPERTY_TO_STRING:
         if ((r = do_action(prop_list, name, M_PROPERTY_TO_STRING, arg, ctx)) !=
             M_PROPERTY_NOT_IMPLEMENTED)
@@ -88,7 +100,7 @@ int m_property_do(const m_option_t *prop_list, const char *name,
             free(val);
             return r;
         }
-        char *str = m_option_print(opt, val);
+        str = m_option_print(opt, val);
         free(val);
         *(char **)arg = str;
         return str != NULL;
@@ -283,22 +295,12 @@ int m_property_int_range(const m_option_t *prop, int action,
 int m_property_flag_ro(const m_option_t *prop, int action,
                        void *arg, int var)
 {
-    switch (action) {
-    case M_PROPERTY_PRINT:
-        *(char **)arg = talloc_strdup(NULL, (var > prop->min) ?
-                               mp_gtext("enabled") : mp_gtext("disabled"));
-        return 1;
-    }
     return m_property_int_ro(prop, action, arg, var);
 }
 
 int m_property_flag(const m_option_t *prop, int action,
                     void *arg, int *var)
 {
-    switch (action) {
-    case M_PROPERTY_PRINT:
-        return m_property_flag_ro(prop, action, arg, *var);
-    }
     return m_property_int_range(prop, action, arg, var);
 }
 
@@ -309,9 +311,6 @@ int m_property_float_ro(const m_option_t *prop, int action,
     case M_PROPERTY_GET:
         *(float *)arg = var;
         return 1;
-    case M_PROPERTY_PRINT:
-        *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
-        return 1;
     }
     return M_PROPERTY_NOT_IMPLEMENTED;
 }
@@ -328,18 +327,6 @@ int m_property_float_range(const m_option_t *prop, int action,
     return m_property_float_ro(prop, action, arg, *var);
 }
 
-int m_property_delay(const m_option_t *prop, int action,
-                     void *arg, float *var)
-{
-    switch (action) {
-    case M_PROPERTY_PRINT:
-        *(char **)arg = talloc_asprintf(NULL, "%d ms", ROUND((*var) * 1000));
-        return 1;
-    default:
-        return m_property_float_range(prop, action, arg, var);
-    }
-}
-
 int m_property_double_ro(const m_option_t *prop, int action,
                          void *arg, double var)
 {
@@ -347,24 +334,10 @@ int m_property_double_ro(const m_option_t *prop, int action,
     case M_PROPERTY_GET:
         *(double *)arg = var;
         return 1;
-    case M_PROPERTY_PRINT:
-        *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
-        return 1;
     }
     return M_PROPERTY_NOT_IMPLEMENTED;
 }
 
-int m_property_time_ro(const m_option_t *prop, int action,
-                       void *arg, double var)
-{
-    switch (action) {
-    case M_PROPERTY_PRINT:
-        *(char **)arg = mp_format_time(var, false);
-        return M_PROPERTY_OK;
-    }
-    return m_property_double_ro(prop, action, arg, var);
-}
-
 int m_property_string_ro(const m_option_t *prop, int action, void *arg,
                          char *str)
 {
@@ -372,19 +345,6 @@ int m_property_string_ro(const m_option_t *prop, int action, void *arg,
     case M_PROPERTY_GET:
         *(char **)arg = str;
         return 1;
-    case M_PROPERTY_PRINT:
-        *(char **)arg = talloc_strdup(NULL, str);
-        return 1;
     }
     return M_PROPERTY_NOT_IMPLEMENTED;
 }
-
-int m_property_bitrate(const m_option_t *prop, int action, void *arg, int rate)
-{
-    switch (action) {
-    case M_PROPERTY_PRINT:
-        *(char **)arg = talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000);
-        return M_PROPERTY_OK;
-    }
-    return m_property_int_ro(prop, action, arg, rate);
-}
diff --git a/m_property.h b/m_property.h
index 180dbbf618..462dad57fc 100644
--- a/m_property.h
+++ b/m_property.h
@@ -190,24 +190,13 @@ int m_property_float_ro(const m_option_t* prop,int action,
 int m_property_float_range(const m_option_t* prop,int action,
                            void* arg,float* var);
 
-/// float with a print function which print the time in ms
-int m_property_delay(const m_option_t* prop,int action,
-                     void* arg,float* var);
-
 /// Implement get, print
 int m_property_double_ro(const m_option_t* prop,int action,
                          void* arg,double var);
 
-/// Implement print
-int m_property_time_ro(const m_option_t* prop,int action,
-                       void* arg,double var);
-
 /// get/print the string
 int m_property_string_ro(const m_option_t* prop,int action,void* arg, char* str);
 
-/// get/print a bitrate
-int m_property_bitrate(const m_option_t* prop,int action,void* arg,int rate);
-
 ///@}
 
 ///@}