From 11f5713e3bbeea8449a97ecb979936e02660321e Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 24 Jan 2018 01:32:56 +0100 Subject: options: add an option type for byte sizes And use it for 2 demuxer options. It could be used for more options later. (Though the --cache options can not use this, because they use KB as base unit.) --- DOCS/man/options.rst | 7 ++-- demux/demux.c | 8 ++--- options/m_option.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ options/m_option.h | 5 +++ player/command.c | 18 ---------- 5 files changed, 108 insertions(+), 25 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 637773e95d..2acc8d8239 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2868,7 +2868,7 @@ Demuxer ``--demuxer-rawvideo-size=`` Frame size in bytes when using ``--demuxer=rawvideo``. -``--demuxer-max-bytes=`` +``--demuxer-max-bytes=`` This controls how much the demuxer is allowed to buffer ahead. The demuxer will normally try to read ahead as much as necessary, or as much is requested with ``--demuxer-readahead-secs``. The option can be used to @@ -2880,9 +2880,10 @@ Demuxer Set these limits higher if you get a packet queue overflow warning, and you think normal playback would be possible with a larger packet queue. - See ``--list-options`` for defaults and value range. + See ``--list-options`` for defaults and value range. ```` options + accept suffixes such as ``KiB`` and ``MiB``. -``--demuxer-max-back-bytes=`` +``--demuxer-max-back-bytes=`` This controls how much past data the demuxer is allowed to preserve. This is useful only if the ``--demuxer-seekable-cache`` option is enabled. Unlike the forward cache, there is no control how many seconds are actually diff --git a/demux/demux.c b/demux/demux.c index d621b9d869..ed6f2c1b31 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -84,8 +84,8 @@ const demuxer_desc_t *const demuxer_list[] = { }; struct demux_opts { - int max_bytes; - int max_bytes_bw; + int64_t max_bytes; + int64_t max_bytes_bw; double min_secs; int force_seekable; double min_secs_cache; @@ -99,8 +99,8 @@ struct demux_opts { const struct m_sub_options demux_conf = { .opts = (const struct m_option[]){ OPT_DOUBLE("demuxer-readahead-secs", min_secs, M_OPT_MIN, .min = 0), - OPT_INTRANGE("demuxer-max-bytes", max_bytes, 0, 0, INT_MAX), - OPT_INTRANGE("demuxer-max-back-bytes", max_bytes_bw, 0, 0, INT_MAX), + OPT_BYTE_SIZE("demuxer-max-bytes", max_bytes, 0, 0, INT_MAX), + OPT_BYTE_SIZE("demuxer-max-back-bytes", max_bytes_bw, 0, 0, INT_MAX), OPT_FLAG("force-seekable", force_seekable, 0), OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0), OPT_FLAG("access-references", access_references, 0), diff --git a/options/m_option.c b/options/m_option.c index 8cdf8aee11..fe656a07ac 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -393,6 +393,101 @@ const m_option_type_t m_option_type_int64 = { .get = int64_get, }; +static int parse_byte_size(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param, void *dst) +{ + if (param.len == 0) + return M_OPT_MISSING_PARAM; + + struct bstr r; + long long tmp_int = bstrtoll(param, &r, 0); + int64_t unit = 1; + if (r.len) { + if (bstrcasecmp0(r, "kib") == 0 || bstrcasecmp0(r, "k") == 0) { + unit = 1024; + } else if (bstrcasecmp0(r, "mib") == 0 || bstrcasecmp0(r, "m") == 0) { + unit = 1024 * 1024; + } else if (bstrcasecmp0(r, "gib") == 0 || bstrcasecmp0(r, "g") == 0) { + unit = 1024 * 1024 * 1024; + } else if (bstrcasecmp0(r, "tib") == 0 || bstrcasecmp0(r, "t") == 0) { + unit = 1024 * 1024 * 1024 * 1024LL; + } else { + mp_err(log, "The %.*s option must be an integer: %.*s\n", + BSTR_P(name), BSTR_P(param)); + mp_err(log, "The following suffixes are also allowed: " + "KiB, MiB, GiB, TiB, K, M, G, T.\n"); + return M_OPT_INVALID; + } + } + + if (tmp_int < 0) { + mp_err(log, "The %.*s option does not support negative numbers: %.*s\n", + BSTR_P(name), BSTR_P(param)); + return M_OPT_OUT_OF_RANGE; + } + + if (INT64_MAX / unit < tmp_int) { + mp_err(log, "The %.*s option overflows: %.*s\n", + BSTR_P(name), BSTR_P(param)); + return M_OPT_OUT_OF_RANGE; + } + + tmp_int *= unit; + + if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) { + mp_err(log, "The %.*s option must be >= %d: %.*s\n", + BSTR_P(name), (int) opt->min, BSTR_P(param)); + return M_OPT_OUT_OF_RANGE; + } + + if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) { + mp_err(log, "The %.*s option must be <= %d: %.*s\n", + BSTR_P(name), (int) opt->max, BSTR_P(param)); + return M_OPT_OUT_OF_RANGE; + } + + if (dst) + *(int64_t *)dst = tmp_int; + + return 1; +} + +char *format_file_size(int64_t size) +{ + double s = size; + if (size < 1024) + return talloc_asprintf(NULL, "%.0f", s); + + if (size < (1024 * 1024)) + return talloc_asprintf(NULL, "%.3f KiB", s / (1024.0)); + + if (size < (1024 * 1024 * 1024)) + return talloc_asprintf(NULL, "%.3f MiB", s / (1024.0 * 1024.0)); + + if (size < (1024LL * 1024LL * 1024LL * 1024LL)) + return talloc_asprintf(NULL, "%.3f GiB", s / (1024.0 * 1024.0 * 1024.0)); + + return talloc_asprintf(NULL, "%.3f TiB", s / (1024.0 * 1024.0 * 1024.0 * 1024.0)); +} + +static char *pretty_print_byte_size(const m_option_t *opt, const void *val) +{ + return format_file_size(*(int64_t *)val); +} + +const m_option_type_t m_option_type_byte_size = { + .name = "ByteSize", + .size = sizeof(int64_t), + .parse = parse_byte_size, + .print = print_int, + .pretty_print = pretty_print_byte_size, + .copy = copy_opt, + .add = add_int64, + .multiply = multiply_int64, + .set = int64_set, + .get = int64_get, +}; + static int parse_intpair(struct mp_log *log, const struct m_option *opt, struct bstr name, struct bstr param, void *dst) { diff --git a/options/m_option.h b/options/m_option.h index 405b59da0a..8c8ae855d1 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -41,6 +41,7 @@ extern const m_option_type_t m_option_type_flag; extern const m_option_type_t m_option_type_dummy_flag; extern const m_option_type_t m_option_type_int; extern const m_option_type_t m_option_type_int64; +extern const m_option_type_t m_option_type_byte_size; extern const m_option_type_t m_option_type_intpair; extern const m_option_type_t m_option_type_float; extern const m_option_type_t m_option_type_double; @@ -371,6 +372,7 @@ struct m_option { const char *deprecation_message; }; +char *format_file_size(int64_t size); // The option has a minimum set in \ref m_option::min. #define M_OPT_MIN (1 << 0) @@ -670,6 +672,9 @@ extern const char m_option_path_separator; #define OPT_COLOR(...) \ OPT_GENERAL(struct m_color, __VA_ARGS__, .type = &m_option_type_color) +#define OPT_BYTE_SIZE(...) \ + OPT_RANGE_(int64_t, __VA_ARGS__, .type = &m_option_type_byte_size) + #define OPT_GEOMETRY(...) \ OPT_GENERAL(struct m_geometry, __VA_ARGS__, .type = &m_option_type_geometry) diff --git a/player/command.c b/player/command.c index c6f23eb9bf..7b36dcd7a2 100644 --- a/player/command.c +++ b/player/command.c @@ -320,24 +320,6 @@ static char *cut_osd_list(struct MPContext *mpctx, char *text, int pos) return new; } -static char *format_file_size(int64_t size) -{ - double s = size; - if (size < 1024) - return talloc_asprintf(NULL, "%.0f", s); - - if (size < (1024 * 1024)) - return talloc_asprintf(NULL, "%.3f KiB", s / (1024.0)); - - if (size < (1024 * 1024 * 1024)) - return talloc_asprintf(NULL, "%.3f MiB", s / (1024.0 * 1024.0)); - - if (size < (1024LL * 1024LL * 1024LL * 1024LL)) - return talloc_asprintf(NULL, "%.3f GiB", s / (1024.0 * 1024.0 * 1024.0)); - - return talloc_asprintf(NULL, "%.3f TiB", s / (1024.0 * 1024.0 * 1024.0 * 1024.0)); -} - static char *format_delay(double time) { return talloc_asprintf(NULL, "%d ms", (int)lrint(time * 1000)); -- cgit v1.2.3