1
mirror of https://github.com/mpv-player/mpv synced 2024-08-24 07:21:49 +02:00

Merge branch 'input_changes' into master

Conflicts:
	DOCS/man/en/vo.rst
	etc/input.conf
	input/input.c
	m_property.c
This commit is contained in:
wm4 2012-10-12 10:17:55 +02:00
commit 85d185441a
33 changed files with 2200 additions and 2409 deletions

View File

@ -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:
* Table of renamed input commands:
=================================== ===================================
Old New
=================================== ===================================
pt_step 1 b playlist_next b
pt_step -1 b playlist_prev b
pt_clear playlist_clear
=================================== ===================================
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
~~~~~

308
DOCS/man/en/input.rst Normal file
View File

@ -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
=========================== = ==================================================

View File

@ -409,6 +409,8 @@ OPTIONS
.. include:: encode.rst
.. include:: input.rst
Taking screenshots
==================

View File

@ -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

View File

@ -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.

View File

@ -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

2
bstr.h
View File

@ -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));
}

View File

@ -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),

1753
command.c

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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 = {

View File

@ -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

View File

@ -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)
{
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;
}
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 i, l;
int pausing = 0;
char *ptr;
const mp_cmd_t *cmd_def;
int on_osd = MP_ON_OSD_AUTO;
struct mp_cmd *cmd = NULL;
void *tmp = talloc_new(NULL);
// Ignore heading spaces.
while (str[0] == ' ' || str[0] == '\t')
++str;
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)
break;
}
if (mp_cmds[i].name == NULL)
return NULL;
cmd_def = &mp_cmds[i];
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,
};
ptr = str;
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] == '#')
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) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
"isn't an integer.\n", cmd_def->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);
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;
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;
}
case 0:
ptr = NULL;
break;
default:
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Unknown argument %d\n", i);
}
}
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);
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
}
int cmd_idx = 0;
while (mp_cmds[cmd_idx].name != NULL) {
if (eat_token(&str, mp_cmds[cmd_idx].name))
break;
cmd_idx++;
}
if (mp_cmds[cmd_idx].name == NULL) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command '%.*s' not found.\n",
BSTR_P(str));
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);
cmd = talloc_ptrtype(NULL, cmd);
*cmd = mp_cmds[cmd_idx];
cmd->pausing = pausing;
cmd->on_osd = on_osd;
for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
struct mp_cmd_arg *cmdarg = &cmd->args[i];
if (!cmdarg->type.type)
break;
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 "
"has broken string escapes.\n", cmd->name, i + 1);
goto error;
}
if (!bstr_eatstart0(&str, "\"")) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d is "
"unterminated.\n", cmd->name, i + 1);
goto error;
}
} else {
if (!read_token(str, &str, &arg))
break;
if (cmdarg->optional && bstrcmp0(arg, "-") == 0)
continue;
}
// 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);
}
if (i < MP_CMD_MAX_ARGS)
cmd->args[i].type = 0;
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;
}
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;
}
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

View File

@ -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

View File

@ -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)));
}

View File

@ -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;

View File

@ -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.
*/

View File

@ -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));
}
static char *print_float_f2(const m_option_t *opt, const void *val)
{
return talloc_asprintf(NULL, "%.2f", VAL(val));
}
static void add_float(const m_option_t *opt, void *val, double add, bool wrap)
{
double tmp = VAL(val);
add_double(opt, &tmp, add, wrap);
VAL(val) = tmp;
}
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,
};
///////////// 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)
{
long long tmp;
int r = parse_longlong(opt, name, param, &tmp);
if (r >= 0 && dst)
*(off_t *)dst = tmp;
return r;
}
static char *print_position(const m_option_t *opt, const void *val)
{
return talloc_asprintf(NULL, "%"PRId64, (int64_t)VAL(val));
}
const m_option_type_t m_option_type_position = {
// Integer (off_t)
.name = "Position",
.size = sizeof(off_t),
.parse = parse_position,
.print = print_position,
.copy = copy_opt,
};
///////////// 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,
};

View File

@ -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}))

View File

@ -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)
return r;
// Fallback to m_option
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_pretty_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)) !=
M_PROPERTY_NOT_IMPLEMENTED)
}
case M_PROPERTY_GET_STRING: {
if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
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)
char *str = m_option_print(&opt, &val);
m_option_free(&opt, &val);
*(char **)arg = str;
return str != NULL;
}
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;
if ((r = m_option_parse(opt, bstr0(opt->name), bstr0(arg), &val)) <= 0)
return r;
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_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 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);
return r;
}
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;
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, ":");
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++;
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;
}

View File

@ -19,209 +19,119 @@
#ifndef MPLAYER_M_PROPERTY_H
#define MPLAYER_M_PROPERTY_H
#include "m_option.h"
#include <stdbool.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).
///@{
struct m_option;
/// \file
extern const struct m_option_type m_option_type_dummy;
/// \defgroup PropertyActions Property actions
/// \ingroup Properties
///@{
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.
/** \param arg Pointer to a variable of the right type.
*/
#define M_PROPERTY_GET 0
// Get the current value.
// arg: pointer to a variable of the type according to the property type
M_PROPERTY_GET,
/// 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 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,
/// 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
// Get human readable string representing the current value.
// If unimplemented, the property wrapper uses the property type as
// fallback.
// arg: char**
M_PROPERTY_PRINT,
/// Set a new value from a string.
/** \param arg String containing the value.
*/
#define M_PROPERTY_PARSE 3
// 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,
/// 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
// Get a string containing a parsable representation.
// Can't be overridden by property implementations.
// arg: char**
M_PROPERTY_GET_STRING,
/// 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
// 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,
/// 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.
// arg: struct m_property_action_arg*
M_PROPERTY_KEY_ACTION,
};
/// Pass down an action to a sub-property.
#define M_PROPERTY_KEY_ACTION 7
// 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
};
/// 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 {
// Argument for M_PROPERTY_KEY_ACTION
struct m_property_action_arg {
const char* key;
int action;
void* arg;
} m_property_action_t;
};
///@}
enum mp_property_return {
// Returned on success.
M_PROPERTY_OK = 1,
/// \defgroup PropertyActionsReturn Property actions return code
/// \ingroup Properties
/// \brief Return values for the control function.
///@{
// Returned on error.
M_PROPERTY_ERROR = 0,
/// Returned on success.
#define M_PROPERTY_OK 1
// Returned when the property can't be used, for example video related
// properties while playing audio only.
M_PROPERTY_UNAVAILABLE = -1,
/// Returned on error.
#define M_PROPERTY_ERROR 0
// Returned if the requested action is not implemented.
M_PROPERTY_NOT_IMPLEMENTED = -2,
/// \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 when asking for a property that doesn't exist.
M_PROPERTY_UNKNOWN = -3,
};
/// Returned if the requested action is not implemented.
#define M_PROPERTY_NOT_IMPLEMENTED -2
/// Returned when asking for a property that doesn't exist.
#define M_PROPERTY_UNKNOWN -3
/// Returned when the action can't be done (like setting the volume when edl mute).
#define M_PROPERTY_DISABLED -4
///@}
/// \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);
// 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 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);
// 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);
// 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);
///@}
///@}
// 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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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)

252
mplayer.c
View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 '%':

View File

@ -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)

View File

@ -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, "");

View File

@ -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);

View File

@ -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)) {