summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-10-12 10:17:55 +0200
committerwm4 <wm4@nowhere>2012-10-12 11:53:53 +0200
commit85d185441acf4691c830db2f40235ac927410d45 (patch)
tree211177793cd5d6b399346be661af8e7528f0f411
parent65fc530f0c3ff02f982a0e4c74988d4a53730f04 (diff)
parente1b15dee4c250bf6509594e241eb2856c8d21e0f (diff)
downloadmpv-85d185441acf4691c830db2f40235ac927410d45.tar.bz2
mpv-85d185441acf4691c830db2f40235ac927410d45.tar.xz
Merge branch 'input_changes' into master
Conflicts: DOCS/man/en/vo.rst etc/input.conf input/input.c m_property.c
-rw-r--r--DOCS/man/en/changes.rst53
-rw-r--r--DOCS/man/en/input.rst308
-rw-r--r--DOCS/man/en/mpv.rst2
-rw-r--r--DOCS/man/en/options.rst72
-rw-r--r--DOCS/man/en/vo.rst2
-rwxr-xr-xTOOLS/mpv_identify.sh23
-rw-r--r--bstr.h2
-rw-r--r--cfg-mplayer.h26
-rw-r--r--command.c1739
-rw-r--r--command.h5
-rw-r--r--defaultopts.c1
-rw-r--r--etc/input.conf162
-rw-r--r--input/input.c591
-rw-r--r--input/input.h92
-rw-r--r--libvo/video_out.c2
-rw-r--r--m_config.c4
-rw-r--r--m_config.h3
-rw-r--r--m_option.c285
-rw-r--r--m_option.h39
-rw-r--r--m_property.c488
-rw-r--r--m_property.h296
-rw-r--r--metadata.h55
-rw-r--r--mp_core.h9
-rw-r--r--mp_osd.h4
-rw-r--r--mpcommon.h2
-rw-r--r--mplayer.c252
-rw-r--r--mplayer.h4
-rw-r--r--options.h4
-rw-r--r--screenshot.c25
-rw-r--r--sub/ass_mp.c39
-rw-r--r--sub/osd_libass.c4
-rw-r--r--sub/sd_ass.c4
-rw-r--r--talloc.c4
33 files changed, 2196 insertions, 2405 deletions
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst
index 5b1c3ea4a6..402bdbd336 100644
--- a/DOCS/man/en/changes.rst
+++ b/DOCS/man/en/changes.rst
@@ -84,7 +84,7 @@ Command line switches
``-no-opt``, or better ``--no-opt``.
* Per-file options are not the default anymore. You can explicitly specify
file local options. See ``Usage`` section.
-* Table of renamed switches:
+* Table of renamed/replaced switches:
=================================== ===================================
Old New
@@ -92,20 +92,53 @@ Command line switches
-nosound --no-audio
-use-filename-title --title="${filename}"
-loop 0 --loop=inf
+ -hardframedrop --framedrop=hard
+ -osdlevel --osd-level
+ -delay --audio-delay
+ -subdelay --sub-delay
+ -subpos --sub-pos
+ -forcedsubsonly --sub-forced-only
=================================== ===================================
input.conf and slave commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* Table of renamed slave commands:
-
- =================================== ===================================
- Old New
- =================================== ===================================
- pt_step 1 b playlist_next b
- pt_step -1 b playlist_prev b
- pt_clear playlist_clear
- =================================== ===================================
+* Table of renamed input commands:
+
+ This lists only commands that are not always gracefully handled by the
+ internal legacy translation layer. If an input.conf contains any legacy
+ commands, they will be displayed with ``-v`` when it is loaded, and show
+ and the replacement commands.
+
+ Properties containing ``_`` to separate words use ``-`` instead.
+
+ +--------------------------------+----------------------------------------+
+ | Old | New |
+ +================================+========================================+
+ | pt_step 1 [0|1] | playlist_next [weak|force] |
+ | | (translation layer can't deal with |
+ | | whitespace) |
+ +--------------------------------+----------------------------------------+
+ | pt_step -1 [0|1] | playlist_prev [weak|force] (same) |
+ +--------------------------------+----------------------------------------+
+ | switch_ratio [<ratio>] | set aspect <ratio> |
+ | | set aspect 0 (to reset aspect) |
+ +--------------------------------+----------------------------------------+
+ | step_property_osd <prop> <step>| cycle <prop> <step> (wraps), |
+ | <dir> | add <prop> <step> (clamps). |
+ | | <dir> parameter unsupported. Use |
+ | | a negative step instead. |
+ +--------------------------------+----------------------------------------+
+ | step_property <prop> <step> | Prefix cycle or add with no-osd: |
+ | <dur> | no-osd cycle <prop> <step> |
+ +--------------------------------+----------------------------------------+
+ | osd_show_property_text <text> | show_text <text> |
+ | | The property expansion format string |
+ | | syntax slightly changed. |
+ +--------------------------------+----------------------------------------+
+ | osd_show_text | Now does the same as |
+ | | osd_show_property_text. |
+ +--------------------------------+----------------------------------------+
Other
~~~~~
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst
new file mode 100644
index 0000000000..58565f0267
--- /dev/null
+++ b/DOCS/man/en/input.rst
@@ -0,0 +1,308 @@
+.. _input:
+
+INPUT.CONF
+==========
+
+The input.conf file consists of a list of key bindings, for example:
+
+| s screenshot # take a screenshot with the s key
+
+Each line maps a key to an input command. Keys are specified with their literal
+value (upper case if combined with ``Shift``), or a name for special keys. For
+example, ``a`` maps to the ``a`` key without shift, and ``A`` maps to ``a``
+with shift.
+
+A list of special keys can be obtained with
+
+| **mplayer** --input=keylist
+
+In general, keys can be combined with ``Shift``, ``Ctrl`` and ``Alt``:
+
+| ctrl+q quit
+
+General input command syntax
+----------------------------
+
+`[Shift+][Ctrl+][Alt+][Meta+]<key> [<prefix>] <command> (<argument>)*`
+
+Newlines always start a new binding. ``#`` starts a comment (outside of quoted
+string arguments). To bind commands to the ``#`` key, ``SHARP`` can be used.
+
+<key> is either the literal character the key produces (ASCII or unicode
+character), or a symbol name.
+
+Arguments are separated by whitespace. This applies even to string arguments.
+For this reason, string arguments should be quoted with ``"``. Inside quotes,
+C style escaping can be used.
+
+Optional arguments can be skipped with ``-``.
+
+List of input commands
+----------------------
+
+ignore
+ Use this to "block" keys that should be unbound, and do nothing. Useful for
+ disabling default bindings, without disabling all bindings with
+ ``--input=default-bindings=no``.
+
+seek <seconds> [relative|absolute|absolute-percent] [default-precise|exact|keyframes]
+ Change the playback position. By default, seeks by a relative amount of
+ seconds.
+
+ The second argument sets the seek mode:
+
+ relative (default)
+ Seek relative to current position (a negative value seeks backwards).
+ absolute
+ Seek to a given time.
+ absolute-percent
+ Seek to agiven percent position.
+
+ The third argument defines how exact the seek is:
+
+ default-precise (default)
+ Follow the default behavior as set by ``--hr-seek``, which by default
+ does imprecise seeks (like ``keyframes``).
+ exact
+ Always do exact/hr/precise seeks (slow).
+ keyframes
+ Always restart playback at keyframe boundaries (fast).
+
+frame_step
+ Basically seek forward by one frame. Actually this plays one frame, then
+ pauses again.
+
+set <property> "<value>"
+ Set the given property to the given value.
+
+add <property> [<value>]
+ Add the given value to the property. On overflow or underflow, clamp the
+ property to the maximum. If <value> is omitted, assume ``1``.
+
+cycle <property> [up|down]
+ Cycle the given property. ``up`` and ``down`` set the cycle direction. On
+ overflow, set the property back to the minimum, on underflow set it to the
+ maximum. If ``up`` or ``down`` is omitted, assume ``up``.
+
+speed_mult <value>
+ Multiply the ``speed`` property by the given value.
+
+screenshot [single|each-frame] [video|window]
+ Take a screenshot.
+
+ First argument:
+
+ <single> (default)
+ Take a single screenshot.
+ <each-frame>
+ Take a screenshot each frame. Issue this command again to stop taking
+ screenshots.
+
+ Second argument:
+
+ <video> (default)
+ Save the video image, in its original resolution. Typically without
+ OSD or subtitles, but the exact behavior depends on the selected video
+ output.
+ <window>
+ Save the contents of the mplayer window. Typically scaled, with OSD and
+ subtitles. The exact behavior depends on the selected video output, and
+ if not support is available, this will act like ``video``.
+
+playlist_next [weak|force]
+ Go to the next entry on the playlist.
+
+ weak (default)
+ If the last file on the playlist is currently played, do nothing.
+ force
+ Terminate playback if there are no more files on the playlist.
+
+playlist_prev [weak|force]
+ Go to the previous entry on the playlist.
+
+ weak (default)
+ If the first file on the playlist is currently played, do nothing.
+ force
+ Terminate playback if the first file is being played.
+
+loadfile "<file>" [replace|append]
+ Load the given file and play it.
+
+ Second argument:
+
+ <replace> (default)
+ Stop playback of the current file, and play the new file immediately.
+ <append>
+ Append the file to the playlist.
+
+loadlist "<playlist>" [replace|append]
+ Load the given playlist file (like ``--playlist``).
+
+playlist_clear
+ Clear the playlist, except the currently played file.
+
+run "<command>"
+ Run the given command with ``/bin/sh -c``. The string is expanded like in
+ ``--playing-msg`` before
+
+quit [<code>]
+ Exit the player using the given exit code.
+
+sub_load "<file>"
+ Load the given subtitle file. It's not selected as current subtitle after
+ loading.
+
+sub_step <skip>
+ Change subtitle timing such, that the subtitle event after the next <skip>
+ subtitle events is displayed. <skip> can be negative to step back.
+
+osd [<level>]
+ Toggle OSD level. If <level> is specified, set the OSD mode
+ (see ``--osd-level`` for valid values).
+
+print_text "<string>"
+ Print text to stdout. The string can contain properties, which are expanded
+ like in ``--playing-msg``.
+
+show_text "<string>" [<duration>] [<level>]
+ Show text on the OSD. The string can contain properties, which are expanded
+ like in ``--playing-msg``. This can be used to show playback time, filename,
+ and so on.
+
+ <duration> is the time in ms to show the message. By default, it uses the
+ same value as ``--osd-duration``.
+
+ <level> is the minimum OSD level to show the text (see ``--osd-level``).
+
+show_progress
+ Show the progress bar, the elapsed time and the total duration of the file
+ on the OSD.
+
+show_chapters
+ Show a list of chapters on the OSD.
+
+show_tracks
+ Show a list of video/audio/subtitle tracks on the OSD.
+
+
+
+Undocumented properties: tv_start_scan, tv_step_channel, tv_step_norm,
+tv_step_chanlist, tv_set_channel, tv_last_channel, tv_set_freq, tv_step_freq,
+tv_set_norm, dvb_set_channel, radio_step_channel, radio_set_channel,
+radio_set_freq, radio_step_freq (all of these should be replaced by properties),
+edl_mark, stop (questionable use), get_property (?), af_switch, af_add, af_del,
+af_clr, af_cmdline, vo_cmdline (experimental).
+
+Input command prefixes
+----------------------
+
+osd-auto (default)
+ Use the default behavior for this command.
+no-osd
+ Do not use any OSD for this command.
+osd-bar
+ If possible, show a bar with this command. Seek commands will show the
+ progress bar, property changing commands may show the newly set value.
+osd-msg
+ If possible, show an OSD message with this command. The seek command shows
+ the current playback time (like ``show_progress``), property changing
+ commands show the newly set value as text.
+osd-msg-bar
+ Combine osd-bar and osd-msg.
+
+
+
+All of these are still overridden by the global ``--osd-level`` settings.
+
+Undocumented prefixes: pausing, pausing_keep, pausing_toggle,
+pausing_keep_force. (Should these be made official?)
+
+Properties
+----------
+
+Properties are used to set mplayer options during runtime, or to query arbitrary
+information. They can be manipulated with the ``set``/``add``/``cycle``
+commands, and retrieved with ``show_text``, or anything else that uses property
+expansion. (See ``--playing-msg`` how properties are expanded.)
+
+``W`` indicates whether the property is generally writeable. If an option
+is referenced, the property should take/return exactly the same values as the
+option.
+
+=========================== = ==================================================
+Name W Comment
+=========================== = ==================================================
+osd-level x see ``--osd-level``
+loop x see ``--loop``
+speed x see ``--speed``
+filename currently played file (path stripped)
+path currently played file (full path)
+demuxer
+stream-pos x byte position in source stream
+stream-start start byte offset in source stream
+stream-end end position in bytes in source stream
+stream-length length in bytes (${stream-end} - ${stream-start})
+stream-time-pos x time position in source stream (also see time-pos)
+length length of the current file in seconds
+percent-pos x position in current file (0-100)
+time-pos x position in current file in seconds
+chapter x current chapter number
+edition x current MKV edition number
+titles number of DVD titles
+chapters number of chapters
+editions number of MKV editions
+angle current DVD angle
+metadata metadata key/value pairs
+metadata/<key> value of metedata entry <key>
+pause x pause status (bool)
+pts-association-mode x see ``--pts-association-mode``
+hr-seek x see ``--hr-seek``
+volume x current volume (0-100)
+mute x current mute status (bool)
+audio-delay x see ``--audio-delay``
+audio-format audio format (codec tag)
+audio-codec audio codec selected for decoding
+audio-bitrate audio bitrate
+samplerate audio samplerate
+channels number of audio channels
+audio x current audio track (similar to ``--aid``)
+balance x audio channel balance
+fullscreen x see ``--fullscreen``
+deinterlace x deinterlacing, if available (bool)
+colormatrix x see ``--colormatrix``
+colormatrix-input-range x see ``--colormatrix-input-range``
+colormatrix-output-range x see ``--colormatrix-output-range``
+ontop x see ``--ontop``
+rootwin x see ``--rootwin``
+border x see ``--border``
+framedrop x see ``--framedrop``
+gamma x see ``--gamma``
+brightness x see ``--brightness``
+contrast x see ``--contrast``
+saturation x see ``--saturation``
+hue x see ``--hue``
+panscan x see ``--panscan``
+vsync x see ``--vsync``
+video-format video format (integer FourCC)
+video-codec video codec selected for decoding
+video-bitrate video bitrate
+width video width
+height video height
+fps FPS (may contain bogus values)
+aspect x video aspect
+video x current video track (similar to ``--vid``)
+program x switch TS program (write-only)
+sub x current subttitle track (similar to ``--sid``)
+sub-delay x see ``--sub-delay``
+sub-pos x see ``--sub-pos``
+sub-visibility x whether current subtitle is rendered
+sub-forced-only x see ``--sub-forced-only``
+sub-scale x subtitle font size multiplicator
+ass-use-margins x see ``--ass-use-margins``
+ass-vsfilter-aspect-compat x see ``--ass-vsfilter-aspect-compat``
+ass-style-override x see ``--ass-style-override``
+tv-brightness
+tv-contrast
+tv-saturation
+tv-hue
+=========================== = ==================================================
diff --git a/DOCS/man/en/mpv.rst b/DOCS/man/en/mpv.rst
index 2cca30c383..6de386fdf9 100644
--- a/DOCS/man/en/mpv.rst
+++ b/DOCS/man/en/mpv.rst
@@ -409,6 +409,8 @@ OPTIONS
.. include:: encode.rst
+.. include:: input.rst
+
Taking screenshots
==================
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index dbac793fa9..c825cd58d6 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -176,6 +176,14 @@
rendering text subtitles. The syntax of the file is exactly like the ``[V4
Styles]`` / ``[V4+ Styles]`` section of SSA/ASS.
+--ass-style-override=<yes|no>
+ Control whether user style overrides should be applied.
+
+ :yes: Apply all the ``--ass-*`` style override options. Changing the default
+ for any of these options can lead to incorrect subtitle rendering.
+ (Default.)
+ :no: Render subtitles as forced by subtitle scripts.
+
--ass-top-margin=<value>
Adds a black band at the top of the frame. The SSA/ASS renderer can place
toptitles there (with ``--ass-use-margins``).
@@ -472,7 +480,7 @@
will stay hidden. Supported by video output drivers which use X11 or
OS X Cocoa.
---delay=<sec>
+--audio-delay=<sec>
audio delay in seconds (positive or negative float value). Negative values
delay the audio, and positive values delay the video.
@@ -624,7 +632,7 @@
there is a change in video parameters, video stream or file. This used to
be the default behavior. Currently only affects X11 VOs.
---forcedsubsonly
+--sub-forced-only
Display only forced subtitles for the DVD subtitle stream selected by e.g.
``--slang``.
@@ -643,11 +651,14 @@
--fps=<float>
Override video framerate. Useful if the original value is wrong or missing.
---framedrop
+--framedrop=<no|yes|hard>
Skip displaying some frames to maintain A/V sync on slow systems. Video
filters are not applied to such frames. For B-frames even decoding is
- skipped completely. May produce unwatchably choppy output. See also
- ``--hardframedrop``.
+ skipped completely. May produce unwatchably choppy output. With ``hard``,
+ decoding and output of any frame can be skipped, and will lead to an even
+ worse playback experience.
+
+ Practical use of this feature is questionable. Disabled by default.
--frames=<number>
Play/convert only first <number> frames, then quit.
@@ -656,6 +667,7 @@
Specifies the character set that will be passed to FriBiDi when decoding
non-UTF-8 subtitles (default: ISO8859-8).
+--fullscreen
--fs
Fullscreen playback (centers movie, and paints black bands around it).
@@ -753,9 +765,6 @@
``--no-grabpointer`` tells the player to not grab the mouse pointer after a
video mode change (``--vm``). Useful for multihead setups.
---hardframedrop
- More intense frame dropping (breaks decoding). Leads to image distortion!
-
--heartbeat-cmd
Command that is executed every 30 seconds during playback via *system()* -
i.e. using the shell.
@@ -1294,7 +1303,7 @@
--osd-fractions
Show OSD times with fractions of seconds.
---osdlevel=<0-3>
+--osd-level=<0-3>
Specifies which mode the OSD should start in.
:0: subtitles only
@@ -1312,9 +1321,6 @@
controls how much of the image is cropped. May not work with all video
output drivers.
- *NOTE*: Values between -1 and 0 are allowed as well, but highly
- experimental and may crash or worse. Use at your own risk!
-
--panscanrange=<-19.0-99.0>
(experimental)
Change the range of the pan-and-scan functionality (default: 1). Positive
@@ -1328,15 +1334,37 @@
See also ``--user``.
--playing-msg=<string>
- Print out a string before starting playback. The following expansions are
- supported:
+ Print out a string before starting playback. The string is expanded for
+ properties, e.g. ``--playing-msg=file: ${filename}`` will print the string
+ ``file: `` followed by the currently played filename.
+
+ The following expansions are supported:
${NAME}
- Expand to the value of the property ``NAME``.
- ?(NAME:TEXT)
- Expand ``TEXT`` only if the property ``NAME`` is available.
- ?(!NAME:TEXT)
- Expand ``TEXT`` only if the property ``NAME`` is not available.
+ Expands to the value of the property ``NAME``. If ``NAME`` starts with
+ ``=``, use the raw value of the property. If retrieving the property
+ fails, expand to an error string. (Use ``${NAME:}`` with a trailing
+ ``:`` to expand to an empty string instead.)
+ ${NAME:STR}
+ Expands to the value of the property ``NAME``, or ``STR`` if the
+ property can't be retrieved. ``STR`` is expanded recursively.
+ ${!NAME:STR}
+ Expands to ``STR`` (recursively) if the property ``NAME`` can't be
+ retrieved.
+ ${?NAME:STR}
+ Expands to ``STR`` (recursively) if the property ``NAME`` is available.
+ $$
+ Expands to ``$``.
+ $}
+ Expands to ``}``. (To produce this character inside rexursive
+ expansion.)
+ $>
+ Disable property expansion and special handling of ``$`` for the rest
+ of the string.
+
+--status-msg=<string>
+ Print out a custom string during playback instead of the standard status
+ line. Expands properties. See ``--playing-msg``.
--playlist=<filename>
Play files according to a playlist file (ASX, Winamp, SMIL, or
@@ -1892,7 +1920,7 @@
- ``--subcp=enca:pl:cp1250`` guess the encoding for Polish, fall back on
cp1250.
---subdelay=<sec>
+--sub-delay=<sec>
Delays subtitles by <sec> seconds. Can be negative.
--subfile=<filename>
@@ -1939,7 +1967,7 @@
*NOTE*: <rate> > movie fps speeds the subtitles up for frame-based
subtitle files and slows them down for time-based ones.
---subpos=<0-100>
+--sub-pos=<0-100>
Specify the position of subtitles on the screen. The value is the vertical
position of the subtitle in % of the screen height.
Can be useful with ``--vf=expand``.
@@ -1980,7 +2008,7 @@
the line used for the OSD and clear it (default: ``^[[A\r^[[K``).
--title
- Set the window title. The string can contain property names.
+ Set the window title. Properties are expanded (see ``--playing-msg``).
--tv=<option1:option2:...>
This option tunes various properties of the TV capture module. For
diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst
index dd5b0f72ef..f7346a55f5 100644
--- a/DOCS/man/en/vo.rst
+++ b/DOCS/man/en/vo.rst
@@ -635,7 +635,7 @@ opengl-old
(no-)osd
Enable or disable support for OSD rendering via OpenGL (default:
enabled). This option is for testing; to disable the OSD use
- ``--osdlevel=0`` instead.
+ ``--osd-level=0`` instead.
sw
Continue even if a software renderer is detected.
diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh
index 49cec2ce94..d09504ab57 100755
--- a/TOOLS/mpv_identify.sh
+++ b/TOOLS/mpv_identify.sh
@@ -59,30 +59,29 @@ fi
__midentify__allprops="
filename
path
- stream_start
- stream_end
- stream_length
+ stream-start
+ stream-end
+ stream-length
demuxer
- switch_program
length
chapters
editions
titles
- switch_audio
- audio_bitrate
- audio_codec
- audio_format
+ audio
+ audio-bitrate
+ audio-codec
+ audio-format
channels
samplerate
- switch_video
+ video
angle
- video_bitrate
- video_codec
- video_format
+ video-bitrate
+ video-codec
+ video-format
aspect
fps
width
diff --git a/bstr.h b/bstr.h
index fab9be5814..dfe6f3a556 100644
--- a/bstr.h
+++ b/bstr.h
@@ -162,7 +162,7 @@ static inline int bstr_find0(struct bstr haystack, const char *needle)
return bstr_find(haystack, bstr0(needle));
}
-static inline int bstr_eatstart0(struct bstr *s, char *prefix)
+static inline int bstr_eatstart0(struct bstr *s, const char *prefix)
{
return bstr_eatstart(s, bstr0(prefix));
}
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index 870dec4649..d317f0eb32 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -382,7 +382,7 @@ const m_option_t common_opts[] = {
{"frames", &play_n_frames_mf, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL},
// seek to byte/seconds position
- {"sb", &seek_to_byte, CONF_TYPE_POSITION, CONF_MIN, 0, 0, NULL},
+ {"sb", &seek_to_byte, CONF_TYPE_INT64, CONF_MIN, 0, 0, NULL},
OPT_TIME("ss", seek_to_sec, 0),
// start paused
@@ -460,7 +460,7 @@ const m_option_t common_opts[] = {
OPT_FLOATRANGE("speed", playback_speed, 0, 0.01, 100.0),
// set a-v distance
- {"delay", &audio_delay, CONF_TYPE_FLOAT, CONF_RANGE, -100.0, 100.0, NULL},
+ {"audio-delay", &audio_delay, CONF_TYPE_FLOAT, CONF_RANGE, -100.0, 100.0, NULL},
// ignore header-specified delay (dwStart)
{"ignore-start", &ignore_start, CONF_TYPE_FLAG, 0, 0, 1, NULL},
@@ -513,12 +513,12 @@ const m_option_t common_opts[] = {
OPT_STRINGLIST("sub", sub_name, 0),
OPT_PATHLIST("sub-paths", sub_paths, 0),
{"subcp", &sub_cp, CONF_TYPE_STRING, 0, 0, 0, NULL},
- {"subdelay", &sub_delay, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL},
+ {"sub-delay", &sub_delay, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL},
{"subfps", &sub_fps, CONF_TYPE_FLOAT, 0, 0.0, 10.0, NULL},
OPT_MAKE_FLAGS("autosub", sub_auto, 0),
{"unicode", &sub_unicode, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"utf8", &sub_utf8, CONF_TYPE_FLAG, 0, 0, 1, NULL},
- {"forcedsubsonly", &forced_subs_only, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {"sub-forced-only", &forced_subs_only, CONF_TYPE_FLAG, 0, 0, 1, NULL},
// specify IFO file for VOBSUB subtitle
{"ifo", &spudec_ifo, CONF_TYPE_STRING, 0, 0, 0, NULL},
// enable Closed Captioning display
@@ -530,7 +530,7 @@ const m_option_t common_opts[] = {
{"font", &font_name, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"subfont", &sub_font_name, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"ffactor", &font_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 10.0, NULL},
- {"subpos", &sub_pos, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL},
+ {"sub-pos", &sub_pos, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL},
{"subwidth", &sub_width_p, CONF_TYPE_INT, CONF_RANGE, 10, 100, NULL},
{"spualign", &spu_alignment, CONF_TYPE_INT, CONF_RANGE, -1, 2, NULL},
{"spuaa", &spu_aamode, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL},
@@ -554,6 +554,8 @@ const m_option_t common_opts[] = {
OPT_STRING("ass-border-color", ass_border_color, 0),
OPT_STRING("ass-styles", ass_styles_file, 0),
OPT_INTRANGE("ass-hinting", ass_hinting, 0, 0, 7),
+ OPT_CHOICE("ass-style-override", ass_style_override, 0,
+ ({"no", 0}, {"yes", 1})),
{NULL, NULL, 0, 0, 0, 0, NULL}
};
@@ -622,6 +624,7 @@ const m_option_t mplayer_opts[]={
// video mode switching: (x11,xv,dga)
OPT_MAKE_FLAGS("vm", vidmode, 0),
// start in fullscreen mode:
+ OPT_MAKE_FLAGS("fullscreen", fullscreen, CONF_GLOBAL),
OPT_MAKE_FLAGS("fs", fullscreen, CONF_GLOBAL),
// set fullscreen switch method (workaround for buggy WMs)
{"fsmode-dontuse", &vo_fsmode, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL},
@@ -632,7 +635,7 @@ const m_option_t mplayer_opts[]={
{"double", &vo_doublebuffering, CONF_TYPE_FLAG, 0, 0, 1, NULL},
// wait for v-sync (gl)
{"vsync", &vo_vsync, CONF_TYPE_FLAG, 0, 0, 1, NULL},
- {"panscan", &vo_panscan, CONF_TYPE_FLOAT, CONF_RANGE, -1.0, 1.0, NULL},
+ {"panscan", &vo_panscan, CONF_TYPE_FLOAT, CONF_RANGE, 0, 1.0, NULL},
OPT_FLOATRANGE("panscanrange", vo_panscanrange, 0, -19.0, 99.0),
OPT_CHOICE("colormatrix", requested_colorspace, 0,
({"auto", MP_CSP_AUTO},
@@ -674,16 +677,20 @@ const m_option_t mplayer_opts[]={
{"use-filedir-conf", &use_filedir_conf, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL},
OPT_INTRANGE("osdlevel", osd_level, 0, 0, 3),
+ OPT_CHOICE("osd-level", osd_level, 0,
+ ({"0", 0}, {"1", 1}, {"2", 2}, {"3", 3})),
OPT_INTRANGE("osd-duration", osd_duration, 0, 0, 3600000),
OPT_MAKE_FLAGS("osd-fractions", osd_fractions, 0),
OPT_STRING("vobsub", vobsub_name, 0),
{"vobsubid", &vobsub_id, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL},
- {"sstep", &step_sec, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL},
+ {"sstep", &step_sec, CONF_TYPE_DOUBLE, CONF_MIN, 0, 0, NULL},
- {"framedrop", &frame_dropping, CONF_TYPE_FLAG, 0, 0, 1, NULL},
- {"hardframedrop", &frame_dropping, CONF_TYPE_FLAG, 0, 0, 2, NULL},
+ OPT_CHOICE("framedrop", frame_dropping, 0,
+ ({"no", 0},
+ {"yes", 1}, {"", 1},
+ {"hard", 2})),
OPT_FLAG_ON("untimed", untimed, 0),
@@ -726,6 +733,7 @@ const m_option_t mplayer_opts[]={
OPT_STRING("term-osd-esc", term_osd_esc, 0, OPTDEF_STR("\x1b[A\r\x1b[K")),
OPT_STRING("playing-msg", playing_msg, 0),
+ OPT_STRING("status-msg", status_msg, 0),
{"slave-broken", &slave_mode, CONF_TYPE_FLAG,CONF_GLOBAL , 0, 1, NULL},
OPT_MAKE_FLAGS("idle", player_idle_mode, CONF_GLOBAL),
diff --git a/command.c b/command.c
index 1cffedfd13..4afc2104e4 100644
--- a/command.c
+++ b/command.c
@@ -39,7 +39,6 @@
#include "m_option.h"
#include "m_property.h"
#include "m_config.h"
-#include "metadata.h"
#include "libmpcodecs/vf.h"
#include "libmpcodecs/vd.h"
#include "mp_osd.h"
@@ -72,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)
{
@@ -105,110 +114,29 @@ static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy,
vo->dheight, vo_fs);
}
-static void choice_get_min_max(const struct m_option *opt, int *min, int *max)
-{
- assert(opt->type == &m_option_type_choice);
- *min = INT_MAX;
- *max = INT_MIN;
- for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) {
- *min = FFMIN(*min, alt->value);
- *max = FFMAX(*max, alt->value);
- }
- if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
- *min = FFMIN(*min, opt->min);
- *max = FFMAX(*max, opt->max);
- }
-}
-
-static void check_choice(int dir, int val, bool *found, int *best, int choice)
-{
- if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) ||
- (dir == +1 && (!(*found) || choice < (*best)) && choice > val))
- {
- *found = true;
- *best = choice;
- }
-}
-
-static int step_choice(const struct m_option *opt, int val, int add, bool wrap)
-{
- assert(opt->type == &m_option_type_choice);
- int dir = add > 0 ? +1 : -1;
- bool found = false;
- int best = 0; // init. value unused
-
- if (add == 0)
- return val;
-
- if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
- int newval = val + add;
- if (val >= opt->min && val <= opt->max &&
- newval >= opt->min && newval <= opt->max)
- {
- found = true;
- best = newval;
- } else {
- check_choice(dir, val, &found, &best, opt->min);
- check_choice(dir, val, &found, &best, opt->max);
- }
- }
-
- for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++)
- check_choice(dir, val, &found, &best, alt->value);
-
- if (!found) {
- int min, max;
- choice_get_min_max(opt, &min, &max);
- best = (dir == -1) ^ wrap ? min : max;
- }
-
- return best;
-}
-
+// Property-option bridge.
static int mp_property_generic_option(struct m_option *prop, int action,
void *arg, MPContext *mpctx)
{
char *optname = prop->priv;
- const struct m_option *opt = m_config_get_option(mpctx->mconfig,
- bstr0(optname));
- void *valptr = m_option_get_ptr(opt, &mpctx->opts);
+ struct m_config_option *opt = m_config_get_co(mpctx->mconfig,
+ bstr0(optname));
+ void *valptr = opt->data;
switch (action) {
case M_PROPERTY_GET_TYPE:
- *(const struct m_option **)arg = opt;
+ *(struct m_option *)arg = *(opt->opt);
return M_PROPERTY_OK;
case M_PROPERTY_GET:
- m_option_copy(opt, arg, valptr);
+ m_option_copy(opt->opt, arg, valptr);
return M_PROPERTY_OK;
case M_PROPERTY_SET:
- m_option_copy(opt, valptr, arg);
+ m_option_copy(opt->opt, valptr, arg);
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- if (opt->type == &m_option_type_choice) {
- int add = arg ? (*(int *)arg) : +1;
- int v = *(int *) valptr;
- *(int *) valptr = step_choice(opt, v, add, true);
- return M_PROPERTY_OK;
- }
- break;
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
-/// OSD level (RW)
-static int mp_property_osdlevel(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- return m_property_choice(prop, action, arg, &mpctx->opts.osd_level);
-}
-
-/// Loop (RW)
-static int mp_property_loop(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- return mp_property_generic_option(prop, action, arg, mpctx);
-}
-
/// Playback speed (RW)
static int mp_property_playback_speed(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
@@ -216,43 +144,45 @@ static int mp_property_playback_speed(m_option_t *prop, int action,
struct MPOpts *opts = &mpctx->opts;
double orig_speed = opts->playback_speed;
switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
+ case M_PROPERTY_SET: {
opts->playback_speed = *(float *) arg;
- goto set;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- opts->playback_speed += (arg ? *(float *) arg : 0.1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
- set:
- M_PROPERTY_CLAMP(prop, opts->playback_speed);
// Adjust time until next frame flip for nosound mode
mpctx->time_frame *= orig_speed / opts->playback_speed;
reinit_audio_chain(mpctx);
return M_PROPERTY_OK;
}
- return m_property_float_range(prop, action, arg, &opts->playback_speed);
+ case M_PROPERTY_PRINT:
+ *(char **)arg = talloc_asprintf(NULL, "x %6.2f", orig_speed);
+ return M_PROPERTY_OK;
+ }
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// filename with path (RO)
static int mp_property_path(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- return m_property_string_ro(prop, action, arg, mpctx->filename);
+ if (action == M_PROPERTY_GET) {
+ *(char **)arg = talloc_strdup(NULL, mpctx->filename);
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// filename without path (RO)
static int mp_property_filename(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- char *f;
if (!mpctx->filename)
return M_PROPERTY_UNAVAILABLE;
- f = (char *)mp_basename(mpctx->filename);
- if (!*f)
- f = mpctx->filename;
- return m_property_string_ro(prop, action, arg, f);
+ if (action == M_PROPERTY_GET) {
+ char *f = (char *)mp_basename(mpctx->filename);
+ if (!*f)
+ f = mpctx->filename;
+ *(char **)arg = talloc_strdup(NULL, f);
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Demuxer name (RO)
@@ -262,7 +192,11 @@ static int mp_property_demuxer(m_option_t *prop, int action, void *arg,
struct demuxer *demuxer = mpctx->master_demuxer;
if (!demuxer)
return M_PROPERTY_UNAVAILABLE;
- return m_property_string_ro(prop, action, arg, (char *)demuxer->desc->name);
+ if (action == M_PROPERTY_GET) {
+ *(char **)arg = talloc_strdup(NULL, demuxer->desc->name);
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Position in the stream (RW)
@@ -272,15 +206,12 @@ static int mp_property_stream_pos(m_option_t *prop, int action, void *arg,
struct stream *stream = mpctx->stream;
if (!stream)
return M_PROPERTY_UNAVAILABLE;
- if (!arg)
- return M_PROPERTY_ERROR;
switch (action) {
case M_PROPERTY_GET:
- *(off_t *) arg = stream_tell(stream);
+ *(int64_t *) arg = stream_tell(stream);
return M_PROPERTY_OK;
case M_PROPERTY_SET:
- M_PROPERTY_CLAMP(prop, *(off_t *) arg);
- stream_seek(stream, *(off_t *) arg);
+ stream_seek(stream, *(int64_t *) arg);
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
@@ -295,7 +226,7 @@ static int mp_property_stream_start(m_option_t *prop, int action,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_GET:
- *(off_t *) arg = stream->start_pos;
+ *(int64_t *) arg = stream->start_pos;
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
@@ -310,7 +241,7 @@ static int mp_property_stream_end(m_option_t *prop, int action, void *arg,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_GET:
- *(off_t *) arg = stream->end_pos;
+ *(int64_t *) arg = stream->end_pos;
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
@@ -325,7 +256,7 @@ static int mp_property_stream_length(m_option_t *prop, int action,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_GET:
- *(off_t *) arg = stream->end_pos - stream->start_pos;
+ *(int64_t *) arg = stream->end_pos - stream->start_pos;
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
@@ -342,7 +273,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);
}
@@ -355,38 +286,26 @@ 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)
static int mp_property_percent_pos(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
{
- int pos;
-
if (!mpctx->num_sources)
return M_PROPERTY_UNAVAILABLE;
switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *)arg);
- pos = *(int *)arg;
- break;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- pos = get_percent_pos(mpctx);
- pos += (arg ? *(int *)arg : 10) *
- (action == M_PROPERTY_STEP_UP ? 1 : -1);
- M_PROPERTY_CLAMP(prop, pos);
- break;
- default:
- return m_property_int_ro(prop, action, arg, get_percent_pos(mpctx));
+ case M_PROPERTY_SET: ;
+ int pos = *(int *)arg;
+ queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0);
+ return M_PROPERTY_OK;
+ case M_PROPERTY_GET:
+ *(int *)arg = get_percent_pos(mpctx);
+ return M_PROPERTY_OK;
}
-
- queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0);
- return M_PROPERTY_OK;
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Current position in seconds (RW)
@@ -398,83 +317,48 @@ static int mp_property_time_pos(m_option_t *prop, int action,
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(double *)arg);
queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0);
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- queue_seek(mpctx, MPSEEK_RELATIVE, (arg ? *(double *)arg : 10.0) *
- (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0), 0);
+ case M_PROPERTY_GET:
+ *(double *)arg = get_current_time(mpctx);
return M_PROPERTY_OK;
}
- return m_property_time_ro(prop, action, arg, get_current_time(mpctx));
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Current chapter (RW)
static int mp_property_chapter(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- struct MPOpts *opts = &mpctx->opts;
- int step_all;
- char *chapter_name = NULL;
-
int chapter = get_current_chapter(mpctx);
if (chapter < -1)
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
*(int *) arg = chapter;
return M_PROPERTY_OK;
case M_PROPERTY_PRINT: {
- if (!arg)
- return M_PROPERTY_ERROR;
- chapter_name = chapter_display_name(mpctx, chapter);
+ char *chapter_name = chapter_display_name(mpctx, chapter);
if (!chapter_name)
return M_PROPERTY_UNAVAILABLE;
*(char **) arg = chapter_name;
return M_PROPERTY_OK;
}
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *)arg);
- step_all = *(int *)arg - chapter;
- chapter += step_all;
- break;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN: {
- step_all = (arg && *(int *)arg != 0 ? *(int *)arg : 1)
- * (action == M_PROPERTY_STEP_UP ? 1 : -1);
+ case M_PROPERTY_SET: ;
+ int step_all = *(int *)arg - chapter;
chapter += step_all;
- if (chapter < 0)
- chapter = 0;
- break;
- }
- default:
- return M_PROPERTY_NOT_IMPLEMENTED;
+ double next_pts = 0;
+ queue_seek(mpctx, MPSEEK_NONE, 0, 0);
+ chapter = seek_chapter(mpctx, chapter, &next_pts);
+ if (chapter >= 0) {
+ if (next_pts > -1.0)
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, next_pts, 0);
+ } else if (step_all > 0)
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ return M_PROPERTY_OK;
}
-
- double next_pts = 0;
- queue_seek(mpctx, MPSEEK_NONE, 0, 0);
- chapter = seek_chapter(mpctx, chapter, &next_pts);
- if (chapter >= 0) {
- if (next_pts > -1.0)
- queue_seek(mpctx, MPSEEK_ABSOLUTE, next_pts, 0);
- chapter_name = chapter_display_name(mpctx, chapter);
- set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, opts->osd_duration,
- "Chapter: %s", chapter_name);
- } else if (step_all > 0)
- mpctx->stop_play = PT_NEXT_ENTRY;
- else
- set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, opts->osd_duration,
- "Chapter: (%d) %s", 0, mp_gtext("unknown"));
- talloc_free(chapter_name);
- return M_PROPERTY_OK;
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
static int mp_property_edition(m_option_t *prop, int action, void *arg,
@@ -491,35 +375,29 @@ static int mp_property_edition(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_GET:
- case M_PROPERTY_PRINT:
- return m_property_int_ro(prop, action, arg, edition);
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *)arg);
+ *(int *)arg = edition;
+ return M_PROPERTY_OK;
+ case M_PROPERTY_SET: {
edition = *(int *)arg;
- break;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN: {
- edition += arg ? *(int *)arg : (action == M_PROPERTY_STEP_UP ? 1 : -1);
- if (edition < 0)
- edition = demuxer->num_editions - 1;
- if (edition >= demuxer->num_editions)
- edition = 0;
- break;
+ if (edition != demuxer->edition) {
+ opts->edition_id = edition;
+ mpctx->stop_play = PT_RESTART;
+ }
+ return M_PROPERTY_OK;
}
- default:
- return M_PROPERTY_NOT_IMPLEMENTED;
+ case M_PROPERTY_GET_TYPE: {
+ struct m_option opt = {
+ .name = prop->name,
+ .type = CONF_TYPE_INT,
+ .flags = CONF_RANGE,
+ .min = 0,
+ .max = demuxer->num_editions - 1,
+ };
+ *(struct m_option *)arg = opt;
+ return M_PROPERTY_OK;
}
-
- if (edition != demuxer->edition) {
- opts->edition_id = edition;
- mpctx->stop_play = PT_RESTART;
- set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, opts->osd_duration,
- "Playing edition %d of %d.", edition + 1,
- demuxer->num_editions);
}
- return M_PROPERTY_OK;
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Number of titles in file
@@ -559,7 +437,6 @@ static int mp_property_editions(m_option_t *prop, int action, void *arg,
static int mp_property_angle(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- struct MPOpts *opts = &mpctx->opts;
struct demuxer *demuxer = mpctx->master_demuxer;
int angle = -1;
int angles;
@@ -574,54 +451,26 @@ static int mp_property_angle(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
*(int *) arg = angle;
return M_PROPERTY_OK;
case M_PROPERTY_PRINT: {
- if (!arg)
- return M_PROPERTY_ERROR;
*(char **) arg = talloc_asprintf(NULL, "%d/%d", angle, angles);
return M_PROPERTY_OK;
}
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- angle = *(int *)arg;
- M_PROPERTY_CLAMP(prop, angle);
- break;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN: {
- int step = 0;
- if (arg)
- step = *(int *)arg;
- if (!step)
- step = 1;
- step *= (action == M_PROPERTY_STEP_UP ? 1 : -1);
- angle += step;
- if (angle < 1) //cycle
- angle = angles;
- else if (angle > angles)
- angle = 1;
- break;
- }
- default:
- return M_PROPERTY_NOT_IMPLEMENTED;
- }
- angle = demuxer_set_angle(demuxer, angle);
- if (angle >= 0) {
- struct sh_video *sh_video = demuxer->video->sh;
- if (sh_video)
- resync_video_stream(sh_video);
-
- struct sh_audio *sh_audio = demuxer->audio->sh;
- if (sh_audio)
- resync_audio_stream(sh_audio);
+ angle = demuxer_set_angle(demuxer, *(int *)arg);
+ if (angle >= 0) {
+ struct sh_video *sh_video = demuxer->video->sh;
+ if (sh_video)
+ resync_video_stream(sh_video);
+
+ struct sh_audio *sh_audio = demuxer->audio->sh;
+ if (sh_audio)
+ resync_audio_stream(sh_audio);
+ }
+ return M_PROPERTY_OK;
}
-
- set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, opts->osd_duration,
- "Angle: %d/%d", angle, angles);
- return M_PROPERTY_OK;
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Demuxer meta data
@@ -632,38 +481,33 @@ static int mp_property_metadata(m_option_t *prop, int action, void *arg,
if (!demuxer)
return M_PROPERTY_UNAVAILABLE;
- m_property_action_t *ka;
- char *meta;
static const m_option_t key_type =
{
"metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL
};
switch (action) {
- case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
- *(char ***)arg = demuxer->info;
+ case M_PROPERTY_GET: {
+ char **slist = NULL;
+ m_option_copy(prop, &slist, &demuxer->info);
+ *(char ***)arg = slist;
return M_PROPERTY_OK;
- case M_PROPERTY_KEY_ACTION:
- if (!arg)
- return M_PROPERTY_ERROR;
- ka = arg;
- if (!(meta = demux_info_get(demuxer, ka->key)))
+ }
+ case M_PROPERTY_KEY_ACTION: {
+ struct m_property_action_arg *ka = arg;
+ char *meta = demux_info_get(demuxer, ka->key);
+ if (!meta)
return M_PROPERTY_UNKNOWN;
switch (ka->action) {
case M_PROPERTY_GET:
- if (!ka->arg)
- return M_PROPERTY_ERROR;
- *(char **)ka->arg = meta;
+ *(char **)ka->arg = talloc_strdup(NULL, meta);
return M_PROPERTY_OK;
case M_PROPERTY_GET_TYPE:
- if (!ka->arg)
- return M_PROPERTY_ERROR;
- *(const m_option_t **)ka->arg = &key_type;
+ *(struct m_option *)ka->arg = key_type;
return M_PROPERTY_OK;
}
}
+ }
return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -674,21 +518,17 @@ static int mp_property_pause(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- if (mpctx->paused == (bool) * (int *)arg)
- return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- if (mpctx->paused) {
- unpause_player(mpctx);
- } else {
+ if (*(int *)arg) {
pause_player(mpctx);
+ } else {
+ unpause_player(mpctx);
}
return M_PROPERTY_OK;
- default:
- return m_property_flag(prop, action, arg, &mpctx->paused);
+ case M_PROPERTY_GET:
+ *(int *)arg = mpctx->paused;
+ return M_PROPERTY_OK;
}
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -702,44 +542,19 @@ static int mp_property_volume(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
mixer_getbothvolume(&mpctx->mixer, arg);
return M_PROPERTY_OK;
- case M_PROPERTY_PRINT: {
- float vol;
- if (!arg)
- return M_PROPERTY_ERROR;
- mixer_getbothvolume(&mpctx->mixer, &vol);
- return m_property_float_range(prop, action, arg, &vol);
- }
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- case M_PROPERTY_SET:
- break;
- default:
- return M_PROPERTY_NOT_IMPLEMENTED;
- }
-
- switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(float *) arg);
mixer_setvolume(&mpctx->mixer, *(float *) arg, *(float *) arg);
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- if (arg && *(float *) arg <= 0)
+ case M_PROPERTY_SWITCH: {
+ struct m_property_switch_arg *sarg = arg;
+ if (sarg->inc <= 0)
mixer_decvolume(&mpctx->mixer);
else
mixer_incvolume(&mpctx->mixer);
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_DOWN:
- if (arg && *(float *) arg <= 0)
- mixer_incvolume(&mpctx->mixer);
- else
- mixer_decvolume(&mpctx->mixer);
- return M_PROPERTY_OK;
+ }
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -754,18 +569,13 @@ static int mp_property_mute(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
mixer_setmute(&mpctx->mixer, *(int *) arg);
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- mixer_setmute(&mpctx->mixer, !mixer_getmute(&mpctx->mixer));
+ case M_PROPERTY_GET:
+ *(int *)arg = mixer_getmute(&mpctx->mixer);
return M_PROPERTY_OK;
- default:
- return m_property_flag_ro(prop, action, arg,
- mixer_getmute(&mpctx->mixer));
}
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Audio delay (RW)
@@ -775,21 +585,14 @@ 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:
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN: {
- int ret;
- float delay = audio_delay;
- ret = m_property_delay(prop, action, arg, &audio_delay);
- if (ret != M_PROPERTY_OK)
- return ret;
- if (mpctx->sh_audio)
- mpctx->delay -= audio_delay - delay;
- }
+ mpctx->delay -= audio_delay - *(float *)arg;
return M_PROPERTY_OK;
- default:
- return m_property_delay(prop, action, arg, &audio_delay);
}
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Audio codec tag (RO)
@@ -807,8 +610,11 @@ static int mp_property_audio_codec(m_option_t *prop, int action,
{
if (!mpctx->sh_audio || !mpctx->sh_audio->codec)
return M_PROPERTY_UNAVAILABLE;
- return m_property_string_ro(prop, action, arg,
- mpctx->sh_audio->codec->name);
+ if (action == M_PROPERTY_GET) {
+ *(char **)arg = talloc_strdup(NULL, mpctx->sh_audio->codec->name);
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Audio bitrate (RO)
@@ -817,7 +623,15 @@ 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;
+ case M_PROPERTY_GET:
+ *(int *)arg = mpctx->sh_audio->i_bps;
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Samplerate (RO)
@@ -828,13 +642,14 @@ static int mp_property_samplerate(m_option_t *prop, int action, void *arg,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
*(char **)arg = talloc_asprintf(NULL, "%d kHz",
mpctx->sh_audio->samplerate / 1000);
return M_PROPERTY_OK;
+ case M_PROPERTY_GET:
+ *(int *)arg = mpctx->sh_audio->samplerate;
+ return M_PROPERTY_OK;
}
- return m_property_int_ro(prop, action, arg, mpctx->sh_audio->samplerate);
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Number of channels (RO)
@@ -845,8 +660,6 @@ static int mp_property_channels(m_option_t *prop, int action, void *arg,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
switch (mpctx->sh_audio->channels) {
case 1:
*(char **) arg = talloc_strdup(NULL, "mono");
@@ -859,8 +672,11 @@ static int mp_property_channels(m_option_t *prop, int action, void *arg,
mpctx->sh_audio->channels);
}
return M_PROPERTY_OK;
+ case M_PROPERTY_GET:
+ *(int *)arg = mpctx->sh_audio->channels;
+ return M_PROPERTY_OK;
}
- return m_property_int_ro(prop, action, arg, mpctx->sh_audio->channels);
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Balance (RW)
@@ -871,14 +687,10 @@ static int mp_property_balance(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
mixer_getbalance(&mpctx->mixer, arg);
return M_PROPERTY_OK;
case M_PROPERTY_PRINT: {
char **str = arg;
- if (!arg)
- return M_PROPERTY_ERROR;
mixer_getbalance(&mpctx->mixer, &bal);
if (bal == 0.f)
*str = talloc_strdup(NULL, "center");
@@ -893,18 +705,7 @@ static int mp_property_balance(m_option_t *prop, int action, void *arg,
}
return M_PROPERTY_OK;
}
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- mixer_getbalance(&mpctx->mixer, &bal);
- bal += (arg ? *(float *)arg : .1f) *
- (action == M_PROPERTY_STEP_UP ? 1.f : -1.f);
- M_PROPERTY_CLAMP(prop, bal);
- mixer_setbalance(&mpctx->mixer, bal);
- return M_PROPERTY_OK;
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(float *)arg);
mixer_setbalance(&mpctx->mixer, *(float *)arg);
return M_PROPERTY_OK;
}
@@ -943,14 +744,9 @@ static int property_switch_track(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
*(int *) arg = track ? track->user_tid : -1;
return M_PROPERTY_OK;
case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
-
if (!track)
*(char **) arg = talloc_strdup(NULL, mp_gtext("disabled"));
else {
@@ -967,18 +763,15 @@ static int property_switch_track(m_option_t *prop, int action, void *arg,
}
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- case M_PROPERTY_SET: {
- int i = (arg ? *((int *) arg) : +1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : +1);
- if (action == M_PROPERTY_SET && arg)
- track = mp_track_by_tid(mpctx, type, i);
- else
- track = track_next(mpctx, type, i > 0 ? +1 : -1, track);
- mp_switch_track(mpctx, type, track);
+ case M_PROPERTY_SWITCH: {
+ struct m_property_switch_arg *sarg = arg;
+ mp_switch_track(mpctx, type,
+ track_next(mpctx, type, sarg->inc >= 0 ? +1 : -1, track));
return M_PROPERTY_OK;
}
+ case M_PROPERTY_SET:
+ mp_switch_track(mpctx, type, mp_track_by_tid(mpctx, type, *(int *)arg));
+ return M_PROPERTY_OK;
default:
return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -998,6 +791,18 @@ static int mp_property_video(m_option_t *prop, int action, void *arg,
return property_switch_track(prop, action, arg, mpctx, STREAM_VIDEO);
}
+static struct track *find_track_by_demuxer_id(MPContext *mpctx,
+ enum stream_type type,
+ int demuxer_id)
+{
+ for (int n = 0; n < mpctx->num_tracks; n++) {
+ struct track *track = mpctx->tracks[n];
+ if (track->type == type && track->demuxer_id == demuxer_id)
+ return track;
+ }
+ return NULL;
+}
+
static int mp_property_program(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
@@ -1008,7 +813,7 @@ static int mp_property_program(m_option_t *prop, int action, void *arg,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
- case M_PROPERTY_STEP_UP:
+ case M_PROPERTY_SWITCH:
case M_PROPERTY_SET:
if (action == M_PROPERTY_SET && arg)
prog.progid = *((int *) arg);
@@ -1023,13 +828,13 @@ static int mp_property_program(m_option_t *prop, int action, void *arg,
"Selected program contains no audio or video streams!\n");
return M_PROPERTY_ERROR;
}
- mp_property_do("switch_audio", M_PROPERTY_SET, &prog.aid, mpctx);
- mp_property_do("switch_video", M_PROPERTY_SET, &prog.vid, mpctx);
+ mp_switch_track(mpctx, STREAM_AUDIO,
+ find_track_by_demuxer_id(mpctx, STREAM_AUDIO, prog.aid));
+ mp_switch_track(mpctx, STREAM_VIDEO,
+ find_track_by_demuxer_id(mpctx, STREAM_VIDEO, prog.vid));
return M_PROPERTY_OK;
-
- default:
- return M_PROPERTY_NOT_IMPLEMENTED;
}
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -1041,68 +846,42 @@ static int mp_property_fullscreen(m_option_t *prop, int action, void *arg,
if (!mpctx->video_out)
return M_PROPERTY_UNAVAILABLE;
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *) arg);
+ if (action == M_PROPERTY_SET) {
if (vo_fs == !!*(int *) arg)
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
if (mpctx->video_out->config_ok)
vo_control(mpctx->video_out, VOCTRL_FULLSCREEN, 0);
mpctx->opts.fullscreen = vo_fs;
return M_PROPERTY_OK;
- default:
- return m_property_flag(prop, action, arg, &vo_fs);
}
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
static int mp_property_deinterlace(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
{
- int deinterlace;
vf_instance_t *vf;
if (!mpctx->sh_video || !mpctx->sh_video->vfilter)
return M_PROPERTY_UNAVAILABLE;
vf = mpctx->sh_video->vfilter;
switch (action) {
case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
vf->control(vf, VFCTRL_GET_DEINTERLACE, arg);
return M_PROPERTY_OK;
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *) arg);
vf->control(vf, VFCTRL_SET_DEINTERLACE, arg);
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- vf->control(vf, VFCTRL_GET_DEINTERLACE, &deinterlace);
- deinterlace = !deinterlace;
- vf->control(vf, VFCTRL_SET_DEINTERLACE, &deinterlace);
- return M_PROPERTY_OK;
}
- int value = 0;
- vf->control(vf, VFCTRL_GET_DEINTERLACE, &value);
- return m_property_flag_ro(prop, action, arg, value);
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
static int colormatrix_property_helper(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
{
int r = mp_property_generic_option(prop, action, arg, mpctx);
- // testing for an actual change is too much effort
- switch (action) {
- case M_PROPERTY_SET:
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
+ if (action == M_PROPERTY_SET) {
if (mpctx->sh_video)
set_video_colorspace(mpctx->sh_video);
- break;
}
return r;
}
@@ -1110,81 +889,75 @@ static int colormatrix_property_helper(m_option_t *prop, int action,
static int mp_property_colormatrix(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
+ if (action != M_PROPERTY_PRINT)
+ return colormatrix_property_helper(prop, action, arg, mpctx);
+
struct MPOpts *opts = &mpctx->opts;
- switch (action) {
- case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
- struct mp_csp_details actual = { .format = -1 };
- char *req_csp = mp_csp_names[opts->requested_colorspace];
- char *real_csp = NULL;
- if (mpctx->sh_video) {
- struct vf_instance *vf = mpctx->sh_video->vfilter;
- if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual) == true) {
- real_csp = mp_csp_names[actual.format];
- } else {
- real_csp = "Unknown";
- }
+ struct mp_csp_details actual = { .format = -1 };
+ char *req_csp = mp_csp_names[opts->requested_colorspace];
+ char *real_csp = NULL;
+ if (mpctx->sh_video) {
+ struct vf_instance *vf = mpctx->sh_video->vfilter;
+ if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual) == true) {
+ real_csp = mp_csp_names[actual.format];
+ } else {
+ real_csp = "Unknown";
}
- char *res;
- if (opts->requested_colorspace == MP_CSP_AUTO && real_csp) {
- // Caveat: doesn't handle the case when the autodetected colorspace
- // is different from the actual colorspace as used by the
- // VO - the OSD will display the VO colorspace without
- // indication that it doesn't match the requested colorspace.
- res = talloc_asprintf(NULL, "Auto (%s)", real_csp);
- } else if (opts->requested_colorspace == actual.format || !real_csp) {
- res = talloc_strdup(NULL, req_csp);
- } else
- res = talloc_asprintf(NULL, mp_gtext("%s, but %s used"),
- req_csp, real_csp);
- *(char **)arg = res;
- return M_PROPERTY_OK;
- default:;
- return colormatrix_property_helper(prop, action, arg, mpctx);
}
+ char *res;
+ if (opts->requested_colorspace == MP_CSP_AUTO && real_csp) {
+ // Caveat: doesn't handle the case when the autodetected colorspace
+ // is different from the actual colorspace as used by the
+ // VO - the OSD will display the VO colorspace without
+ // indication that it doesn't match the requested colorspace.
+ res = talloc_asprintf(NULL, "Auto (%s)", real_csp);
+ } else if (opts->requested_colorspace == actual.format || !real_csp) {
+ res = talloc_strdup(NULL, req_csp);
+ } else
+ res = talloc_asprintf(NULL, mp_gtext("%s, but %s used"),
+ req_csp, real_csp);
+ *(char **)arg = res;
+ return M_PROPERTY_OK;
}
static int levels_property_helper(int offset, m_option_t *prop, int action,
void *arg, MPContext *mpctx)
{
- char *optname = prop->priv;
- const struct m_option *opt = m_config_get_option(mpctx->mconfig,
- bstr0(optname));
- int *valptr = (int *)m_option_get_ptr(opt, &mpctx->opts);
+ if (action != M_PROPERTY_PRINT)
+ return colormatrix_property_helper(prop, action, arg, mpctx);
- switch (action) {
- case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
- struct mp_csp_details actual = {0};
- int actual_level = -1;
- char *req_level = m_option_print(opt, valptr);
- char *real_level = NULL;
- if (mpctx->sh_video) {
- struct vf_instance *vf = mpctx->sh_video->vfilter;
- if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual) == true) {
- actual_level = *(enum mp_csp_levels *)(((char *)&actual) + offset);
- real_level = m_option_print(opt, &actual_level);
- } else {
- real_level = talloc_strdup(NULL, "Unknown");
- }
+ struct m_option opt = {0};
+ mp_property_generic_option(prop, M_PROPERTY_GET_TYPE, &opt, mpctx);
+ assert(opt.type);
+
+ int requested = 0;
+ mp_property_generic_option(prop, M_PROPERTY_GET, &requested, mpctx);
+
+ struct mp_csp_details actual = {0};
+ int actual_level = -1;
+ char *req_level = m_option_print(&opt, &requested);
+ char *real_level = NULL;
+ if (mpctx->sh_video) {
+ struct vf_instance *vf = mpctx->sh_video->vfilter;
+ if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual) == true) {
+ actual_level = *(enum mp_csp_levels *)(((char *)&actual) + offset);
+ real_level = m_option_print(&opt, &actual_level);
+ } else {
+ real_level = talloc_strdup(NULL, "Unknown");
}
- char *res;
- if (*valptr == MP_CSP_LEVELS_AUTO && real_level) {
- res = talloc_asprintf(NULL, "Auto (%s)", real_level);
- } else if (*valptr == actual_level || !real_level) {
- res = talloc_strdup(NULL, real_level);
- } else
- res = talloc_asprintf(NULL, mp_gtext("%s, but %s used"),
- req_level, real_level);
- talloc_free(req_level);
- talloc_free(real_level);
- *(char **)arg = res;
- return M_PROPERTY_OK;
- default:;
- return colormatrix_property_helper(prop, action, arg, mpctx);
}
+ char *res;
+ if (requested == MP_CSP_LEVELS_AUTO && real_level) {
+ res = talloc_asprintf(NULL, "Auto (%s)", real_level);
+ } else if (requested == actual_level || !real_level) {
+ res = talloc_strdup(NULL, real_level);
+ } else
+ res = talloc_asprintf(NULL, mp_gtext("%s, but %s used"),
+ req_level, real_level);
+ talloc_free(req_level);
+ talloc_free(real_level);
+ *(char **)arg = res;
+ return M_PROPERTY_OK;
}
static int mp_property_colormatrix_input_range(m_option_t *prop, int action,
@@ -1210,27 +983,10 @@ static int mp_property_panscan(m_option_t *prop, int action, void *arg,
|| vo_control(mpctx->video_out, VOCTRL_GET_PANSCAN, NULL) != VO_TRUE)
return M_PROPERTY_UNAVAILABLE;
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(float *) arg);
- vo_panscan = *(float *) arg;
- vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL);
- return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- vo_panscan += (arg ? *(float *) arg : 0.1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
- if (vo_panscan > 1)
- vo_panscan = 1;
- else if (vo_panscan < 0)
- vo_panscan = 0;
+ int r = mp_property_generic_option(prop, action, arg, mpctx);
+ if (action == M_PROPERTY_SET)
vo_control(mpctx->video_out, VOCTRL_SET_PANSCAN, NULL);
- return M_PROPERTY_OK;
- default:
- return m_property_float_range(prop, action, arg, &vo_panscan);
- }
+ return r;
}
/// Helper to set vo flags.
@@ -1243,21 +999,14 @@ static int mp_property_vo_flag(m_option_t *prop, int action, void *arg,
if (!mpctx->video_out)
return M_PROPERTY_UNAVAILABLE;
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *) arg);
+ if (action == M_PROPERTY_SET) {
if (*vo_var == !!*(int *) arg)
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
if (mpctx->video_out->config_ok)
vo_control(mpctx->video_out, vo_ctrl, 0);
return M_PROPERTY_OK;
- default:
- return m_property_flag(prop, action, arg, vo_var);
}
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// Window always on top (RW)
@@ -1284,26 +1033,13 @@ static int mp_property_border(m_option_t *prop, int action, void *arg,
&vo_border, mpctx);
}
-/// Framedropping state (RW)
-static int mp_property_framedropping(m_option_t *prop, int action,
+static int mp_property_framedrop(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
{
-
if (!mpctx->sh_video)
return M_PROPERTY_UNAVAILABLE;
- switch (action) {
- case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
- *(char **) arg = talloc_strdup(NULL, frame_dropping == 1 ?
- mp_gtext("enabled") :
- (frame_dropping == 2 ? mp_gtext("hard") :
- mp_gtext("disabled")));
- return M_PROPERTY_OK;
- default:
- return m_property_choice(prop, action, arg, &frame_dropping);
- }
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// Color settings, try to use vf/vo then fall back on TV. (RW)
@@ -1323,9 +1059,6 @@ static int mp_property_gamma(m_option_t *prop, int action, void *arg,
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *) arg);
*gamma = *(int *) arg;
r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
if (r <= 0)
@@ -1333,30 +1066,19 @@ static int mp_property_gamma(m_option_t *prop, int action, void *arg,
return r;
case M_PROPERTY_GET:
if (get_video_colors(mpctx->sh_video, prop->name, &val) > 0) {
- if (!arg)
- return M_PROPERTY_ERROR;
*(int *)arg = val;
return M_PROPERTY_OK;
}
break;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- *gamma += (arg ? *(int *) arg : 1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
- M_PROPERTY_CLAMP(prop, *gamma);
- r = set_video_colors(mpctx->sh_video, prop->name, *gamma);
- if (r <= 0)
- break;
- return r;
default:
- return M_PROPERTY_NOT_IMPLEMENTED;
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
#ifdef CONFIG_TV
if (mpctx->sh_video->gsh->demuxer->type == DEMUXER_TYPE_TV) {
int l = strlen(prop->name);
char tv_prop[3 + l + 1];
- sprintf(tv_prop, "tv_%s", prop->name);
+ sprintf(tv_prop, "tv-%s", prop->name);
return mp_property_do(tv_prop, action, arg, mpctx);
}
#endif
@@ -1368,7 +1090,7 @@ static int mp_property_gamma(m_option_t *prop, int action, void *arg,
static int mp_property_vsync(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- return m_property_flag(prop, action, arg, &vo_vsync);
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// Video codec tag (RO)
@@ -1380,8 +1102,6 @@ static int mp_property_video_format(m_option_t *prop, int action,
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
switch (mpctx->sh_video->format) {
case 0x10000001:
meta = talloc_strdup(NULL, "mpeg1");
@@ -1404,8 +1124,11 @@ static int mp_property_video_format(m_option_t *prop, int action,
}
*(char **)arg = meta;
return M_PROPERTY_OK;
+ case M_PROPERTY_GET:
+ *(int *)arg = mpctx->sh_video->format;
+ return M_PROPERTY_OK;
}
- return m_property_int_ro(prop, action, arg, mpctx->sh_video->format);
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
/// Video codec name (RO)
@@ -1414,8 +1137,11 @@ static int mp_property_video_codec(m_option_t *prop, int action,
{
if (!mpctx->sh_video || !mpctx->sh_video->codec)
return M_PROPERTY_UNAVAILABLE;
- return m_property_string_ro(prop, action, arg,
- mpctx->sh_video->codec->name);
+ if (action == M_PROPERTY_GET) {
+ *(char **)arg = talloc_strdup(NULL, mpctx->sh_video->codec->name);
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -1425,7 +1151,11 @@ 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);
+ if (action == 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)
@@ -1461,24 +1191,33 @@ static int mp_property_aspect(m_option_t *prop, int action, void *arg,
{
if (!mpctx->sh_video)
return M_PROPERTY_UNAVAILABLE;
- return m_property_float_ro(prop, action, arg, mpctx->sh_video->aspect);
+ switch (action) {
+ case M_PROPERTY_SET: {
+ float f = *(float *)arg;
+ if (f < 0.1)
+ f = (float)mpctx->sh_video->disp_w / mpctx->sh_video->disp_h;
+ mpctx->opts.movie_aspect = f;
+ video_reset_aspect(mpctx->sh_video);
+ return M_PROPERTY_OK;
+ }
+ case M_PROPERTY_GET:
+ *(float *)arg = mpctx->sh_video->aspect;
+ return M_PROPERTY_OK;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
-
-/// Text subtitle position (RW)
-static int mp_property_sub_pos(m_option_t *prop, int action, void *arg,
+// For subtitle related properties using the generic option bridge.
+// - Fail as unavailable if no video is active
+// - Trigger OSD state update when property is set
+static int property_sub_helper(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
+ if (!mpctx->sh_video)
+ return M_PROPERTY_UNAVAILABLE;
+ if (action == M_PROPERTY_SET)
vo_osd_changed(OSDTYPE_SUBTITLE);
- default:
- return m_property_int_range(prop, action, arg, &sub_pos);
- }
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// Selected subtitles (RW)
@@ -1494,74 +1233,49 @@ 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);
-}
-
-/// Subtitle visibility (RW)
-static int mp_property_sub_visibility(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- struct MPOpts *opts = &mpctx->opts;
-
- if (!mpctx->sh_video)
- return M_PROPERTY_UNAVAILABLE;
-
switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- vo_osd_changed(OSDTYPE_SUBTITLE);
- if (vo_spudec)
- vo_osd_changed(OSDTYPE_SPU);
- default:
- return m_property_flag(prop, action, arg, &opts->sub_visibility);
+ case M_PROPERTY_PRINT:
+ *(char **)arg = format_delay(sub_delay);
+ return M_PROPERTY_OK;
}
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
-#ifdef CONFIG_ASS
-/// Use margins for libass subtitles (RW)
-static int mp_property_ass_use_margins(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
+static int mp_property_sub_pos(m_option_t *prop, int action, void *arg,
+ MPContext *mpctx)
{
- struct MPOpts *opts = &mpctx->opts;
if (!mpctx->sh_video)
return M_PROPERTY_UNAVAILABLE;
-
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- vo_osd_changed(OSDTYPE_SUBTITLE);
- default:
- return m_property_flag(prop, action, arg, &opts->ass_use_margins);
+ if (action == M_PROPERTY_PRINT) {
+ *(char **)arg = talloc_asprintf(NULL, "%d/100", sub_pos);
+ return M_PROPERTY_OK;
}
+ return property_sub_helper(prop, action, arg, mpctx);
}
-static int mp_property_ass_vsfilter_aspect_compat(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
+/// Subtitle visibility (RW)
+static int mp_property_sub_visibility(m_option_t *prop, int action,
+ void *arg, MPContext *mpctx)
{
+ struct MPOpts *opts = &mpctx->opts;
+
if (!mpctx->sh_video)
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
+ opts->sub_visibility = *(int *)arg;
vo_osd_changed(OSDTYPE_SUBTITLE);
- default:
- return m_property_flag(prop, action, arg,
- &mpctx->opts.ass_vsfilter_aspect_compat);
+ if (vo_spudec)
+ vo_osd_changed(OSDTYPE_SPU);
+ return M_PROPERTY_OK;
+ case M_PROPERTY_GET:
+ *(int *)arg = opts->sub_visibility;
+ return M_PROPERTY_OK;
}
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
-#endif
-
/// Show only forced subtitles (RW)
static int mp_property_sub_forced_only(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
@@ -1569,19 +1283,12 @@ static int mp_property_sub_forced_only(m_option_t *prop, int action,
if (!vo_spudec)
return M_PROPERTY_UNAVAILABLE;
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- m_property_flag(prop, action, arg, &forced_subs_only);
+ if (action == M_PROPERTY_SET) {
+ forced_subs_only = *(int *)arg;
spudec_set_forced_subs_only(vo_spudec, forced_subs_only);
return M_PROPERTY_OK;
- default:
- return m_property_flag(prop, action, arg, &forced_subs_only);
}
-
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// Subtitle scale (RW)
@@ -1590,34 +1297,19 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg,
{
struct MPOpts *opts = &mpctx->opts;
+ float *pscale = opts->ass_enabled
+ ? &opts->ass_font_scale : &text_font_scale_factor;
+
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(float *) arg);
- if (opts->ass_enabled)
- opts->ass_font_scale = *(float *) arg;
- text_font_scale_factor = *(float *) arg;
+ *pscale = *(float *) arg;
vo_osd_resized();
return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- if (opts->ass_enabled) {
- opts->ass_font_scale += (arg ? *(float *) arg : 0.1) *
- (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
- M_PROPERTY_CLAMP(prop, opts->ass_font_scale);
- }
- text_font_scale_factor += (arg ? *(float *) arg : 0.1) *
- (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
- M_PROPERTY_CLAMP(prop, text_font_scale_factor);
- vo_osd_resized();
+ case M_PROPERTY_GET:
+ *(float *)arg = *pscale;
return M_PROPERTY_OK;
- default:
- if (opts->ass_enabled)
- return m_property_float_ro(prop, action, arg, opts->ass_font_scale);
- else
- return m_property_float_ro(prop, action, arg, text_font_scale_factor);
}
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
@@ -1634,73 +1326,65 @@ static tvi_handle_t *get_tvh(struct MPContext *mpctx)
static int mp_property_tv_color(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- int r, val;
tvi_handle_t *tvh = get_tvh(mpctx);
if (!tvh)
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_SET:
- if (!arg)
- return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *) arg);
return tv_set_color_options(tvh, prop->offset, *(int *) arg);
case M_PROPERTY_GET:
return tv_get_color_options(tvh, prop->offset, arg);
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- if ((r = tv_get_color_options(tvh, prop->offset, &val)) >= 0) {
- if (!r)
- return M_PROPERTY_ERROR;
- val += (arg ? *(int *) arg : 1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
- M_PROPERTY_CLAMP(prop, val);
- return tv_set_color_options(tvh, prop->offset, val);
- }
- return M_PROPERTY_ERROR;
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
#endif
+// Use option-to-property-bridge. (The property and option have the same names.)
+#define M_OPTION_PROPERTY(name) \
+ {(name), mp_property_generic_option, &m_option_type_dummy, 0, 0, 0, (name)}
+
+// OPTION_PROPERTY(), but with a custom property handler. The custom handler
+// must let unknown operations fall back to mp_property_generic_option().
+#define M_OPTION_PROPERTY_CUSTOM(name, handler) \
+ {(name), (handler), &m_option_type_dummy, 0, 0, 0, (name)}
+#define M_OPTION_PROPERTY_CUSTOM_(name, handler, ...) \
+ {(name), (handler), &m_option_type_dummy, 0, 0, 0, (name), __VA_ARGS__}
+
/// All properties available in MPlayer.
/** \ingroup Properties
*/
static const m_option_t mp_properties[] = {
// General
- { "osdlevel", mp_property_osdlevel, CONF_TYPE_INT,
- M_OPT_RANGE, 0, 3, NULL },
- { "loop", mp_property_loop, &m_option_type_choice,
- 0, 0, 0, "loop" },
- { "speed", mp_property_playback_speed, CONF_TYPE_FLOAT,
- M_OPT_RANGE, 0.01, 100.0, NULL },
+ M_OPTION_PROPERTY("osd-level"),
+ M_OPTION_PROPERTY("loop"),
+ M_OPTION_PROPERTY_CUSTOM("speed", mp_property_playback_speed),
{ "filename", mp_property_filename, CONF_TYPE_STRING,
0, 0, 0, NULL },
{ "path", mp_property_path, CONF_TYPE_STRING,
0, 0, 0, NULL },
{ "demuxer", mp_property_demuxer, CONF_TYPE_STRING,
0, 0, 0, NULL },
- { "stream_pos", mp_property_stream_pos, CONF_TYPE_POSITION,
+ { "stream-pos", mp_property_stream_pos, CONF_TYPE_INT64,
M_OPT_MIN, 0, 0, NULL },
- { "stream_start", mp_property_stream_start, CONF_TYPE_POSITION,
+ { "stream-start", mp_property_stream_start, CONF_TYPE_INT64,
M_OPT_MIN, 0, 0, NULL },
- { "stream_end", mp_property_stream_end, CONF_TYPE_POSITION,
+ { "stream-end", mp_property_stream_end, CONF_TYPE_INT64,
M_OPT_MIN, 0, 0, NULL },
- { "stream_length", mp_property_stream_length, CONF_TYPE_POSITION,
+ { "stream-length", mp_property_stream_length, CONF_TYPE_INT64,
M_OPT_MIN, 0, 0, NULL },
- { "stream_time_pos", mp_property_stream_time_pos, CONF_TYPE_TIME,
+ { "stream-time-pos", mp_property_stream_time_pos, CONF_TYPE_TIME,
M_OPT_MIN, 0, 0, NULL },
{ "length", mp_property_length, CONF_TYPE_TIME,
M_OPT_MIN, 0, 0, NULL },
- { "percent_pos", mp_property_percent_pos, CONF_TYPE_INT,
+ { "percent-pos", mp_property_percent_pos, CONF_TYPE_INT,
M_OPT_RANGE, 0, 100, NULL },
- { "time_pos", mp_property_time_pos, CONF_TYPE_TIME,
+ { "time-pos", mp_property_time_pos, CONF_TYPE_TIME,
M_OPT_MIN, 0, 0, NULL },
{ "chapter", mp_property_chapter, CONF_TYPE_INT,
M_OPT_MIN, 0, 0, NULL },
- { "edition", mp_property_edition, CONF_TYPE_INT,
- M_OPT_MIN, -1, 0, NULL },
+ M_OPTION_PROPERTY_CUSTOM("edition", mp_property_edition),
{ "titles", mp_property_titles, CONF_TYPE_INT,
0, 0, 0, NULL },
{ "chapters", mp_property_chapters, CONF_TYPE_INT,
@@ -1712,71 +1396,60 @@ static const m_option_t mp_properties[] = {
0, 0, 0, NULL },
{ "pause", mp_property_pause, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
- { "pts_association_mode", mp_property_generic_option, &m_option_type_choice,
- 0, 0, 0, "pts-association-mode" },
- { "hr_seek", mp_property_generic_option, &m_option_type_choice,
- 0, 0, 0, "hr-seek" },
+ M_OPTION_PROPERTY("pts-association-mode"),
+ M_OPTION_PROPERTY("hr-seek"),
// Audio
{ "volume", mp_property_volume, CONF_TYPE_FLOAT,
M_OPT_RANGE, 0, 100, NULL },
{ "mute", mp_property_mute, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
- { "audio_delay", mp_property_audio_delay, CONF_TYPE_FLOAT,
- M_OPT_RANGE, -100, 100, NULL },
- { "audio_format", mp_property_audio_format, CONF_TYPE_INT,
+ M_OPTION_PROPERTY_CUSTOM("audio-delay", mp_property_audio_delay),
+ { "audio-format", mp_property_audio_format, CONF_TYPE_INT,
0, 0, 0, NULL },
- { "audio_codec", mp_property_audio_codec, CONF_TYPE_STRING,
+ { "audio-codec", mp_property_audio_codec, CONF_TYPE_STRING,
0, 0, 0, NULL },
- { "audio_bitrate", mp_property_audio_bitrate, CONF_TYPE_INT,
+ { "audio-bitrate", mp_property_audio_bitrate, CONF_TYPE_INT,
0, 0, 0, NULL },
{ "samplerate", mp_property_samplerate, CONF_TYPE_INT,
0, 0, 0, NULL },
{ "channels", mp_property_channels, CONF_TYPE_INT,
0, 0, 0, NULL },
- { "switch_audio", mp_property_audio, CONF_TYPE_INT,
+ { "audio", mp_property_audio, CONF_TYPE_INT,
CONF_RANGE, -2, 65535, NULL },
{ "balance", mp_property_balance, CONF_TYPE_FLOAT,
M_OPT_RANGE, -1, 1, NULL },
// Video
- { "fullscreen", mp_property_fullscreen, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
+ M_OPTION_PROPERTY_CUSTOM("fullscreen", mp_property_fullscreen),
{ "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
- { "colormatrix", mp_property_colormatrix, &m_option_type_choice,
- 0, 0, 0, "colormatrix" },
- { "colormatrix_input_range", mp_property_colormatrix_input_range, &m_option_type_choice,
- 0, 0, 0, "colormatrix-input-range" },
- { "colormatrix_output_range", mp_property_colormatrix_output_range, &m_option_type_choice,
- 0, 0, 0, "colormatrix-output-range" },
- { "ontop", mp_property_ontop, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
- { "rootwin", mp_property_rootwin, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
- { "border", mp_property_border, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
- { "framedropping", mp_property_framedropping, CONF_TYPE_INT,
- M_OPT_RANGE, 0, 2, NULL },
- { "gamma", mp_property_gamma, CONF_TYPE_INT,
- M_OPT_RANGE, -100, 100, .offset = offsetof(struct MPOpts, vo_gamma_gamma)},
- { "brightness", mp_property_gamma, CONF_TYPE_INT,
- M_OPT_RANGE, -100, 100, .offset = offsetof(struct MPOpts, vo_gamma_brightness) },
- { "contrast", mp_property_gamma, CONF_TYPE_INT,
- M_OPT_RANGE, -100, 100, .offset = offsetof(struct MPOpts, vo_gamma_contrast) },
- { "saturation", mp_property_gamma, CONF_TYPE_INT,
- M_OPT_RANGE, -100, 100, .offset = offsetof(struct MPOpts, vo_gamma_saturation) },
- { "hue", mp_property_gamma, CONF_TYPE_INT,
- M_OPT_RANGE, -100, 100, .offset = offsetof(struct MPOpts, vo_gamma_hue) },
- { "panscan", mp_property_panscan, CONF_TYPE_FLOAT,
- M_OPT_RANGE, 0, 1, NULL },
- { "vsync", mp_property_vsync, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
- { "video_format", mp_property_video_format, CONF_TYPE_INT,
+ M_OPTION_PROPERTY_CUSTOM("colormatrix", mp_property_colormatrix),
+ M_OPTION_PROPERTY_CUSTOM("colormatrix-input-range",
+ mp_property_colormatrix_input_range),
+ M_OPTION_PROPERTY_CUSTOM("colormatrix-output-range",
+ mp_property_colormatrix_output_range),
+ M_OPTION_PROPERTY_CUSTOM("ontop", mp_property_ontop),
+ M_OPTION_PROPERTY_CUSTOM("rootwin", mp_property_rootwin),
+ M_OPTION_PROPERTY_CUSTOM("border", mp_property_border),
+ M_OPTION_PROPERTY_CUSTOM("framedrop", mp_property_framedrop),
+ M_OPTION_PROPERTY_CUSTOM_("gamma", mp_property_gamma,
+ .offset = offsetof(struct MPOpts, vo_gamma_gamma)),
+ M_OPTION_PROPERTY_CUSTOM_("brightness", mp_property_gamma,
+ .offset = offsetof(struct MPOpts, vo_gamma_brightness)),
+ M_OPTION_PROPERTY_CUSTOM_("contrast", mp_property_gamma,
+ .offset = offsetof(struct MPOpts, vo_gamma_contrast)),
+ M_OPTION_PROPERTY_CUSTOM_("saturation", mp_property_gamma,
+ .offset = offsetof(struct MPOpts, vo_gamma_saturation)),
+ M_OPTION_PROPERTY_CUSTOM_("hue", mp_property_gamma,
+ .offset = offsetof(struct MPOpts, vo_gamma_hue)),
+ M_OPTION_PROPERTY_CUSTOM("panscan", mp_property_panscan),
+ M_OPTION_PROPERTY_CUSTOM_("vsync", mp_property_vsync),
+ { "video-format", mp_property_video_format, CONF_TYPE_INT,
0, 0, 0, NULL },
- { "video_codec", mp_property_video_codec, CONF_TYPE_STRING,
+ { "video-codec", mp_property_video_codec, CONF_TYPE_STRING,
0, 0, 0, NULL },
- { "video_bitrate", mp_property_video_bitrate, CONF_TYPE_INT,
+ { "video-bitrate", mp_property_video_bitrate, CONF_TYPE_INT,
0, 0, 0, NULL },
{ "width", mp_property_width, CONF_TYPE_INT,
0, 0, 0, NULL },
@@ -1785,53 +1458,49 @@ static const m_option_t mp_properties[] = {
{ "fps", mp_property_fps, CONF_TYPE_FLOAT,
0, 0, 0, NULL },
{ "aspect", mp_property_aspect, CONF_TYPE_FLOAT,
- 0, 0, 0, NULL },
- { "switch_video", mp_property_video, CONF_TYPE_INT,
+ CONF_RANGE, 0, 10, NULL },
+ { "video", mp_property_video, CONF_TYPE_INT,
CONF_RANGE, -2, 65535, NULL },
- { "switch_program", mp_property_program, CONF_TYPE_INT,
+ { "program", mp_property_program, CONF_TYPE_INT,
CONF_RANGE, -1, 65535, NULL },
// Subs
{ "sub", mp_property_sub, CONF_TYPE_INT,
M_OPT_MIN, -1, 0, NULL },
- { "sub_delay", mp_property_sub_delay, CONF_TYPE_FLOAT,
- 0, 0, 0, NULL },
- { "sub_pos", mp_property_sub_pos, CONF_TYPE_INT,
- M_OPT_RANGE, 0, 100, NULL },
- { "sub_visibility", mp_property_sub_visibility, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
- { "sub_forced_only", mp_property_sub_forced_only, CONF_TYPE_FLAG,
+ M_OPTION_PROPERTY_CUSTOM("sub-delay", mp_property_sub_delay),
+ M_OPTION_PROPERTY_CUSTOM("sub-pos", mp_property_sub_pos),
+ { "sub-visibility", mp_property_sub_visibility, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
- { "sub_scale", mp_property_sub_scale, CONF_TYPE_FLOAT,
+ M_OPTION_PROPERTY_CUSTOM("sub-forced-only", mp_property_sub_forced_only),
+ { "sub-scale", mp_property_sub_scale, CONF_TYPE_FLOAT,
M_OPT_RANGE, 0, 100, NULL },
#ifdef CONFIG_ASS
- { "ass_use_margins", mp_property_ass_use_margins, CONF_TYPE_FLAG,
- M_OPT_RANGE, 0, 1, NULL },
- { "ass_vsfilter_aspect_compat", mp_property_ass_vsfilter_aspect_compat,
- CONF_TYPE_FLAG, M_OPT_RANGE, 0, 1, NULL },
+ M_OPTION_PROPERTY_CUSTOM("ass-use-margins", property_sub_helper),
+ M_OPTION_PROPERTY_CUSTOM("ass-vsfilter-aspect-compat", property_sub_helper),
+ M_OPTION_PROPERTY_CUSTOM("ass-style-override", property_sub_helper),
#endif
#ifdef CONFIG_TV
- { "tv_brightness", mp_property_tv_color, CONF_TYPE_INT,
+ { "tv-brightness", mp_property_tv_color, CONF_TYPE_INT,
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_BRIGHTNESS },
- { "tv_contrast", mp_property_tv_color, CONF_TYPE_INT,
+ { "tv-contrast", mp_property_tv_color, CONF_TYPE_INT,
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_CONTRAST },
- { "tv_saturation", mp_property_tv_color, CONF_TYPE_INT,
+ { "tv-saturation", mp_property_tv_color, CONF_TYPE_INT,
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_SATURATION },
- { "tv_hue", mp_property_tv_color, CONF_TYPE_INT,
+ { "tv-hue", mp_property_tv_color, CONF_TYPE_INT,
M_OPT_RANGE, -100, 100, .offset = TV_COLOR_HUE },
#endif
{0},
};
-
-int mp_property_do(const char *name, int action, void *val, void *ctx)
+int mp_property_do(const char *name, int action, void *val,
+ struct MPContext *ctx)
{
return m_property_do(mp_properties, name, action, val, ctx);
}
-char *mp_property_print(const char *name, void *ctx)
+char *mp_property_print(const char *name, struct MPContext *ctx)
{
char *ret = NULL;
if (mp_property_do(name, M_PROPERTY_PRINT, &ret, ctx) <= 0)
@@ -1839,7 +1508,7 @@ char *mp_property_print(const char *name, void *ctx)
return ret;
}
-char *property_expand_string(MPContext *mpctx, char *str)
+char *mp_property_expand_string(struct MPContext *mpctx, char *str)
{
return m_properties_expand_string(mp_properties, str, mpctx);
}
@@ -1852,227 +1521,140 @@ void property_print_help(void)
/* List of default ways to show a property on OSD.
*
- * Setting osd_progbar to -1 displays seek bar, other nonzero displays
- * a bar showing the current position between min/max values of the
- * property. In this case osd_msg is only used for terminal output
- * if there is no video; it'll be a label shown together with percentage.
- *
- * Otherwise setting osd_msg will show the string on OSD, formatted with
- * the text value of the property as argument.
+ * If osd_progbar is set, a bar showing the current position between min/max
+ * values of the property is shown. In this case osd_msg is only used for
+ * terminal output if there is no video; it'll be a label shown together with
+ * percentage.
*/
static struct property_osd_display {
- /// property name
+ // property name
const char *name;
- /// progressbar type
- int osd_progbar; // -1 is special value for seek indicators
- /// osd msg id if it must be shared
+ // name used on OSD
+ const char *osd_name;
+ // progressbar type
+ int osd_progbar;
+ // osd msg id if it must be shared
int osd_id;
- /// osd msg template
- const char *osd_msg;
+ // Needs special ways to display the new value (seeks are delayed)
+ int seek_msg, seek_bar;
} property_osd_display[] = {
// general
- { "loop", 0, -1, _("Loop: %s") },
- { "chapter", -1, -1, NULL },
- { "pts_association_mode", 0, -1, "PTS association mode: %s" },
- { "hr_seek", 0, -1, "hr-seek: %s" },
- { "speed", 0, -1, _("Speed: x %6s") },
+ { "loop", _("Loop") },
+ { "chapter", .seek_msg = OSD_SEEK_INFO_CHAPTER_TEXT,
+ .seek_bar = OSD_SEEK_INFO_BAR },
+ { "edition", .seek_msg = OSD_SEEK_INFO_EDITION },
+ { "pts-association-mode", "PTS association mode" },
+ { "hr-seek", "hr-seek" },
+ { "speed", _("Speed") },
// audio
- { "volume", OSD_VOLUME, -1, _("Volume") },
- { "mute", 0, -1, _("Mute: %s") },
- { "audio_delay", 0, -1, _("A-V delay: %s") },
- { "switch_audio", 0, -1, _("Audio: %s") },
- { "balance", OSD_BALANCE, -1, _("Balance") },
+ { "volume", _("Volume"), .osd_progbar = OSD_VOLUME },
+ { "mute", _("Mute") },
+ { "audio-delay", _("A-V delay") },
+ { "audio", _("Audio") },
+ { "balance", _("Balance"), .osd_progbar = OSD_BALANCE },
// video
- { "panscan", OSD_PANSCAN, -1, _("Panscan") },
- { "ontop", 0, -1, _("Stay on top: %s") },
- { "rootwin", 0, -1, _("Rootwin: %s") },
- { "border", 0, -1, _("Border: %s") },
- { "framedropping", 0, -1, _("Framedropping: %s") },
- { "deinterlace", 0, -1, _("Deinterlace: %s") },
- { "colormatrix", 0, -1, _("YUV colormatrix: %s") },
- { "colormatrix_input_range", 0, -1, _("YUV input range: %s") },
- { "colormatrix_output_range", 0, -1, _("RGB output range: %s") },
- { "gamma", OSD_BRIGHTNESS, -1, _("Gamma") },
- { "brightness", OSD_BRIGHTNESS, -1, _("Brightness") },
- { "contrast", OSD_CONTRAST, -1, _("Contrast") },
- { "saturation", OSD_SATURATION, -1, _("Saturation") },
- { "hue", OSD_HUE, -1, _("Hue") },
- { "vsync", 0, -1, _("VSync: %s") },
+ { "panscan", _("Panscan"), .osd_progbar = OSD_PANSCAN },
+ { "ontop", _("Stay on top") },
+ { "rootwin", _("Rootwin") },
+ { "border", _("Border") },
+ { "framedrop", _("Framedrop") },
+ { "deinterlace", _("Deinterlace") },
+ { "colormatrix", _("YUV colormatrix") },
+ { "colormatrix-input-range", _("YUV input range") },
+ { "colormatrix-output-range", _("RGB output range") },
+ { "gamma", _("Gamma"), .osd_progbar = OSD_BRIGHTNESS },
+ { "brightness", _("Brightness"), .osd_progbar = OSD_BRIGHTNESS },
+ { "contrast", _("Contrast"), .osd_progbar = OSD_CONTRAST },
+ { "saturation", _("Saturation"), .osd_progbar = OSD_SATURATION },
+ { "hue", _("Hue"), .osd_progbar = OSD_HUE },
+ { "vsync", _("VSync") },
+ { "angle", _("Angle") },
// subs
- { "sub", 0, -1, _("Subtitles: %s") },
- { "sub_pos", 0, -1, _("Sub position: %s/100") },
- { "sub_delay", 0, OSD_MSG_SUB_DELAY, _("Sub delay: %s") },
- { "sub_visibility", 0, -1, _("Subtitles: %s") },
- { "sub_forced_only", 0, -1, _("Forced sub only: %s") },
- { "sub_scale", 0, -1, _("Sub Scale: %s")},
- { "ass_vsfilter_aspect_compat", 0, -1,
- _("Subtitle VSFilter aspect compat: %s")},
+ { "sub", _("Subtitles") },
+ { "sub-pos", _("Sub position") },
+ { "sub-delay", _("Sub delay"), .osd_id = OSD_MSG_SUB_DELAY },
+ { "sub-visibility", _("Subtitles") },
+ { "sub-forced-only", _("Forced sub only") },
+ { "sub-scale", _("Sub Scale")},
+ { "ass-vsfilter-aspect-compat", _("Subtitle VSFilter aspect compat")},
+ { "ass-style-override", _("ASS subtitle style override")},
#ifdef CONFIG_TV
- { "tv_brightness", OSD_BRIGHTNESS, -1, _("Brightness") },
- { "tv_hue", OSD_HUE, -1, _("Hue") },
- { "tv_saturation", OSD_SATURATION, -1, _("Saturation") },
- { "tv_contrast", OSD_CONTRAST, -1, _("Contrast") },
+ { "tv-brightness", _("Brightness"), .osd_progbar = OSD_BRIGHTNESS },
+ { "tv-hue", _("Hue"), .osd_progbar = OSD_HUE},
+ { "tv-saturation", _("Saturation"), .osd_progbar = OSD_SATURATION },
+ { "tv-contrast", _("Contrast"), .osd_progbar = OSD_CONTRAST },
#endif
- {}
+ {0}
};
-static int show_property_osd(MPContext *mpctx, const char *pname)
+static void show_property_osd(MPContext *mpctx, const char *pname,
+ enum mp_on_osd osd_mode)
{
struct MPOpts *opts = &mpctx->opts;
- int r;
- m_option_t *prop;
+ struct m_option prop = {0};
struct property_osd_display *p;
+ if (mp_property_do(pname, M_PROPERTY_GET_TYPE, &prop, mpctx) <= 0)
+ return;
+
+ int osd_progbar = 0;
+ const char *osd_name = NULL;
+
// look for the command
- for (p = property_osd_display; p->name; p++)
- if (!strcmp(p->name, pname))
+ for (p = property_osd_display; p->name; p++) {
+ if (!strcmp(p->name, prop.name)) {
+ osd_progbar = p->seek_bar ? 1 : p->osd_progbar;
+ osd_name = p->seek_msg ? "" : mp_gtext(p->osd_name);
break;
-
+ }
+ }
if (!p->name)
- return -1;
-
- if (mp_property_do(pname, M_PROPERTY_GET_TYPE, &prop, mpctx) <= 0 || !prop)
- return -1;
-
- if (p->osd_progbar == -1)
- mpctx->add_osd_seek_info = true;
- else if (p->osd_progbar) {
- if (prop->type == CONF_TYPE_INT) {
- if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0)
- set_osd_bar(mpctx, p->osd_progbar, mp_gtext(p->osd_msg),
- prop->min, prop->max, r);
- } else if (prop->type == CONF_TYPE_FLOAT) {
+ p = NULL;
+
+ if (osd_mode != MP_ON_OSD_AUTO) {
+ osd_name = osd_name ? osd_name : prop.name;
+ if (!(osd_mode & MP_ON_OSD_MSG))
+ osd_name = NULL;
+ osd_progbar = osd_progbar ? osd_progbar : ' ';
+ if (!(osd_mode & MP_ON_OSD_BAR))
+ osd_progbar = 0;
+ }
+
+ if (p && (p->seek_msg || p->seek_bar)) {
+ mpctx->add_osd_seek_info |=
+ (osd_name ? p->seek_msg : 0) | (osd_progbar ? p->seek_bar : 0);
+ return;
+ }
+
+ if (osd_progbar && (prop.flags & CONF_RANGE) == CONF_RANGE) {
+ if (prop.type == CONF_TYPE_INT) {
+ int i;
+ if (mp_property_do(prop.name, M_PROPERTY_GET, &i, mpctx) > 0)
+ set_osd_bar(mpctx, osd_progbar, osd_name,
+ prop.min, prop.max, i);
+ } else if (prop.type == CONF_TYPE_FLOAT) {
float f;
- if (mp_property_do(pname, M_PROPERTY_GET, &f, mpctx) > 0)
- set_osd_bar(mpctx, p->osd_progbar, mp_gtext(p->osd_msg),
- prop->min, prop->max, f);
- } else {
- mp_msg(MSGT_CPLAYER, MSGL_ERR,
- "Property use an unsupported type.\n");
- return -1;
+ if (mp_property_do(prop.name, M_PROPERTY_GET, &f, mpctx) > 0)
+ set_osd_bar(mpctx, osd_progbar, osd_name,
+ prop.min, prop.max, f);
}
- return 0;
+ if (osd_mode == MP_ON_OSD_AUTO)
+ return;
}
- if (p->osd_msg) {
- char *val = mp_property_print(pname, mpctx);
+ if (osd_name) {
+ char *val = mp_property_print(prop.name, mpctx);
if (val) {
- int index = p - property_osd_display;
- set_osd_tmsg(mpctx, p->osd_id >= 0 ? p->osd_id : OSD_MSG_PROPERTY + index,
- 1, opts->osd_duration, p->osd_msg, val);
+ int osd_id = 0;
+ if (p) {
+ int index = p - property_osd_display;
+ osd_id = p->osd_id ? p->osd_id : OSD_MSG_PROPERTY + index;
+ }
+ set_osd_tmsg(mpctx, osd_id, 1, opts->osd_duration,
+ "%s: %s", osd_name, val);
talloc_free(val);
}
}
- return 0;
-}
-
-
-/**
- * Command to property bridge
- *
- * It is used to handle most commands that just set a property
- * and optionally display something on the OSD.
- * Two kinds of commands are handled: adjust or toggle.
- *
- * Adjust commands take 1 or 2 parameters: <value> <abs>
- * If <abs> is non-zero the property is set to the given value
- * otherwise it is adjusted.
- *
- * Toggle commands take 0 or 1 parameters. With no parameter
- * or a value less than the property minimum it just steps the
- * property to its next or previous value respectively.
- * Otherwise it sets it to the given value.
- */
-
-/// List of the commands that can be handled by setting a property.
-static struct {
- /// property name
- const char *name;
- /// cmd id
- int cmd;
- /// set/adjust or toggle command
- int toggle;
-} set_prop_cmd[] = {
- // general
- { "loop", MP_CMD_LOOP, 0},
- { "chapter", MP_CMD_SEEK_CHAPTER, 0},
- { "angle", MP_CMD_SWITCH_ANGLE, 0},
- { "pause", MP_CMD_PAUSE, 0},
- // audio
- { "volume", MP_CMD_VOLUME, 0},
- { "mute", MP_CMD_MUTE, 1},
- { "audio_delay", MP_CMD_AUDIO_DELAY, 0},
- { "switch_audio", MP_CMD_SWITCH_AUDIO, 1},
- { "balance", MP_CMD_BALANCE, 0},
- // video
- { "fullscreen", MP_CMD_VO_FULLSCREEN, 1},
- { "panscan", MP_CMD_PANSCAN, 0},
- { "ontop", MP_CMD_VO_ONTOP, 1},
- { "rootwin", MP_CMD_VO_ROOTWIN, 1},
- { "border", MP_CMD_VO_BORDER, 1},
- { "framedropping", MP_CMD_FRAMEDROPPING, 1},
- { "gamma", MP_CMD_GAMMA, 0},
- { "brightness", MP_CMD_BRIGHTNESS, 0},
- { "contrast", MP_CMD_CONTRAST, 0},
- { "saturation", MP_CMD_SATURATION, 0},
- { "hue", MP_CMD_HUE, 0},
- { "vsync", MP_CMD_SWITCH_VSYNC, 1},
- // subs
- { "sub", MP_CMD_SUB_SELECT, 1},
- { "sub_pos", MP_CMD_SUB_POS, 0},
- { "sub_delay", MP_CMD_SUB_DELAY, 0},
- { "sub_visibility", MP_CMD_SUB_VISIBILITY, 1},
- { "sub_forced_only", MP_CMD_SUB_FORCED_ONLY, 1},
- { "sub_scale", MP_CMD_SUB_SCALE, 0},
-#ifdef CONFIG_ASS
- { "ass_use_margins", MP_CMD_ASS_USE_MARGINS, 1},
-#endif
-#ifdef CONFIG_TV
- { "tv_brightness", MP_CMD_TV_SET_BRIGHTNESS, 0},
- { "tv_hue", MP_CMD_TV_SET_HUE, 0},
- { "tv_saturation", MP_CMD_TV_SET_SATURATION, 0},
- { "tv_contrast", MP_CMD_TV_SET_CONTRAST, 0},
-#endif
- {}
-};
-
-/// Handle commands that set a property.
-static bool set_property_command(MPContext *mpctx, mp_cmd_t *cmd)
-{
- int i, r;
- m_option_t *prop;
- const char *pname;
-
- // look for the command
- for (i = 0; set_prop_cmd[i].name; i++)
- if (set_prop_cmd[i].cmd == cmd->id)
- break;
- if (!(pname = set_prop_cmd[i].name))
- return 0;
-
- if (mp_property_do(pname, M_PROPERTY_GET_TYPE, &prop, mpctx) <= 0 || !prop)
- return 0;
-
- // toggle command
- if (set_prop_cmd[i].toggle) {
- // set to value
- if (cmd->nargs > 0 && cmd->args[0].v.i >= prop->min)
- r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx);
- else if (cmd->nargs > 0)
- r = mp_property_do(pname, M_PROPERTY_STEP_DOWN, NULL, mpctx);
- else
- r = mp_property_do(pname, M_PROPERTY_STEP_UP, NULL, mpctx);
- } else if (cmd->args[1].v.i) //set
- r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v, mpctx);
- else // adjust
- r = mp_property_do(pname, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx);
-
- if (r <= 0)
- return 1;
-
- show_property_osd(mpctx, pname);
-
- return 1;
}
static const char *property_error_string(int error_value)
@@ -2086,8 +1668,6 @@ static const char *property_error_string(int error_value)
return "NOT_IMPLEMENTED";
case M_PROPERTY_UNKNOWN:
return "PROPERTY_UNKNOWN";
- case M_PROPERTY_DISABLED:
- return "DISABLED";
}
return "UNKNOWN";
}
@@ -2176,34 +1756,37 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
sh_audio_t *const sh_audio = mpctx->sh_audio;
sh_video_t *const sh_video = mpctx->sh_video;
int osd_duration = opts->osd_duration;
- int case_fallthrough_hack = 0;
- if (set_property_command(mpctx, cmd))
- goto old_pause_hack; // was handled already
+ bool auto_osd = cmd->on_osd == MP_ON_OSD_AUTO;
+ bool msg_osd = auto_osd || (cmd->on_osd & MP_ON_OSD_MSG);
+ bool bar_osd = auto_osd || (cmd->on_osd & MP_ON_OSD_BAR);
+ int osdl = msg_osd ? 1 : OSD_LEVEL_INVISIBLE;
switch (cmd->id) {
case MP_CMD_SEEK: {
- mpctx->add_osd_seek_info = true;
float v = cmd->args[0].v.f;
int abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
int exact = (cmd->nargs > 2) ? cmd->args[2].v.i : 0;
+ int function;
if (abs == 2) { // Absolute seek to a timestamp in seconds
queue_seek(mpctx, MPSEEK_ABSOLUTE, v, exact);
- mpctx->osd_function = v > get_current_time(mpctx) ?
- OSD_FFW : OSD_REW;
+ function = v > get_current_time(mpctx) ? OSD_FFW : OSD_REW;
} else if (abs) { /* Absolute seek by percentage */
queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, exact);
- mpctx->osd_function = OSD_FFW; // Direction isn't set correctly
+ function = OSD_FFW; // Direction isn't set correctly
} else {
queue_seek(mpctx, MPSEEK_RELATIVE, v, exact);
- mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW;
+ function = (v > 0) ? OSD_FFW : OSD_REW;
}
+ if (bar_osd)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
+ if (msg_osd && !auto_osd)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT;
+ if (mpctx->add_osd_seek_info)
+ mpctx->osd_function = function;
break;
}
- case MP_CMD_SET_PROPERTY_OSD:
- case_fallthrough_hack = 1;
-
- case MP_CMD_SET_PROPERTY: {
- int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_PARSE,
+ case MP_CMD_SET: {
+ int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_SET_STRING,
cmd->args[1].v.s, mpctx);
if (r == M_PROPERTY_UNKNOWN)
mp_msg(MSGT_CPLAYER, MSGL_WARN,
@@ -2212,67 +1795,36 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
mp_msg(MSGT_CPLAYER, MSGL_WARN,
"Failed to set property '%s' to '%s'.\n",
cmd->args[0].v.s, cmd->args[1].v.s);
- else if (case_fallthrough_hack)
- show_property_osd(mpctx, cmd->args[0].v.s);
- if (r <= 0)
- mp_msg(MSGT_GLOBAL, MSGL_INFO,
- "ANS_ERROR=%s\n", property_error_string(r));
+ else
+ show_property_osd(mpctx, cmd->args[0].v.s, cmd->on_osd);
break;
}
- case MP_CMD_STEP_PROPERTY_OSD:
- case_fallthrough_hack = 1;
-
- case MP_CMD_STEP_PROPERTY: {
- void *arg = NULL;
- int r, i;
- double d;
- off_t o;
- if (cmd->args[1].v.f) {
- m_option_t *prop;
- if ((r = mp_property_do(cmd->args[0].v.s,
- M_PROPERTY_GET_TYPE,
- &prop, mpctx)) <= 0)
- goto step_prop_err;
- if (prop->type == CONF_TYPE_INT ||
- prop->type == CONF_TYPE_FLAG ||
- prop->type == &m_option_type_choice)
- i = cmd->args[1].v.f, arg = &i;
- else if (prop->type == CONF_TYPE_FLOAT)
- arg = &cmd->args[1].v.f;
- else if (prop->type == CONF_TYPE_DOUBLE ||
- prop->type == CONF_TYPE_TIME)
- d = cmd->args[1].v.f, arg = &d;
- else if (prop->type == CONF_TYPE_POSITION)
- o = cmd->args[1].v.f, arg = &o;
- else
- mp_msg(MSGT_CPLAYER, MSGL_WARN,
- "Ignoring step size stepping property '%s'.\n",
- cmd->args[0].v.s);
- }
- r = mp_property_do(cmd->args[0].v.s,
- cmd->args[2].v.i < 0 ?
- M_PROPERTY_STEP_DOWN : M_PROPERTY_STEP_UP,
- arg, mpctx);
- step_prop_err:
+ case MP_CMD_ADD:
+ case MP_CMD_CYCLE:
+ {
+ struct m_property_switch_arg s = {
+ .inc = 1,
+ .wrap = cmd->id == MP_CMD_CYCLE,
+ };
+ if (cmd->args[1].v.f)
+ s.inc = cmd->args[1].v.f;
+ int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_SWITCH, &s, mpctx);
if (r == M_PROPERTY_UNKNOWN)
mp_msg(MSGT_CPLAYER, MSGL_WARN,
"Unknown property: '%s'\n", cmd->args[0].v.s);
else if (r <= 0)
mp_msg(MSGT_CPLAYER, MSGL_WARN,
- "Failed to increment property '%s' by %f.\n",
- cmd->args[0].v.s, cmd->args[1].v.f);
- else if (case_fallthrough_hack)
- show_property_osd(mpctx, cmd->args[0].v.s);
- if (r <= 0)
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_ERROR=%s\n",
- property_error_string(r));
+ "Failed to increment property '%s' by %g.\n",
+ cmd->args[0].v.s, s.inc);
+ else
+ show_property_osd(mpctx, cmd->args[0].v.s, cmd->on_osd);
break;
}
case MP_CMD_GET_PROPERTY: {
char *tmp;
- int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_TO_STRING,
+ int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_GET_STRING,
&tmp, mpctx);
if (r <= 0) {
mp_msg(MSGT_CPLAYER, MSGL_WARN,
@@ -2309,32 +1861,11 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
}
break;
- case MP_CMD_SWITCH_RATIO:
- if (!sh_video)
- break;
- if (cmd->nargs == 0 || cmd->args[0].v.f == -1)
- opts->movie_aspect = (float) sh_video->disp_w / sh_video->disp_h;
- else
- opts->movie_aspect = cmd->args[0].v.f;
- video_reset_aspect(sh_video);
- break;
-
- case MP_CMD_SPEED_INCR: {
+ case MP_CMD_SPEED_MULT: {
float v = cmd->args[0].v.f;
- mp_property_do("speed", M_PROPERTY_STEP_UP, &v, mpctx);
- show_property_osd(mpctx, "speed");
- break;
- }
-
- case MP_CMD_SPEED_MULT:
- case_fallthrough_hack = true;
-
- case MP_CMD_SPEED_SET: {
- float v = cmd->args[0].v.f;
- if (case_fallthrough_hack)
- v *= mpctx->opts.playback_speed;
+ v *= mpctx->opts.playback_speed;
mp_property_do("speed", M_PROPERTY_SET, &v, mpctx);
- show_property_osd(mpctx, "speed");
+ show_property_osd(mpctx, "speed", cmd->on_osd);
break;
}
@@ -2380,7 +1911,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
}
#endif
if (available)
- set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, 1, osd_duration,
+ set_osd_tmsg(mpctx, OSD_MSG_SUB_DELAY, osdl, osd_duration,
"Sub delay: %d ms", ROUND(sub_delay * 1000));
}
break;
@@ -2395,9 +1926,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
opts->osd_level = (opts->osd_level + 1) % (max + 1);
else
opts->osd_level = v > max ? max : v;
- /* Show OSD state when disabled, but not when an explicit
- argument is given to the OSD command, i.e. in slave mode. */
- if (v == -1 && opts->osd_level <= 1)
+ if (msg_osd && opts->osd_level <= 1)
set_osd_tmsg(mpctx, OSD_MSG_OSD_STATUS, 0, osd_duration,
"OSD: %s",
opts->osd_level ? mp_gtext("enabled") :
@@ -2407,24 +1936,23 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
break;
}
- case MP_CMD_OSD_SHOW_TEXT:
- set_osd_msg(mpctx, OSD_MSG_TEXT, cmd->args[2].v.i,
- (cmd->args[1].v.i <
- 0 ? osd_duration : cmd->args[1].v.i),
- "%s", cmd->args[0].v.s);
+ case MP_CMD_PRINT_TEXT: {
+ char *txt = mp_property_expand_string(mpctx, cmd->args[0].v.s);
+ if (txt) {
+ mp_msg(MSGT_GLOBAL, MSGL_INFO, "%s\n", txt);
+ talloc_free(txt);
+ }
break;
+ }
- case MP_CMD_OSD_SHOW_PROPERTY_TEXT: {
- char *txt = m_properties_expand_string(mp_properties,
- cmd->args[0].v.s,
- mpctx);
- // if no argument supplied use default osd_duration, else <arg> ms.
+ case MP_CMD_SHOW_TEXT: {
+ char *txt = mp_property_expand_string(mpctx, cmd->args[0].v.s);
if (txt) {
+ // if no argument supplied use default osd_duration, else <arg> ms.
set_osd_msg(mpctx, OSD_MSG_TEXT, cmd->args[2].v.i,
- (cmd->args[1].v.i <
- 0 ? osd_duration : cmd->args[1].v.i),
+ (cmd->args[1].v.i < 0 ? osd_duration : cmd->args[1].v.i),
"%s", txt);
- free(txt);
+ talloc_free(txt);
}
break;
}
@@ -2486,8 +2014,10 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
mpctx->stop_play = PT_STOP;
break;
- case MP_CMD_OSD_SHOW_PROGRESSION:
- mp_show_osd_progression(mpctx);
+ case MP_CMD_SHOW_PROGRESS:
+ mpctx->add_osd_seek_info |=
+ (msg_osd ? OSD_SEEK_INFO_TEXT : 0) |
+ (bar_osd ? OSD_SEEK_INFO_BAR : 0);
break;
#ifdef CONFIG_RADIO
@@ -2499,7 +2029,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
else
radio_step_channel(mpctx->stream, RADIO_CHANNEL_LOWER);
if (radio_get_channel_name(mpctx->stream)) {
- set_osd_tmsg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
+ set_osd_tmsg(OSD_MSG_RADIO_CHANNEL, osdl, osd_duration,
"Channel: %s",
radio_get_channel_name(mpctx->stream));
}
@@ -2510,7 +2040,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
if (mpctx->stream && mpctx->stream->type == STREAMTYPE_RADIO) {
radio_set_channel(mpctx->stream, cmd->args[0].v.s);
if (radio_get_channel_name(mpctx->stream)) {
- set_osd_tmsg(OSD_MSG_RADIO_CHANNEL, 1, osd_duration,
+ set_osd_tmsg(OSD_MSG_RADIO_CHANNEL, osdl, osd_duration,
"Channel: %s",
radio_get_channel_name(mpctx->stream));
}
@@ -2539,7 +2069,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
#ifdef CONFIG_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_freq(mpctx->stream, ROUND(cmd->args[0].v.f));
- set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+ set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
@@ -2552,7 +2082,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
#ifdef CONFIG_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_force_freq_step(mpctx->stream, ROUND(cmd->args[0].v.f));
- set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: f %d",
+ set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: f %d",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_frequency(mpctx->stream));
}
@@ -2573,7 +2103,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
tv_step_channel(get_tvh(mpctx), TV_CHANNEL_LOWER);
}
if (tv_channel_list) {
- set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration,
+ set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration,
"Channel: %s", tv_channel_current->name);
//vo_osd_changed(OSDTYPE_SUBTITLE);
}
@@ -2582,7 +2112,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
else if (mpctx->stream &&
mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_channel_step(mpctx->stream, cmd->args[0].v.i);
- set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+ set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
@@ -2611,7 +2141,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
if (get_tvh(mpctx)) {
tv_set_channel(get_tvh(mpctx), cmd->args[0].v.s);
if (tv_channel_list) {
- set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration,
+ set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration,
"Channel: %s", tv_channel_current->name);
//vo_osd_changed(OSDTYPE_SUBTITLE);
}
@@ -2619,7 +2149,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
#ifdef CONFIG_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_channel(mpctx->stream, cmd->args[0].v.s);
- set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+ set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
@@ -2644,7 +2174,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
if (get_tvh(mpctx)) {
tv_last_channel(get_tvh(mpctx));
if (tv_channel_list) {
- set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration,
+ set_osd_tmsg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration,
"Channel: %s", tv_channel_current->name);
//vo_osd_changed(OSDTYPE_SUBTITLE);
}
@@ -2652,7 +2182,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
#ifdef CONFIG_PVR
else if (mpctx->stream && mpctx->stream->type == STREAMTYPE_PVR) {
pvr_set_lastchannel(mpctx->stream);
- set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, 1, osd_duration, "%s: %s",
+ set_osd_msg(mpctx, OSD_MSG_TV_CHANNEL, osdl, osd_duration, "%s: %s",
pvr_get_current_channelname(mpctx->stream),
pvr_get_current_stationname(mpctx->stream));
}
@@ -2676,143 +2206,17 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
}
break;
- case MP_CMD_GET_SUB_VISIBILITY:
- if (sh_video) {
- mp_msg(MSGT_GLOBAL, MSGL_INFO,
- "ANS_SUB_VISIBILITY=%d\n", opts->sub_visibility);
- }
- break;
-
case MP_CMD_SCREENSHOT:
screenshot_request(mpctx, cmd->args[0].v.i, cmd->args[1].v.i);
break;
- case MP_CMD_GET_TIME_LENGTH:
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_LENGTH=%.2f\n",
- get_time_length(mpctx));
- break;
-
- case MP_CMD_GET_FILENAME: {
- char *inf = get_metadata(mpctx, META_NAME);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_FILENAME='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_VIDEO_CODEC: {
- char *inf = get_metadata(mpctx, META_VIDEO_CODEC);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_CODEC='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_VIDEO_BITRATE: {
- char *inf = get_metadata(mpctx, META_VIDEO_BITRATE);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_BITRATE='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_VIDEO_RESOLUTION: {
- char *inf = get_metadata(mpctx, META_VIDEO_RESOLUTION);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VIDEO_RESOLUTION='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_AUDIO_CODEC: {
- char *inf = get_metadata(mpctx, META_AUDIO_CODEC);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_CODEC='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_AUDIO_BITRATE: {
- char *inf = get_metadata(mpctx, META_AUDIO_BITRATE);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_BITRATE='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_AUDIO_SAMPLES: {
- char *inf = get_metadata(mpctx, META_AUDIO_SAMPLES);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_AUDIO_SAMPLES='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_TITLE: {
- char *inf = get_metadata(mpctx, META_INFO_TITLE);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TITLE='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_ARTIST: {
- char *inf = get_metadata(mpctx, META_INFO_ARTIST);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ARTIST='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_ALBUM: {
- char *inf = get_metadata(mpctx, META_INFO_ALBUM);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_ALBUM='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_YEAR: {
- char *inf = get_metadata(mpctx, META_INFO_YEAR);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_YEAR='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_COMMENT: {
- char *inf = get_metadata(mpctx, META_INFO_COMMENT);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_COMMENT='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_TRACK: {
- char *inf = get_metadata(mpctx, META_INFO_TRACK);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_TRACK='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_META_GENRE: {
- char *inf = get_metadata(mpctx, META_INFO_GENRE);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_META_GENRE='%s'\n", inf);
- talloc_free(inf);
- break;
- }
-
- case MP_CMD_GET_VO_FULLSCREEN:
- if (mpctx->video_out && mpctx->video_out->config_ok)
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_VO_FULLSCREEN=%d\n", vo_fs);
- break;
-
- case MP_CMD_GET_PERCENT_POS:
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_PERCENT_POSITION=%d\n",
- get_percent_pos(mpctx));
- break;
-
- case MP_CMD_GET_TIME_POS: {
- float pos = get_current_time(mpctx);
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_TIME_POSITION=%.1f\n", pos);
- break;
- }
-
case MP_CMD_RUN:
#ifndef __MINGW32__
if (!fork()) {
- char *exp_cmd = property_expand_string(mpctx, cmd->args[0].v.s);
- if (exp_cmd) {
- execl("/bin/sh", "sh", "-c", exp_cmd, NULL);
- free(exp_cmd);
+ char *s = mp_property_expand_string(mpctx, cmd->args[0].v.s);
+ if (s) {
+ execl("/bin/sh", "sh", "-c", s, NULL);
+ talloc_free(s);
}
exit(0);
}
@@ -2838,9 +2242,9 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
mp_msg(MSGT_CPLAYER, MSGL_INFO, "Setting vo cmd line to '%s'.\n",
s);
if (vo_control(mpctx->video_out, VOCTRL_SET_COMMAND_LINE, s) > 0) {
- set_osd_msg(mpctx, OSD_MSG_TEXT, 1, osd_duration, "vo='%s'", s);
+ set_osd_msg(mpctx, OSD_MSG_TEXT, osdl, osd_duration, "vo='%s'", s);
} else {
- set_osd_msg(mpctx, OSD_MSG_TEXT, 1, osd_duration, "Failed!");
+ set_osd_msg(mpctx, OSD_MSG_TEXT, osdl, osd_duration, "Failed!");
}
}
break;
@@ -2901,7 +2305,6 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
"Received unknown cmd %s\n", cmd->name);
}
-old_pause_hack:
switch (cmd->pausing) {
case 1: // "pausing"
pause_player(mpctx);
diff --git a/command.h b/command.h
index 1367fa88e4..0a339c5705 100644
--- a/command.h
+++ b/command.h
@@ -23,7 +23,10 @@ struct MPContext;
struct mp_cmd;
void run_command(struct MPContext *mpctx, struct mp_cmd *cmd);
-char *property_expand_string(struct MPContext *mpctx, char *str);
+char *mp_property_expand_string(struct MPContext *mpctx, char *str);
void property_print_help(void);
+int mp_property_do(const char* name, int action, void* val,
+ struct MPContext *mpctx);
+char* mp_property_print(const char *name, struct MPContext *mpctx);
#endif /* MPLAYER_COMMAND_H */
diff --git a/defaultopts.c b/defaultopts.c
index 17cc18a112..c844cd66d8 100644
--- a/defaultopts.c
+++ b/defaultopts.c
@@ -55,6 +55,7 @@ void set_default_mplayer_options(struct MPOpts *opts)
#endif
.ass_font_scale = 1,
.ass_vsfilter_aspect_compat = 1,
+ .ass_style_override = 1,
.use_embedded_fonts = 1,
.lavc_param = {
diff --git a/etc/input.conf b/etc/input.conf
index 0dec4fa4b0..f9906b23a4 100644
--- a/etc/input.conf
+++ b/etc/input.conf
@@ -11,27 +11,25 @@
#
# Note that merely removing default key bindings from this file won't remove
# the default bindings mpv was compiled with, unless
-# --input=nodefault-bindings
+# --input=no-default-bindings
# is specified.
#
# Lines starting with # are comments. Use SHARP to assign the # key.
#
-# Some characters need to be escaped. In particular, if you want to display
-# a '\' character as part of an osd_show_property_text OSD message, you have to
-# escape 2 times:
-# key osd_show_property_text "This is a single backslash: \\\\!"
+# Strings need to be quoted and escaped:
+# KEY show_text "This is a single backslash: \\ and a quote: \" !"
#
# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
# modifiers Shift, Ctrl, Alt and Meta, but note that currently reading
# key combinations is only supported through the video windows of certain
# output drivers (not in output windows of other drivers or in a terminal).
-MOUSE_BTN0_DBL vo_fullscreen # toggle fullscreen on/off
-MOUSE_BTN2 pause # toggle pause on/off
+MOUSE_BTN0_DBL cycle fullscreen # toggle fullscreen on/off
+MOUSE_BTN2 cycle pause # toggle pause on/off
MOUSE_BTN3 seek 10
MOUSE_BTN4 seek -10
-MOUSE_BTN5 volume 1
-MOUSE_BTN6 volume -1
+MOUSE_BTN5 add volume 1
+MOUSE_BTN6 add volume -1
# Seek units are in seconds, but note that these are limited by keyframes
RIGHT seek 10
@@ -39,95 +37,95 @@ LEFT seek -10
UP seek 60
DOWN seek -60
# Do smaller, always exact (non-keyframe-limited), seeks with shift.
-Shift+RIGHT seek 1 0 1
-Shift+LEFT seek -1 0 1
-Shift+UP seek 5 0 1
-Shift+DOWN seek -5 0 1
+# Don't show them on the OSD (no-osd).
+Shift+RIGHT no-osd seek 1 - exact
+Shift+LEFT no-osd seek -1 - exact
+Shift+UP no-osd seek 5 - exact
+Shift+DOWN no-osd seek -5 - exact
PGUP seek 600
PGDWN seek -600
-+ audio_delay 0.100 # this changes audio/video sync
-- audio_delay -0.100
++ add audio-delay 0.100 # this changes audio/video sync
+- add audio-delay -0.100
[ speed_mult 0.9091 # scale playback speed
] speed_mult 1.1
{ speed_mult 0.5
} speed_mult 2.0
-BS speed_set 1.0 # reset speed to normal
+BS set speed 1.0 # reset speed to normal
q quit
q {encode} quit
ESC quit
-p pause # toggle pause/playback mode
+p cycle pause # toggle pause/playback mode
. frame_step # advance one frame and pause
-SPACE pause
+SPACE cycle pause
> playlist_next # skip to next file
-ENTER playlist_next 1 # skip to next file or quit
+ENTER playlist_next force # skip to next file or quit
< playlist_prev # skip to previous file
o osd # cycle through OSD mode
-I osd_show_property_text "${filename}" # display filename in osd
-P osd_show_progression
-z sub_delay -0.1 # subtract 100 ms delay from subs
-x sub_delay +0.1 # add
+I show_text "${filename}" # display filename in osd
+P show_progress
+z add sub-delay -0.1 # subtract 100 ms delay from subs
+x add sub-delay +0.1 # add
g sub_step -1 # immediately display next subtitle
y sub_step +1 # previous
-9 volume -1
-/ volume -1
-0 volume 1
-* volume 1
-( balance -0.1 # adjust audio balance in favor of left
-) balance 0.1 # right
-m mute
-1 contrast -1
-2 contrast 1
-3 brightness -1
-4 brightness 1
-5 hue -1
-6 hue 1
-7 saturation -1
-8 saturation 1
-d frame_drop # cycle through framedrop modes
+9 add volume -1
+/ add volume -1
+0 add volume 1
+* add volume 1
+( add balance -0.1 # adjust audio balance in favor of left
+) add balance 0.1 # right
+m cycle mute
+1 add contrast -1
+2 add contrast 1
+3 add brightness -1
+4 add brightness 1
+5 add hue -1
+6 add hue 1
+7 add saturation -1
+8 add saturation 1
+d cycle framedrop # cycle through framedrop modes
# toggle deinterlacer; requires either vdpau output, -vf yadif or kerndeint
-D step_property_osd deinterlace
-c step_property_osd colormatrix
+D cycle deinterlace
+c cycle colormatrix
# Next 3 currently only work with --no-ass
-r sub_pos -1 # move subtitles up
-t sub_pos +1 # down
-v sub_visibility
+r add sub-pos -1 # move subtitles up
+t add sub-pos +1 # down
+v cycle sub-visibility
# stretch SSA/ASS subtitles with anamorphic videos to match historical
-V step_property_osd ass_vsfilter_aspect_compat
-j sub_select # cycle through subtitles
-J sub_select -3 # ...backwards
-F forced_subs_only
-SHARP switch_audio # switch audio streams
-_ step_property switch_video
-TAB step_property switch_program
+V cycle ass-vsfilter-aspect-compat
+j cycle sub # cycle through subtitles
+J cycle sub down # ...backwards
+F cycle sub-forced-only
+SHARP cycle audio # switch audio streams
+_ cycle video
+TAB cycle program
i edl_mark # for use with --edlout mode
-T vo_ontop # toggle video window ontop of other windows
-f vo_fullscreen # toggle fullscreen
-C step_property_osd capturing
-s screenshot 0 # take a png screenshot
-S screenshot 1 # ...on every frame
-Alt+s screenshot 0 1 # take a screenshot of window contents
-Alt+S screenshot 1 1 # ...on every frame
-w panscan -0.1 # zoom out with -panscan 0 -fs
-e panscan +0.1 # in
+T cycle ontop # toggle video window ontop of other windows
+f cycle fullscreen # toggle fullscreen
+s screenshot # take a png screenshot
+S screenshot each-frame # ...on every frame
+Alt+s screenshot - window # take a screenshot of window contents
+Alt+S screenshot each-frame window # ...on every frame
+w add panscan -0.1 # zoom out with -panscan 0 -fs
+e add panscan +0.1 # in
POWER quit
-MENU osd
-PLAY pause
-PAUSE pause
-PLAYPAUSE pause
+MENU cycle osd
+PLAY cycle pause
+PAUSE cycle pause
+PLAYPAUSE cycle pause
STOP quit
FORWARD seek 60
REWIND seek -60
NEXT playlist_next
PREV playlist_prev
-VOLUME_UP volume 1
-VOLUME_DOWN volume -1
-MUTE mute
+VOLUME_UP add volume 1
+VOLUME_DOWN add volume -1
+MUTE cycle mute
CLOSE_WIN quit
CLOSE_WIN {encode} quit
-! seek_chapter -1 # skip to previous chapter
-@ seek_chapter 1 # next
-E step_property_osd edition # next edition
-A switch_angle 1
+! add chapter -1 # skip to previous chapter
+@ add chapter 1 # next
+E cycle edition # next edition
+A cycle angle
U stop
# TV
@@ -140,16 +138,16 @@ u tv_step_chanlist
# Apple Remote section
#
-AR_PLAY pause
+AR_PLAY cycle pause
AR_PLAY_HOLD quit
AR_NEXT seek 30
AR_NEXT_HOLD seek 120
AR_PREV seek -10
AR_PREV_HOLD seek -120
-AR_MENU osd
-AR_MENU_HOLD mute
-AR_VUP volume 1
-AR_VDOWN volume -1
+AR_MENU cycle osd
+AR_MENU_HOLD cycle mute
+AR_VUP add volume 1
+AR_VDOWN add volume -1
#
# Joystick section
@@ -161,15 +159,15 @@ JOY_AXIS0_PLUS seek 10
JOY_AXIS0_MINUS seek -10
JOY_AXIS1_MINUS seek 60
JOY_AXIS1_PLUS seek -60
-JOY_BTN0 pause
-JOY_BTN1 osd
-JOY_BTN2 volume 1
-JOY_BTN3 volume -1
+JOY_BTN0 cycle pause
+JOY_BTN1 cycle osd
+JOY_BTN2 add volume 1
+JOY_BTN3 add volume -1
#
# Not assigned by default
# (not an exhaustive list of unbound commands)
#
-#? sub_scale +0.1 # increase subtitle font size
-#? sub_scale -0.1 # decrease subtitle font size
+#? add sub-scale +0.1 # increase subtitle font size
+#? add sub-scale -0.1 # decrease subtitle font size
diff --git a/input/input.c b/input/input.c
index 1a4b66be8d..9b41d01229 100644
--- a/input/input.c
+++ b/input/input.c
@@ -85,79 +85,64 @@ struct key_name {
* argument value if the user didn't give enough arguments to specify it.
* A command can take a maximum of MP_CMD_MAX_ARGS arguments (10).
*/
-#define ARG_INT { .type = MP_CMD_ARG_INT }
-#define OARG_INT(def) { .type = MP_CMD_ARG_INT, .optional = true, .v.i = def }
-#define ARG_FLOAT { .type = MP_CMD_ARG_FLOAT }
-#define OARG_FLOAT(def) { .type = MP_CMD_ARG_FLOAT, .optional = true, .v.f = def }
-#define ARG_STRING { .type = MP_CMD_ARG_STRING }
-#define OARG_STRING(def) { .type = MP_CMD_ARG_STRING, .optional = true, .v.s = def }
+
+#define ARG_INT { .type = {"", NULL, &m_option_type_int} }
+#define ARG_FLOAT { .type = {"", NULL, &m_option_type_float} }
+#define ARG_STRING { .type = {"", NULL, &m_option_type_string} }
+#define ARG_CHOICE(c) { .type = {"", NULL, &m_option_type_choice, \
+ M_CHOICES(c)} }
+
+#define OARG_FLOAT(def) { .type = {"", NULL, &m_option_type_float}, \
+ .optional = true, .v.f = def }
+#define OARG_INT(def) { .type = {"", NULL, &m_option_type_int}, \
+ .optional = true, .v.i = def }
+#define OARG_CHOICE(def, c) { .type = {"", NULL, &m_option_type_choice, \
+ M_CHOICES(c)}, \
+ .optional = true, .v.i = def }
+
+static int parse_cycle_dir(const struct m_option *opt, struct bstr name,
+ struct bstr param, void *dst);
+static const struct m_option_type m_option_type_cycle_dir = {
+ .name = "up|down",
+ .parse = parse_cycle_dir,
+};
static const mp_cmd_t mp_cmds[] = {
+ { MP_CMD_IGNORE, "ignore", },
#ifdef CONFIG_RADIO
{ MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", { ARG_INT } },
{ MP_CMD_RADIO_SET_CHANNEL, "radio_set_channel", { ARG_STRING } },
{ MP_CMD_RADIO_SET_FREQ, "radio_set_freq", { ARG_FLOAT } },
{ MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", {ARG_FLOAT } },
#endif
- { MP_CMD_SEEK, "seek", { ARG_FLOAT, OARG_INT(0), OARG_INT(0) } },
+ { MP_CMD_SEEK, "seek", {
+ ARG_FLOAT,
+ OARG_CHOICE(0, ({"relative", 0}, {"0", 0},
+ {"absolute-percent", 1}, {"1", 1},
+ {"absolute", 2}, {"2", 2})),
+ OARG_CHOICE(0, ({"default-precise", 0}, {"0", 0},
+ {"exact", 1}, {"1", 1},
+ {"keyframes", -1}, {"-1", -1})),
+ }},
{ MP_CMD_EDL_MARK, "edl_mark", },
- { MP_CMD_AUDIO_DELAY, "audio_delay", { ARG_FLOAT, OARG_INT(0) } },
- { MP_CMD_SPEED_INCR, "speed_incr", { ARG_FLOAT } },
{ MP_CMD_SPEED_MULT, "speed_mult", { ARG_FLOAT } },
- { MP_CMD_SPEED_SET, "speed_set", { ARG_FLOAT } },
{ MP_CMD_QUIT, "quit", { OARG_INT(0) } },
{ MP_CMD_STOP, "stop", },
- { MP_CMD_PAUSE, "pause", },
{ MP_CMD_FRAME_STEP, "frame_step", },
- { MP_CMD_PLAYLIST_NEXT, "playlist_next", { OARG_INT(0) } },
- { MP_CMD_PLAYLIST_PREV, "playlist_prev", { OARG_INT(0) } },
- { MP_CMD_LOOP, "loop", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_SUB_DELAY, "sub_delay", { ARG_FLOAT, OARG_INT(0) } },
- { MP_CMD_SUB_STEP, "sub_step", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_PLAYLIST_NEXT, "playlist_next", {
+ OARG_CHOICE(0, ({"weak", 0}, {"0", 0},
+ {"force", 1}, {"1", 1})),
+ }},
+ { MP_CMD_PLAYLIST_PREV, "playlist_prev", {
+ OARG_CHOICE(0, ({"weak", 0}, {"0", 0},
+ {"force", 1}, {"1", 1})),
+ }},
+ { MP_CMD_SUB_STEP, "sub_step", { ARG_INT } },
{ MP_CMD_OSD, "osd", { OARG_INT(-1) } },
- { MP_CMD_OSD_SHOW_TEXT, "osd_show_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } },
- { MP_CMD_OSD_SHOW_PROPERTY_TEXT, "osd_show_property_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } },
- { MP_CMD_OSD_SHOW_PROGRESSION, "osd_show_progression", },
- { MP_CMD_VOLUME, "volume", { ARG_FLOAT, OARG_INT(0) } },
- { MP_CMD_BALANCE, "balance", { ARG_FLOAT, OARG_INT(0) } },
- { MP_CMD_MIXER_USEMASTER, "use_master", },
- { MP_CMD_MUTE, "mute", { OARG_INT(-1) } },
- { MP_CMD_CONTRAST, "contrast", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_GAMMA, "gamma", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_BRIGHTNESS, "brightness", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_HUE, "hue", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_SATURATION, "saturation", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_FRAMEDROPPING, "frame_drop", { OARG_INT(-1) } },
- { MP_CMD_SUB_POS, "sub_pos", { ARG_INT, OARG_INT(0) } },
- { MP_CMD_SUB_ALIGNMENT, "sub_alignment", { OARG_INT(-1) } },
- { MP_CMD_SUB_VISIBILITY, "sub_visibility", { OARG_INT(-1) } },
+ { MP_CMD_PRINT_TEXT, "print_text", { ARG_STRING } },
+ { MP_CMD_SHOW_TEXT, "show_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } },
+ { MP_CMD_SHOW_PROGRESS, "show_progress", },
{ MP_CMD_SUB_LOAD, "sub_load", { ARG_STRING } },
- { MP_CMD_SUB_SELECT, "vobsub_lang", { OARG_INT(-2) } }, // for compatibility
- { MP_CMD_SUB_SELECT, "sub_select", { OARG_INT(-2) } },
- { MP_CMD_SUB_SCALE, "sub_scale", { ARG_FLOAT, OARG_INT(0) } },
-#ifdef CONFIG_ASS
- { MP_CMD_ASS_USE_MARGINS, "ass_use_margins", { OARG_INT(-1) } },
-#endif
- { MP_CMD_GET_PERCENT_POS, "get_percent_pos", },
- { MP_CMD_GET_TIME_POS, "get_time_pos", },
- { MP_CMD_GET_TIME_LENGTH, "get_time_length", },
- { MP_CMD_GET_FILENAME, "get_file_name", },
- { MP_CMD_GET_VIDEO_CODEC, "get_video_codec", },
- { MP_CMD_GET_VIDEO_BITRATE, "get_video_bitrate", },
- { MP_CMD_GET_VIDEO_RESOLUTION, "get_video_resolution", },
- { MP_CMD_GET_AUDIO_CODEC, "get_audio_codec", },
- { MP_CMD_GET_AUDIO_BITRATE, "get_audio_bitrate", },
- { MP_CMD_GET_AUDIO_SAMPLES, "get_audio_samples", },
- { MP_CMD_GET_META_TITLE, "get_meta_title", },
- { MP_CMD_GET_META_ARTIST, "get_meta_artist", },
- { MP_CMD_GET_META_ALBUM, "get_meta_album", },
- { MP_CMD_GET_META_YEAR, "get_meta_year", },
- { MP_CMD_GET_META_COMMENT, "get_meta_comment", },
- { MP_CMD_GET_META_TRACK, "get_meta_track", },
- { MP_CMD_GET_META_GENRE, "get_meta_genre", },
- { MP_CMD_SWITCH_AUDIO, "switch_audio", { OARG_INT(-1) } },
- { MP_CMD_SWITCH_ANGLE, "switch_angle", { OARG_INT(-1) } },
- { MP_CMD_SWITCH_TITLE, "switch_title", { OARG_INT(-1) } },
#ifdef CONFIG_TV
{ MP_CMD_TV_START_SCAN, "tv_start_scan", },
{ MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", { ARG_INT } },
@@ -168,38 +153,40 @@ static const mp_cmd_t mp_cmds[] = {
{ MP_CMD_TV_SET_FREQ, "tv_set_freq", { ARG_FLOAT } },
{ MP_CMD_TV_STEP_FREQ, "tv_step_freq", { ARG_FLOAT } },
{ MP_CMD_TV_SET_NORM, "tv_set_norm", { ARG_STRING } },
- { MP_CMD_TV_SET_BRIGHTNESS, "tv_set_brightness", { ARG_INT, OARG_INT(1) } },
- { MP_CMD_TV_SET_CONTRAST, "tv_set_contrast", { ARG_INT, OARG_INT(1) } },
- { MP_CMD_TV_SET_HUE, "tv_set_hue", { ARG_INT, OARG_INT(1) } },
- { MP_CMD_TV_SET_SATURATION, "tv_set_saturation", { ARG_INT, OARG_INT(1) } },
#endif
- { MP_CMD_SUB_FORCED_ONLY, "forced_subs_only", { OARG_INT(-1) } },
#ifdef CONFIG_DVBIN
{ MP_CMD_DVB_SET_CHANNEL, "dvb_set_channel", { ARG_INT, ARG_INT } },
#endif
- { MP_CMD_SWITCH_RATIO, "switch_ratio", { OARG_FLOAT(0) } },
- { MP_CMD_VO_FULLSCREEN, "vo_fullscreen", { OARG_INT(-1) } },
- { MP_CMD_VO_ONTOP, "vo_ontop", { OARG_INT(-1) } },
- { MP_CMD_VO_ROOTWIN, "vo_rootwin", { OARG_INT(-1) } },
- { MP_CMD_VO_BORDER, "vo_border", { OARG_INT(-1) } },
- { MP_CMD_SCREENSHOT, "screenshot", { OARG_INT(0), OARG_INT(0) } },
- { MP_CMD_PANSCAN, "panscan", { ARG_FLOAT, OARG_INT(0) } },
- { MP_CMD_SWITCH_VSYNC, "switch_vsync", { OARG_INT(0) } },
- { MP_CMD_LOADFILE, "loadfile", { ARG_STRING, OARG_INT(0) } },
- { MP_CMD_LOADLIST, "loadlist", { ARG_STRING, OARG_INT(0) } },
+ { MP_CMD_SCREENSHOT, "screenshot", {
+ OARG_CHOICE(0, ({"single", 0}, {"0", 0},
+ {"each-frame", 1}, {"1", 1})),
+ OARG_CHOICE(0, ({"video", 0}, {"0", 0},
+ {"window", 1}, {"1", 1})),
+ }},
+ { MP_CMD_LOADFILE, "loadfile", {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"replace", 0}, {"0", 0},
+ {"append", 1}, {"1", 1})),
+ }},
+ { MP_CMD_LOADLIST, "loadlist", {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"replace", 0}, {"0", 0},
+ {"append", 1}, {"1", 1})),
+ }},
{ MP_CMD_PLAYLIST_CLEAR, "playlist_clear", },
{ MP_CMD_RUN, "run", { ARG_STRING } },
- { MP_CMD_GET_VO_FULLSCREEN, "get_vo_fullscreen", },
- { MP_CMD_GET_SUB_VISIBILITY, "get_sub_visibility", },
{ MP_CMD_KEYDOWN_EVENTS, "key_down_event", { ARG_INT } },
- { MP_CMD_SET_PROPERTY, "set_property", { ARG_STRING, ARG_STRING } },
- { MP_CMD_SET_PROPERTY_OSD, "set_property_osd", { ARG_STRING, ARG_STRING } },
+ { MP_CMD_SET, "set", { ARG_STRING, ARG_STRING } },
{ MP_CMD_GET_PROPERTY, "get_property", { ARG_STRING } },
- { MP_CMD_STEP_PROPERTY, "step_property", { ARG_STRING, OARG_FLOAT(0), OARG_INT(0) } },
- { MP_CMD_STEP_PROPERTY_OSD, "step_property_osd", { ARG_STRING, OARG_FLOAT(0), OARG_INT(0) } },
+ { MP_CMD_ADD, "add", { ARG_STRING, OARG_FLOAT(0) } },
+ { MP_CMD_CYCLE, "cycle", {
+ ARG_STRING,
+ { .type = {"", NULL, &m_option_type_cycle_dir},
+ .optional = true,
+ .v.f = 1 },
+ }},
- { MP_CMD_SEEK_CHAPTER, "seek_chapter", { ARG_INT, OARG_INT(0) } },
{ MP_CMD_SET_MOUSE_POS, "set_mouse_pos", { ARG_INT, ARG_INT } },
{ MP_CMD_AF_SWITCH, "af_switch", { ARG_STRING } },
@@ -208,14 +195,71 @@ static const mp_cmd_t mp_cmds[] = {
{ MP_CMD_AF_CLR, "af_clr", },
{ MP_CMD_AF_CMDLINE, "af_cmdline", { ARG_STRING, ARG_STRING } },
- { MP_CMD_SHOW_CHAPTERS, "show_chapters_osd", },
- { MP_CMD_SHOW_TRACKS, "show_tracks_osd", },
+ { MP_CMD_SHOW_CHAPTERS, "show_chapters", },
+ { MP_CMD_SHOW_TRACKS, "show_tracks", },
{ MP_CMD_VO_CMDLINE, "vo_cmdline", { ARG_STRING } },
{0}
};
+// Map legacy commands to proper commands
+struct legacy_cmd {
+ const char *old, *new;
+};
+static const struct legacy_cmd legacy_cmds[] = {
+ {"loop", "cycle loop"},
+ {"seek_chapter", "add chapter"},
+ {"switch_angle", "cycle angle"},
+ {"pause", "cycle pause"},
+ {"volume", "add volume"},
+ {"mute", "cycle mute"},
+ {"audio_delay", "add audio-delay"},
+ {"switch_audio", "cycle audio"},
+ {"balance", "add balance"},
+ {"vo_fullscreen", "no-osd cycle fullscreen"},
+ {"panscan", "add panscan"},
+ {"vo_ontop", "cycle ontop"},
+ {"vo_rootwin", "cycle rootwin"},
+ {"vo_border", "cycle border"},
+ {"frame_drop", "cycle framedrop"},
+ {"gamma", "add gamma"},
+ {"brightness", "add brightness"},
+ {"contrast", "add contrast"},
+ {"saturation", "add saturation"},
+ {"hue", "add hue"},
+ {"switch_vsync", "cycle vsync"},
+ {"sub_select", "cycle sub"},
+ {"sub_pos", "add sub-pos"},
+ {"sub_delay", "add sub-delay"},
+ {"sub_visibility", "cycle sub-visibility"},
+ {"forced_subs_only", "cycle sub-forced-only"},
+ {"sub_scale", "add sub-scale"},
+ {"ass_use_margins", "cycle ass-use-margins"},
+ {"tv_set_brightness", "add tv-brightness"},
+ {"tv_set_hue", "add tv-hue"},
+ {"tv_set_saturation", "add tv-saturation"},
+ {"tv_set_contrast", "add tv-contrast"},
+ {"step_property_osd", "cycle"},
+ {"step_property", "no-osd cycle"},
+ {"set_property", "no-osd set"},
+ {"set_property_osd", "set"},
+ {"speed_set", "set speed"},
+ {"osd_show_text", "show_text"},
+ {"osd_show_property_text", "show_text"},
+ {"osd_show_progression", "show_progress"},
+ {"show_chapters_osd", "show_chapters"},
+ {"show_tracks_osd", "show_tracks"},
+ // Approximate (can fail if user added additional whitespace)
+ {"pt_step 1", "playlist_next"},
+ {"pt_step -1", "playlist_prev"},
+ // Switch_ratio without argument resets aspect ratio
+ {"switch_ratio ", "set aspect "},
+ {"switch_ratio", "set aspect 0"},
+ {0}
+};
+
+
/// The names of the keys as used in input.conf
/// If you add some new keys, you also need to add them here
@@ -698,146 +742,240 @@ int mp_input_add_key_fd(struct input_ctx *ictx, int fd, int select,
return 1;
}
-mp_cmd_t *mp_input_parse_cmd(char *str)
+static int parse_cycle_dir(const struct m_option *opt, struct bstr name,
+ struct bstr param, void *dst)
{
- int i, l;
- int pausing = 0;
- char *ptr;
- const mp_cmd_t *cmd_def;
+ float val;
+ if (bstrcmp0(param, "up") == 0) {
+ val = +1;
+ } else if (bstrcmp0(param, "down") == 0) {
+ val = -1;
+ } else {
+ return m_option_type_float.parse(opt, name, param, dst);
+ }
+ *(float *)dst = val;
+ return 1;
+}
+
+static bool read_token(bstr str, bstr *out_rest, bstr *out_token)
+{
+ bstr t = bstr_lstrip(str);
+ int next = bstrcspn(t, WHITESPACE "#");
+ // Handle comments
+ if (t.start[next] == '#')
+ t = bstr_splice(t, 0, next);
+ if (!t.len)
+ return false;
+ *out_token = bstr_splice(t, 0, next);
+ *out_rest = bstr_cut(t, next);
+ return true;
+}
+
+static bool eat_token(bstr *str, const char *tok)
+{
+ bstr rest, token;
+ if (read_token(*str, &rest, &token) && bstrcmp0(token, tok) == 0) {
+ *str = rest;
+ return true;
+ }
+ return false;
+}
- // Ignore heading spaces.
- while (str[0] == ' ' || str[0] == '\t')
- ++str;
+static bool append_escape(bstr *code, char **str)
+{
+ if (code->len < 1)
+ return false;
+ char replace = 0;
+ switch (code->start[0]) {
+ case '"': replace = '"'; break;
+ case '\\': replace = '\\'; break;
+ case 'b': replace = '\b'; break;
+ case 'f': replace = '\f'; break;
+ case 'n': replace = '\n'; break;
+ case 'r': replace = '\r'; break;
+ case 't': replace = '\t'; break;
+ case 'e': replace = '\x1b'; break;
+ case '\'': replace = '\''; break;
+ }
+ if (replace) {
+ *str = talloc_strndup_append_buffer(*str, &replace, 1);
+ *code = bstr_cut(*code, 1);
+ return true;
+ }
+ if (code->start[0] == 'x' && code->len >= 3) {
+ bstr num = bstr_splice(*code, 1, 3);
+ char c = bstrtoll(num, &num, 16);
+ if (!num.len)
+ return false;
+ *str = talloc_strndup_append_buffer(*str, &c, 1);
+ *code = bstr_cut(*code, 3);
+ return true;
+ }
+ if (code->start[0] == 'u' && code->len >= 5) {
+ bstr num = bstr_splice(*code, 1, 5);
+ int c = bstrtoll(num, &num, 16);
+ if (num.len)
+ return false;
+ *str = append_utf8_buffer(*str, c);
+ *code = bstr_cut(*code, 5);
+ return true;
+ }
+ return false;
+}
+
+static bool read_escaped_string(void *talloc_ctx, bstr *str, bstr *literal)
+{
+ bstr t = *str;
+ char *new = talloc_strdup(talloc_ctx, "");
+ while (t.len) {
+ if (t.start[0] == '"')
+ break;
+ if (t.start[0] == '\\') {
+ t = bstr_cut(t, 1);
+ if (!append_escape(&t, &new))
+ goto error;
+ } else {
+ new = talloc_strndup_append_buffer(new, t.start, 1);
+ t = bstr_cut(t, 1);
+ }
+ }
+ int len = str->len - t.len;
+ *literal = new ? bstr0(new) : bstr_splice(*str, 0, len);
+ *str = bstr_cut(*str, len);
+ return true;
+error:
+ talloc_free(new);
+ return false;
+}
+
+mp_cmd_t *mp_input_parse_cmd(bstr str)
+{
+ int pausing = 0;
+ int on_osd = MP_ON_OSD_AUTO;
+ struct mp_cmd *cmd = NULL;
+ void *tmp = talloc_new(NULL);
- if (strncmp(str, "pausing ", 8) == 0) {
+ if (eat_token(&str, "pausing")) {
pausing = 1;
- str = &str[8];
- } else if (strncmp(str, "pausing_keep ", 13) == 0) {
+ } else if (eat_token(&str, "pausing_keep")) {
pausing = 2;
- str = &str[13];
- } else if (strncmp(str, "pausing_toggle ", 15) == 0) {
+ } else if (eat_token(&str, "pausing_toggle")) {
pausing = 3;
- str = &str[15];
- } else if (strncmp(str, "pausing_keep_force ", 19) == 0) {
+ } else if (eat_token(&str, "pausing_keep_force")) {
pausing = 4;
- str = &str[19];
}
- ptr = str + strcspn(str, "\t ");
- if (*ptr != 0)
- l = ptr - str;
- else
- l = strlen(str);
-
- if (l == 0)
- return NULL;
-
- for (i = 0; mp_cmds[i].name != NULL; i++) {
- if (strncasecmp(mp_cmds[i].name, str, l) == 0)
+ str = bstr_lstrip(str);
+ for (const struct legacy_cmd *entry = legacy_cmds; entry->old; entry++) {
+ size_t old_len = strlen(entry->old);
+ if (bstrcasecmp(bstr_splice(str, 0, old_len),
+ (bstr) {(char *)entry->old, old_len}) == 0)
+ {
+ mp_tmsg(MSGT_INPUT, MSGL_V, "Warning: command '%s' is "
+ "deprecated, replaced with '%s'. Fix your input.conf!\n",
+ entry->old, entry->new);
+ bstr s = bstr_cut(str, old_len);
+ str = bstr0(talloc_asprintf(tmp, "%s%.*s", entry->new, BSTR_P(s)));
break;
+ }
}
- if (mp_cmds[i].name == NULL)
- return NULL;
+ if (eat_token(&str, "no-osd")) {
+ on_osd = MP_ON_OSD_NO;
+ } else if (eat_token(&str, "osd-bar")) {
+ on_osd = MP_ON_OSD_BAR;
+ } else if (eat_token(&str, "osd-msg")) {
+ on_osd = MP_ON_OSD_MSG;
+ } else if (eat_token(&str, "osd-msg-bar")) {
+ on_osd = MP_ON_OSD_MSG | MP_ON_OSD_BAR;
+ } else if (eat_token(&str, "osd-auto")) {
+ // default
+ }
- cmd_def = &mp_cmds[i];
+ int cmd_idx = 0;
+ while (mp_cmds[cmd_idx].name != NULL) {
+ if (eat_token(&str, mp_cmds[cmd_idx].name))
+ break;
+ cmd_idx++;
+ }
- mp_cmd_t *cmd = talloc_ptrtype(NULL, cmd);
- *cmd = (mp_cmd_t){
- .id = cmd_def->id,
- .name = talloc_strdup(cmd, cmd_def->name),
- .pausing = pausing,
- };
+ if (mp_cmds[cmd_idx].name == NULL) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command '%.*s' not found.\n",
+ BSTR_P(str));
+ goto error;
+ }
- ptr = str;
+ cmd = talloc_ptrtype(NULL, cmd);
+ *cmd = mp_cmds[cmd_idx];
+ cmd->pausing = pausing;
+ cmd->on_osd = on_osd;
- for (i = 0; ptr && i < MP_CMD_MAX_ARGS; i++) {
- while (ptr[0] != ' ' && ptr[0] != '\t' && ptr[0] != '\0')
- ptr++;
- if (ptr[0] == '\0')
- break;
- while (ptr[0] == ' ' || ptr[0] == '\t')
- ptr++;
- if (ptr[0] == '\0' || ptr[0] == '#')
+ for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
+ struct mp_cmd_arg *cmdarg = &cmd->args[i];
+ if (!cmdarg->type.type)
break;
- cmd->args[i].type = cmd_def->args[i].type;
- switch (cmd_def->args[i].type) {
- case MP_CMD_ARG_INT:
- errno = 0;
- cmd->args[i].v.i = atoi(ptr);
- if (errno != 0) {
+ cmd->nargs++;
+ str = bstr_lstrip(str);
+ bstr arg = {0};
+ if (cmdarg->type.type == &m_option_type_string &&
+ bstr_eatstart0(&str, "\""))
+ {
+ if (!read_escaped_string(tmp, &str, &arg)) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
- "isn't an integer.\n", cmd_def->name, i + 1);
+ "has broken string escapes.\n", cmd->name, i + 1);
goto error;
}
- break;
- case MP_CMD_ARG_FLOAT:
- errno = 0;
- cmd->args[i].v.f = atof(ptr);
- if (errno != 0) {
- mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
- "isn't a float.\n", cmd_def->name, i + 1);
+ if (!bstr_eatstart0(&str, "\"")) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d is "
+ "unterminated.\n", cmd->name, i + 1);
goto error;
}
- break;
- case MP_CMD_ARG_STRING: {
- int term = ' ';
- if (*ptr == '\'' || *ptr == '"')
- term = *ptr++;
- char *argptr = talloc_size(cmd, strlen(ptr) + 1);
- cmd->args[i].v.s = argptr;
- while (1) {
- if (*ptr == 0) {
- if (term == ' ')
- break;
- mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d is "
- "unterminated.\n", cmd_def->name, i + 1);
- goto error;
- }
- if (*ptr == term || (*ptr == '\t' && term == ' '))
- break;
- if (*ptr == '\\')
- ptr++;
- if (*ptr != 0)
- *argptr++ = *ptr++;
- }
- *argptr = 0;
- break;
+ } else {
+ if (!read_token(str, &str, &arg))
+ break;
+ if (cmdarg->optional && bstrcmp0(arg, "-") == 0)
+ continue;
}
- case 0:
- ptr = NULL;
- break;
- default:
- mp_tmsg(MSGT_INPUT, MSGL_ERR, "Unknown argument %d\n", i);
+ // Prevent option API from trying to deallocate static strings
+ cmdarg->v = ((struct mp_cmd_arg) {{0}}).v;
+ int r = m_option_parse(&cmdarg->type, bstr0(cmd->name), arg, &cmdarg->v);
+ if (r < 0) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
+ "can't be parsed: %s.\n", cmd->name, i + 1,
+ m_option_strerror(r));
+ goto error;
}
+ if (cmdarg->type.type == &m_option_type_string)
+ cmdarg->v.s = talloc_steal(cmd, cmdarg->v.s);
}
- cmd->nargs = i;
- int min_args;
- for (min_args = 0; min_args < MP_CMD_MAX_ARGS
- && cmd_def->args[min_args].type
- && !cmd_def->args[min_args].optional; min_args++);
- if (cmd->nargs < min_args) {
- mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command \"%s\" requires at least %d "
- "arguments, we found only %d so far.\n", cmd_def->name,
- min_args, cmd->nargs);
+ bstr dummy;
+ if (read_token(str, &dummy, &dummy)) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s has trailing unused "
+ "arguments: '%.*s'.\n", cmd->name, BSTR_P(str));
+ // Better make it fatal to make it clear something is wrong.
goto error;
}
- for (; i < MP_CMD_MAX_ARGS && cmd_def->args[i].type; i++) {
- memcpy(&cmd->args[i], &cmd_def->args[i], sizeof(struct mp_cmd_arg));
- if (cmd_def->args[i].type == MP_CMD_ARG_STRING
- && cmd_def->args[i].v.s != NULL)
- cmd->args[i].v.s = talloc_strdup(cmd, cmd_def->args[i].v.s);
+ int min_args = 0;
+ while (min_args < MP_CMD_MAX_ARGS && cmd->args[min_args].type.type
+ && !cmd->args[min_args].optional)
+ {
+ min_args++;
+ }
+ if (cmd->nargs < min_args) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s requires at least %d "
+ "arguments, we found only %d so far.\n", cmd->name, min_args,
+ cmd->nargs);
+ goto error;
}
- if (i < MP_CMD_MAX_ARGS)
- cmd->args[i].type = 0;
-
+ talloc_free(tmp);
return cmd;
- error:
- mp_cmd_free(cmd);
+error:
+ talloc_free(cmd);
+ talloc_free(tmp);
return NULL;
}
@@ -972,15 +1110,14 @@ static char *find_bind_for_key(const struct cmd_bind *binds, int n, int *keys)
}
static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx,
- bool builtin,
- char *section)
+ bool builtin, bstr section)
{
struct cmd_bind_section *bind_section = ictx->cmd_bind_sections;
- if (section == NULL)
- section = "default";
+ if (section.len == 0)
+ section = bstr0("default");
while (bind_section) {
- if (strcmp(section, bind_section->section) == 0
+ if (bstrcmp0(section, bind_section->section) == 0
&& builtin == bind_section->is_builtin)
return bind_section;
if (bind_section->next == NULL)
@@ -995,7 +1132,7 @@ static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx,
bind_section = ictx->cmd_bind_sections;
}
bind_section->cmd_binds = NULL;
- bind_section->section = talloc_strdup(bind_section, section);
+ bind_section->section = bstrdup0(bind_section, section);
bind_section->is_builtin = builtin;
bind_section->next = NULL;
return bind_section;
@@ -1005,9 +1142,9 @@ static char *section_find_bind_for_key(struct input_ctx *ictx,
bool builtin, char *section,
int n, int *keys)
{
- struct cmd_bind_section *bs = get_bind_section(ictx, builtin, section);
- const struct cmd_bind *binds = bs->cmd_binds;
- return binds ? find_bind_for_key(binds, n, keys) : NULL;
+ struct cmd_bind_section *bs = get_bind_section(ictx, builtin,
+ bstr0(section));
+ return bs->cmd_binds ? find_bind_for_key(bs->cmd_binds, n, keys) : NULL;
}
static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
@@ -1032,9 +1169,7 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
talloc_free(key_buf);
return NULL;
}
- if (strcmp(cmd, "ignore") == 0)
- return NULL;
- ret = mp_input_parse_cmd(cmd);
+ ret = mp_input_parse_cmd(bstr0(cmd));
if (!ret) {
char *key_buf = get_key_combo_name(keys, n);
mp_tmsg(MSGT_INPUT, MSGL_ERR,
@@ -1176,7 +1311,7 @@ static void read_cmd_fd(struct input_ctx *ictx, struct input_fd *cmd_fd)
char *text;
while ((r = read_cmd(cmd_fd, &text)) >= 0) {
ictx->got_new_events = true;
- struct mp_cmd *cmd = mp_input_parse_cmd(text);
+ struct mp_cmd *cmd = mp_input_parse_cmd(bstr0(text));
talloc_free(text);
if (cmd)
queue_add(&ictx->control_cmd_queue, cmd, false);
@@ -1323,7 +1458,7 @@ int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd)
mp_cmd_t *mp_input_get_cmd(struct input_ctx *ictx, int time, int peek_only)
{
if (async_quit_request)
- return mp_input_parse_cmd("quit 1");
+ return mp_input_parse_cmd(bstr0("quit 1"));
if (ictx->control_cmd_queue.first || ictx->key_cmd_queue.first)
time = 0;
@@ -1358,8 +1493,8 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
ret = talloc_memdup(NULL, cmd, sizeof(mp_cmd_t));
ret->name = talloc_strdup(ret, cmd->name);
- for (i = 0; i < MP_CMD_MAX_ARGS && cmd->args[i].type; i++) {
- if (cmd->args[i].type == MP_CMD_ARG_STRING && cmd->args[i].v.s != NULL)
+ for (i = 0; i < MP_CMD_MAX_ARGS; i++) {
+ if (cmd->args[i].type.type == &m_option_type_string)
ret->args[i].v.s = talloc_strdup(ret, cmd->args[i].v.s);
}
@@ -1428,24 +1563,14 @@ static int get_input_from_name(char *name, int *keys)
return 1;
}
-static void bind_keys(struct input_ctx *ictx, bool builtin,
+static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section,
const int keys[MP_MAX_KEY_DOWN + 1], bstr command)
{
int i = 0, j;
struct cmd_bind *bind = NULL;
struct cmd_bind_section *bind_section = NULL;
- char *section = NULL;
-
- if (bstr_startswith0(command, "{")) {
- int p = bstrchr(command, '}');
- if (p != -1) {
- bstr bsection = bstr_strip(bstr_splice(command, 1, p));
- section = bstrdup0(NULL, bsection);
- command = bstr_lstrip(bstr_cut(command, p + 1));
- }
- }
+
bind_section = get_bind_section(ictx, builtin, section);
- talloc_free(section);
if (bind_section->cmd_binds) {
for (i = 0; bind_section->cmd_binds[i].cmd != NULL; i++) {
@@ -1496,8 +1621,21 @@ static int parse_config(struct input_ctx *ictx, bool builtin, bstr data)
continue;
}
talloc_free(name);
- bind_keys(ictx, builtin, keys, command);
+
+ bstr section = {0};
+ if (bstr_startswith0(command, "{")) {
+ int p = bstrchr(command, '}');
+ if (p != -1) {
+ section = bstr_strip(bstr_splice(command, 1, p));
+ command = bstr_lstrip(bstr_cut(command, p + 1));
+ }
+ }
+
+ bind_keys(ictx, builtin, section, keys, command);
n_binds++;
+
+ // Print warnings if invalid commands are encountered.
+ talloc_free(mp_input_parse_cmd(command));
}
return n_binds;
@@ -1702,24 +1840,11 @@ static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam)
{
const mp_cmd_t *cmd;
int i, j;
- const char *type;
for (i = 0; (cmd = &mp_cmds[i])->name != NULL; i++) {
printf("%-20.20s", cmd->name);
- for (j = 0; j < MP_CMD_MAX_ARGS && cmd->args[j].type; j++) {
- switch (cmd->args[j].type) {
- case MP_CMD_ARG_INT:
- type = "Integer";
- break;
- case MP_CMD_ARG_FLOAT:
- type = "Float";
- break;
- case MP_CMD_ARG_STRING:
- type = "String";
- break;
- default:
- type = "??";
- }
+ for (j = 0; j < MP_CMD_MAX_ARGS && cmd->args[j].type.type; j++) {
+ const char *type = cmd->args[j].type.type->name;
if (cmd->args[j].optional)
printf(" [%s]", type);
else
diff --git a/input/input.h b/input/input.h
index ddd9016203..988565cb40 100644
--- a/input/input.h
+++ b/input/input.h
@@ -20,106 +20,49 @@
#define MPLAYER_INPUT_H
#include <stdbool.h>
+#include "bstr.h"
+#include "m_option.h"
// All command IDs
enum mp_command_type {
+ MP_CMD_IGNORE,
MP_CMD_SEEK,
- MP_CMD_AUDIO_DELAY,
MP_CMD_QUIT,
- MP_CMD_PAUSE,
- MP_CMD_GRAB_FRAMES, // deprecated: was a no-op command for years
MP_CMD_PLAYLIST_NEXT,
MP_CMD_PLAYLIST_PREV,
- MP_CMD_SUB_DELAY,
MP_CMD_OSD,
- MP_CMD_VOLUME,
- MP_CMD_MIXER_USEMASTER,
- MP_CMD_CONTRAST,
- MP_CMD_BRIGHTNESS,
- MP_CMD_HUE,
- MP_CMD_SATURATION,
- MP_CMD_FRAMEDROPPING,
MP_CMD_TV_STEP_CHANNEL,
MP_CMD_TV_STEP_NORM,
MP_CMD_TV_STEP_CHANNEL_LIST,
- MP_CMD_VO_FULLSCREEN,
- MP_CMD_SUB_POS,
MP_CMD_SCREENSHOT,
- MP_CMD_PANSCAN,
- MP_CMD_MUTE,
MP_CMD_LOADFILE,
MP_CMD_LOADLIST,
MP_CMD_PLAYLIST_CLEAR,
- MP_CMD_GAMMA,
- MP_CMD_SUB_VISIBILITY,
- MP_CMD_VOBSUB_LANG, // deprecated: combined with SUB_SELECT
- MP_CMD_GET_TIME_LENGTH,
- MP_CMD_GET_PERCENT_POS,
MP_CMD_SUB_STEP,
MP_CMD_TV_SET_CHANNEL,
MP_CMD_EDL_MARK,
- MP_CMD_SUB_ALIGNMENT,
MP_CMD_TV_LAST_CHANNEL,
- MP_CMD_OSD_SHOW_TEXT,
MP_CMD_TV_SET_FREQ,
MP_CMD_TV_SET_NORM,
- MP_CMD_TV_SET_BRIGHTNESS,
- MP_CMD_TV_SET_CONTRAST,
- MP_CMD_TV_SET_HUE,
- MP_CMD_TV_SET_SATURATION,
- MP_CMD_GET_VO_FULLSCREEN,
- MP_CMD_GET_SUB_VISIBILITY,
- MP_CMD_SUB_FORCED_ONLY,
- MP_CMD_VO_ONTOP,
- MP_CMD_SUB_SELECT,
- MP_CMD_VO_ROOTWIN,
- MP_CMD_SWITCH_VSYNC,
- MP_CMD_SWITCH_RATIO,
MP_CMD_FRAME_STEP,
- MP_CMD_SPEED_INCR,
MP_CMD_SPEED_MULT,
- MP_CMD_SPEED_SET,
MP_CMD_RUN,
- MP_CMD_SWITCH_AUDIO,
- MP_CMD_GET_TIME_POS,
MP_CMD_SUB_LOAD,
MP_CMD_KEYDOWN_EVENTS,
- MP_CMD_VO_BORDER,
- MP_CMD_SET_PROPERTY,
- MP_CMD_SET_PROPERTY_OSD,
+ MP_CMD_SET,
MP_CMD_GET_PROPERTY,
- MP_CMD_OSD_SHOW_PROPERTY_TEXT,
- MP_CMD_OSD_SHOW_PROGRESSION,
- MP_CMD_SEEK_CHAPTER,
- MP_CMD_GET_FILENAME,
- MP_CMD_GET_VIDEO_CODEC,
- MP_CMD_GET_VIDEO_BITRATE,
- MP_CMD_GET_VIDEO_RESOLUTION,
- MP_CMD_GET_AUDIO_CODEC,
- MP_CMD_GET_AUDIO_BITRATE,
- MP_CMD_GET_AUDIO_SAMPLES,
- MP_CMD_GET_META_TITLE,
- MP_CMD_GET_META_ARTIST,
- MP_CMD_GET_META_ALBUM,
- MP_CMD_GET_META_YEAR,
- MP_CMD_GET_META_COMMENT,
- MP_CMD_GET_META_TRACK,
- MP_CMD_GET_META_GENRE,
+ MP_CMD_PRINT_TEXT,
+ MP_CMD_SHOW_TEXT,
+ MP_CMD_SHOW_PROGRESS,
MP_CMD_RADIO_STEP_CHANNEL,
MP_CMD_RADIO_SET_CHANNEL,
MP_CMD_RADIO_SET_FREQ,
MP_CMD_SET_MOUSE_POS,
- MP_CMD_STEP_PROPERTY,
- MP_CMD_STEP_PROPERTY_OSD,
+ MP_CMD_ADD,
+ MP_CMD_CYCLE,
MP_CMD_RADIO_STEP_FREQ,
MP_CMD_TV_STEP_FREQ,
- MP_CMD_LOOP,
- MP_CMD_BALANCE,
- MP_CMD_SUB_SCALE,
MP_CMD_TV_START_SCAN,
- MP_CMD_SWITCH_ANGLE,
- MP_CMD_ASS_USE_MARGINS,
- MP_CMD_SWITCH_TITLE,
MP_CMD_STOP,
/// DVB commands
@@ -139,11 +82,6 @@ enum mp_command_type {
MP_CMD_VO_CMDLINE,
};
-// The arg types
-#define MP_CMD_ARG_INT 1
-#define MP_CMD_ARG_FLOAT 2
-#define MP_CMD_ARG_STRING 3
-
#define MP_CMD_MAX_ARGS 10
// Error codes for the drivers
@@ -159,6 +97,13 @@ enum mp_command_type {
// Key FIFO was full - release events may be lost, zero button-down status
#define MP_INPUT_RELEASE_ALL -5
+enum mp_on_osd {
+ MP_ON_OSD_NO = 0, // prefer not using OSD
+ MP_ON_OSD_AUTO = 1, // use default behavior of the specific command
+ MP_ON_OSD_BAR = 2, // force a bar, if applicable
+ MP_ON_OSD_MSG = 4, // force a message, if applicable
+};
+
enum mp_input_section_flags {
// If a key binding is not defined in the current section, search the
// default section for it ("default" refers to bindings with no section
@@ -169,7 +114,7 @@ enum mp_input_section_flags {
struct input_ctx;
struct mp_cmd_arg {
- int type;
+ struct m_option type;
bool optional;
union {
int i;
@@ -184,6 +129,7 @@ typedef struct mp_cmd {
struct mp_cmd_arg args[MP_CMD_MAX_ARGS];
int nargs;
int pausing;
+ enum mp_on_osd on_osd;
struct mp_cmd *queue_next;
} mp_cmd_t;
@@ -235,7 +181,7 @@ struct mp_cmd *mp_input_get_cmd(struct input_ctx *ictx, int time,
int peek_only);
/* Parse text and return corresponding struct mp_cmd. */
-struct mp_cmd *mp_input_parse_cmd(char *str);
+struct mp_cmd *mp_input_parse_cmd(bstr str);
// After getting a command from mp_input_get_cmd you need to free it using this
// function
diff --git a/libvo/video_out.c b/libvo/video_out.c
index 41d2250c3b..db56828e1d 100644
--- a/libvo/video_out.c
+++ b/libvo/video_out.c
@@ -509,5 +509,5 @@ void vo_mouse_movement(struct vo *vo, int posx, int posy)
if (!enable_mouse_movements)
return;
snprintf(cmd_str, sizeof(cmd_str), "set_mouse_pos %i %i", posx, posy);
- mp_input_queue_cmd(vo->input_ctx, mp_input_parse_cmd(cmd_str));
+ mp_input_queue_cmd(vo->input_ctx, mp_input_parse_cmd(bstr0(cmd_str)));
}
diff --git a/m_config.c b/m_config.c
index c8cf250807..9ed09da751 100644
--- a/m_config.c
+++ b/m_config.c
@@ -365,8 +365,8 @@ int m_config_register_options(struct m_config *config,
return 1;
}
-static struct m_config_option *m_config_get_co(const struct m_config *config,
- struct bstr name)
+struct m_config_option *m_config_get_co(const struct m_config *config,
+ struct bstr name)
{
struct m_config_option *co;
diff --git a/m_config.h b/m_config.h
index 6bb1f4ff35..9098a23c97 100644
--- a/m_config.h
+++ b/m_config.h
@@ -152,6 +152,9 @@ int m_config_parse_suboptions(struct m_config *config, char *name,
const struct m_option *m_config_get_option(const struct m_config *config,
struct bstr name);
+struct m_config_option *m_config_get_co(const struct m_config *config,
+ struct bstr name);
+
/* Print a list of all registered options.
* \param config The config object.
*/
diff --git a/m_option.c b/m_option.c
index 1fef1fd86e..d48d4016b8 100644
--- a/m_option.c
+++ b/m_option.c
@@ -26,15 +26,18 @@
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
+#include <limits.h>
#include <inttypes.h>
#include <unistd.h>
#include <assert.h>
+#include <libavutil/common.h>
+#include <libavutil/avstring.h>
+
#include "talloc.h"
#include "m_option.h"
#include "mp_msg.h"
#include "stream/url.h"
-#include "libavutil/avstring.h"
char *m_option_strerror(int code)
{
@@ -87,6 +90,14 @@ static void copy_opt(const m_option_t *opt, void *dst, const void *src)
#define VAL(x) (*(int *)(x))
+static int clamp_flag(const m_option_t *opt, void *val)
+{
+ if (VAL(val) == opt->min || VAL(val) == opt->max)
+ return 0;
+ VAL(val) = opt->min;
+ return M_OPT_OUT_OF_RANGE;
+}
+
static int parse_flag(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -120,6 +131,15 @@ static char *print_flag(const m_option_t *opt, const void *val)
return talloc_strdup(NULL, "yes");
}
+static void add_flag(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ if (fabs(add) < 0.5)
+ return;
+ bool state = VAL(val) != opt->min;
+ state = wrap ? !state : add > 0;
+ VAL(val) = state ? opt->max : opt->min;
+}
+
const m_option_type_t m_option_type_flag = {
// need yes or no in config files
.name = "Flag",
@@ -128,10 +148,30 @@ const m_option_type_t m_option_type_flag = {
.parse = parse_flag,
.print = print_flag,
.copy = copy_opt,
+ .add = add_flag,
+ .clamp = clamp_flag,
};
// Integer
+#undef VAL
+
+static int clamp_longlong(const m_option_t *opt, void *val)
+{
+ long long v = *(long long *)val;
+ int r = 0;
+ if ((opt->flags & M_OPT_MAX) && (v > opt->max)) {
+ v = opt->max;
+ r = M_OPT_OUT_OF_RANGE;
+ }
+ if ((opt->flags & M_OPT_MIN) && (v < opt->min)) {
+ v = opt->min;
+ r = M_OPT_OUT_OF_RANGE;
+ }
+ *(long long *)val = v;
+ return r;
+}
+
static int parse_longlong(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -169,6 +209,22 @@ static int parse_longlong(const m_option_t *opt, struct bstr name,
return 1;
}
+static int clamp_int(const m_option_t *opt, void *val)
+{
+ long long tmp = *(int *)val;
+ int r = clamp_longlong(opt, &tmp);
+ *(int *)val = tmp;
+ return r;
+}
+
+static int clamp_int64(const m_option_t *opt, void *val)
+{
+ long long tmp = *(int64_t *)val;
+ int r = clamp_longlong(opt, &tmp);
+ *(int64_t *)val = tmp;
+ return r;
+}
+
static int parse_int(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -189,12 +245,39 @@ static int parse_int64(const m_option_t *opt, struct bstr name,
return r;
}
-
static char *print_int(const m_option_t *opt, const void *val)
{
if (opt->type->size == sizeof(int64_t))
return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val);
- return talloc_asprintf(NULL, "%d", VAL(val));
+ return talloc_asprintf(NULL, "%d", *(const int *)val);
+}
+
+static void add_int64(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ int64_t v = *(int64_t *)val;
+
+ v = v + add;
+
+ bool is64 = opt->type->size == sizeof(int64_t);
+ int64_t nmin = is64 ? INT64_MIN : INT_MIN;
+ int64_t nmax = is64 ? INT64_MAX : INT_MAX;
+
+ int64_t min = (opt->flags & M_OPT_MIN) ? opt->min : nmin;
+ int64_t max = (opt->flags & M_OPT_MAX) ? opt->max : nmax;
+
+ if (v < min)
+ v = wrap ? max : min;
+ if (v > max)
+ v = wrap ? min : max;
+
+ *(int64_t *)val = v;
+}
+
+static void add_int(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ int64_t tmp = *(int *)val;
+ add_int64(opt, &tmp, add, wrap);
+ *(int *)val = tmp;
}
const m_option_type_t m_option_type_int = {
@@ -203,6 +286,8 @@ const m_option_type_t m_option_type_int = {
.parse = parse_int,
.print = print_int,
.copy = copy_opt,
+ .add = add_int,
+ .clamp = clamp_int,
};
const m_option_type_t m_option_type_int64 = {
@@ -211,6 +296,8 @@ const m_option_type_t m_option_type_int64 = {
.parse = parse_int64,
.print = print_int,
.copy = copy_opt,
+ .add = add_int64,
+ .clamp = clamp_int64,
};
static int parse_intpair(const struct m_option *opt, struct bstr name,
@@ -256,6 +343,21 @@ const struct m_option_type m_option_type_intpair = {
.copy = copy_opt,
};
+static int clamp_choice(const m_option_t *opt, void *val)
+{
+ int v = *(int *)val;
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ if (v >= opt->min && v <= opt->max)
+ return 0;
+ }
+ ;
+ for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) {
+ if (alt->value == v)
+ return 0;
+ }
+ return M_OPT_INVALID;
+}
+
static int parse_choice(const struct m_option *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -303,12 +405,75 @@ static char *print_choice(const m_option_t *opt, const void *val)
abort();
}
+static void choice_get_min_max(const struct m_option *opt, int *min, int *max)
+{
+ assert(opt->type == &m_option_type_choice);
+ *min = INT_MAX;
+ *max = INT_MIN;
+ for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) {
+ *min = FFMIN(*min, alt->value);
+ *max = FFMAX(*max, alt->value);
+ }
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ *min = FFMIN(*min, opt->min);
+ *max = FFMAX(*max, opt->max);
+ }
+}
+
+static void check_choice(int dir, int val, bool *found, int *best, int choice)
+{
+ if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) ||
+ (dir == +1 && (!(*found) || choice < (*best)) && choice > val))
+ {
+ *found = true;
+ *best = choice;
+ }
+}
+
+static void add_choice(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ assert(opt->type == &m_option_type_choice);
+ int dir = add > 0 ? +1 : -1;
+ bool found = false;
+ int ival = *(int *)val;
+ int best = 0; // init. value unused
+
+ if (fabs(add) < 0.5)
+ return;
+
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ int newval = ival + add;
+ if (ival >= opt->min && ival <= opt->max &&
+ newval >= opt->min && newval <= opt->max)
+ {
+ found = true;
+ best = newval;
+ } else {
+ check_choice(dir, ival, &found, &best, opt->min);
+ check_choice(dir, ival, &found, &best, opt->max);
+ }
+ }
+
+ for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++)
+ check_choice(dir, ival, &found, &best, alt->value);
+
+ if (!found) {
+ int min, max;
+ choice_get_min_max(opt, &min, &max);
+ best = (dir == -1) ^ wrap ? min : max;
+ }
+
+ *(int *)val = best;
+}
+
const struct m_option_type m_option_type_choice = {
.name = "String", // same as arbitrary strings in option list for now
.size = sizeof(int),
.parse = parse_choice,
.print = print_choice,
.copy = copy_opt,
+ .add = add_choice,
+ .clamp = clamp_choice,
};
// Float
@@ -316,6 +481,22 @@ const struct m_option_type m_option_type_choice = {
#undef VAL
#define VAL(x) (*(double *)(x))
+static int clamp_double(const m_option_t *opt, void *val)
+{
+ double v = VAL(val);
+ int r = 0;
+ if ((opt->flags & M_OPT_MAX) && (v > opt->max)) {
+ v = opt->max;
+ r = M_OPT_OUT_OF_RANGE;
+ }
+ if ((opt->flags & M_OPT_MIN) && (v < opt->min)) {
+ v = opt->min;
+ r = M_OPT_OUT_OF_RANGE;
+ }
+ VAL(val) = v;
+ return r;
+}
+
static int parse_double(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -374,22 +555,53 @@ 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);
+
+ v = v + add;
+
+ double min = (opt->flags & M_OPT_MIN) ? opt->min : -INFINITY;
+ double max = (opt->flags & M_OPT_MAX) ? opt->max : +INFINITY;
+
+ if (v < min)
+ v = wrap ? max : min;
+ if (v > max)
+ v = wrap ? min : max;
+
+ VAL(val) = v;
+}
+
const m_option_type_t m_option_type_double = {
// double precision float or ratio (numerator[:/]denominator)
.name = "Double",
.size = sizeof(double),
.parse = parse_double,
.print = print_double,
+ .pretty_print = print_double_f2,
.copy = copy_opt,
+ .clamp = clamp_double,
};
#undef VAL
#define VAL(x) (*(float *)(x))
+static int clamp_float(const m_option_t *opt, void *val)
+{
+ double tmp = VAL(val);
+ int r = clamp_double(opt, &tmp);
+ VAL(val) = tmp;
+ return r;
+}
+
static int parse_float(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -402,53 +614,49 @@ 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));
}
-const m_option_type_t m_option_type_float = {
- // floating point number or ratio (numerator[:/]denominator)
- .name = "Float",
- .size = sizeof(float),
- .parse = parse_float,
- .print = print_float,
- .copy = copy_opt,
-};
-
-///////////// Position
-#undef VAL
-#define VAL(x) (*(off_t *)(x))
-
-static int parse_position(const m_option_t *opt, struct bstr name,
- struct bstr param, void *dst)
+static char *print_float_f2(const m_option_t *opt, const void *val)
{
- long long tmp;
- int r = parse_longlong(opt, name, param, &tmp);
- if (r >= 0 && dst)
- *(off_t *)dst = tmp;
- return r;
+ return talloc_asprintf(NULL, "%.2f", VAL(val));
}
-static char *print_position(const m_option_t *opt, const void *val)
+static void add_float(const m_option_t *opt, void *val, double add, bool wrap)
{
- return talloc_asprintf(NULL, "%"PRId64, (int64_t)VAL(val));
+ double tmp = VAL(val);
+ add_double(opt, &tmp, add, wrap);
+ VAL(val) = tmp;
}
-const m_option_type_t m_option_type_position = {
- // Integer (off_t)
- .name = "Position",
- .size = sizeof(off_t),
- .parse = parse_position,
- .print = print_position,
+const m_option_type_t m_option_type_float = {
+ // floating point number or ratio (numerator[:/]denominator)
+ .name = "Float",
+ .size = sizeof(float),
+ .parse = parse_float,
+ .print = print_float,
+ .pretty_print = print_float_f2,
.copy = copy_opt,
+ .add = add_float,
+ .clamp = clamp_float,
};
-
///////////// String
#undef VAL
#define VAL(x) (*(char **)(x))
+static int clamp_str(const m_option_t *opt, void *val)
+{
+ char *v = VAL(val);
+ int len = v ? strlen(v) : 0;
+ if ((opt->flags & M_OPT_MIN) && (len < opt->min))
+ return M_OPT_OUT_OF_RANGE;
+ if ((opt->flags & M_OPT_MAX) && (len > opt->max))
+ return M_OPT_OUT_OF_RANGE;
+ return 0;
+}
+
static int parse_str(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -507,6 +715,7 @@ const m_option_type_t m_option_type_string = {
.print = print_str,
.copy = copy_str,
.free = free_str,
+ .clamp = clamp_str,
};
//////////// String list
@@ -1024,12 +1233,20 @@ 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,
+ .clamp = clamp_double,
};
diff --git a/m_option.h b/m_option.h
index 2bd9054ac2..94d832eb6d 100644
--- a/m_option.h
+++ b/m_option.h
@@ -43,7 +43,6 @@ extern const m_option_type_t m_option_type_float;
extern const m_option_type_t m_option_type_double;
extern const m_option_type_t m_option_type_string;
extern const m_option_type_t m_option_type_string_list;
-extern const m_option_type_t m_option_type_position;
extern const m_option_type_t m_option_type_time;
extern const m_option_type_t m_option_type_time_size;
extern const m_option_type_t m_option_type_choice;
@@ -167,7 +166,6 @@ struct m_sub_options {
#define CONF_TYPE_PRINT_FUNC (&m_option_type_print_func)
#define CONF_TYPE_SUBCONFIG (&m_option_type_subconfig)
#define CONF_TYPE_STRING_LIST (&m_option_type_string_list)
-#define CONF_TYPE_POSITION (&m_option_type_position)
#define CONF_TYPE_IMGFMT (&m_option_type_imgfmt)
#define CONF_TYPE_AFMT (&m_option_type_afmt)
#define CONF_TYPE_SPAN (&m_option_type_span)
@@ -230,6 +228,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.
@@ -243,6 +246,18 @@ struct m_option_type {
* set to NULL.
*/
void (*free)(void *dst);
+
+ // Add the value add to the value in val. For types that are not numeric,
+ // add gives merely the direction. The wrap parameter determines whether
+ // the value is clipped, or wraps around to the opposite max/min.
+ void (*add)(const m_option_t *opt, void *val, double add, bool wrap);
+
+ // Clamp the value in val to the option's valid value range.
+ // Return values:
+ // M_OPT_OUT_OF_RANGE: val was invalid, and modified (clamped) to be valid
+ // M_OPT_INVALID: val was invalid, and can't be made valid
+ // 0: val was already valid and is unchanged
+ int (*clamp)(const m_option_t *opt, void *val);
};
// Option description
@@ -408,12 +423,6 @@ char *m_option_strerror(int code);
*/
const m_option_t *m_option_list_find(const m_option_t *list, const char *name);
-static inline void *m_option_get_ptr(const struct m_option *opt,
- void *optstruct)
-{
- return opt->new ? (char *) optstruct + opt->offset : opt->p;
-}
-
// Helper to parse options, see \ref m_option_type::parse.
static inline int m_option_parse(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
@@ -430,6 +439,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)
@@ -483,12 +501,13 @@ static inline void m_option_free(const m_option_t *opt, void *dst)
#define OPT_SETTINGSLIST(optname, varname, flags, objlist) OPT_GENERAL(optname, varname, flags, .type = &m_option_type_obj_settings_list, .priv = objlist)
#define OPT_AUDIOFORMAT(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_afmt)
#define OPT_HELPER_REMOVEPAREN(...) __VA_ARGS__
+#define M_CHOICES(choices) .priv = (void *)&(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}
#define OPT_CHOICE(...) OPT_CHOICE_(__VA_ARGS__, .type = &m_option_type_choice)
-#define OPT_CHOICE_(optname, varname, flags, choices, ...) OPT_GENERAL(optname, varname, flags, .priv = (void *)&(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}, __VA_ARGS__)
+#define OPT_CHOICE_(optname, varname, flags, choices, ...) OPT_GENERAL(optname, varname, flags, M_CHOICES(choices), __VA_ARGS__)
// Union of choices and an int range. The choice values can be included in the
// int range, or be completely separate - both works.
#define OPT_CHOICE_OR_INT(...) OPT_CHOICE_OR_INT_(__VA_ARGS__, .type = &m_option_type_choice)
-#define OPT_CHOICE_OR_INT_(optname, varname, flags, minval, maxval, choices, ...) OPT_GENERAL(optname, varname, (flags) | CONF_RANGE, .min = minval, .max = maxval, .priv = (void *)&(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}, __VA_ARGS__)
+#define OPT_CHOICE_OR_INT_(optname, varname, flags, minval, maxval, choices, ...) OPT_GENERAL(optname, varname, (flags) | CONF_RANGE, .min = minval, .max = maxval, M_CHOICES(choices), __VA_ARGS__)
#define OPT_TIME(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_time)
#define OPT_TRACKCHOICE(name, var) OPT_CHOICE_OR_INT(name, var, 0, 0, 8190, ({"no", -2}, {"auto", -1}))
diff --git a/m_property.c b/m_property.c
index ac68d86163..c8cf4e3dcf 100644
--- a/m_property.c
+++ b/m_property.c
@@ -25,7 +25,9 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <unistd.h>
+#include <assert.h>
+
+#include <libavutil/common.h>
#include "talloc.h"
#include "m_option.h"
@@ -33,173 +35,254 @@
#include "mp_msg.h"
#include "mpcommon.h"
+const struct m_option_type m_option_type_dummy = {
+ .name = "Unknown",
+};
+
+struct legacy_prop {
+ const char *old, *new;
+};
+static const struct legacy_prop legacy_props[] = {
+ {"switch_video", "video"},
+ {"switch_audio", "audio"},
+ {"switch_program", "program"},
+ {"framedropping", "framedrop"},
+ {"osdlevel", "osd-level"},
+ {0}
+};
+
+static bool translate_legacy_property(const char *name, char *buffer,
+ size_t buffer_size)
+{
+ if (strlen(name) + 1 > buffer_size)
+ return false;
+
+ const char *old_name = name;
+
+ for (int n = 0; legacy_props[n].new; n++) {
+ if (strcmp(name, legacy_props[n].old) == 0) {
+ name = legacy_props[n].new;
+ break;
+ }
+ }
+
+ snprintf(buffer, buffer_size, "%s", name);
+
+ // Old names used "_" instead of "-"
+ for (int n = 0; buffer[n]; n++) {
+ if (buffer[n] == '_')
+ buffer[n] = '-';
+ }
+
+ if (strcmp(old_name, buffer) != 0) {
+ mp_msg(MSGT_CPLAYER, MSGL_V, "Warning: property '%s' is deprecated, "
+ "replaced with '%s'. Fix your input.conf!\n", old_name, buffer);
+ }
+
+ return true;
+}
+
static int do_action(const m_option_t *prop_list, const char *name,
int action, void *arg, void *ctx)
{
const char *sep;
const m_option_t *prop;
- m_property_action_t ka;
- int r;
if ((sep = strchr(name, '/')) && sep[1]) {
int len = sep - name;
char base[len + 1];
memcpy(base, name, len);
base[len] = 0;
prop = m_option_list_find(prop_list, base);
- ka.key = sep + 1;
- ka.action = action;
- ka.arg = arg;
+ struct m_property_action_arg ka = {
+ .key = sep + 1,
+ .action = action,
+ .arg = arg,
+ };
action = M_PROPERTY_KEY_ACTION;
arg = &ka;
} else
prop = m_option_list_find(prop_list, name);
if (!prop)
return M_PROPERTY_UNKNOWN;
- r = ((m_property_ctrl_f)prop->p)(prop, action, arg, ctx);
- if (action == M_PROPERTY_GET_TYPE && r < 0) {
- if (!arg)
- return M_PROPERTY_ERROR;
- *(const m_option_t **)arg = prop;
+ int (*control)(const m_option_t*, int, void*, void*) = prop->p;
+ int r = control(prop, action, arg, ctx);
+ if (action == M_PROPERTY_GET_TYPE && r < 0 &&
+ prop->type != &m_option_type_dummy)
+ {
+ *(struct m_option *)arg = *prop;
return M_PROPERTY_OK;
}
return r;
}
-int m_property_do(const m_option_t *prop_list, const char *name,
+int m_property_do(const m_option_t *prop_list, const char *in_name,
int action, void *arg, void *ctx)
{
- const m_option_t *opt;
union m_option_value val = {0};
int r;
+ char name[64];
+ if (!translate_legacy_property(in_name, name, sizeof(name)))
+ return M_PROPERTY_UNKNOWN;
+
+ struct m_option opt = {0};
+ r = do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx);
+ if (r <= 0)
+ return r;
+ assert(opt.type);
+
switch (action) {
- case M_PROPERTY_PRINT:
+ 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
- case M_PROPERTY_TO_STRING:
- if ((r = do_action(prop_list, name, M_PROPERTY_TO_STRING, arg, ctx)) !=
- M_PROPERTY_NOT_IMPLEMENTED)
- return r;
- // fallback on the options API. Get the type, value and print.
- if ((r =
- do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
+ // Fallback to m_option
+ if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
return r;
+ char *str = m_option_pretty_print(&opt, &val);
+ m_option_free(&opt, &val);
+ *(char **)arg = str;
+ return str != NULL;
+ }
+ case M_PROPERTY_GET_STRING: {
if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
return r;
- if (!arg)
- return M_PROPERTY_ERROR;
- char *str = m_option_print(opt, &val);
+ char *str = m_option_print(&opt, &val);
+ m_option_free(&opt, &val);
*(char **)arg = str;
return str != NULL;
- case M_PROPERTY_PARSE:
- // try the property own parsing func
- if ((r = do_action(prop_list, name, M_PROPERTY_PARSE, arg, ctx)) !=
+ }
+ case M_PROPERTY_SET_STRING: {
+ // (reject 0 return value: success, but empty string with flag)
+ if (m_option_parse(&opt, bstr0(name), bstr0(arg), &val) <= 0)
+ return M_PROPERTY_ERROR;
+ r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx);
+ m_option_free(&opt, &val);
+ return r;
+ }
+ case M_PROPERTY_SWITCH: {
+ struct m_property_switch_arg *sarg = arg;
+ if ((r = do_action(prop_list, name, M_PROPERTY_SWITCH, arg, ctx)) !=
M_PROPERTY_NOT_IMPLEMENTED)
return r;
- // fallback on the options API, get the type and parse.
- if ((r =
- do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
- return r;
- if (!arg)
- return M_PROPERTY_ERROR;
- if ((r = m_option_parse(opt, bstr0(opt->name), bstr0(arg), &val)) <= 0)
+ // Fallback to m_option
+ if (!opt.type->add)
+ return M_PROPERTY_NOT_IMPLEMENTED;
+ if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
return r;
+ opt.type->add(&opt, &val, sarg->inc, sarg->wrap);
r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx);
- m_option_free(opt, &val);
+ m_option_free(&opt, &val);
return r;
}
- return do_action(prop_list, name, action, arg, ctx);
+ case M_PROPERTY_SET: {
+ if (!opt.type->clamp) {
+ mp_msg(MSGT_CPLAYER, MSGL_WARN, "Property '%s' without clamp().\n",
+ name);
+ } else {
+ m_option_copy(&opt, &val, arg);
+ r = opt.type->clamp(&opt, arg);
+ m_option_free(&opt, &val);
+ if (r != 0) {
+ mp_msg(MSGT_CPLAYER, MSGL_ERR,
+ "Property '%s': invalid value.\n", name);
+ return M_PROPERTY_ERROR;
+ }
+ }
+ return do_action(prop_list, name, M_PROPERTY_SET, arg, ctx);
+ }
+ default:
+ return do_action(prop_list, name, action, arg, ctx);
+ }
}
-char *m_properties_expand_string(const m_option_t *prop_list, char *str,
+static int m_property_do_bstr(const m_option_t *prop_list, bstr name,
+ int action, void *arg, void *ctx)
+{
+ char name0[64];
+ if (name.len >= sizeof(name0))
+ return M_PROPERTY_UNKNOWN;
+ snprintf(name0, sizeof(name0), "%.*s", BSTR_P(name));
+ return m_property_do(prop_list, name0, action, arg, ctx);
+}
+
+static void append_str(char **s, int *len, bstr append)
+{
+ MP_TARRAY_GROW(NULL, *s, *len + append.len);
+ memcpy(*s + *len, append.start, append.len);
+ *len = *len + append.len;
+}
+
+char *m_properties_expand_string(const m_option_t *prop_list, char *str0,
void *ctx)
{
- int l, fr = 0, pos = 0, size = strlen(str) + 512;
- char *p = NULL, *e, *ret = malloc(size), num_val;
- int skip = 0, lvl = 0, skip_lvl = 0;
-
- while (str[0]) {
- if (str[0] == '\\') {
- int sl = 1;
- switch (str[1]) {
- case 'e':
- p = "\x1b", l = 1; break;
- case 'n':
- p = "\n", l = 1; break;
- case 'r':
- p = "\r", l = 1; break;
- case 't':
- p = "\t", l = 1; break;
- case 'x':
- if (str[2]) {
- char num[3] = { str[2], str[3], 0 };
- char *end = num;
- num_val = strtol(num, &end, 16);
- sl = end - num + 1;
- l = 1;
- p = &num_val;
- } else
- l = 0;
- break;
- default:
- p = str + 1, l = 1;
- }
- str += 1 + sl;
- } else if (lvl > 0 && str[0] == ')') {
- if (skip && lvl <= skip_lvl)
- skip = 0;
- lvl--, str++, l = 0;
- } else if (str[0] == '$' && str[1] == '{'
- && (e = strchr(str + 2, '}'))) {
- str += 2;
- int method = M_PROPERTY_PRINT;
- if (str[0] == '=') {
- str += 1;
- method = M_PROPERTY_TO_STRING;
- }
- int pl = e - str;
- char pname[pl + 1];
- memcpy(pname, str, pl);
- pname[pl] = 0;
- if (m_property_do(prop_list, pname, method, &p, ctx) >= 0 && p)
- l = strlen(p), fr = 1;
- else
- l = 0;
- str = e + 1;
- } else if (str[0] == '?' && str[1] == '('
- && (e = strchr(str + 2, ':'))) {
- lvl++;
+ char *ret = NULL;
+ int ret_len = 0;
+ bool skip = false;
+ int level = 0, skip_level = 0;
+ bstr str = bstr0(str0);
+
+ while (str.len) {
+ if (level > 0 && bstr_eatstart0(&str, "}")) {
+ if (skip && level <= skip_level)
+ skip = false;
+ level--;
+ } else if (bstr_startswith0(str, "${") && bstr_find0(str, "}") >= 0) {
+ str = bstr_cut(str, 2);
+ level++;
+
+ // Assume ":" and "}" can't be part of the property name
+ // => if ":" comes before "}", it must be for the fallback
+ int term_pos = bstrcspn(str, ":}");
+ bstr name = bstr_splice(str, 0, term_pos < 0 ? str.len : term_pos);
+ str = bstr_cut(str, term_pos);
+ bool have_fallback = bstr_eatstart0(&str, ":");
+
if (!skip) {
- int is_not = str[2] == '!';
- int pl = e - str - (is_not ? 3 : 2);
- char pname[pl + 1];
- memcpy(pname, str + (is_not ? 3 : 2), pl);
- pname[pl] = 0;
- if (m_property_do(prop_list, pname, M_PROPERTY_GET, NULL, ctx) < 0) {
- if (!is_not)
- skip = 1, skip_lvl = lvl;
- } else if (is_not)
- skip = 1, skip_lvl = lvl;
+ bool cond_yes = bstr_eatstart0(&name, "?");
+ bool cond_no = !cond_yes && bstr_eatstart0(&name, "!");
+ bool raw = bstr_eatstart0(&name, "=");
+ int method = (raw || cond_yes || cond_no)
+ ? M_PROPERTY_GET_STRING : M_PROPERTY_PRINT;
+
+ char *s = NULL;
+ int r = m_property_do_bstr(prop_list, name, method, &s, ctx);
+ if (cond_yes || cond_no) {
+ skip = (!!s != cond_yes);
+ } else {
+ skip = !!s;
+ char *append = s;
+ if (!s && !have_fallback && !raw) {
+ append = r == M_PROPERTY_UNAVAILABLE
+ ? "(unavailable)" : "(error)";
+ }
+ append_str(&ret, &ret_len, bstr0(append));
+ }
+ talloc_free(s);
+ if (skip)
+ skip_level = level;
}
- str = e + 1, l = 0;
- } else
- p = str, l = 1, str++;
+ } else if (level == 0 && bstr_eatstart0(&str, "$>")) {
+ append_str(&ret, &ret_len, str);
+ break;
+ } else {
+ char c;
- if (skip || l <= 0)
- continue;
+ // Other combinations, e.g. "$x", are added verbatim
+ if (bstr_eatstart0(&str, "$$")) {
+ c = '$';
+ } else if (bstr_eatstart0(&str, "$}")) {
+ c = '}';
+ } else {
+ c = str.start[0];
+ str = bstr_cut(str, 1);
+ }
- if (pos + l + 1 > size) {
- size = pos + l + 512;
- ret = realloc(ret, size);
+ if (!skip)
+ MP_TARRAY_APPEND(NULL, ret, ret_len, c);
}
- memcpy(ret + pos, p, l);
- pos += l;
- if (fr)
- talloc_free(p), fr = 0;
}
- ret[pos] = 0;
+ MP_TARRAY_APPEND(NULL, ret, ret_len, '\0');
return ret;
}
@@ -231,193 +314,32 @@ void m_properties_print_help_list(const m_option_t *list)
mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d properties\n", count);
}
-// Some generic property implementations
-
int m_property_int_ro(const m_option_t *prop, int action,
void *arg, int var)
{
- switch (action) {
- case M_PROPERTY_GET:
- if (!arg)
- return 0;
+ if (action == M_PROPERTY_GET) {
*(int *)arg = var;
- return 1;
+ return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
-int m_property_int_range(const m_option_t *prop, int action,
- void *arg, int *var)
-{
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return 0;
- M_PROPERTY_CLAMP(prop, *(int *)arg);
- *var = *(int *)arg;
- return 1;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- *var += (arg ? *(int *)arg : 1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
- M_PROPERTY_CLAMP(prop, *var);
- return 1;
- }
- return m_property_int_ro(prop, action, arg, *var);
-}
-
-int m_property_choice(const m_option_t *prop, int action,
- void *arg, int *var)
-{
- switch (action) {
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max;
- *var %= (int)prop->max + 1;
- return 1;
- }
- return m_property_int_range(prop, action, arg, var);
-}
-
-int m_property_flag_ro(const m_option_t *prop, int action,
- void *arg, int var)
-{
- switch (action) {
- case M_PROPERTY_PRINT:
- if (!arg)
- return 0;
- *(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_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- *var = *var == prop->min ? prop->max : prop->min;
- return 1;
- case M_PROPERTY_PRINT:
- return m_property_flag_ro(prop, action, arg, *var);
- }
- return m_property_int_range(prop, action, arg, var);
-}
-
int m_property_float_ro(const m_option_t *prop, int action,
void *arg, float var)
{
- switch (action) {
- case M_PROPERTY_GET:
- if (!arg)
- return 0;
+ if (action == M_PROPERTY_GET) {
*(float *)arg = var;
- return 1;
- case M_PROPERTY_PRINT:
- if (!arg)
- return 0;
- *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
- return 1;
+ return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
-int m_property_float_range(const m_option_t *prop, int action,
- void *arg, float *var)
-{
- switch (action) {
- case M_PROPERTY_SET:
- if (!arg)
- return 0;
- M_PROPERTY_CLAMP(prop, *(float *)arg);
- *var = *(float *)arg;
- return 1;
- case M_PROPERTY_STEP_UP:
- case M_PROPERTY_STEP_DOWN:
- *var += (arg ? *(float *)arg : 0.1) *
- (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
- M_PROPERTY_CLAMP(prop, *var);
- return 1;
- }
- 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:
- if (!arg)
- return 0;
- *(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)
{
- switch (action) {
- case M_PROPERTY_GET:
- if (!arg)
- return 0;
+ if (action == M_PROPERTY_GET) {
*(double *)arg = var;
- return 1;
- case M_PROPERTY_PRINT:
- if (!arg)
- return 0;
- *(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:
- if (!arg)
- return M_PROPERTY_ERROR;
- else {
- *(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)
-{
- switch (action) {
- case M_PROPERTY_GET:
- if (!arg)
- return 0;
- *(char **)arg = str;
- return 1;
- case M_PROPERTY_PRINT:
- if (!arg)
- return 0;
- *(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:
- if (!arg)
- return M_PROPERTY_ERROR;
- *(char **)arg = talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000);
return M_PROPERTY_OK;
}
- return m_property_int_ro(prop, action, arg, rate);
+ return M_PROPERTY_NOT_IMPLEMENTED;
}
diff --git a/m_property.h b/m_property.h
index 0a94b26335..462068987c 100644
--- a/m_property.h
+++ b/m_property.h
@@ -19,209 +19,119 @@
#ifndef MPLAYER_M_PROPERTY_H
#define MPLAYER_M_PROPERTY_H
-#include "m_option.h"
-
-/// \defgroup Properties
-///
-/// Properties provide an interface to query and set the state of various
-/// things in MPlayer. The API is based on the \ref Options API like the
-/// \ref Config, but instead of using variables, properties use an ioctl like
-/// function. The function is used to perform various actions like get and set
-/// (see \ref PropertyActions).
-///@{
-
-/// \file
-
-/// \defgroup PropertyActions Property actions
-/// \ingroup Properties
-///@{
-
-/// Get the current value.
-/** \param arg Pointer to a variable of the right type.
- */
-#define M_PROPERTY_GET 0
-
-/// Get a string representing the current value.
-/** Set the variable to a newly allocated string or NULL.
- * \param arg Pointer to a char* variable.
- */
-#define M_PROPERTY_PRINT 1
-
-/// Set a new value.
-/** The variable is updated to the value actually set.
- * \param arg Pointer to a variable of the right type.
- */
-#define M_PROPERTY_SET 2
-
-/// Set a new value from a string.
-/** \param arg String containing the value.
- */
-#define M_PROPERTY_PARSE 3
-
-/// Increment the current value.
-/** The sign of the argument is also taken into account if applicable.
- * \param arg Pointer to a variable of the right type or NULL.
- */
-#define M_PROPERTY_STEP_UP 4
-
-/// Decrement the current value.
-/** The sign of the argument is also taken into account if applicable.
- * \param arg Pointer to a variable of the right type or NULL.
- */
-#define M_PROPERTY_STEP_DOWN 5
-
-/// Get a string containg a parsable representation.
-/** Set the variable to a newly allocated string or NULL.
- * \param arg Pointer to a char* variable.
- */
-#define M_PROPERTY_TO_STRING 6
-
-/// Pass down an action to a sub-property.
-#define M_PROPERTY_KEY_ACTION 7
-
-/// Get a m_option describing the property.
-#define M_PROPERTY_GET_TYPE 8
-
-///@}
-
-/// \defgroup PropertyActionsArg Property actions argument type
-/// \ingroup Properties
-/// \brief Types used as action argument.
-///@{
-
-/// Argument for \ref M_PROPERTY_KEY_ACTION
-typedef struct {
+#include <stdbool.h>
+
+struct m_option;
+
+extern const struct m_option_type m_option_type_dummy;
+
+enum mp_property_action {
+ // Get the property type. This defines the fundamental data type read from
+ // or written to the property.
+ // If unimplemented, the m_option entry that defines the property is used.
+ // arg: m_option*
+ M_PROPERTY_GET_TYPE,
+
+ // Get the current value.
+ // arg: pointer to a variable of the type according to the property type
+ M_PROPERTY_GET,
+
+ // Set a new value. The property wrapper will make sure that only valid
+ // values are set (e.g. according to the property type's min/max range).
+ // If unimplemented, the property is read-only.
+ // arg: pointer to a variable of the type according to the property type
+ M_PROPERTY_SET,
+
+ // Get human readable string representing the current value.
+ // If unimplemented, the property wrapper uses the property type as
+ // fallback.
+ // arg: char**
+ M_PROPERTY_PRINT,
+
+ // Switch the property up/down by a given value.
+ // If unimplemented, the property wrapper uses the property type as
+ // fallback.
+ // arg: struct m_property_switch_arg*
+ M_PROPERTY_SWITCH,
+
+ // Get a string containing a parsable representation.
+ // Can't be overridden by property implementations.
+ // arg: char**
+ M_PROPERTY_GET_STRING,
+
+ // Set a new value from a string. The property wrapper parses this using the
+ // parse function provided by the property type.
+ // Can't be overridden by property implementations.
+ // arg: char*
+ M_PROPERTY_SET_STRING,
+
+ // Pass down an action to a sub-property.
+ // arg: struct m_property_action_arg*
+ M_PROPERTY_KEY_ACTION,
+};
+
+// Argument for M_PROPERTY_SWITCH
+struct m_property_switch_arg {
+ double inc; // value to add to property, or cycle direction
+ bool wrap; // whether value should wrap around on over/underflow
+};
+
+// Argument for M_PROPERTY_KEY_ACTION
+struct m_property_action_arg {
const char* key;
int action;
void* arg;
-} m_property_action_t;
-
-///@}
-
-/// \defgroup PropertyActionsReturn Property actions return code
-/// \ingroup Properties
-/// \brief Return values for the control function.
-///@{
-
-/// Returned on success.
-#define M_PROPERTY_OK 1
+};
-/// Returned on error.
-#define M_PROPERTY_ERROR 0
+enum mp_property_return {
+ // Returned on success.
+ M_PROPERTY_OK = 1,
-/// \brief Returned when the property can't be used, for example something about
-/// the subs while playing audio only
-#define M_PROPERTY_UNAVAILABLE -1
+ // Returned on error.
+ M_PROPERTY_ERROR = 0,
-/// Returned if the requested action is not implemented.
-#define M_PROPERTY_NOT_IMPLEMENTED -2
+ // Returned when the property can't be used, for example video related
+ // properties while playing audio only.
+ M_PROPERTY_UNAVAILABLE = -1,
-/// Returned when asking for a property that doesn't exist.
-#define M_PROPERTY_UNKNOWN -3
+ // Returned if the requested action is not implemented.
+ M_PROPERTY_NOT_IMPLEMENTED = -2,
-/// Returned when the action can't be done (like setting the volume when edl mute).
-#define M_PROPERTY_DISABLED -4
+ // Returned when asking for a property that doesn't exist.
+ M_PROPERTY_UNKNOWN = -3,
+};
-///@}
-
-/// \ingroup Properties
-/// \brief Property action callback.
-typedef int(*m_property_ctrl_f)(const m_option_t* prop,int action,void* arg,void *ctx);
-
-/// Do an action on a property.
-/** \param prop_list The list of properties.
- * \param prop The path of the property.
- * \param action See \ref PropertyActions.
- * \param arg Argument, usually a pointer to the data type used by the property.
- * \return See \ref PropertyActionsReturn.
- */
-int m_property_do(const m_option_t* prop_list, const char* prop,
+// Access a property.
+// action: one of m_property_action
+// ctx: opaque value passed through to property implementation
+// returns: one of mp_property_return
+int m_property_do(const struct m_option* prop_list, const char* property_name,
int action, void* arg, void *ctx);
-/// Print a list of properties.
-void m_properties_print_help_list(const m_option_t* list);
-
-/// Expand a property string.
-/** This function allows to print strings containing property values.
- * ${NAME} is expanded to the value of property NAME or an empty
- * string in case of error. $(NAME:STR) expand STR only if the property
- * NAME is available.
- *
- * \param prop_list An array of \ref m_option describing the available
- * properties.
- * \param str The string to expand.
- * \return The newly allocated expanded string.
- */
-char* m_properties_expand_string(const m_option_t* prop_list,char* str, void *ctx);
-
-// Helpers to use MPlayer's properties
-
-/// Do an action with an MPlayer property.
-int mp_property_do(const char* name,int action, void* val, void *ctx);
-
-/// Get the value of a property as a string suitable for display in an UI.
-char* mp_property_print(const char *name, void* ctx);
-
-/// \defgroup PropertyImplHelper Property implementation helpers
-/// \ingroup Properties
-/// \brief Helper functions for common property types.
-///@{
-
-/// Clamp a value according to \ref m_option::min and \ref m_option::max.
-#define M_PROPERTY_CLAMP(prop,val) do { \
- if(((prop)->flags & M_OPT_MIN) && (val) < (prop)->min) \
- (val) = (prop)->min; \
- else if(((prop)->flags & M_OPT_MAX) && (val) > (prop)->max) \
- (val) = (prop)->max; \
- } while(0)
-
-/// Implement get.
-int m_property_int_ro(const m_option_t* prop,int action,
- void* arg,int var);
-
-/// Implement set, get and step up/down.
-int m_property_int_range(const m_option_t* prop,int action,
- void* arg,int* var);
-
-/// Same as m_property_int_range but cycle.
-int m_property_choice(const m_option_t* prop,int action,
- void* arg,int* var);
-
-int m_property_flag_ro(const m_option_t* prop,int action,
- void* arg,int var);
-
-/// Switch betwen min and max.
-int m_property_flag(const m_option_t* prop,int action,
- void* arg,int* var);
-
-/// Implement get, print.
-int m_property_float_ro(const m_option_t* prop,int action,
- void* arg,float var);
-
-/// Implement set, get and step up/down
-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);
-
-///@}
-
-///@}
+// Print a list of properties.
+void m_properties_print_help_list(const struct m_option* list);
+
+// Expand a property string.
+// This function allows to print strings containing property values.
+// ${NAME} is expanded to the value of property NAME.
+// If NAME starts with '=', use the raw value of the property.
+// ${NAME:STR} expands to the property, or STR if the property is not
+// available.
+// ${?NAME:STR} expands to STR if the property is available.
+// ${!NAME:STR} expands to STR if the property is not available.
+// General syntax: "${" ["?" | "!"] ["="] NAME ":" STR "}"
+// STR is recursively expanded using the same rules.
+// "$$" can be used to escape "$", and "$}" to escape "}".
+// "$>" disables parsing of "$" for the rest of the string.
+char* m_properties_expand_string(const struct m_option* prop_list, char *str,
+ void *ctx);
+
+// Trivial helpers for implementing properties.
+int m_property_int_ro(const struct m_option* prop, int action, void* arg,
+ int var);
+int m_property_float_ro(const struct m_option* prop, int action, void* arg,
+ float var);
+int m_property_double_ro(const struct m_option* prop, int action, void* arg,
+ double var);
#endif /* MPLAYER_M_PROPERTY_H */
diff --git a/metadata.h b/metadata.h
deleted file mode 100644
index 06c3822d81..0000000000
--- a/metadata.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * set of helper routines for stream metadata and properties retrieval
- *
- * Copyright (C) 2006 Benjamin Zores
- *
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPLAYER_METADATA_H
-#define MPLAYER_METADATA_H
-
-typedef enum metadata_s metadata_t;
-enum metadata_s {
- /* common info */
- META_NAME = 0,
-
- /* video stream properties */
- META_VIDEO_CODEC,
- META_VIDEO_BITRATE,
- META_VIDEO_RESOLUTION,
-
- /* audio stream properties */
- META_AUDIO_CODEC,
- META_AUDIO_BITRATE,
- META_AUDIO_SAMPLES,
-
- /* ID3 tags and other stream infos */
- META_INFO_TITLE,
- META_INFO_ARTIST,
- META_INFO_ALBUM,
- META_INFO_YEAR,
- META_INFO_COMMENT,
- META_INFO_TRACK,
- META_INFO_GENRE
-};
-
-struct MPContext;
-
-char *get_metadata(struct MPContext *mpctx, metadata_t type);
-
-#endif /* MPLAYER_METADATA_H */
diff --git a/mp_core.h b/mp_core.h
index c786663182..111372bcc2 100644
--- a/mp_core.h
+++ b/mp_core.h
@@ -77,6 +77,13 @@ struct chapter {
char *name;
};
+enum mp_osd_seek_info {
+ OSD_SEEK_INFO_BAR = 1,
+ OSD_SEEK_INFO_TEXT = 2,
+ OSD_SEEK_INFO_CHAPTER_TEXT = 4,
+ OSD_SEEK_INFO_EDITION = 8,
+};
+
struct track {
enum stream_type type;
// The type specific ID, also called aid (audio), sid (subs), vid (video).
@@ -127,7 +134,7 @@ typedef struct MPContext {
char *terminal_osd_text;
subtitle subs; // subtitle list used when reading subtitles from demuxer
- bool add_osd_seek_info;
+ int add_osd_seek_info; // bitfield of enum mp_osd_seek_info
unsigned int osd_visible;
int osd_function;
diff --git a/mp_osd.h b/mp_osd.h
index 0e9476a4f8..444b54736c 100644
--- a/mp_osd.h
+++ b/mp_osd.h
@@ -19,7 +19,6 @@
#ifndef MPLAYER_MP_OSD_H
#define MPLAYER_MP_OSD_H
-#define OSD_MSG_TV_CHANNEL 0
#define OSD_MSG_TEXT 1
#define OSD_MSG_SUB_DELAY 2
#define OSD_MSG_SPEED 3
@@ -27,12 +26,14 @@
#define OSD_MSG_BAR 5
#define OSD_MSG_PAUSE 6
#define OSD_MSG_RADIO_CHANNEL 7
+#define OSD_MSG_TV_CHANNEL 8
/// Base id for messages generated from the commmand to property bridge.
#define OSD_MSG_PROPERTY 0x100
#define OSD_MSG_SUB_BASE 0x1000
#define MAX_OSD_LEVEL 3
#define MAX_TERM_OSD_LEVEL 1
+#define OSD_LEVEL_INVISIBLE 4
struct MPContext;
@@ -40,6 +41,5 @@ void set_osd_bar(struct MPContext *mpctx, int type,const char* name,double min,d
void set_osd_msg(struct MPContext *mpctx, int id, int level, int time, const char* fmt, ...);
void set_osd_tmsg(struct MPContext *mpctx, int id, int level, int time, const char* fmt, ...);
void rm_osd_msg(struct MPContext *mpctx, int id);
-void mp_show_osd_progression(struct MPContext *mpctx);
#endif /* MPLAYER_MP_OSD_H */
diff --git a/mpcommon.h b/mpcommon.h
index 472a2e1943..674d9b1554 100644
--- a/mpcommon.h
+++ b/mpcommon.h
@@ -41,7 +41,7 @@
do { \
size_t nextidx_ = (nextidx); \
size_t nelems_ = MP_TALLOC_ELEMS(p); \
- if (nextidx_ <= nelems_) \
+ if (nextidx_ >= nelems_) \
p = talloc_realloc_size((ctx), p, \
(nextidx_ + 1) * sizeof((p)[0]) * 2);\
} while (0)
diff --git a/mplayer.c b/mplayer.c
index 460572b0ae..dcf9b62af0 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -204,8 +204,8 @@ static const char av_desync_help_text[] = _(
static int drop_frame_cnt; // total number of dropped frames
// seek:
-static off_t seek_to_byte;
-static off_t step_sec;
+static int64_t seek_to_byte;
+static double step_sec;
static m_time_size_t end_at = { .type = END_AT_NONE, .pos = 0 };
@@ -230,7 +230,6 @@ static int ignore_start = 0;
double force_fps = 0;
static int force_srate = 0;
-int frame_dropping = 0; // option 0=no drop 1= drop vo 2= drop decode
static int play_n_frames = -1;
static int play_n_frames_mf = -1;
@@ -247,8 +246,6 @@ int use_filedir_conf;
#include "mpcommon.h"
#include "command.h"
-#include "metadata.h"
-
static void reset_subtitles(struct MPContext *mpctx);
static void reinit_subs(struct MPContext *mpctx);
@@ -260,129 +257,6 @@ static float get_relative_time(struct MPContext *mpctx)
return delta * 0.000001;
}
-static int is_valid_metadata_type(struct MPContext *mpctx, metadata_t type)
-{
- switch (type) {
- /* check for valid video stream */
- case META_VIDEO_CODEC:
- case META_VIDEO_BITRATE:
- case META_VIDEO_RESOLUTION:
- if (!mpctx->sh_video)
- return 0;
- break;
-
- /* check for valid audio stream */
- case META_AUDIO_CODEC:
- case META_AUDIO_BITRATE:
- case META_AUDIO_SAMPLES:
- if (!mpctx->sh_audio)
- return 0;
- break;
-
- /* check for valid demuxer */
- case META_INFO_TITLE:
- case META_INFO_ARTIST:
- case META_INFO_ALBUM:
- case META_INFO_YEAR:
- case META_INFO_COMMENT:
- case META_INFO_TRACK:
- case META_INFO_GENRE:
- if (!mpctx->master_demuxer)
- return 0;
- break;
-
- default:
- break;
- }
-
- return 1;
-}
-
-static char *get_demuxer_info(struct MPContext *mpctx, char *tag)
-{
- char **info = mpctx->master_demuxer->info;
- int n;
-
- if (!info || !tag)
- return talloc_strdup(NULL, "");
-
- for (n = 0; info[2 * n] != NULL; n++)
- if (!strcasecmp(info[2 * n], tag))
- break;
-
- return talloc_strdup(NULL, info[2 * n + 1] ? info[2 * n + 1] : "");
-}
-
-char *get_metadata(struct MPContext *mpctx, metadata_t type)
-{
- sh_audio_t * const sh_audio = mpctx->sh_audio;
- sh_video_t * const sh_video = mpctx->sh_video;
-
- if (!is_valid_metadata_type(mpctx, type))
- return NULL;
-
- switch (type) {
- case META_NAME:
- return talloc_strdup(NULL, mp_basename(mpctx->filename));
- case META_VIDEO_CODEC:
- if (sh_video->format == 0x10000001)
- return talloc_strdup(NULL, "mpeg1");
- else if (sh_video->format == 0x10000002)
- return talloc_strdup(NULL, "mpeg2");
- else if (sh_video->format == 0x10000004)
- return talloc_strdup(NULL, "mpeg4");
- else if (sh_video->format == 0x10000005)
- return talloc_strdup(NULL, "h264");
- else if (sh_video->format >= 0x20202020)
- return talloc_asprintf(NULL, "%.4s", (char *) &sh_video->format);
- else
- return talloc_asprintf(NULL, "0x%08X", sh_video->format);
- case META_VIDEO_BITRATE:
- return talloc_asprintf(NULL, "%d kbps",
- (int) (sh_video->i_bps * 8 / 1024));
- case META_VIDEO_RESOLUTION:
- return talloc_asprintf(NULL, "%d x %d", sh_video->disp_w,
- sh_video->disp_h);
- case META_AUDIO_CODEC:
- if (sh_audio->codec && sh_audio->codec->name)
- return talloc_strdup(NULL, sh_audio->codec->name);
- return talloc_strdup(NULL, "");
- case META_AUDIO_BITRATE:
- return talloc_asprintf(NULL, "%d kbps",
- (int) (sh_audio->i_bps * 8 / 1000));
- case META_AUDIO_SAMPLES:
- return talloc_asprintf(NULL, "%d Hz, %d ch.", sh_audio->samplerate,
- sh_audio->channels);
-
- /* check for valid demuxer */
- case META_INFO_TITLE:
- return get_demuxer_info(mpctx, "Title");
-
- case META_INFO_ARTIST:
- return get_demuxer_info(mpctx, "Artist");
-
- case META_INFO_ALBUM:
- return get_demuxer_info(mpctx, "Album");
-
- case META_INFO_YEAR:
- return get_demuxer_info(mpctx, "Year");
-
- case META_INFO_COMMENT:
- return get_demuxer_info(mpctx, "Comment");
-
- case META_INFO_TRACK:
- return get_demuxer_info(mpctx, "Track");
-
- case META_INFO_GENRE:
- return get_demuxer_info(mpctx, "Genre");
-
- default:
- break;
- }
-
- return talloc_strdup(NULL, "");
-}
-
static void print_stream(struct MPContext *mpctx, struct track *t, int id)
{
struct sh_stream *s = t->stream;
@@ -1124,7 +998,7 @@ void init_vo_spudec(struct MPContext *mpctx)
if (vo_spudec != NULL) {
mpctx->initialized_flags |= INITIALIZED_SPUDEC;
- mp_property_do("sub_forced_only", M_PROPERTY_SET, &forced_subs_only,
+ mp_property_do("sub-forced-only", M_PROPERTY_SET, &forced_subs_only,
mpctx);
}
}
@@ -1164,6 +1038,30 @@ static void sadd_percentage(char *buf, int len, int percent) {
saddf(buf, len, " (%d%%)", percent);
}
+static int get_term_width(void)
+{
+ get_screen_size();
+ int width = screen_width > 0 ? screen_width : 80;
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+ /* Windows command line is broken (MinGW's rxvt works, but we
+ * should not depend on that). */
+ width--;
+#endif
+ return width;
+}
+
+static void write_status_line(struct MPContext *mpctx, const char *line)
+{
+ if (erase_to_end_of_line) {
+ mp_msg(MSGT_STATUSLINE, MSGL_STATUS,
+ "%s%s\r", line, erase_to_end_of_line);
+ } else {
+ int pos = strlen(line);
+ int width = get_term_width() - pos;
+ mp_msg(MSGT_STATUSLINE, MSGL_STATUS, "%s%*s\r", line, width, "");
+ }
+}
+
static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
{
struct MPOpts *opts = &mpctx->opts;
@@ -1187,19 +1085,16 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
if (opts->quiet)
return;
- int width;
- char *line;
- get_screen_size();
- if (screen_width > 0)
- width = screen_width;
- else
- width = 80;
-#if defined(__MINGW32__) || defined(__CYGWIN__)
- /* Windows command line is broken (MinGW's rxvt works, but we
- * should not depend on that). */
- width--;
-#endif
- line = malloc(width + 1); // one additional char for the terminating null
+ if (opts->status_msg) {
+ char *r = mp_property_expand_string(mpctx, opts->status_msg);
+ write_status_line(mpctx, r);
+ talloc_free(r);
+ return;
+ }
+
+ // one additional char for the terminating null
+ int width = get_term_width() + 1;
+ char *line = malloc(width);
line[0] = '\0';
// Playback status
@@ -1278,15 +1173,7 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
#endif
// end
- if (erase_to_end_of_line) {
- mp_msg(MSGT_STATUSLINE, MSGL_STATUS,
- "%s%s\r", line, erase_to_end_of_line);
- } else {
- int pos = strlen(line);
- memset(&line[pos], ' ', width - pos);
- line[width] = 0;
- mp_msg(MSGT_STATUSLINE, MSGL_STATUS, "%s\r", line);
- }
+ write_status_line(mpctx, line);
free(line);
}
@@ -1361,6 +1248,8 @@ static mp_osd_msg_t *add_osd_msg(struct MPContext *mpctx, int id, int level,
static void set_osd_msg_va(struct MPContext *mpctx, int id, int level, int time,
const char *fmt, va_list ap)
{
+ if (level == OSD_LEVEL_INVISIBLE)
+ return;
mp_osd_msg_t *msg = add_osd_msg(mpctx, id, level, time);
msg->msg = talloc_vasprintf(msg, fmt, ap);
}
@@ -1545,6 +1434,35 @@ static void sadd_osd_status(char *buffer, int len, struct MPContext *mpctx,
}
}
+// OSD messages initated by seeking commands are added lazily with this
+// function, because multiple successive seek commands can be coalesced.
+static void add_seek_osd_messages(struct MPContext *mpctx)
+{
+ if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_BAR)
+ set_osd_bar(mpctx, 0, "Position", 0, 100, get_percent_pos(mpctx));
+ if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_TEXT) {
+ mp_osd_msg_t *msg = add_osd_msg(mpctx, OSD_MSG_TEXT, 1,
+ mpctx->opts.osd_duration);
+ msg->show_position = true;
+ }
+ if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_CHAPTER_TEXT) {
+ char *chapter = chapter_display_name(mpctx, get_current_chapter(mpctx));
+ set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, mpctx->opts.osd_duration,
+ "Chapter: %s", chapter);
+ talloc_free(chapter);
+ }
+ assert(mpctx->master_demuxer);
+ if ((mpctx->add_osd_seek_info & OSD_SEEK_INFO_EDITION)
+ && mpctx->master_demuxer)
+ {
+ set_osd_tmsg(mpctx, OSD_MSG_TEXT, 1, mpctx->opts.osd_duration,
+ "Playing edition %d of %d.",
+ mpctx->master_demuxer->edition + 1,
+ mpctx->master_demuxer->num_editions);
+ }
+ mpctx->add_osd_seek_info = 0;
+}
+
/**
* \brief Update the OSD message line.
*
@@ -1559,10 +1477,7 @@ static void update_osd_msg(struct MPContext *mpctx)
struct MPOpts *opts = &mpctx->opts;
struct osd_state *osd = mpctx->osd;
- if (mpctx->add_osd_seek_info) {
- set_osd_bar(mpctx, 0, "Position", 0, 100, get_percent_pos(mpctx));
- mpctx->add_osd_seek_info = false;
- }
+ add_seek_osd_messages(mpctx);
// Look if we have a msg
mp_osd_msg_t *msg = get_osd_msg(mpctx);
@@ -1603,15 +1518,6 @@ static void update_osd_msg(struct MPContext *mpctx)
}
}
-void mp_show_osd_progression(struct MPContext *mpctx)
-{
- mp_osd_msg_t *msg = add_osd_msg(mpctx, OSD_MSG_TEXT, 1,
- mpctx->opts.osd_duration);
- msg->show_position = true;
-
- set_osd_bar(mpctx, 0, "Position", 0, 100, get_percent_pos(mpctx));
-}
-
void reinit_audio_chain(struct MPContext *mpctx)
{
struct MPOpts *opts = &mpctx->opts;
@@ -1916,7 +1822,7 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time)
&& !mpctx->restart_playback) {
++drop_frame_cnt;
++dropped_frames;
- return frame_dropping;
+ return mpctx->opts.frame_dropping;
} else
dropped_frames = 0;
}
@@ -2292,10 +2198,9 @@ static void vo_update_window_title(struct MPContext *mpctx)
{
if (!mpctx->video_out)
return;
- char *title = property_expand_string(mpctx, mpctx->opts.vo_wintitle);
+ char *title = mp_property_expand_string(mpctx, mpctx->opts.vo_wintitle);
talloc_free(mpctx->video_out->window_title);
- mpctx->video_out->window_title = talloc_strdup(mpctx->video_out, title);
- free(title);
+ mpctx->video_out->window_title = talloc_steal(mpctx, title);
}
int reinit_video_chain(struct MPContext *mpctx)
@@ -3605,7 +3510,7 @@ static void open_vobsubs_from_options(struct MPContext *mpctx)
mpctx->initialized_flags |= INITIALIZED_VOBSUB;
// TODO: let frontend do the selection
vobsub_set_from_lang(vo_vobsub, mpctx->opts.sub_lang);
- mp_property_do("sub_forced_only", M_PROPERTY_SET, &forced_subs_only,
+ mp_property_do("sub-forced-only", M_PROPERTY_SET, &forced_subs_only,
mpctx);
for (int i = 0; i < vobsub_get_indexes_count(vo_vobsub); i++) {
@@ -3798,6 +3703,8 @@ static void play_current_file(struct MPContext *mpctx)
encode_lavc_discontinuity(mpctx->encode_lavc_ctx);
#endif
+ mpctx->add_osd_seek_info &= OSD_SEEK_INFO_EDITION;
+
m_config_enter_file_local(mpctx->mconfig);
load_per_protocol_config(mpctx->mconfig, mpctx->filename);
@@ -3828,7 +3735,8 @@ static void play_current_file(struct MPContext *mpctx)
}
#ifdef CONFIG_ASS
- ass_set_style_overrides(mpctx->ass_library, opts->ass_force_style_list);
+ if (opts->ass_style_override)
+ ass_set_style_overrides(mpctx->ass_library, opts->ass_force_style_list);
#endif
if (mpctx->video_out && mpctx->video_out->config_ok)
vo_control(mpctx->video_out, VOCTRL_RESUME, NULL);
@@ -3996,9 +3904,9 @@ goto_enable_cache:
}
if (opts->playing_msg) {
- char *msg = property_expand_string(mpctx, opts->playing_msg);
+ char *msg = mp_property_expand_string(mpctx, opts->playing_msg);
mp_msg(MSGT_CPLAYER, MSGL_INFO, "%s", msg);
- free(msg);
+ talloc_free(msg);
}
// Disable the term OSD in verbose mode
diff --git a/mplayer.h b/mplayer.h
index d1618bf929..651ab7b9d1 100644
--- a/mplayer.h
+++ b/mplayer.h
@@ -31,10 +31,6 @@ extern float audio_delay;
extern double force_fps;
-extern int frame_dropping;
-
-extern int auto_quality;
-
extern int vobsub_id;
struct MPContext;
diff --git a/options.h b/options.h
index b8bf0b4963..090ea50535 100644
--- a/options.h
+++ b/options.h
@@ -41,7 +41,6 @@ typedef struct MPOpts {
int osd_duration;
int osd_fractions;
char *vobsub_name;
- int auto_quality;
int untimed;
int loop_times;
int ordered_chapters;
@@ -61,9 +60,11 @@ typedef struct MPOpts {
float hr_seek_demuxer_offset;
int autosync;
int softsleep;
+ int frame_dropping;
int term_osd;
char *term_osd_esc;
char *playing_msg;
+ char *status_msg;
int player_idle_mode;
int consolecontrols;
int doubleclick_time;
@@ -115,6 +116,7 @@ typedef struct MPOpts {
char *ass_color;
char *ass_border_color;
char *ass_styles_file;
+ int ass_style_override;
int ass_hinting;
struct lavc_param {
int workaround_bugs;
diff --git a/screenshot.c b/screenshot.c
index 79356ed9a2..1f2b0694fc 100644
--- a/screenshot.c
+++ b/screenshot.c
@@ -27,10 +27,9 @@
#include "talloc.h"
#include "screenshot.h"
#include "mp_core.h"
-#include "m_property.h"
+#include "command.h"
#include "bstr.h"
#include "mp_msg.h"
-#include "metadata.h"
#include "path.h"
#include "libmpcodecs/mp_image.h"
#include "libmpcodecs/dec_video.h"
@@ -67,19 +66,6 @@ static char *stripext(void *talloc_ctx, const char *s)
return talloc_asprintf(talloc_ctx, "%.*s", end - s, s);
}
-static char *do_format_property(struct MPContext *mpctx, struct bstr s) {
- struct bstr prop_name = s;
- int fallbackpos = bstrchr(s, ':');
- if (fallbackpos >= 0)
- prop_name = bstr_splice(prop_name, 0, fallbackpos);
- char *pn = bstrdup0(NULL, prop_name);
- char *res = mp_property_print(pn, mpctx);
- talloc_free(pn);
- if (!res && fallbackpos >= 0)
- res = bstrdup0(NULL, bstr_cut(s, fallbackpos + 1));
- return res;
-}
-
#ifdef _WIN32
#define ILLEGAL_FILENAME_CHARS "?\"/\\<>*|:"
#else
@@ -154,14 +140,13 @@ static char *create_fname(struct MPContext *mpctx, char *template,
}
case 'f':
case 'F': {
- char *video_file = get_metadata(mpctx, META_NAME);
+ char *video_file = mp_basename(mpctx->filename);
if (video_file) {
char *name = video_file;
if (fmt == 'F')
name = stripext(res, video_file);
append_filename(&res, name);
}
- talloc_free(video_file);
break;
}
case 'p':
@@ -188,11 +173,13 @@ static char *create_fname(struct MPContext *mpctx, char *template,
if (!end)
goto error_exit;
struct bstr prop = bstr_splice(bstr0(template), 0, end - template);
- template = end + 1;
- char *s = do_format_property(mpctx, prop);
+ char *tmp = talloc_asprintf(NULL, "${%.*s}", BSTR_P(prop));
+ char *s = mp_property_expand_string(mpctx, tmp);
+ talloc_free(tmp);
if (s)
append_filename(&res, s);
talloc_free(s);
+ template = end + 1;
break;
}
case '%':
diff --git a/sub/ass_mp.c b/sub/ass_mp.c
index 202664578b..908a552acf 100644
--- a/sub/ass_mp.c
+++ b/sub/ass_mp.c
@@ -47,7 +47,7 @@ ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
track->PlayResY = 288;
track->WrapStyle = 0;
- if (opts->ass_styles_file)
+ if (opts->ass_styles_file && opts->ass_style_override)
ass_read_styles(track, opts->ass_styles_file, sub_cp);
if (track->n_styles == 0) {
@@ -95,7 +95,9 @@ ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
style->ScaleY = 1.;
}
- ass_process_force_style(track);
+ if (opts->ass_style_override)
+ ass_process_force_style(track);
+
return track;
}
@@ -228,17 +230,32 @@ ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname,
void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts,
struct mp_eosd_res *dim, bool unscaled)
{
- int hinting;
ass_set_frame_size(priv, dim->w, dim->h);
ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr);
- ass_set_use_margins(priv, opts->ass_use_margins);
- ass_set_font_scale(priv, opts->ass_font_scale);
- if (!unscaled && (opts->ass_hinting & 4))
- hinting = 0;
- else
- hinting = opts->ass_hinting & 3;
- ass_set_hinting(priv, hinting);
- ass_set_line_spacing(priv, opts->ass_line_spacing);
+
+ int set_use_margins = 0;
+ int set_sub_pos = 0;
+ float set_line_spacing = 0;
+ float set_font_scale = 1;
+ int set_hinting = 0;
+ if (opts->ass_style_override) {
+ set_use_margins = opts->ass_use_margins;
+ set_sub_pos = 100 - sub_pos;
+ set_line_spacing = opts->ass_line_spacing;
+ set_font_scale = opts->ass_font_scale;
+ if (!unscaled && (opts->ass_hinting & 4))
+ set_hinting = 0;
+ else
+ set_hinting = opts->ass_hinting & 3;
+ }
+
+ ass_set_use_margins(priv, set_use_margins);
+#if LIBASS_VERSION >= 0x01010000
+ ass_set_line_position(priv, set_sub_pos);
+#endif
+ ass_set_font_scale(priv, set_font_scale);
+ ass_set_hinting(priv, set_hinting);
+ ass_set_line_spacing(priv, set_line_spacing);
}
void mp_ass_configure_fonts(ASS_Renderer *priv)
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index e770215ce6..9b0bbb01ab 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -345,8 +345,10 @@ void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t* obj)
ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style;
- style->MarginV = obj->osd_track->PlayResY * ((100 - sub_pos)/110.0);
update_font_scale(obj->osd_track, style, text_font_scale_factor);
+#if LIBASS_VERSION >= 0x01010000
+ ass_set_line_position(osd->osd_render, 100 - sub_pos);
+#endif
char *text = talloc_strdup(NULL, "");
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 9295cab07d..fcedc9fec5 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -135,7 +135,9 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
return;
double scale = osd->normal_scale;
- if (ctx->vsfilter_aspect && opts->ass_vsfilter_aspect_compat)
+ bool use_vs_aspect = opts->ass_style_override
+ ? opts->ass_vsfilter_aspect_compat : 1;
+ if (ctx->vsfilter_aspect && use_vs_aspect)
scale = osd->vsfilter_scale;
ASS_Renderer *renderer = osd->ass_renderer;
mp_ass_configure(renderer, opts, &osd->dim, osd->unscaled);
diff --git a/talloc.c b/talloc.c
index 87842c5acd..9b73fc19f0 100644
--- a/talloc.c
+++ b/talloc.c
@@ -1421,7 +1421,7 @@ char *talloc_strdup_append_buffer(char *s, const char *a)
char *talloc_strndup_append(char *s, const char *a, size_t n)
{
if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
+ return talloc_strndup(NULL, a, n);
}
if (unlikely(!a)) {
@@ -1440,7 +1440,7 @@ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
size_t slen;
if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
+ return talloc_strndup(NULL, a, n);
}
if (unlikely(!a)) {