From f3c933e5d3501c71e7f38dc62b27096a90090d5e Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 25 Feb 2014 23:59:27 +0100 Subject: [PATCH] options: allow changing options at runtime Allow changing all options at runtime, except some cherry-picked options, which are disabled with M_OPT_FIXED. --- DOCS/man/en/input.rst | 6 +++-- libmpv/client.h | 11 +++++--- options/m_option.h | 16 ++++++++---- options/options.c | 61 +++++++++++++++++++++++-------------------- player/command.c | 4 +-- 5 files changed, 55 insertions(+), 43 deletions(-) diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 62990af372..320e9cfd48 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -1009,8 +1009,10 @@ an option at runtime. See ``--vf`` and the ``vf`` command. ``options/`` (RW) - Read-only access to value of option ``--``. If the player is in idle - mode, the option can be changed by writing to this property. + Read-only access to value of option ``--``. Most options can be + changed at runtime by writing to this property. Note that many options + require reloading the file for changes to take effect. If there is an + equivalent property, prefer setting the property instead. Property Expansion ------------------ diff --git a/libmpv/client.h b/libmpv/client.h index 606fabbce5..0c0cde7b0f 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -561,11 +561,14 @@ void mpv_free_node_contents(mpv_node *node); /** * Set an option. Note that you can't normally set options during runtime. It - * works in uninitialized state (see mpv_create()), and in some cases in idle - * mode. + * works in uninitialized state (see mpv_create()), and in some cases in at + * runtime. * - * You can use mpv_set_property() to change options during playback, but this - * does not work with all options. + * Changing options at runtime does not always work. For some options, attempts + * to change them simply fails. Many other options may require reloading the + * file for changes to take effect. In general, you should prefer calling + * mpv_set_property() to change settings during playback, because the property + * mechanism guarantees that changes take effect immediately. * * @param name Option name. This is the same as on the mpv command line, but * without the leading "--". diff --git a/options/m_option.h b/options/m_option.h index 1a9bf784b6..6a38a7f4e6 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -350,6 +350,12 @@ struct m_option { // This option can't be set per-file when used with struct m_config. #define M_OPT_GLOBAL (1 << 4) +// Can not be freely changed at runtime (normally, all options can be changed, +// even if the settings don't get effective immediately). Note that an option +// might still change even if this is set, e.g. via properties or per-file +// options. +#define M_OPT_FIXED (1 << 5) + // The option should be set during command line pre-parsing #define M_OPT_PRE_PARSE (1 << 6) @@ -361,7 +367,7 @@ struct m_option { #define CONF_MAX M_OPT_MAX #define CONF_RANGE M_OPT_RANGE #define CONF_NOCFG M_OPT_NOCFG -#define CONF_GLOBAL M_OPT_GLOBAL +#define CONF_GLOBAL (M_OPT_GLOBAL | M_OPT_FIXED) #define CONF_PRE_PARSE M_OPT_PRE_PARSE // These flags are used to describe special parser capabilities or behavior. @@ -661,10 +667,10 @@ extern const char m_option_path_separator; #define OPT_STRING_VALIDATE(...) \ OPT_STRING_VALIDATE_(__VA_ARGS__, .type = &m_option_type_string) -#define OPT_PRINT(optname, fn) \ - {.name = optname, \ - .flags = M_OPT_GLOBAL | M_OPT_NOCFG | M_OPT_PRE_PARSE, \ - .type = &m_option_type_print_fn, \ +#define OPT_PRINT(optname, fn) \ + {.name = optname, \ + .flags = M_OPT_FIXED | M_OPT_GLOBAL | M_OPT_NOCFG | M_OPT_PRE_PARSE, \ + .type = &m_option_type_print_fn, \ .priv = MP_EXPECT_TYPE(m_opt_print_fn, fn) } // subconf must have the type struct m_sub_options. diff --git a/options/options.c b/options/options.c index 08e22594d8..d777fac215 100644 --- a/options/options.c +++ b/options/options.c @@ -208,18 +208,19 @@ extern const m_option_t mp_input_opts[]; const m_option_t mp_opts[] = { // handled in command line pre-parser (parse_commandline.c) {"v", NULL, CONF_TYPE_STORE, CONF_GLOBAL | CONF_NOCFG, 0, 0, NULL}, - {"playlist", NULL, CONF_TYPE_STRING, CONF_NOCFG | M_OPT_MIN, 1, 0, NULL}, - {"{", NULL, CONF_TYPE_STORE, CONF_NOCFG, 0, 0, NULL}, - {"}", NULL, CONF_TYPE_STORE, CONF_NOCFG, 0, 0, NULL}, + {"playlist", NULL, CONF_TYPE_STRING, CONF_NOCFG | M_OPT_MIN | M_OPT_FIXED, + 1, 0, NULL}, + {"{", NULL, CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED, 0, 0, NULL}, + {"}", NULL, CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED, 0, 0, NULL}, // handled in m_config.c - { "include", NULL, CONF_TYPE_STRING }, - { "profile", NULL, CONF_TYPE_STRING_LIST }, - { "show-profile", NULL, CONF_TYPE_STRING, CONF_NOCFG }, - { "list-options", NULL, CONF_TYPE_STORE, CONF_NOCFG }, + { "include", NULL, CONF_TYPE_STRING, M_OPT_FIXED }, + { "profile", NULL, CONF_TYPE_STRING_LIST, M_OPT_FIXED }, + { "show-profile", NULL, CONF_TYPE_STRING, CONF_NOCFG | M_OPT_FIXED }, + { "list-options", NULL, CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED }, // handled in main.c (looks at the raw argv[]) - {"leak-report", NULL, CONF_TYPE_STORE, CONF_GLOBAL | CONF_NOCFG }, + {"leak-report", NULL, CONF_TYPE_STORE, CONF_GLOBAL | CONF_NOCFG | M_OPT_FIXED }, OPT_FLAG("shuffle", shuffle, CONF_GLOBAL | CONF_NOCFG), @@ -238,11 +239,11 @@ const m_option_t mp_opts[] = { OPT_FLAG("config", load_config, CONF_GLOBAL | CONF_NOCFG | CONF_PRE_PARSE), OPT_STRING("config-dir", force_configdir, CONF_GLOBAL | CONF_NOCFG | CONF_PRE_PARSE), - OPT_STRINGLIST("reset-on-next-file", reset_options, CONF_GLOBAL), + OPT_STRINGLIST("reset-on-next-file", reset_options, M_OPT_GLOBAL), #if HAVE_LUA OPT_STRINGLIST("lua", lua_files, CONF_GLOBAL), - OPT_KEYVALUELIST("lua-opts", lua_opts, CONF_GLOBAL), + OPT_KEYVALUELIST("lua-opts", lua_opts, M_OPT_GLOBAL), OPT_FLAG("osc", lua_load_osc, CONF_GLOBAL), #endif @@ -256,7 +257,8 @@ const m_option_t mp_opts[] = { ({"no", 0}), OPTDEF_INT(320)), OPT_FLOATRANGE("cache-min", stream_cache_min_percent, 0, 0, 99), - OPT_FLOATRANGE("cache-seek-min", stream_cache_seek_min_percent, 0, 0, 99), + OPT_FLOATRANGE("cache-seek-min", stream_cache_seek_min_percent, 0, + 0, 99), OPT_CHOICE_OR_INT("cache-pause", stream_cache_pause, 0, 0, 40, ({"no", -1})), @@ -289,7 +291,7 @@ const m_option_t mp_opts[] = { // ------------------------- demuxer options -------------------- - OPT_CHOICE_OR_INT("frames", play_frames, 0, 0, INT_MAX, + OPT_CHOICE_OR_INT("frames", play_frames, M_OPT_FIXED, 0, INT_MAX, ({"all", -1})), // seek to byte/seconds position @@ -298,7 +300,7 @@ const m_option_t mp_opts[] = { OPT_REL_TIME("end", play_end, 0), OPT_REL_TIME("length", play_length, 0), - OPT_FLAG("pause", pause, 0), + OPT_FLAG("pause", pause, M_OPT_FIXED), OPT_FLAG("keep-open", keep_open, 0), // AVI and Ogg only: (re)build index at startup @@ -353,11 +355,12 @@ const m_option_t mp_opts[] = { OPT_FLOATRANGE("mc", default_max_pts_correction, 0, 0, 100), // force video/audio rate: - OPT_DOUBLE("fps", force_fps, CONF_MIN, 0), + OPT_DOUBLE("fps", force_fps, CONF_MIN | M_OPT_FIXED), OPT_INTRANGE("srate", force_srate, 0, 1000, 8*48000), OPT_CHMAP("channels", audio_output_channels, CONF_MIN, .min = 1), OPT_AUDIOFORMAT("format", audio_output_format, 0), - OPT_DOUBLE("speed", playback_speed, M_OPT_RANGE, .min = 0.01, .max = 100.0), + OPT_DOUBLE("speed", playback_speed, M_OPT_RANGE | M_OPT_FIXED, + .min = 0.01, .max = 100.0), // set a-v distance OPT_FLOATRANGE("audio-delay", audio_delay, 0, -100.0, 100.0), @@ -365,11 +368,11 @@ const m_option_t mp_opts[] = { // ------------------------- codec/vfilter options -------------------- OPT_SETTINGSLIST("af-defaults", af_defs, 0, &af_obj_list), - OPT_SETTINGSLIST("af*", af_settings, 0, &af_obj_list), + OPT_SETTINGSLIST("af*", af_settings, M_OPT_FIXED, &af_obj_list), OPT_SETTINGSLIST("vf-defaults", vf_defs, 0, &vf_obj_list), - OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list), + OPT_SETTINGSLIST("vf*", vf_settings, M_OPT_FIXED, &vf_obj_list), - OPT_CHOICE("deinterlace", deinterlace, M_OPT_OPTIONAL_PARAM, + OPT_CHOICE("deinterlace", deinterlace, M_OPT_OPTIONAL_PARAM | M_OPT_FIXED, ({"auto", -1}, {"no", 0}, {"yes", 1}, {"", 1})), @@ -460,8 +463,8 @@ const m_option_t mp_opts[] = { OPT_SETTINGSLIST("ao-defaults", ao_defs, 0, &ao_obj_list), OPT_FLAG("fixed-vo", fixed_vo, CONF_GLOBAL), OPT_FLAG("force-window", force_vo, CONF_GLOBAL), - OPT_FLAG("ontop", vo.ontop, 0), - OPT_FLAG("border", vo.border, 0), + OPT_FLAG("ontop", vo.ontop, M_OPT_FIXED), + OPT_FLAG("border", vo.border, M_OPT_FIXED), OPT_CHOICE("softvol", softvol, 0, ({"no", SOFTVOL_NO}, @@ -475,7 +478,7 @@ const m_option_t mp_opts[] = { {"no", 0}, {"yes", 1}, {"", 1})), OPT_STRING("volume-restore-data", mixer_restore_volume_data, 0), - OPT_FLAG("gapless-audio", gapless_audio, 0), + OPT_FLAG("gapless-audio", gapless_audio, M_OPT_FIXED), OPT_GEOMETRY("geometry", vo.geometry, 0), OPT_SIZE_BOX("autofit", vo.autofit, 0), @@ -488,11 +491,11 @@ const m_option_t mp_opts[] = { OPT_FLOATRANGE("monitoraspect", vo.force_monitor_aspect, 0, 0.0, 9.0), OPT_FLOATRANGE("monitorpixelaspect", vo.monitor_pixel_aspect, 0, 0.2, 9.0), // start in fullscreen mode: - OPT_FLAG("fullscreen", vo.fullscreen, 0), - OPT_FLAG("fs", vo.fullscreen, 0), + OPT_FLAG("fullscreen", vo.fullscreen, M_OPT_FIXED), + OPT_FLAG("fs", vo.fullscreen, M_OPT_FIXED), // set fullscreen switch method (workaround for buggy WMs) OPT_INTRANGE("fsmode-dontuse", vo.fsmode, 0, 31, 4096), - OPT_FLAG("native-keyrepeat", vo.native_keyrepeat, 0), + OPT_FLAG("native-keyrepeat", vo.native_keyrepeat, M_OPT_FIXED), OPT_FLOATRANGE("panscan", vo.panscan, 0, 0.0, 1.0), OPT_FLOATRANGE("video-zoom", vo.zoom, 0, -20.0, 20.0), OPT_FLOATRANGE("video-pan-x", vo.pan_x, 0, -3.0, 3.0), @@ -547,7 +550,7 @@ const m_option_t mp_opts[] = { //---------------------- mplayer-only options ------------------------ - OPT_FLAG("use-filedir-conf", use_filedir_conf, CONF_GLOBAL), + OPT_FLAG("use-filedir-conf", use_filedir_conf, M_OPT_GLOBAL), OPT_CHOICE("osd-level", osd_level, 0, ({"0", 0}, {"1", 1}, {"2", 2}, {"3", 3})), OPT_INTRANGE("osd-duration", osd_duration, 0, 0, 3600000), @@ -562,10 +565,10 @@ const m_option_t mp_opts[] = { {"yes", 1}, {"hard", 2})), - OPT_FLAG("untimed", untimed, 0), + OPT_FLAG("untimed", untimed, M_OPT_FIXED), - OPT_STRING("stream-capture", stream_capture, 0), - OPT_STRING("stream-dump", stream_dump, 0), + OPT_STRING("stream-capture", stream_capture, M_OPT_FIXED), + OPT_STRING("stream-dump", stream_dump, M_OPT_FIXED), OPT_CHOICE_OR_INT("loop", loop_times, M_OPT_GLOBAL, 2, 10000, ({"no", -1}, {"1", -1}, @@ -609,7 +612,7 @@ const m_option_t mp_opts[] = { OPT_STRING("osd-status-msg", osd_status_msg, 0), OPT_FLAG("slave-broken", slave_mode, CONF_GLOBAL), - OPT_FLAG("idle", player_idle_mode, CONF_GLOBAL), + OPT_FLAG("idle", player_idle_mode, M_OPT_GLOBAL), OPT_INTRANGE("key-fifo-size", input.key_fifo_size, CONF_GLOBAL, 2, 65000), OPT_FLAG("consolecontrols", consolecontrols, CONF_GLOBAL), OPT_FLAG("mouse-movements", vo.enable_mouse_movements, CONF_GLOBAL), diff --git a/player/command.c b/player/command.c index 11a5422add..feaf4788d2 100644 --- a/player/command.c +++ b/player/command.c @@ -1991,9 +1991,7 @@ static int access_options(struct m_property_action_arg *ka, MPContext *mpctx) m_option_copy(opt->opt, ka->arg, opt->data); return M_PROPERTY_OK; case M_PROPERTY_SET: - if (!(mpctx->initialized_flags & INITIALIZED_PLAYBACK) && - !(opt->opt->flags & (M_OPT_PRE_PARSE | M_OPT_GLOBAL))) - { + if (!(opt->opt->flags & (M_OPT_PRE_PARSE | M_OPT_FIXED))) { m_option_copy(opt->opt, opt->data, ka->arg); return M_PROPERTY_OK; }