Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6b85c9170 | ||
|
|
5d74fa7dc0 | ||
|
|
a2fa0d0b68 | ||
|
|
b86a2316df | ||
|
|
912d668ea8 | ||
|
|
c398ab7520 | ||
|
|
68839e4e77 | ||
|
|
51dbb5607e | ||
|
|
139f6b5de7 | ||
|
|
118d7a310e | ||
|
|
0a81fe1cf9 | ||
|
|
8956229ee4 | ||
|
|
992bdc9411 | ||
|
|
5d3657e092 | ||
|
|
06065dc5ef | ||
|
|
2a99e7ae12 | ||
|
|
b99dc17f8e | ||
|
|
8bb57c0387 | ||
|
|
13259f35c8 | ||
|
|
a049a3240e | ||
|
|
0af8811b15 | ||
|
|
6a8d1cdd49 | ||
|
|
b5357e8ba7 | ||
|
|
65c75112a7 | ||
|
|
e41dbc3019 | ||
|
|
7022a24542 | ||
|
|
403f489f6c | ||
|
|
e9c43258b8 | ||
|
|
c3ae2ff107 | ||
|
|
ea1b183f4c | ||
|
|
e543853a7f | ||
|
|
9340f19ba2 | ||
|
|
53798b6465 | ||
|
|
d7e587acc9 | ||
|
|
6fb12a5fda | ||
|
|
3825dc63b2 | ||
|
|
e6291697e3 | ||
|
|
6789f9b094 | ||
|
|
387f501278 | ||
|
|
39f515cb6a | ||
|
|
13dcf82a96 | ||
|
|
202f14aa29 | ||
|
|
75cab315ea | ||
|
|
ba3f6f3779 | ||
|
|
1648ff8a0f | ||
|
|
abbc8fc84a | ||
|
|
7debdde9b9 | ||
|
|
81d125efd8 | ||
|
|
ff531b71e3 | ||
|
|
3a5cbf3907 | ||
|
|
6f4d918cb7 | ||
|
|
8d29d5b5d7 | ||
|
|
39fc5e1deb | ||
|
|
e3a57272a7 | ||
|
|
486b3ce6f8 | ||
|
|
82231fd74d | ||
|
|
052584c9e2 | ||
|
|
52fea2f909 | ||
|
|
026cccaddf | ||
|
|
ea50f6fdef | ||
|
|
33c24b07e4 | ||
|
|
5f547e57e3 | ||
|
|
51f10c512e | ||
|
|
ab07caf39d | ||
|
|
2aba6972cf | ||
|
|
2f1af04745 | ||
|
|
d3111ee777 | ||
|
|
1d385b0dae | ||
|
|
7e6456f43a | ||
|
|
b6920372c2 | ||
|
|
86ab4b8a9f | ||
|
|
b81ae52f50 | ||
|
|
c245d04c37 | ||
|
|
f549cec0ac | ||
|
|
6487ba4864 | ||
|
|
1557ca6712 | ||
|
|
b344da22ae | ||
|
|
ef2bbd5a7a | ||
|
|
73a5bde518 | ||
|
|
b712095d89 | ||
|
|
3751065f97 | ||
|
|
c239b7de7e | ||
|
|
45c97aea78 | ||
|
|
b6cbf74518 | ||
|
|
0fe3e9ca5e | ||
|
|
9f30cd8292 | ||
|
|
f0ab9f05f1 | ||
|
|
dd339b200b | ||
|
|
e6dedbcc23 | ||
|
|
a314b1013f | ||
|
|
0f110ad0e2 | ||
|
|
41002c46f5 | ||
|
|
29d74ca2f5 | ||
|
|
077dd27df2 | ||
|
|
cad6fb038b | ||
|
|
733218b233 | ||
|
|
88f10ec84f | ||
|
|
2361ec35aa | ||
|
|
68d2903cb1 | ||
|
|
e2e9a7faa8 | ||
|
|
343da8d73d | ||
|
|
441febfcba | ||
|
|
cb46f73cbb | ||
|
|
1500c84226 | ||
|
|
9eef41dec1 | ||
|
|
f0fd663320 | ||
|
|
b9153ee177 | ||
|
|
f4db6b8479 | ||
|
|
5f2822d502 | ||
|
|
9664bc23d5 | ||
|
|
6f6c4a57ec | ||
|
|
caa14e3d45 | ||
|
|
3a43682355 | ||
|
|
075edc6fee | ||
|
|
2ac74977c5 | ||
|
|
01e95468f9 | ||
|
|
efbfc00741 | ||
|
|
6fe83fdc33 | ||
|
|
6ba2bbd090 | ||
|
|
9179e8ed21 | ||
|
|
c296b6204f | ||
|
|
e300bfcf3a | ||
|
|
9df797575f | ||
|
|
78b3852f7e | ||
|
|
7783f0b7d7 | ||
|
|
75d12c174f | ||
|
|
14c232bdbf | ||
|
|
47f3cc7e6b | ||
|
|
b521f15ae9 | ||
|
|
33598182a0 | ||
|
|
f66f0b34c8 | ||
|
|
af6126adbe | ||
|
|
d080851a30 | ||
|
|
41d9f2f058 | ||
|
|
89674854ce | ||
|
|
23639e5b0e | ||
|
|
e13eb3fede | ||
|
|
bf385e1140 | ||
|
|
fe872f5688 | ||
|
|
6b5e5b6843 | ||
|
|
5fca497698 | ||
|
|
995962291a | ||
|
|
b6ba87af4b | ||
|
|
fb67db8b72 | ||
|
|
bf5c97a6c3 | ||
|
|
df85c76b7f | ||
|
|
44a7cb7f0e | ||
|
|
ce65ea3345 | ||
|
|
b62634c051 | ||
|
|
75fe626aa6 | ||
|
|
fe7db61035 | ||
|
|
32f235bcef | ||
|
|
a802afb206 | ||
|
|
297f9f1bec | ||
|
|
f504661852 | ||
|
|
57eca14a45 | ||
|
|
ed8540c38e | ||
|
|
0525f5fa93 | ||
|
|
08432fcbd1 | ||
|
|
2415b69572 | ||
|
|
3ecc6d0a79 | ||
|
|
9e972ed7d2 | ||
|
|
62d4a3891a | ||
|
|
79e20ff485 | ||
|
|
74c342c6d3 | ||
|
|
f8659d0013 | ||
|
|
554c3a1bda | ||
|
|
cb604d5412 | ||
|
|
a3e8ff624c | ||
|
|
2d34171bec | ||
|
|
ffc9aa8104 | ||
|
|
b44d075164 | ||
|
|
b7d5cbd375 | ||
|
|
dc48893630 | ||
|
|
d1d5e9dda4 | ||
|
|
7fa26bfd9c | ||
|
|
4395a4f837 | ||
|
|
56616b0b01 | ||
|
|
17e3e800e1 | ||
|
|
ccf3458f8a | ||
|
|
c47ae06ed8 | ||
|
|
8716c2e88f | ||
|
|
15baf2789c | ||
|
|
03fec24e19 | ||
|
|
b8ade7c99b | ||
|
|
f845f64c2a | ||
|
|
b83bfea05d | ||
|
|
cf5c3fc31a | ||
|
|
8bfcae748c | ||
|
|
9c9cf125ad | ||
|
|
5968a307d5 | ||
|
|
d1f5b926ac | ||
|
|
2b0c620b22 | ||
|
|
98f1b5fb98 | ||
|
|
1b5b23b948 | ||
|
|
f143665864 | ||
|
|
30d147687f | ||
|
|
88a07c5f53 | ||
|
|
e24ba8fa7f | ||
|
|
ffbc85cde9 | ||
|
|
8f1a889f75 | ||
|
|
9b6c93e904 | ||
|
|
c56f5f0681 | ||
|
|
215268ea34 | ||
|
|
d2e8bc4499 | ||
|
|
c48bd0ef18 | ||
|
|
9def3682d1 | ||
|
|
5819a4e301 | ||
|
|
060599ac6a | ||
|
|
0ccceecdc6 | ||
|
|
6dc9280b58 | ||
|
|
3905c46f9a | ||
|
|
5c0c0e469b | ||
|
|
f7471b7ff4 | ||
|
|
6a0df47d94 | ||
|
|
fb8f2a812e | ||
|
|
00f8ee573b | ||
|
|
08cbac311d | ||
|
|
60a0815b4c | ||
|
|
5edd6a8caa | ||
|
|
0e72f64ff4 | ||
|
|
876ec446f3 | ||
|
|
8c39c6903b | ||
|
|
e8cdc22245 | ||
|
|
b261e1e782 | ||
|
|
9a873cc53b | ||
|
|
274e71ee8b | ||
|
|
343f5ca24b | ||
|
|
043512045e | ||
|
|
6ac0ef78c5 | ||
|
|
3f7e43c2e2 | ||
|
|
71681e04ee | ||
|
|
440e0a98ab | ||
|
|
1e684e3cca | ||
|
|
eec7660274 | ||
|
|
defcb9047e | ||
|
|
fc1c004cd8 | ||
|
|
484328fe04 | ||
|
|
ebc04333d2 | ||
|
|
5ca654301b | ||
|
|
7383b45682 | ||
|
|
fdc5388f8c | ||
|
|
76818e3dc7 | ||
|
|
d054a7181f | ||
|
|
04320d26eb | ||
|
|
c157641019 | ||
|
|
5324fb731f | ||
|
|
9213db0d49 | ||
|
|
d66f2a679b | ||
|
|
27e3f04de7 | ||
|
|
ea94b01e6b | ||
|
|
5e30e7a041 | ||
|
|
35e8b6c1e6 | ||
|
|
ca55a32922 | ||
|
|
c8cc1f401b | ||
|
|
7177ef3e1c | ||
|
|
a2fce5ba26 | ||
|
|
c3097422f2 | ||
|
|
8bb9632e27 | ||
|
|
2048ad2b8a | ||
|
|
622f9cf1aa | ||
|
|
4552ee286b | ||
|
|
062423381d | ||
|
|
2372b0a6f6 | ||
|
|
2f1eb49e9f | ||
|
|
355361e1e3 | ||
|
|
5a7b1ff4c0 | ||
|
|
591e21a2eb | ||
|
|
c6b7a4dace | ||
|
|
2a4e7dcaad | ||
|
|
d4d8b3a4fc | ||
|
|
9f0e7bb998 | ||
|
|
e66c098228 | ||
|
|
618d7f59b0 | ||
|
|
723e3ec8d9 | ||
|
|
9ab0f60d44 | ||
|
|
e5cefa346d | ||
|
|
c36aaeeb2a | ||
|
|
c4e01cc00d | ||
|
|
1d9032f011 | ||
|
|
13786dc643 | ||
|
|
69283bc0f8 | ||
|
|
633eb30cbe | ||
|
|
327cb2a06c | ||
|
|
9e6b9d8a98 | ||
|
|
726ef35aa8 | ||
|
|
4ab860cddc | ||
|
|
cc813647d5 | ||
|
|
6cd80e972e | ||
|
|
3878a59e2c | ||
|
|
2619d8eff4 | ||
|
|
d889d1fbaa | ||
|
|
e955ae9000 | ||
|
|
4236321835 | ||
|
|
4f263dce34 | ||
|
|
590caeb2bd | ||
|
|
0c2c059826 | ||
|
|
9bc39b352e | ||
|
|
ece86d1061 | ||
|
|
c92450d7fb | ||
|
|
a85eecfe40 | ||
|
|
eb14b18a33 | ||
|
|
9770ce6c44 | ||
|
|
b92d3b6d44 | ||
|
|
cd7c7d0841 | ||
|
|
b2c84a91b6 | ||
|
|
849480d0c9 | ||
|
|
a07dae57e3 | ||
|
|
72c6bf1345 | ||
|
|
2c917219cf | ||
|
|
423e53ba0b | ||
|
|
f2e25e9e1f | ||
|
|
b2657814c9 | ||
|
|
4fa6bcbb90 | ||
|
|
875aeb0f5c | ||
|
|
c72df80460 | ||
|
|
907bf83297 | ||
|
|
3659f9e416 | ||
|
|
ce05413a87 | ||
|
|
453fea87fa | ||
|
|
1393d79417 | ||
|
|
192a7344d9 | ||
|
|
e4e1dc3c79 | ||
|
|
d32bee5f01 | ||
|
|
17dbb39dec | ||
|
|
6b4f560f3c | ||
|
|
ec3c428e5f | ||
|
|
e22ae2cba0 | ||
|
|
aae47146a7 | ||
|
|
7539928c1c | ||
|
|
c55d859920 | ||
|
|
2057209057 | ||
|
|
b10dcecf7d | ||
|
|
7dde096d8a | ||
|
|
e024906408 | ||
|
|
ce8dae3f0d | ||
|
|
f519887fe7 | ||
|
|
7614f2b3a6 | ||
|
|
4d75514321 | ||
|
|
af1379c43d | ||
|
|
e65a8d7b61 | ||
|
|
5f88e6a0db | ||
|
|
3bb134969e | ||
|
|
6f6d2eb770 | ||
|
|
f3b3702025 | ||
|
|
d223959cda | ||
|
|
ae3bbc4f63 | ||
|
|
cb2cb540f4 | ||
|
|
3e0d4de988 | ||
|
|
251ecf6e4b | ||
|
|
edbb8f6286 | ||
|
|
0110b738d5 | ||
|
|
bda614bfd8 | ||
|
|
f42e4374d5 | ||
|
|
a9a55ea7f2 | ||
|
|
5e56c07417 | ||
|
|
5086b2d456 | ||
|
|
7af6e64db7 | ||
|
|
eed99d3609 | ||
|
|
a05f20ea1e | ||
|
|
ed62f56a40 | ||
|
|
37d6604d70 | ||
|
|
872b7a2654 | ||
|
|
c226bc7616 | ||
|
|
e60a36bd4e | ||
|
|
bc97d60542 | ||
|
|
4121016689 | ||
|
|
b636b19058 | ||
|
|
cb9b60ef19 | ||
|
|
31f28da0f3 | ||
|
|
ef0b2e33b1 | ||
|
|
2a5b61244f | ||
|
|
c4ba600832 | ||
|
|
c218d9e960 | ||
|
|
a47d849df7 | ||
|
|
6980575e15 | ||
|
|
724f60bf9a | ||
|
|
74d4073771 | ||
|
|
93104142f4 | ||
|
|
9a5e062a04 | ||
|
|
6b676d82fd | ||
|
|
af103aebd7 | ||
|
|
969c011522 | ||
|
|
1a8af89b7d | ||
|
|
e057629493 | ||
|
|
cb31e72589 | ||
|
|
ed644b0d33 | ||
|
|
23993e91f3 | ||
|
|
68dc869d6a | ||
|
|
e5f61c2bd5 | ||
|
|
2fbd1d3610 | ||
|
|
05e4df3f0c | ||
|
|
4aaa83339c | ||
|
|
5d2dfbdfca | ||
|
|
4e3663a2da | ||
|
|
e6952c7053 | ||
|
|
0f83caf96a | ||
|
|
1e53fc3a15 | ||
|
|
a1dec6f54a | ||
|
|
bbcd0b6a03 | ||
|
|
7bba97b301 | ||
|
|
0a0967f48b | ||
|
|
e02cb674ce | ||
|
|
f5bbb5aed2 | ||
|
|
07f8b64754 | ||
|
|
3a7e86ff6e | ||
|
|
12e251c29e | ||
|
|
814dacdd7d | ||
|
|
86fa1e6129 | ||
|
|
795b65b2ff |
No files matched your search
@@ -8,12 +8,14 @@ If you're not using git master or the latest release, update.
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Log files
|
||||
### Log file
|
||||
|
||||
Make a log file made with -v or --log-file=output.txt, paste it to
|
||||
http://sprunge.us or a similar site, and replace this text with a link to it.
|
||||
|
||||
Do not bother reporting a bug if you do not provide the required information.
|
||||
Providing a log file is strongly encouraged. It is very helpful for reproducing
|
||||
bugs or getting important technical context. Without a log it might not be
|
||||
possible to analyze and fix certain bugs.
|
||||
|
||||
### Sample files
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
/demux/ebml_types.h
|
||||
/sub/osd_font.h
|
||||
/player/lua/*.inc
|
||||
/player/builtin_conf.inc
|
||||
/DOCS/man/mpv.1
|
||||
/DOCS/man/mpv.aux
|
||||
/DOCS/man/mpv.log
|
||||
|
||||
@@ -12,6 +12,8 @@ env:
|
||||
global:
|
||||
# Coverity token
|
||||
- secure: "H21mSRlMhk4BKS0xHZvCFGJxteCP0hRVUxTuNfM2Z9HBsyutuLEYMtViLO86VtM+Tqla3xXPzUdS4ozLwI72Ax/5ZUDXACROj73yW6QhFB5D6rLut12+FjqC7M33Qv2hl0xwgNBmR5dsm1ToP37+Wn+ecJQNvN8fkTXF+HVzOEw="
|
||||
# Travis token for mpv.io
|
||||
- secure: "nlTVLJK6kRhtXvhKCoJ3YdFGHuKaq/eHowfPw25hqRWuBOZd+HjHY5KIYjV7SxuKFDpJE4GpNcvA3Q31nsqomxpkLYgrwjg6TSazN7ZP+x85ZgV1QGFebrPfGm2n5UR5CAPAwFoeF3pZheLi4bajVzwq1fWW+x3grS188P9OZso="
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
@@ -42,6 +44,7 @@ script:
|
||||
- ./bootstrap.py
|
||||
- ./waf configure
|
||||
- ./waf build
|
||||
after_script: TOOLS/travis-rebuild-website
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
@@ -32,7 +32,26 @@ API changes
|
||||
|
||||
::
|
||||
|
||||
--- mpv 0.19.0
|
||||
--- mpv 0.21.0 ---
|
||||
1.23 - deprecate setting "no-" options via mpv_set_option*(). For example,
|
||||
instead of "no-video=" you should set "video=no".
|
||||
- do not override the SIGPIPE signal handler anymore. This was done as
|
||||
workaround for the FFmpeg TLS code, which has been fixed long ago.
|
||||
- deprecate mpv_suspend() and mpv_resume(). They will be stubbed out
|
||||
in mpv 0.22.0.
|
||||
- make mpv_set_property() work to some degree before mpv_initialize().
|
||||
It can now be used instead of mpv_set_option().
|
||||
- semi-deprecate mpv_set_option()/mpv_set_option_string(). You should
|
||||
use mpv_set_property() instead. There are some deprecated properties
|
||||
which conflict with some options (see client.h remarks on
|
||||
mpv_set_option()), for which mpv_set_option() might still be required.
|
||||
In future mpv releases, the conflicting deprecated options/properties
|
||||
will be removed, and mpv_set_option() will internally translate API
|
||||
calls to mpv_set_property().
|
||||
- qthelper.hpp: deprecate get_property_variant, set_property_variant,
|
||||
mpv_set_option, command_variant, and replace them with get_property,
|
||||
set_property, command.
|
||||
--- mpv 0.19.0 ---
|
||||
1.22 - add stream_cb API for custom protocols
|
||||
--- mpv 0.18.1 ---
|
||||
---- - remove "status" log level from mpv_request_log_messages() docs. This
|
||||
|
||||
@@ -104,10 +104,10 @@ Installing MSYS2
|
||||
It doesn't matter whether the i686 or the x86_64 version is used. Both can
|
||||
build 32-bit and 64-bit binaries when running on a 64-bit version of Windows.
|
||||
|
||||
2. Start a MinGW-w64 shell (``mingw64_shell.bat``). Note that this is different
|
||||
2. Start a MinGW-w64 shell (``mingw64.exe``). Note that this is different
|
||||
from the MSYS2 shell that is started from the final installation dialog.
|
||||
|
||||
For a 32-bit build, use ``mingw32_shell.bat``.
|
||||
For a 32-bit build, use ``mingw32.exe``.
|
||||
|
||||
Updating MSYS2
|
||||
--------------
|
||||
@@ -118,7 +118,7 @@ separately.
|
||||
```bash
|
||||
# Check for core updates. If instructed, close the shell window and reopen it
|
||||
# before continuing.
|
||||
update-core
|
||||
pacman -Syu
|
||||
|
||||
# Update everything else
|
||||
pacman -Su
|
||||
|
||||
@@ -19,6 +19,86 @@ Interface changes
|
||||
|
||||
::
|
||||
|
||||
--- mpv 0.21.0 ---
|
||||
- setting certain options at runtime will now take care of updating them
|
||||
property (see for example issue #3281). On the other hand, it will also
|
||||
do runtime verification and reject option changes that do not work
|
||||
(example: setting the "vf" option to a filter during playback, which fails
|
||||
to initialize - the option value will remain at its old value). In general,
|
||||
"set name value" should be mostly equivalent to "set options/name value"
|
||||
in cases where the "name" property is not deprecated and "options/name"
|
||||
exists - deviations from this are either bugs, or documented as caveats
|
||||
in the "Inconsistencies between options and properties" manpage section.
|
||||
- deprecate _all_ --vo and --ao suboptions. Generally, all suboptions are
|
||||
replaced by global options, which do exactly the same. For example,
|
||||
"--vo=opengl:scale=nearest" turns into "--scale=nearest". In some cases,
|
||||
the global option is prefixed, e.g. "--vo=opengl:pbo" turns into
|
||||
"--opengl-pbo".
|
||||
Most of the exact replacements are documented here:
|
||||
https://github.com/mpv-player/mpv/wiki/Option-replacement-list
|
||||
- remove --vo=opengl-hq. Set --profile=opengl-hq instead. Note that this
|
||||
profile does not force the VO. This means if you use the --vo option to
|
||||
set another VO, it won't work. But this also means it can be used with
|
||||
opengl-cb.
|
||||
- remove the --vo=opengl "pre-shaders", "post-shaders" and "scale-shader"
|
||||
sub-options: they were deprecated in favor of "user-shaders"
|
||||
- deprecate --vo-defaults (no replacement)
|
||||
- remove the vo-cmdline command. You can set OpenGL renderer options
|
||||
directly via properties instead.
|
||||
- deprecate the device/sink options on all AOs. Use --audio-device instead.
|
||||
- deprecate "--ao=wasapi:exclusive" and "--ao=coreaudio:exclusive",
|
||||
use --audio-exclusive instead.
|
||||
- subtle changes in how "--no-..." options are treated mean that they are
|
||||
not accessible under "options/..." anymore (instead, these are resolved
|
||||
at parsing time). This does not affect options which start with "--no-",
|
||||
but do not use the mechanism for negation options.
|
||||
(Also see client API change for API version 1.23.)
|
||||
- rename the following properties
|
||||
- "demuxer" -> "current-demuxer"
|
||||
- "fps" -> "container-fps"
|
||||
- "idle" -> "idle-active"
|
||||
- "cache" -> "cache-percent"
|
||||
the old names are deprecated and will change behavior in mpv 0.22.0.
|
||||
- remove deprecated "hwdec-active" and "hwdec-detected" properties
|
||||
- deprecate the ao and vo auto-profiles (they never made any sense)
|
||||
- deprecate "--vo=direct3d_shaders" - use "--vo=direct3d" instead.
|
||||
Change "--vo=direct3d" to always use shaders by default.
|
||||
- deprecate --playlist-pos option, renamed to --playlist-start
|
||||
- deprecate the --chapter option, as it is redundant with --start/--end,
|
||||
and conflicts with the semantics of the "chapter" property
|
||||
- rename --sub-text-* to --sub-* and --ass-* to --sub-ass-* (old options
|
||||
deprecated)
|
||||
- incompatible change to cdda:// protocol options: the part after cdda://
|
||||
now always sets the device, not the span or speed to be played. No
|
||||
separating extra "/" is needed. The hidden --cdda-device options is also
|
||||
deleted (it was redundant with the documented --cdrom-device).
|
||||
- deprecate --vo=rpi. It will be removed in mpv 0.22.0. Its functionality
|
||||
was folded into --vo=opengl, which now uses RPI hardware decoding by
|
||||
treating it as a hardware overlay (without applying GL filtering). Also
|
||||
to be changed in 0.22.0: the --fs flag will be reset to "no" by default
|
||||
(like on the other platforms).
|
||||
- deprecate --mute=auto (informally has been since 0.18.1)
|
||||
- deprecate "resume" and "suspend" IPC commands. They will be completely
|
||||
removed in 0.22.0.
|
||||
- deprecate mp.suspend(), mp.resume(), mp.resume_all() Lua scripting
|
||||
commands, as well as setting mp.use_suspend. They will be completely
|
||||
removed in 0.22.0.
|
||||
- the "seek" command's absolute seek mode will now interpret negative
|
||||
seek times as relative from the end of the file (and clamps seeks that
|
||||
still go before 0)
|
||||
- add almost all options to the property list, meaning you can change
|
||||
options without adding "options/" to the property name (a new section
|
||||
has been added to the manpage describing some conflicting behavior
|
||||
between options and properties)
|
||||
- implement changing sub-speed during playback
|
||||
- make many previously fixed options changeable at runtime (for example
|
||||
--terminal, --osc, --ytdl, can all be enable/disabled after
|
||||
mpv_initialize() - this can be extended to other still fixed options
|
||||
on user requests)
|
||||
--- mpv 0.20.0 ---
|
||||
- add --image-display-duration option - this also means that image duration
|
||||
is not influenced by --mf-fps anymore in the general case (this is an
|
||||
incompatible change)
|
||||
--- mpv 0.19.0 ---
|
||||
- deprecate "balance" option/property (no replacement)
|
||||
--- mpv 0.18.1 ---
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
Client API (libmpv) documentation and examples
|
||||
==============================================
|
||||
|
||||
libmpv lets you embed mpv as a library. It is meant to enable development of
|
||||
GUI frontends.
|
||||
|
||||
Since libmpv merely allows access to underlying mechanisms that can control
|
||||
mpv, documentation is spread over a few places:
|
||||
|
||||
- https://github.com/mpv-player/mpv/blob/master/libmpv/client.h
|
||||
- http://mpv.io/manual/master/#options
|
||||
- http://mpv.io/manual/master/#list-of-input-commands
|
||||
- http://mpv.io/manual/master/#properties
|
||||
- https://github.com/mpv-player/mpv-examples/tree/master/libmpv
|
||||
+20
-6
@@ -312,6 +312,13 @@ Available filters are:
|
||||
``mpv '--af=format=channels=5.1' '--audio-channels=5.1'`` would always force
|
||||
remixing audio to 5.1 and output it like this.
|
||||
|
||||
This filter supports the following ``af-command`` commands:
|
||||
|
||||
``set-matrix``
|
||||
Set the ``<matrix>`` argument dynamically. This can be used to change
|
||||
the mixing matrix at runtime, without reinitializing the entire filter
|
||||
chain.
|
||||
|
||||
``drc[=method:target]``
|
||||
Applies dynamic range compression. This maximizes the volume by compressing
|
||||
the audio signal's dynamic range. (Formerly called ``volnorm``.)
|
||||
@@ -394,10 +401,6 @@ Available filters are:
|
||||
``mpv --af=scaletempo=stride=30:overlap=.50:search=10 media.ogg``
|
||||
Would tweak the quality and performance parameters.
|
||||
|
||||
``mpv --af=format=float,scaletempo media.ogg``
|
||||
Would make scaletempo use float code. Maybe faster on some
|
||||
platforms.
|
||||
|
||||
``mpv --af=scaletempo=scale=1.2:speed=pitch audio.ogg``
|
||||
Would play media at 1.2x normal speed, with audio at normal pitch.
|
||||
Changing playback speed would change pitch, leaving audio tempo at
|
||||
@@ -406,9 +409,13 @@ Available filters are:
|
||||
``rubberband``
|
||||
High quality pitch correction with librubberband. This can be used in place
|
||||
of ``scaletempo``, and will be used to adjust audio pitch when playing
|
||||
at speed different from normal.
|
||||
at speed different from normal. It can also be used to adjust audio pitch
|
||||
without changing playback speed.
|
||||
|
||||
This filter has a number of sub-options. You can list them with
|
||||
``<pitch-scale>``
|
||||
Sets the pitch scaling factor. Frequencies are multiplied by this value.
|
||||
|
||||
This filter has a number of additional sub-options. You can list them with
|
||||
``mpv --af=rubberband=help``. This will also show the default values
|
||||
for each option. The options are not documented here, because they are
|
||||
merely passed to librubberband. Look at the librubberband documentation
|
||||
@@ -417,6 +424,13 @@ Available filters are:
|
||||
(The mapping of the mpv rubberband filter sub-option names and values to
|
||||
those of librubberband follows a simple pattern: ``"Option" + Name + Value``.)
|
||||
|
||||
This filter supports the following ``af-command`` commands:
|
||||
|
||||
``set-pitch``
|
||||
Set the ``<pitch-scale>`` argument dynamically. This can be used to
|
||||
change the playback pitch at runtime. Note that speed is controlled
|
||||
using the standard ``speed`` property, not ``af-command``.
|
||||
|
||||
``lavfi=graph``
|
||||
Filter audio using FFmpeg's libavfilter.
|
||||
|
||||
|
||||
+74
-117
@@ -4,18 +4,17 @@ AUDIO OUTPUT DRIVERS
|
||||
Audio output drivers are interfaces to different audio output facilities. The
|
||||
syntax is:
|
||||
|
||||
``--ao=<driver1[:suboption1[=value]:...],driver2,...[,]>``
|
||||
``--ao=<driver1,driver2,...[,]>``
|
||||
Specify a priority list of audio output drivers to be used.
|
||||
|
||||
If the list has a trailing ',', mpv will fall back on drivers not contained
|
||||
in the list. Suboptions are optional and can mostly be omitted.
|
||||
|
||||
You can also set defaults for each driver. The defaults are applied before the
|
||||
normal driver parameters.
|
||||
in the list.
|
||||
|
||||
``--ao-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
|
||||
Set defaults for each driver.
|
||||
|
||||
Deprecated. No replacement.
|
||||
|
||||
.. note::
|
||||
|
||||
See ``--ao=help`` for a list of compiled-in audio output drivers. The
|
||||
@@ -23,87 +22,19 @@ normal driver parameters.
|
||||
where PulseAudio is used. On BSD systems, ``--ao=oss`` or ``--ao=sndio``
|
||||
may work (the latter being experimental).
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
- ``--ao=alsa,oss,`` Try the ALSA driver, then the OSS driver, then others.
|
||||
- ``--ao=alsa:resample=yes:device=[plughw:0,3]`` Lets ALSA resample and
|
||||
sets the device-name as first card, fourth device.
|
||||
|
||||
Available audio output drivers are:
|
||||
|
||||
``alsa`` (Linux only)
|
||||
ALSA audio output driver
|
||||
|
||||
``device=<device>``
|
||||
Sets the device name. For ac3 output via S/PDIF, use an "iec958" or
|
||||
"spdif" device, unless you really know how to set it correctly.
|
||||
``resample=yes``
|
||||
Enable ALSA resampling plugin. (This is disabled by default, because
|
||||
some drivers report incorrect audio delay in some cases.)
|
||||
``mixer-device=<device>``
|
||||
Set the mixer device used with ``--no-softvol`` (default: ``default``).
|
||||
``mixer-name=<name>``
|
||||
Set the name of the mixer element (default: ``Master``). This is for
|
||||
example ``PCM`` or ``Master``.
|
||||
``mixer-index=<number>``
|
||||
Set the index of the mixer channel (default: 0). Consider the output of
|
||||
"``amixer scontrols``", then the index is the number that follows the
|
||||
name of the element.
|
||||
``non-interleaved``
|
||||
Allow output of non-interleaved formats (if the audio decoder uses
|
||||
this format). Currently disabled by default, because some popular
|
||||
ALSA plugins are utterly broken with non-interleaved formats.
|
||||
``ignore-chmap``
|
||||
Don't read or set the channel map of the ALSA device - only request the
|
||||
required number of channels, and then pass the audio as-is to it. This
|
||||
option most likely should not be used. It can be useful for debugging,
|
||||
or for static setups with a specially engineered ALSA configuration (in
|
||||
this case you should always force the same layout with ``--audio-channels``,
|
||||
or it will work only for files which use the layout implicit to your
|
||||
ALSA device).
|
||||
|
||||
.. note::
|
||||
|
||||
MPlayer and mplayer2 required you to replace any ',' with '.' and
|
||||
any ':' with '=' in the ALSA device name. mpv does not do this anymore.
|
||||
Instead, quote the device name:
|
||||
|
||||
``--ao=alsa:device=[plug:surround50]``
|
||||
|
||||
Note that the ``[`` and ``]`` simply quote the device name. With some
|
||||
shells (like zsh), you have to quote the option string to prevent the
|
||||
shell from interpreting the brackets instead of passing them to mpv.
|
||||
|
||||
Actually, you should use the ``--audio-device`` option, instead of
|
||||
setting the device directly.
|
||||
See `ALSA audio output options`_ for options specific to this AO.
|
||||
|
||||
.. warning::
|
||||
|
||||
Handling of multichannel/surround audio changed in mpv 0.8.0 from the
|
||||
behavior in MPlayer/mplayer2 and older versions of mpv.
|
||||
|
||||
The old behavior is that the player always downmixed to stereo by
|
||||
default. The ``--audio-channels`` (or ``--channels`` before that) option
|
||||
had to be set to get multichannel audio. Then playing stereo would
|
||||
use the ``default`` device (which typically allows multiple programs
|
||||
to play audio at the same time via dmix), while playing anything with
|
||||
more channels would open one of the hardware devices, e.g. via the
|
||||
``surround51`` alias (typically with exclusive access). Whether the
|
||||
player would use exclusive access or not would depend on the file
|
||||
being played.
|
||||
|
||||
The new behavior since mpv 0.8.0 always enables multichannel audio,
|
||||
i.e. ``--audio-channels=auto`` is the default. However, since ALSA
|
||||
provides no good way to play multichannel audio in a non-exclusive
|
||||
way (without blocking other applications from using audio), the player
|
||||
is restricted to the capabilities of the ``default`` device by default,
|
||||
which means it supports only stereo and mono (at least with current
|
||||
typical ALSA configurations). But if a hardware device is selected,
|
||||
then multichannel audio will typically work.
|
||||
|
||||
The short story is: if you want multichannel audio with ALSA, use
|
||||
``--audio-device`` to select the device (use ``--audio-device=help``
|
||||
to get a list of all devices and their mpv name).
|
||||
To get multichannel/surround audio, use ``--audio-channels=auto``. The
|
||||
default for this option is ``auto-safe``, which makes this audio otuput
|
||||
explicitly reject multichannel output, as there is no way to detect
|
||||
whether a certain channel layout is actually supported.
|
||||
|
||||
You can also try `using the upmix plugin <http://git.io/vfuAy>`_.
|
||||
This setup enables multichannel audio on the ``default`` device
|
||||
@@ -113,31 +44,36 @@ Available audio output drivers are:
|
||||
``oss``
|
||||
OSS audio output driver
|
||||
|
||||
``<dsp-device>``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--oss-device``
|
||||
Sets the audio output device (default: ``/dev/dsp``).
|
||||
``<mixer-device>``
|
||||
Deprecated, use ``--audio-device``.
|
||||
``--oss-mixer-device``
|
||||
Sets the audio mixer device (default: ``/dev/mixer``).
|
||||
``<mixer-channel>``
|
||||
``--oss-mixer-channel``
|
||||
Sets the audio mixer channel (default: ``pcm``). Other valid values
|
||||
include **vol, pcm, line**. For a complete list of options look for
|
||||
``SOUND_DEVICE_NAMES`` in ``/usr/include/linux/soundcard.h``.
|
||||
|
||||
``jack``
|
||||
JACK (Jack Audio Connection Kit) audio output driver
|
||||
JACK (Jack Audio Connection Kit) audio output driver.
|
||||
|
||||
``port=<name>``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--jack-port=<name>``
|
||||
Connects to the ports with the given name (default: physical ports).
|
||||
``name=<client>``
|
||||
``--jack-name=<client>``
|
||||
Client name that is passed to JACK (default: ``mpv``). Useful
|
||||
if you want to have certain connections established automatically.
|
||||
``(no-)autostart``
|
||||
``--jack-autostart=<yes|no>``
|
||||
Automatically start jackd if necessary (default: disabled). Note that
|
||||
this tends to be unreliable and will flood stdout with server messages.
|
||||
``(no-)connect``
|
||||
``--jack-connect=<yes|no>``
|
||||
Automatically create connections to output ports (default: enabled).
|
||||
When enabled, the maximum number of output channels will be limited to
|
||||
the number of available output ports.
|
||||
``std-channel-layout=waveext|any``
|
||||
``--jack-std-channel-layout=<waveext|any>``
|
||||
Select the standard channel layout (default: waveext). JACK itself has no
|
||||
notion of channel layouts (i.e. assigning which speaker a given
|
||||
channel is supposed to map to) - it just takes whatever the application
|
||||
@@ -157,7 +93,9 @@ Available audio output drivers are:
|
||||
Automatically redirects to ``coreaudio_exclusive`` when playing compressed
|
||||
formats.
|
||||
|
||||
``change-physical-format=<yes|no>``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--coreaudio-change-physical-format=<yes|no>``
|
||||
Change the physical format to one similar to the requested audio format
|
||||
(default: no). This has the advantage that multichannel audio output
|
||||
will actually work. The disadvantage is that it will change the
|
||||
@@ -165,11 +103,13 @@ Available audio output drivers are:
|
||||
setting in the ``Audio Devices`` dialog in the ``Audio MIDI Setup``
|
||||
utility. Note that this does not affect the selected speaker setup.
|
||||
|
||||
``exclusive``
|
||||
``--coreaudio-exclusive``
|
||||
Deprecated, use ``--audio-exclusive``.
|
||||
Use exclusive mode access. This merely redirects to
|
||||
``coreaudio_exclusive``, but should be preferred over using that AO
|
||||
directly.
|
||||
|
||||
|
||||
``coreaudio_exclusive`` (Mac OS X only)
|
||||
Native Mac OS X audio output driver using direct device access and
|
||||
exclusive mode (bypasses the sound server).
|
||||
@@ -183,18 +123,21 @@ Available audio output drivers are:
|
||||
``pulse``
|
||||
PulseAudio audio output driver
|
||||
|
||||
``[<host>][:<output sink>]``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--pulse-host=<host>``, ``--pulse-sink=<sink>``
|
||||
Specify the host and optionally output sink to use. An empty <host>
|
||||
string uses a local connection, "localhost" uses network transfer
|
||||
(most likely not what you want).
|
||||
Deprecated, use ``--audio-device``.
|
||||
|
||||
``buffer=<1-2000|native>``
|
||||
``--pulse-buffer=<1-2000|native>``
|
||||
Set the audio buffer size in milliseconds. A higher value buffers
|
||||
more data, and has a lower probability of buffer underruns. A smaller
|
||||
value makes the audio stream react faster, e.g. to playback speed
|
||||
changes. Default: 250.
|
||||
|
||||
``latency-hacks=<yes|no>``
|
||||
``--pulse-latency-hacks=<yes|no>``
|
||||
Enable hacks to workaround PulseAudio timing bugs (default: no). If
|
||||
enabled, mpv will do elaborate latency calculations on its own. If
|
||||
disabled, it will use PulseAudio automatically updated timing
|
||||
@@ -214,61 +157,67 @@ Available audio output drivers are:
|
||||
environments, such as systems where none of the other drivers
|
||||
are available.
|
||||
|
||||
``buflen=<length>``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--sdl-buflen=<length>``
|
||||
Sets the audio buffer length in seconds. Is used only as a hint by the
|
||||
sound system. Playing a file with ``-v`` will show the requested and
|
||||
obtained exact buffer size. A value of 0 selects the sound system
|
||||
default.
|
||||
|
||||
``bufcnt=<count>``
|
||||
``--sdl-bufcnt=<count>``
|
||||
Sets the number of extra audio buffers in mpv. Usually needs not be
|
||||
changed.
|
||||
|
||||
``null``
|
||||
Produces no audio output but maintains video playback speed. Use
|
||||
``--ao=null:untimed`` for benchmarking.
|
||||
Produces no audio output but maintains video playback speed. You can use
|
||||
``--ao=null --ao-null-untimed`` for benchmarking.
|
||||
|
||||
``untimed``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-null-untimed``
|
||||
Do not simulate timing of a perfect audio device. This means audio
|
||||
decoding will go as fast as possible, instead of timing it to the
|
||||
system clock.
|
||||
|
||||
``buffer``
|
||||
``--ao-null-buffer``
|
||||
Simulated buffer length in seconds.
|
||||
|
||||
``outburst``
|
||||
``--ao-null-outburst``
|
||||
Simulated chunk size in samples.
|
||||
|
||||
``speed``
|
||||
``--ao-null-speed``
|
||||
Simulated audio playback speed as a multiplier. Usually, a real audio
|
||||
device will not go exactly as fast as the system clock. It will deviate
|
||||
just a little, and this option helps to simulate this.
|
||||
|
||||
``latency``
|
||||
``--ao-null-latency``
|
||||
Simulated device latency. This is additional to EOF.
|
||||
|
||||
``broken-eof``
|
||||
``--ao-null-broken-eof``
|
||||
Simulate broken audio drivers, which always add the fixed device
|
||||
latency to the reported audio playback position.
|
||||
|
||||
``broken-delay``
|
||||
``--ao-null-broken-delay``
|
||||
Simulate broken audio drivers, which don't report latency correctly.
|
||||
|
||||
``channel-layouts``
|
||||
``--ao-null-channel-layouts``
|
||||
If not empty, this is a ``,`` separated list of channel layouts the
|
||||
AO allows. This can be used to test channel layout selection.
|
||||
|
||||
``pcm``
|
||||
Raw PCM/WAVE file writer audio output
|
||||
|
||||
``(no-)waveheader``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-pcm-waveheader=<yes|no>``
|
||||
Include or do not include the WAVE header (default: included). When
|
||||
not included, raw PCM will be generated.
|
||||
``file=<filename>``
|
||||
``--ao-pcm-file=<filename>``
|
||||
Write the sound to ``<filename>`` instead of the default
|
||||
``audiodump.wav``. If ``no-waveheader`` is specified, the default is
|
||||
``audiodump.pcm``.
|
||||
``(no-)append``
|
||||
``--ao-pcm-append=<yes|no>``
|
||||
Append to the file, instead of overwriting it. Always use this with the
|
||||
``no-waveheader`` option - with ``waveheader`` it's broken, because
|
||||
it will write a WAVE header every time the file is opened.
|
||||
@@ -280,14 +229,19 @@ Available audio output drivers are:
|
||||
confused with RoarAudio, which is something completely
|
||||
different.
|
||||
|
||||
``host=<name/path>``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--rsound-host=<name/path>``
|
||||
Set the address of the server (default: localhost). Can be either a
|
||||
network hostname for TCP connections or a Unix domain socket path
|
||||
starting with '/'.
|
||||
``port=<number>``
|
||||
``--rsound-port=<number>``
|
||||
Set the TCP port used for connecting to the server (default: 12345).
|
||||
Not used if connecting to a Unix domain socket.
|
||||
|
||||
These options are deprecated. If anyone cares enough, their functionality
|
||||
can be added back using ``--audio-device``.
|
||||
|
||||
``sndio``
|
||||
Audio output to the OpenBSD sndio sound system
|
||||
|
||||
@@ -296,16 +250,24 @@ Available audio output drivers are:
|
||||
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
|
||||
layouts.)
|
||||
|
||||
``device=<device>``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-sndio-device=<device>``
|
||||
sndio device to use (default: ``$AUDIODEVICE``, resp. ``snd0``).
|
||||
Deprecated, use ``--audio-device``.
|
||||
|
||||
``wasapi``
|
||||
Audio output to the Windows Audio Session API.
|
||||
|
||||
``exclusive``
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-wasapi-exclusive``
|
||||
Deprecated, use ``--audio-exclusive``.
|
||||
Requests exclusive, direct hardware access. By definition prevents
|
||||
sound playback of any other program until mpv exits.
|
||||
``device=<id>``
|
||||
``--ao-wasapi-device=<id>``
|
||||
Deprecated, use ``--audio-device``.
|
||||
|
||||
Uses the requested endpoint instead of the system's default audio
|
||||
endpoint. Both an ordinal number (0,1,2,...) and the GUID
|
||||
String are valid; the GUID string is guaranteed to not change
|
||||
@@ -313,8 +275,3 @@ Available audio output drivers are:
|
||||
|
||||
Also supports searching active devices by human-readable name. If more
|
||||
than one device matches the name, refuses loading it.
|
||||
|
||||
This option is mostly deprecated in favour of the more general
|
||||
``--audio-device`` option. That said, ``--audio-device=help`` will give
|
||||
a list of valid device GUIDs (prefixed with ``wasapi/``), as well as
|
||||
their human readable names, which should work here.
|
||||
@@ -8,6 +8,11 @@ There is no real changelog, but you can look at the following things:
|
||||
|
||||
https://github.com/mpv-player/mpv/releases
|
||||
* The git log, which is the "real" changelog
|
||||
* The files ``client-api-changes.rst`` and ``interface-changes.rst`` in the
|
||||
``DOCS`` sub directoryon the git repository, which document API and user
|
||||
interface changes (the latter usually documents breaking changes only, rather
|
||||
than additions).
|
||||
* The file ``mplayer-changes.rst`` in the ``DOCS`` sub directory on the git
|
||||
repository, which used to be in place of this section. It documents some
|
||||
changes that happened since mplayer2 forked off MPlayer.
|
||||
changes that happened since mplayer2 forked off MPlayer. (Not updated
|
||||
anymore.)
|
||||
+138
-191
@@ -95,7 +95,7 @@ List of Input Commands
|
||||
relative (default)
|
||||
Seek relative to current position (a negative value seeks backwards).
|
||||
absolute
|
||||
Seek to a given time.
|
||||
Seek to a given time (a negative value starts from the end of the file).
|
||||
absolute-percent
|
||||
Seek to a given percent position.
|
||||
relative-percent
|
||||
@@ -526,7 +526,7 @@ Input Commands that are Possibly Subject to Change
|
||||
``disable-section "<section>"``
|
||||
Disable the named input section. Undoes ``enable-section``.
|
||||
|
||||
``define-section "<section>" "<contents>" [default|forced]``
|
||||
``define-section "<section>" "<contents>" [default|force]``
|
||||
Create a named input section, or replace the contents of an already existing
|
||||
input section. The ``contents`` parameter uses the same syntax as the
|
||||
``input.conf`` file (except that using the section syntax in it is not
|
||||
@@ -544,7 +544,7 @@ Input Commands that are Possibly Subject to Change
|
||||
<default> (also used if parameter omitted)
|
||||
Use a key binding defined by this section only if the user hasn't
|
||||
already bound this key to a command.
|
||||
<forced>
|
||||
<force>
|
||||
Always bind a key. (The input section that was made active most recently
|
||||
wins if there are ambiguities.)
|
||||
|
||||
@@ -665,13 +665,6 @@ Input Commands that are Possibly Subject to Change
|
||||
(the ``ab-loop-a`` property); the second the ``B`` point, and the third
|
||||
will clear both points.
|
||||
|
||||
``vo-cmdline "<args>"``
|
||||
Reset the sub-option of the current VO. Currently works with ``opengl``
|
||||
(including ``opengl-hq``). The argument is the sub-option string usually
|
||||
passed to the VO on the command line. Not all sub-options can be set, but
|
||||
those which can will be reset even if they don't appear in the argument.
|
||||
This command might be changed or removed in the future.
|
||||
|
||||
``drop-buffers``
|
||||
Drop audio/video/demuxer buffers, and restart from fresh. Might help with
|
||||
unseekable streams that are going out of sync.
|
||||
@@ -698,6 +691,17 @@ Input Commands that are Possibly Subject to Change
|
||||
``af-command "<label>" "<cmd>" "<args>"``
|
||||
Same as ``vf-command``, but for audio filters.
|
||||
|
||||
``apply-profile "<name>"``
|
||||
Apply the contents of a named profile. This is like using ``profile=name``
|
||||
in a config file, except you can map it to a key binding to change it at
|
||||
runtime.
|
||||
|
||||
There is no such thing as "unapplying" a profile - applying a profile
|
||||
merely sets all option values listed within the profile.
|
||||
|
||||
``load-script "<path>"``
|
||||
Load a script, similar to the ``--script`` option.
|
||||
|
||||
Undocumented commands: ``tv-last-channel`` (TV/DVB only),
|
||||
``ao-reload`` (experimental/internal).
|
||||
|
||||
@@ -838,20 +842,12 @@ an option at runtime.
|
||||
Property list
|
||||
-------------
|
||||
|
||||
``osd-level`` (RW)
|
||||
See ``--osd-level``.
|
||||
.. note::
|
||||
|
||||
``osd-scale`` (RW)
|
||||
OSD font size multiplier, see ``--osd-scale``.
|
||||
|
||||
``loop`` (RW)
|
||||
See ``--loop``.
|
||||
|
||||
``loop-file`` (RW)
|
||||
See ``--loop-file`` (uses ``yes``/``no``).
|
||||
|
||||
``speed`` (RW)
|
||||
See ``--speed``.
|
||||
Most options can be set as runtime via properties as well. Just remove the
|
||||
leading ``--`` from the option name. These are not documented. Only
|
||||
properties which do not exist as option with the same name, or which have
|
||||
very different behavior from the options are documented below.
|
||||
|
||||
``audio-speed-correction``, ``video-speed-correction``
|
||||
Factor multiplied with ``speed`` at which the player attempts to play the
|
||||
@@ -911,9 +907,11 @@ Property list
|
||||
list of format names, e.g. mp4 is ``mov,mp4,m4a,3gp,3g2,mj2`` (the list
|
||||
may grow in the future for any format).
|
||||
|
||||
``demuxer``
|
||||
``current-demuxer``
|
||||
Name of the current demuxer. (This is useless.)
|
||||
|
||||
(Renamed from ``demuxer``.)
|
||||
|
||||
``stream-path``
|
||||
Filename (full path) of the stream layer filename. (This is probably
|
||||
useless. It looks like this can be different from ``path`` only when
|
||||
@@ -989,6 +987,12 @@ Property list
|
||||
Remaining length of the file in seconds. Note that the file duration is not
|
||||
always exactly known, so this is an estimate.
|
||||
|
||||
``audio-pts`` (R)
|
||||
Current audio playback position in current file in seconds. Unlike time-pos,
|
||||
this updates more often than once per frame. For audio-only files, it is
|
||||
mostly equivalent to time-pos, while for video-only files this property is
|
||||
not available.
|
||||
|
||||
``playtime-remaining``
|
||||
``time-remaining`` scaled by the current ``speed``.
|
||||
|
||||
@@ -1078,10 +1082,6 @@ Property list
|
||||
"title" MPV_FORMAT_STRING
|
||||
"default" MPV_FORMAT_FLAG
|
||||
|
||||
``ab-loop-a``, ``ab-loop-b`` (RW)
|
||||
Set/get A-B loop points. See corresponding options and ``ab-loop`` command
|
||||
for details.
|
||||
|
||||
``angle`` (RW)
|
||||
Current DVD angle.
|
||||
|
||||
@@ -1154,13 +1154,12 @@ Property list
|
||||
``af-metadata/<filter-label>``
|
||||
Equivalent to ``vf-metadata/<filter-label>``, but for audio filters.
|
||||
|
||||
``pause`` (RW)
|
||||
Pause status. This is usually ``yes`` or ``no``. See ``--pause``.
|
||||
|
||||
``idle``
|
||||
``idle-active``
|
||||
Return ``yes`` if no file is loaded, but the player is staying around
|
||||
because of the ``--idle`` option.
|
||||
|
||||
(Renamed from ``idle``.)
|
||||
|
||||
``core-idle``
|
||||
Return ``yes`` if the playback core is paused, otherwise ``no``. This can
|
||||
be different ``pause`` in special situations, such as when the player
|
||||
@@ -1236,25 +1235,12 @@ Property list
|
||||
is loaded, or when switching ordered chapter segments. This is because
|
||||
the same underlying code is used for seeking and resyncing.)
|
||||
|
||||
``hr-seek`` (RW)
|
||||
See ``--hr-seek``.
|
||||
|
||||
``mixer-active``
|
||||
Return ``yes`` if the audio mixer is active, ``no`` otherwise.
|
||||
|
||||
This option is relatively useless. Before mpv 0.18.1, it could be used to
|
||||
infer behavior of the ``volume`` property.
|
||||
|
||||
``volume`` (RW)
|
||||
Current volume (see ``--volume`` for details).
|
||||
|
||||
``volume-max`` (RW)
|
||||
Current maximum value the volume property can be set to. (Equivalent to the
|
||||
``--volume-max`` option.)
|
||||
|
||||
``mute`` (RW)
|
||||
Current mute status (``yes``/``no``).
|
||||
|
||||
``ao-volume`` (RW)
|
||||
System volume. This property is available only if mpv audio output is
|
||||
currently active, and only if the underlying implementation supports volume
|
||||
@@ -1266,9 +1252,6 @@ Property list
|
||||
Similar to ``ao-volume``, but controls the mute state. May be unimplemented
|
||||
even if ``ao-volume`` works.
|
||||
|
||||
``audio-delay`` (RW)
|
||||
See ``--audio-delay``.
|
||||
|
||||
``audio-codec``
|
||||
Audio codec selected for decoding.
|
||||
|
||||
@@ -1316,28 +1299,6 @@ Property list
|
||||
Same as ``audio-params``, but the format of the data written to the audio
|
||||
API.
|
||||
|
||||
``aid`` (RW)
|
||||
Current audio track (similar to ``--aid``).
|
||||
|
||||
``audio`` (RW)
|
||||
Alias for ``aid``.
|
||||
|
||||
``balance`` (RW)
|
||||
Audio channel balance. (The implementation of this feature is rather odd.
|
||||
It doesn't change the volumes of each channel, but instead sets up a pan
|
||||
matrix to mix the left and right channels.)
|
||||
|
||||
Deprecated.
|
||||
|
||||
``fullscreen`` (RW)
|
||||
See ``--fullscreen``.
|
||||
|
||||
``deinterlace`` (RW)
|
||||
See ``--deinterlace``.
|
||||
|
||||
``field-dominance`` (RW)
|
||||
See ``--field-dominance``
|
||||
|
||||
``colormatrix`` (R)
|
||||
Redirects to ``video-params/colormatrix``. This parameter (as well as
|
||||
similar ones) can be overridden with the ``format`` video filter.
|
||||
@@ -1345,42 +1306,9 @@ Property list
|
||||
``colormatrix-input-range`` (R)
|
||||
See ``colormatrix``.
|
||||
|
||||
``video-output-levels`` (RW)
|
||||
See ``--video-output-levels``,
|
||||
|
||||
``colormatrix-primaries`` (R)
|
||||
See ``colormatrix``.
|
||||
|
||||
``taskbar-progress`` (RW)
|
||||
See ``--taskbar-progress``.
|
||||
|
||||
``ontop`` (RW)
|
||||
See ``--ontop``.
|
||||
|
||||
``border`` (RW)
|
||||
See ``--border``.
|
||||
|
||||
``on-all-workspaces`` (RW)
|
||||
See ``--on-all-workspaces``. Unsetting may not work on all WMs.
|
||||
|
||||
``framedrop`` (RW)
|
||||
See ``--framedrop``.
|
||||
|
||||
``gamma`` (RW)
|
||||
See ``--gamma``.
|
||||
|
||||
``brightness`` (RW)
|
||||
See ``--brightness``.
|
||||
|
||||
``contrast`` (RW)
|
||||
See ``--contrast``.
|
||||
|
||||
``saturation`` (RW)
|
||||
See ``--saturation``.
|
||||
|
||||
``hue`` (RW)
|
||||
See ``--hue``.
|
||||
|
||||
``hwdec`` (RW)
|
||||
Reflects the ``--hwdec`` option.
|
||||
|
||||
@@ -1413,27 +1341,6 @@ Property list
|
||||
multiple interop drivers for the same hardware decoder, depending on
|
||||
platform and VO.
|
||||
|
||||
``hwdec-active``
|
||||
Deprecated. To be removed in mpv 0.20.0. Use ``hwdec-current`` instead.
|
||||
|
||||
Return ``yes`` or ``no``, depending on whether any type of hardware decoding
|
||||
is actually in use.
|
||||
|
||||
``hwdec-detected``
|
||||
Deprecated. To be removed in mpv 0.20.0.
|
||||
|
||||
If hardware decoding is active, this returns the hardware decoder in use.
|
||||
Otherwise, it returns either ``no``, or if applicable, the currently loaded
|
||||
hardware decoding API. This is known only once the VO has opened (and
|
||||
possibly later). With some VOs (like ``opengl``), this is never known in
|
||||
advance, but only when the decoder attempted to create the hw decoder
|
||||
successfully. Also, hw decoders with ``-copy`` suffix will return ``no``
|
||||
while no video is being decoded. All this reflects how detecting hw decoders
|
||||
are detected and used internally in mpv.
|
||||
|
||||
``panscan`` (RW)
|
||||
See ``--panscan``.
|
||||
|
||||
``video-format``
|
||||
Video format as string.
|
||||
|
||||
@@ -1534,6 +1441,9 @@ Property list
|
||||
These have the same values as ``video-out-params/dw`` and
|
||||
``video-out-params/dh``.
|
||||
|
||||
``video-dec-params``
|
||||
Exactly like ``video-params``, but no overrides applied.
|
||||
|
||||
``video-out-params``
|
||||
Same as ``video-params``, but after video filters have been applied. If
|
||||
there are no video filters in use, this will contain the same values as
|
||||
@@ -1556,10 +1466,12 @@ Property list
|
||||
``video-frame-info/tff``
|
||||
``video-frame-info/repeat``
|
||||
|
||||
``fps``
|
||||
``container-fps``
|
||||
Container FPS. This can easily contain bogus values. For videos that use
|
||||
modern container formats or video codecs, this will often be incorrect.
|
||||
|
||||
(Renamed from ``fps``.)
|
||||
|
||||
``estimated-vf-fps``
|
||||
Estimated/measured FPS of the video filter chain output. (If no filters
|
||||
are used, this corresponds to decoder output.) This uses the average of
|
||||
@@ -1580,7 +1492,10 @@ Property list
|
||||
|
||||
``display-names``
|
||||
Names of the displays that the mpv window covers. On X11, these
|
||||
are the xrandr names (LVDS1, HDMI1, DP1, VGA1, etc.).
|
||||
are the xrandr names (LVDS1, HDMI1, DP1, VGA1, etc.). On Windows, these
|
||||
are the GDI names (\\.\DISPLAY1, \\.\DISPLAY2, etc.) and the first display
|
||||
in the list will be the one that Windows considers associated with the
|
||||
window (as determined by the MonitorFromWindow API.)
|
||||
|
||||
``display-fps`` (RW)
|
||||
The refresh rate of the current display. Currently, this is the lowest FPS
|
||||
@@ -1600,6 +1515,9 @@ Property list
|
||||
``video-aspect`` (RW)
|
||||
Video aspect, see ``--video-aspect``.
|
||||
|
||||
If video is active, this reports the effective aspect value, instead of
|
||||
the value of the ``--video-aspect`` option.
|
||||
|
||||
``osd-width``, ``osd-height``
|
||||
Last known OSD width (can be 0). This is needed if you want to use the
|
||||
``overlay-add`` command. It gives you the actual OSD size, which can be
|
||||
@@ -1608,71 +1526,24 @@ Property list
|
||||
``osd-par``
|
||||
Last known OSD display pixel aspect (can be 0).
|
||||
|
||||
``vid`` (RW)
|
||||
Current video track (similar to ``--vid``).
|
||||
|
||||
``video`` (RW)
|
||||
Alias for ``vid``.
|
||||
|
||||
``video-align-x``, ``video-align-y`` (RW)
|
||||
See ``--video-align-x`` and ``--video-align-y``.
|
||||
|
||||
``video-pan-x``, ``video-pan-y`` (RW)
|
||||
See ``--video-pan-x`` and ``--video-pan-y``.
|
||||
|
||||
``video-zoom`` (RW)
|
||||
See ``--video-zoom``.
|
||||
|
||||
``video-unscaled`` (W)
|
||||
See ``--video-unscaled``.
|
||||
|
||||
``program`` (W)
|
||||
Switch TS program (write-only).
|
||||
|
||||
``dvb-channel`` (W)
|
||||
Pair of integers: card,channel of current DVB stream.
|
||||
Can be switched to switch to another channel on the same card.
|
||||
Can be switched to switch to another channel on the same card.
|
||||
|
||||
``dvb-channel-name`` (RW)
|
||||
Name of current DVB program.
|
||||
On write, a channel-switch to the named channel on the same
|
||||
card is performed. Can also be used for channel switching.
|
||||
card is performed. Can also be used for channel switching.
|
||||
|
||||
``sid`` (RW)
|
||||
Current subtitle track (similar to ``--sid``).
|
||||
``sub-text``
|
||||
Return the current subtitle text. Formatting is stripped. If a subtitle
|
||||
is selected, but no text is currently visible, or the subtitle is not
|
||||
text-based (i.e. DVD/BD subtitles), an empty string is returned.
|
||||
|
||||
``secondary-sid`` (RW)
|
||||
Secondary subtitle track (see ``--secondary-sid``).
|
||||
|
||||
``sub`` (RW)
|
||||
Alias for ``sid``.
|
||||
|
||||
``sub-delay`` (RW)
|
||||
See ``--sub-delay``.
|
||||
|
||||
``sub-pos`` (RW)
|
||||
See ``--sub-pos``.
|
||||
|
||||
``sub-visibility`` (RW)
|
||||
See ``--sub-visibility``.
|
||||
|
||||
``sub-forced-only`` (RW)
|
||||
See ``--sub-forced-only``.
|
||||
|
||||
``sub-scale`` (RW)
|
||||
Subtitle font size multiplier.
|
||||
|
||||
``ass-force-margins`` (RW)
|
||||
See ``--ass-force-margins``.
|
||||
|
||||
``sub-use-margins`` (RW)
|
||||
See ``--sub-use-margins``.
|
||||
|
||||
``ass-vsfilter-aspect-compat`` (RW)
|
||||
See ``--ass-vsfilter-aspect-compat``.
|
||||
|
||||
``ass-style-override`` (RW)
|
||||
See ``--ass-style-override``.
|
||||
This property is experimental and might be removed in the future.
|
||||
|
||||
``stream-capture`` (RW)
|
||||
A filename, see ``--stream-capture``. Setting this will start capture using
|
||||
@@ -1884,11 +1755,8 @@ Property list
|
||||
"title" MPV_FORMAT_STRING
|
||||
"time" MPV_FORMAT_DOUBLE
|
||||
|
||||
``af`` (RW)
|
||||
See ``--af`` and the ``af`` command.
|
||||
|
||||
``vf`` (RW)
|
||||
See ``--vf`` and the ``vf`` command.
|
||||
``af``, ``vf`` (RW)
|
||||
See ``--vf``/``--af`` and the ``vf``/``af`` command.
|
||||
|
||||
When querying the property with the client API using ``MPV_FORMAT_NODE``,
|
||||
or with Lua ``mp.get_property_native``, this will return a mpv_node with
|
||||
@@ -1906,12 +1774,6 @@ Property list
|
||||
|
||||
It's also possible to write the property using this format.
|
||||
|
||||
``video-rotate`` (RW)
|
||||
See ``--video-rotate`` option.
|
||||
|
||||
``video-stereo-mode`` (RW)
|
||||
See ``--video-stereo-mode`` option.
|
||||
|
||||
``seekable``
|
||||
Return whether it's generally possible to seek in the current file.
|
||||
|
||||
@@ -2151,6 +2013,10 @@ Property list
|
||||
require reloading the file for changes to take effect. If there is an
|
||||
equivalent property, prefer setting the property instead.
|
||||
|
||||
There shouldn't be any reason to access ``options/<name>`` instead of
|
||||
``<name>``, except in situations in which the properties have different
|
||||
behavior or conflicting semantics.
|
||||
|
||||
``file-local-options/<name>``
|
||||
Similar to ``options/<name>``, but when setting an option through this
|
||||
property, the option is reset to its old value once the current file has
|
||||
@@ -2204,6 +2070,87 @@ Property list
|
||||
``property-list``
|
||||
Return the list of top-level properties.
|
||||
|
||||
``profile-list``
|
||||
Return the list of profiles and their contents. This is highly
|
||||
implementation-specific, and may change any time. Currently, it returns
|
||||
an array of options for each profile. Each option has a name and a value,
|
||||
with the value currently always being a string. Note that the options array
|
||||
is not a map, as order matters and duplicate entries are possible. Recursive
|
||||
profiles are not expanded, and show up as special ``profile`` options.
|
||||
|
||||
Inconsistencies between options and properties
|
||||
----------------------------------------------
|
||||
|
||||
You can access (almost) all options as properties, though there are some
|
||||
caveats with some properties (due to historical reasons):
|
||||
|
||||
``vid``, ``aid``, ``sid``
|
||||
While playback is active, you can set existing tracks only. (The option
|
||||
allows setting any track ID, and which tracks to enable is chosen at
|
||||
loading time.)
|
||||
|
||||
Option changes at runtime are affected by this as well.
|
||||
|
||||
``deinterlace``
|
||||
While video is active, this behaves differently from the option. It will
|
||||
never return the ``auto`` value (but the state as observed by the video
|
||||
chain). If you set ``auto``, the property will set this as the option value,
|
||||
and will return the actual video chain state as observed instead of auto.
|
||||
|
||||
``video-aspect``
|
||||
While video is active, always returns the effective aspect ratio. Setting
|
||||
a special value (like ``no``, values ``<= 0``) will make the property
|
||||
set this as option, and return whatever actual aspect was derived from the
|
||||
option setting.
|
||||
|
||||
``brightness`` (and other color options)
|
||||
If ``--vo=xv`` is used, these properties may return the adapter's current
|
||||
values instead of the option values.
|
||||
|
||||
``display-fps``
|
||||
If a VO is created, this will return either the actual display FPS, or
|
||||
an invalid value, instead of the option value.
|
||||
|
||||
``vf``, ``af``
|
||||
If you set the properties during playback, and the filter chain fails to
|
||||
reinitialize, the new value will be rejected. Setting the option or
|
||||
setting the property outside of playback will always succeed/fail in the
|
||||
same way. Also, there are no ``vf-add`` etc. properties, but you can use
|
||||
the ``vf``/``af`` group of commands to achieve the same.
|
||||
|
||||
Option changes at runtime are affected by this as well.
|
||||
|
||||
``edition``
|
||||
While a file is loaded, the property will always return the effective
|
||||
edition, and setting the ``auto`` value will show somewhat strange behavior
|
||||
(the property eventually switching to whatever is the default edition).
|
||||
|
||||
``playlist``
|
||||
The property is read-only and returns the current internal playlist. The
|
||||
option is for loading playlist during command line parsing. For client API
|
||||
uses, you should use the ``loadlist`` command instead.
|
||||
|
||||
``window-scale``
|
||||
Might verify the set value when setting while a window is created.
|
||||
|
||||
``audio-file``, ``sub-file``, ``external-file``
|
||||
These options/properties are actually lists of filenames. To make the
|
||||
command-line interface easier, each ``--audio-file=...`` option appends
|
||||
the full string to the internal list. However, when used as properties,
|
||||
every time you set the property as a string the internal list will be
|
||||
replaced with a single entry containing the string you set. ``,`` or other
|
||||
separators are never used. You have to use ``MPV_FORMAT_NODE_ARRAY`` (or
|
||||
corresponding API, e.g. ``mp.set_property_native()`` with a table in Lua)
|
||||
to set multiple entries.
|
||||
|
||||
Strictly speaking, option access via API (e.g. ``mpv_set_option_string()``)
|
||||
has the same problem, and it's only a difference between CLI/API.
|
||||
|
||||
``demuxer``, ``idle``, ``length``, ``audio-samplerate``, ``audio-channels``, ``audio-format``, ``fps``, ``cache``, ``playlist-pos``, ``chapter``
|
||||
These behave completely different as property, but are deprecated (newer
|
||||
aliases which don't conflict have been added). After the deprecation period
|
||||
they will be changed to the proper option behavior.
|
||||
|
||||
Property Expansion
|
||||
------------------
|
||||
|
||||
|
||||
@@ -242,12 +242,16 @@ extra commands can also be used as part of the protocol:
|
||||
command.
|
||||
|
||||
``suspend``
|
||||
Deprecated, will be removed completely in 0.21.0.
|
||||
|
||||
Suspend the mpv main loop. There is a long-winded explanation of this in
|
||||
the C API function ``mpv_suspend()``. In short, this prevents the player
|
||||
from displaying the next video frame, so that you don't get blocked when
|
||||
trying to access the player.
|
||||
|
||||
``resume``
|
||||
Deprecated, will be removed completely in 0.21.0.
|
||||
|
||||
Undo one ``suspend`` call. ``suspend`` increments an internal counter, and
|
||||
``resume`` decrements it. When 0 is reached, the player is actually resumed.
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
EMBEDDING INTO OTHER PROGRAMS (LIBMPV)
|
||||
======================================
|
||||
|
||||
mpv can be embedded into other programs as video/audio playback backend. The
|
||||
recommended way to do so is using libmpv. See ``libmpv/client.h`` in the mpv
|
||||
source code repository. This provides a C API. Bindings for other languages
|
||||
might be available (see wiki).
|
||||
|
||||
Since libmpv merely allows access to underlying mechanisms that can control
|
||||
mpv, further documentation is spread over a few places:
|
||||
|
||||
- https://github.com/mpv-player/mpv/blob/master/libmpv/client.h
|
||||
- http://mpv.io/manual/master/#options
|
||||
- http://mpv.io/manual/master/#list-of-input-commands
|
||||
- http://mpv.io/manual/master/#properties
|
||||
- https://github.com/mpv-player/mpv-examples/tree/master/libmpv
|
||||
+23
-1
@@ -412,6 +412,8 @@ These also live in the ``mp`` module, but are documented separately as they
|
||||
are useful only in special situations.
|
||||
|
||||
``mp.suspend()``
|
||||
This function has been deprecated in mpv 0.21.0 (no replacement).
|
||||
|
||||
Suspend the mpv main loop. There is a long-winded explanation of this in
|
||||
the C API function ``mpv_suspend()``. In short, this prevents the player
|
||||
from displaying the next video frame, so that you don't get blocked when
|
||||
@@ -420,11 +422,15 @@ are useful only in special situations.
|
||||
Before mpv 0.17.0, this was automatically called by the event handler.
|
||||
|
||||
``mp.resume()``
|
||||
This function has been deprecated in mpv 0.21.0 (no replacement).
|
||||
|
||||
Undo one ``mp.suspend()`` call. ``mp.suspend()`` increments an internal
|
||||
counter, and ``mp.resume()`` decrements it. When 0 is reached, the player
|
||||
is actually resumed.
|
||||
|
||||
``mp.resume_all()``
|
||||
This function has been deprecated in mpv 0.21.0 (no replacement).
|
||||
|
||||
This resets the internal suspend counter and resumes the player. (It's
|
||||
like calling ``mp.resume()`` until the player is actually resumed.)
|
||||
|
||||
@@ -450,6 +456,13 @@ are useful only in special situations.
|
||||
``mp.get_wakeup_pipe()`` if you're interested in properly working
|
||||
notification of new events and working timers.
|
||||
|
||||
``mp.register_idle(fn)``
|
||||
Register an event loop idle handler. Idle handlers are called before the
|
||||
script goes to sleep after handling all new events. This can be used for
|
||||
example to delay processing of property change events: if you're observing
|
||||
multiple properties at once, you might not want to act on each property
|
||||
change, but only when all change notifications have been received.
|
||||
|
||||
``mp.enable_messages(level)``
|
||||
Set the minimum log level of which mpv message output to receive. These
|
||||
messages are normally printed to the terminal. By calling this function,
|
||||
@@ -633,7 +646,16 @@ strictly part of the guaranteed API.
|
||||
Set to ``true`` if the process has been killed by mpv as a result
|
||||
of ``cancellable`` being set to ``true``.
|
||||
|
||||
In all cases, ``mp.resume_all()`` is implicitly called.
|
||||
``utils.subprocess_detached(t)``
|
||||
Runs an external process and detaches it from mpv's control.
|
||||
|
||||
The parameter ``t`` is a table. The function reads the following entries:
|
||||
|
||||
``args``
|
||||
Array of strings of the same semantics as the ``args`` used in the
|
||||
``subprocess`` function.
|
||||
|
||||
The function returns ``nil``.
|
||||
|
||||
``utils.parse_json(str [, trail])``
|
||||
Parses the given string argument as JSON, and returns it as a Lua table. On
|
||||
|
||||
+33
-39
@@ -143,11 +143,11 @@ Ctrl + and Ctrl -
|
||||
u
|
||||
Switch between applying no style overrides to SSA/ASS subtitles, and
|
||||
overriding them almost completely with the normal subtitle style. See
|
||||
``--ass-style-override`` for more info.
|
||||
``--sub-ass-style-override`` for more info.
|
||||
|
||||
V
|
||||
Toggle subtitle VSFilter aspect compatibility mode. See
|
||||
``--ass-vsfilter-aspect-compat`` for more info.
|
||||
``--sub-ass-vsfilter-aspect-compat`` for more info.
|
||||
|
||||
r and t
|
||||
Move subtitles up/down.
|
||||
@@ -268,15 +268,16 @@ command line.
|
||||
The suboption parser can quote strings with ``"`` and ``[...]``.
|
||||
Additionally, there is a special form of quoting with ``%n%`` described below.
|
||||
|
||||
For example, the ``opengl`` VO can take multiple options:
|
||||
For example, assume the hypothetical ``foo`` filter can take multiple options:
|
||||
|
||||
``mpv test.mkv --vo=opengl:scale=lanczos:icc-profile=file.icc,xv``
|
||||
``mpv test.mkv --vf=foo:option1=value1:option2:option3=value3,bar``
|
||||
|
||||
This passes ``scale=lanczos`` and ``icc-profile=file.icc`` to ``opengl``,
|
||||
and also specifies ``xv`` as fallback VO. If the icc-profile path contains
|
||||
spaces or characters like ``,`` or ``:``, you need to quote them:
|
||||
This passes ``option1`` and ``option3`` to the ``foo`` filter, with ``option2``
|
||||
as flag (implicitly ``option2=yes``), and adds a ``bar`` filter after that. If
|
||||
an option contains spaces or characters like ``,`` or ``:``, you need to quote
|
||||
them:
|
||||
|
||||
``mpv '--vo=opengl:icc-profile="file with spaces.icc",xv'``
|
||||
``mpv '--vf=foo:option1="option value with spaces",bar'``
|
||||
|
||||
Shells may actually strip some quotes from the string passed to the commandline,
|
||||
so the example quotes the string twice, ensuring that mpv receives the ``"``
|
||||
@@ -297,11 +298,11 @@ It is started with ``%`` and has the following format::
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``mpv --ao=pcm:file=%10%C:test.wav test.avi``
|
||||
``mpv '--vf=foo:option1=%11%quoted text' test.avi``
|
||||
|
||||
Or in a script:
|
||||
|
||||
``mpv --ao=pcm:file=%`expr length "$NAME"`%"$NAME" test.avi``
|
||||
``mpv --vf=foo:option1=%`expr length "$NAME"`%"$NAME" test.avi``
|
||||
|
||||
Suboptions passed to the client API are also subject to escaping. Using
|
||||
``mpv_set_option_string()`` is exactly like passing ``--name=data`` to the
|
||||
@@ -309,8 +310,7 @@ command line (but without shell processing of the string). Some options
|
||||
support passing values in a more structured way instead of flat strings, and
|
||||
can avoid the suboption parsing mess. For example, ``--vf`` supports
|
||||
``MPV_FORMAT_NODE``, which lets you pass suboptions as a nested data structure
|
||||
of maps and arrays. (``--vo`` supports this in the same way, although this
|
||||
fact is undocumented.)
|
||||
of maps and arrays.
|
||||
|
||||
Paths
|
||||
-----
|
||||
@@ -528,7 +528,8 @@ profile name ``default`` to continue with normal options.
|
||||
|
||||
[slow]
|
||||
profile-desc="some profile name"
|
||||
vo=opengl:scale=ewa_lanczos:scale-radius=16
|
||||
# reference a builtin profile
|
||||
profile=opengl-hq
|
||||
|
||||
[fast]
|
||||
vo=vdpau
|
||||
@@ -549,10 +550,6 @@ Some profiles are loaded automatically. The following example demonstrates this:
|
||||
|
||||
::
|
||||
|
||||
[vo.vdpau]
|
||||
# Use hardware decoding
|
||||
hwdec=vdpau
|
||||
|
||||
[protocol.dvd]
|
||||
profile-desc="profile for dvd:// streams"
|
||||
alang=en
|
||||
@@ -561,11 +558,7 @@ Some profiles are loaded automatically. The following example demonstrates this:
|
||||
profile-desc="profile for .flv files"
|
||||
vf=flip
|
||||
|
||||
[ao.alsa]
|
||||
device=spdif
|
||||
|
||||
The profile name follows the schema ``type.name``, where type can be ``vo``
|
||||
to match the value the ``--vo`` option is set to, ``ao`` for ``--ao``,
|
||||
The profile name follows the schema ``type.name``, where type can be
|
||||
``protocol`` for the input/output protocol in use (see ``--list-protocols``),
|
||||
and ``extension`` for the extension of the path of the currently played file
|
||||
(*not* the file format).
|
||||
@@ -688,7 +681,7 @@ PROTOCOLS
|
||||
``mf://[filemask|@listfile]`` ``--mf-...``
|
||||
Play a series of images as video.
|
||||
|
||||
``cdda://track[-endtrack][:speed][/device]`` ``--cdrom-device=PATH`` ``--cdda-...``
|
||||
``cdda://[device]`` ``--cdrom-device=PATH`` ``--cdda-...``
|
||||
Play CD.
|
||||
|
||||
``lavf://...``
|
||||
@@ -743,24 +736,32 @@ Currently this happens only in the following cases:
|
||||
or file associations provided by desktop environments)
|
||||
- if started from explorer.exe on Windows (technically, if it was started on
|
||||
Windows, and all of the stdout/stderr/stdin handles are unset)
|
||||
- manually adding ``--profile=pseudo-gui`` to the command line
|
||||
- started out of the bundle on OSX
|
||||
- if you manually use ``--player-operation-mode=pseudo-gui`` on the command line
|
||||
|
||||
This mode implicitly adds ``--profile=pseudo-gui`` to the command line, with
|
||||
the ``pseudo-gui`` profile being predefined with the following contents:
|
||||
This mode applies options from the builtin profile ``builtin-pseudo-gui``, but
|
||||
only if these haven't been set in the user's config file or on the command line.
|
||||
Also, for compatibility with the old pseudo-gui behavior, the options in the
|
||||
``pseudo-gui`` profile are applied unconditionally. In addition, the profile
|
||||
makes sure to enable the pseudo-GUI mode, so that ``--profile=pseudo-gui``
|
||||
works like in older mpv releases. The profiles are currently defined as follows:
|
||||
|
||||
::
|
||||
|
||||
[pseudo-gui]
|
||||
[builtin-pseudo-gui]
|
||||
terminal=no
|
||||
force-window=yes
|
||||
idle=once
|
||||
screenshot-directory=~~desktop/
|
||||
[pseudo-gui]
|
||||
player-operation-mode=pseudo-gui
|
||||
|
||||
This follows the mpv config file format. To customize pseudo-GUI mode, you can
|
||||
put your own ``pseudo-gui`` profile into your ``mpv.conf``. This profile will
|
||||
enhance the default profile, rather than overwrite it.
|
||||
.. warning::
|
||||
|
||||
The profile always overrides other settings in ``mpv.conf``.
|
||||
Currently, you can extend the ``pseudo-gui`` profile in the config file the
|
||||
normal way. This is deprecated. In future mpv releases, the behavior might
|
||||
change, and not apply your additional settings, and/or use a different
|
||||
profile name.
|
||||
|
||||
|
||||
.. include:: options.rst
|
||||
@@ -785,14 +786,7 @@ The profile always overrides other settings in ``mpv.conf``.
|
||||
|
||||
.. include:: changes.rst
|
||||
|
||||
|
||||
EMBEDDING INTO OTHER PROGRAMS (LIBMPV)
|
||||
======================================
|
||||
|
||||
mpv can be embedded into other programs as video/audio playback backend. The
|
||||
recommended way to do so is using libmpv. See ``libmpv/client.h`` in the mpv
|
||||
source code repository. This provides a C API. Bindings for other languages
|
||||
might be available (see wiki).
|
||||
.. include:: libmpv.rst
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
=====================
|
||||
|
||||
+1219
-175
File diff suppressed because it is too large.
Load diff
+53
-63
@@ -20,22 +20,25 @@ The Interface
|
||||
|
||||
::
|
||||
|
||||
+------------------+-----------+--------------------+
|
||||
| playlist prev | title | playlist next |
|
||||
+-------+------+---+--+------+-+----+------+--------+
|
||||
| audio | skip | seek | | seek | skip | full |
|
||||
+-------+ back | back | play | frwd | frwd | screen |
|
||||
| sub | | | | | | |
|
||||
+-------+------+------+------+------+------+--------+
|
||||
| seekbar |
|
||||
+----------------+--------------+-------------------+
|
||||
| time passed | cache status | time remaining |
|
||||
+----------------+--------------+-------------------+
|
||||
+---------+----------+----------------------------+-------------+
|
||||
| pl prev | pl next | title | cache |
|
||||
+------+--+---+------+---------+-----------+------+-------+-----+
|
||||
| play | skip | skip | time | seekbar | time | audio | sub |
|
||||
| | back | frwd | elapsed | | left | | |
|
||||
+------+------+------+---------+-----------+------+-------+-----+
|
||||
|
||||
|
||||
playlist prev
|
||||
pl prev
|
||||
============= ================================================
|
||||
left-click play previous file in playlist
|
||||
right-click show playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
pl next
|
||||
============= ================================================
|
||||
left-click play next file in playlist
|
||||
right-click show playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
@@ -47,55 +50,33 @@ title
|
||||
right-click show filename
|
||||
============= ================================================
|
||||
|
||||
playlist next
|
||||
============= ================================================
|
||||
left-click play next file in playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
audio and sub
|
||||
| Displays selected track and amount of available tracks
|
||||
|
||||
============= ================================================
|
||||
left-click cycle audio/sub tracks forward
|
||||
right-click cycle audio/sub tracks backwards
|
||||
shift+L-click show available audio/sub tracks
|
||||
============= ================================================
|
||||
|
||||
skip back
|
||||
============= ================================================
|
||||
left-click go to beginning of chapter / previous chapter
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
seek back
|
||||
============= ================================================
|
||||
left-click skip back 5 seconds
|
||||
right-click skip back 30 seconds
|
||||
shift-L-click skip back 1 frame
|
||||
============= ================================================
|
||||
cache
|
||||
| Shows current cache fill status
|
||||
|
||||
play
|
||||
============= ================================================
|
||||
left-click toggle play/pause
|
||||
============= ================================================
|
||||
|
||||
seek frwd
|
||||
skip back
|
||||
============= ================================================
|
||||
left-click skip forward 10 seconds
|
||||
right-click skip forward 60 seconds
|
||||
shift-L-click skip forward 1 frame
|
||||
left-click go to beginning of chapter / previous chapter
|
||||
right-click show chapters
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
skip frwd
|
||||
============= ================================================
|
||||
left-click go to next chapter
|
||||
right-click show chapters
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
fullscreen
|
||||
time elapsed
|
||||
| Shows current playback position timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle fullscreen
|
||||
left-click toggle displaying timecodes with milliseconds
|
||||
============= ================================================
|
||||
|
||||
seekbar
|
||||
@@ -105,23 +86,22 @@ seekbar
|
||||
left-click seek to position
|
||||
============= ================================================
|
||||
|
||||
time passed
|
||||
| Shows current playback position timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle displaying timecodes with milliseconds
|
||||
============= ================================================
|
||||
|
||||
cache status
|
||||
| Shows current cache fill status (only visible when below 45%)
|
||||
|
||||
time remaining
|
||||
time left
|
||||
| Shows remaining playback time timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle between total and remaining time
|
||||
============= ================================================
|
||||
|
||||
audio and sub
|
||||
| Displays selected track and amount of available tracks
|
||||
|
||||
============= ================================================
|
||||
left-click cycle audio/sub tracks forward
|
||||
right-click cycle audio/sub tracks backwards
|
||||
shift+L-click show available audio/sub tracks
|
||||
============= ================================================
|
||||
|
||||
Key Bindings
|
||||
~~~~~~~~~~~~
|
||||
|
||||
@@ -176,11 +156,11 @@ Configurable Options
|
||||
| Enable the OSC when fullscreen
|
||||
|
||||
``scalewindowed``
|
||||
| Default: 1.0
|
||||
| Default: 1.5
|
||||
| Scale factor of the OSC when windowed
|
||||
|
||||
``scalefullscreen``
|
||||
| Default: 1.0
|
||||
| Default: 1.5
|
||||
| Scale factor of the OSC when fullscreen
|
||||
|
||||
``scaleforcedwindow``
|
||||
@@ -200,6 +180,10 @@ Configurable Options
|
||||
| Default: 0.0
|
||||
| Horizontal alignment, -1 (left) to 1 (right)
|
||||
|
||||
``barmargin``
|
||||
| Default: 0
|
||||
| Margin from bottom (bottombar) or top (topbar), in pixels
|
||||
|
||||
``boxalpha``
|
||||
| Default: 80
|
||||
| Alpha of the background box, 0 (opaque) to 255 (fully transparent)
|
||||
@@ -214,27 +198,33 @@ Configurable Options
|
||||
| Duration of fade out in ms, 0 = no fade
|
||||
|
||||
``deadzonesize``
|
||||
| Default: 0
|
||||
| Default: 1
|
||||
| Size of the deadzone. The deadzone is an area that makes the mouse act
|
||||
like leaving the window. Movement there won't make the OSC show up and
|
||||
it will hide immediately if the mouse enters it. The deadzone starts
|
||||
at the window border opposite to the OSC and the size controls how much
|
||||
of the window it will span. Values between 0 and 1.
|
||||
of the window it will span. Values between 0 and 1, where 0 means the
|
||||
OSC will always popup with mouse movement in the window, and 1 means the
|
||||
OSC will only show up when the mouse hovers it.
|
||||
|
||||
``minmousemove``
|
||||
| Default: 3
|
||||
| Default: 0
|
||||
| Minimum amount of pixels the mouse has to move between ticks to make
|
||||
the OSC show up
|
||||
|
||||
``layout``
|
||||
| Default: box
|
||||
| Default: bottombar
|
||||
| The layout for the OSC. Currently available are: box, slimbox,
|
||||
bottombar and topbar.
|
||||
|
||||
``seekbarstyle``
|
||||
| Default: slider
|
||||
| Default: bar
|
||||
| Sets the style of the seekbar, slider (diamond marker) or bar (fill)
|
||||
|
||||
``tooltipborder``
|
||||
| Default: 1
|
||||
| Size of the tooltip outline when using bottombar or topbar layouts
|
||||
|
||||
``timetotal``
|
||||
| Default: no
|
||||
| Show total time instead of time remaining
|
||||
|
||||
+117
-953
File diff suppressed because it is too large.
Load diff
@@ -7,8 +7,8 @@ large part of which is incompatible or completely changes how the player
|
||||
behaves. Although there are still many similarities to its ancestors, **mpv**
|
||||
should generally be treated as a completely different program.
|
||||
|
||||
.. note::
|
||||
These lists are incomplete.
|
||||
.. admonition:: Warning
|
||||
This document is not updated anymore, and is incomplete and outdated.
|
||||
|
||||
General Changes from MPlayer to mpv
|
||||
-----------------------------------
|
||||
@@ -262,13 +262,14 @@ Command Line Switches
|
||||
``-ssf <sub>`` ``--sws-...``
|
||||
``-stop-xscreensaver`` ``--stop-screensaver``
|
||||
``-sub-fuzziness`` ``--sub-auto``
|
||||
``-sub-text-*`` ``--sub-*``
|
||||
``-sub`` ``--sub-file``
|
||||
``-subcp`` ``--sub-codepage``
|
||||
``-subdelay`` ``--sub-delay``
|
||||
``-subfile`` ``--sub-file``
|
||||
``-subfont-*`` ``--sub-text-*``, ``--osd-*``
|
||||
``-subfont-*`` ``--sub-*``, ``--osd-*``
|
||||
``-subfont-text-scale`` ``--sub-scale``
|
||||
``-subfont`` ``--sub-text-font``
|
||||
``-subfont`` ``--sub-font``
|
||||
``-subfps`` ``--sub-fps``
|
||||
``-subpos`` ``--sub-pos``
|
||||
``-sws`` ``--sws-scaler``
|
||||
|
||||
+209
@@ -1,3 +1,212 @@
|
||||
Release 0.21.0
|
||||
==============
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- config: allow profile forward-references in default profile
|
||||
- demux_lavf: "support" mov edit lists and log errors if used (FFmpeg only)
|
||||
- hwdec: Add support for CUDA and cuvid/NvDecode (mostly useful on Linux where VDPAU still lacks HEVC Main 10 support; keep using DXVA2 on Windows)
|
||||
- osc: add right-click behavior to playlist and chapter buttons
|
||||
- osc: add user-alterable margin for top/bottombar
|
||||
- rpi: add --hwdec=rpi-copy (#3604)
|
||||
- sd_lavc: enable teletext
|
||||
- vaapi: support drm devices when running in vaapi-copy mode
|
||||
- vd_lavc: Add hwdec wrapper for crystalhd
|
||||
- vo_opengl: add hw overlay support and use it for RPI
|
||||
- vo_opengl: basic mali fbdev support
|
||||
- vo_opengl: rpi: merge vo_rpi features
|
||||
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- vo_opengl: remove pre/post/scale-shaders in favor of user-shaders
|
||||
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
||||
- config: deprecate ao and vo auto-profiles
|
||||
- vo_rpi: deprecate this VO
|
||||
|
||||
|
||||
Options and Commands
|
||||
--------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- add --teletext-page option
|
||||
- af_pan: add af-command support to change the matrix
|
||||
- af_rubberband: add af-command and option to change the pitch
|
||||
- command: add a load-script command
|
||||
- command: add a video-dec-params property
|
||||
- command: add an apply-profile command
|
||||
- command: add audio-pts property to get the audio pts
|
||||
- command: add options to property list
|
||||
- command: add sub-text property for current subtitle text
|
||||
- command: export profile list as a property (#977)
|
||||
- options: add --hwdec=yes as alias for --hwdec=auto
|
||||
- player: add --player-operation-mode=pseudo-gui
|
||||
- player: add --video-osd=no option to disable video OSD (#3387)
|
||||
- player: add --watch-later-directory option
|
||||
- stream_bluray: select title by playlist (bd://mpls/[playlist])
|
||||
- vo_opengl: disable glFlush() by default, and add an option to enable it for testing
|
||||
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- af_rubberband: default to channels=together
|
||||
- command: allow absolute seeks relative to end of stream
|
||||
- command: make bitrate properties observable
|
||||
- command: make most options observable
|
||||
- msg: make --log-file and --dump-stats accept config path expansion (#3591)
|
||||
- options: deprecate --playlist-pos to --playlist-start
|
||||
- options: make input options generally runtime-settable
|
||||
- options: rename subtitle options (--sub-text- → --sub; --ass- → --sub-ass-)
|
||||
- osc: change default layout to bottombar, seekbarstyle to bar, use larger scalewindowed and scalefullscreen
|
||||
- player: make --terminal, --log-file, --dump-stats, --osc, --ytdl, --audio-*, --priority, --stop-screensaver (#3615) settable at runtime
|
||||
- vo_drm: change CLI options
|
||||
- Change connector selection to accept human readable names (such as eDP-1, HDMI-A-2) rather than arbitrary numbers.
|
||||
- Change GPU selection to accept GPU number rather than device paths.
|
||||
- Merge connector and GPU selection into one --drm-connector.
|
||||
- Add support for --drm-connector=help.
|
||||
- Add support for --drm-* in EGL backend.
|
||||
- vo_opengl: rename 3dlut-size to icc-3dlut-size
|
||||
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- command: remove hwdec-active and hwdec-detected properties
|
||||
- command: remove vo-cmdline
|
||||
- options: drop unreferenced --bluray-angle option
|
||||
- vo, ao: disable positional parameter suboptions
|
||||
- vo_xv: replace no-colorkey with ck-method=none
|
||||
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
||||
- all VOs and AOs: deprecate sub-options, add them as global options
|
||||
- command: deprecate "cache" property, replace with "cache-percent"
|
||||
- deprecate --vo-defaults
|
||||
- deprecate --vo=opengl-hq alias in favor of opengl-hq profile
|
||||
- options: deprecate --mute=auto
|
||||
- vo_direct3d: deprecate direct3d_shaders alias, use shaders by default
|
||||
- vo_opengl: deprecate 'drm-egl' backend and introduce 'drm' instead
|
||||
|
||||
|
||||
Fixes and Minor Enhancements
|
||||
----------------------------
|
||||
|
||||
- TOOLS/zsh.pl: die if we can't parse main options
|
||||
- TOOLS/zsh.pl: don't filter files by extension (#2273)
|
||||
- ao_alsa: try to fallback to "hdmi" before "iec958" for spdif
|
||||
- ao_rsound: fix compilation (#3501)
|
||||
- aspect: use nominal width instead of actual width for video-unscaled
|
||||
- audio/out: prevent underruns with spdif under certain conditions
|
||||
- audio: fix late audio start (#3610)
|
||||
- audio: fix missed wakeup when changing audio output device
|
||||
- audio: fix segfault when yanking USB DAC
|
||||
- charset_conv: Use CP949 instead of EUC-KR
|
||||
- command: don't log "ignore" command with -v verbosity
|
||||
- command: try selecting the next track if track switching fails (#3446)
|
||||
- demux_mkv: don't crash if --ordered-chapters-files fails
|
||||
- displayconfig: treat a refresh rate of 1 as invalid
|
||||
- ipc: log when listening to IPC socket (#3598)
|
||||
- macOS: fix fullscreen regression on 10.11 and newer (#3364)
|
||||
- mp_image: fix clearing to black with p010 format
|
||||
- osc: Fix scaling issues when toggling fullscreen (#3429)
|
||||
- osc: align text vertically in top/bottombar (#2093)
|
||||
- osc: change seekbar background's alpha scaling
|
||||
- osc: fix display of chapters and playlist scaling
|
||||
- osc: move tooltip to inside seekbar for top/bottombar
|
||||
- osc: show playlist/chapter list on prev/next instead of osd
|
||||
- path: default ~~ paths to home directory (#3591)
|
||||
- player: do not let pseudo-gui override user config settings
|
||||
- player: enable reading from stdin after loading input.conf
|
||||
- player: fix instant subtitle refresh on track switches
|
||||
- player: make --force-window work with opengl-cb
|
||||
- stream_file: don't use poll() on directories (would hang on macOS; #3530, #3649)
|
||||
- stream_lavf: fix determining seekability (#1701)
|
||||
- sub: actually apply text alignment options to non-ASS subtitles
|
||||
- terminal-win: support modifier keys in console input (#3625)
|
||||
- vo_drm: fix segfault when using invalid card
|
||||
- vo_opengl: apply 90° rotation to chroma texture size (#3568)
|
||||
- vo_opengl: fix incorrect video rendering after vdpau preemption recovery
|
||||
- vo_opengl: partially fix dumb-mode cropping with rotation
|
||||
- vo_opengl: rpi: use overlay for yuv420p too
|
||||
- w32_common: initialize playback status as soon as possible (#3482)
|
||||
- wayland: reject resize events with either dimension being 0 (#3679)
|
||||
- x11: fix external fullscreen update (#3570)
|
||||
- ytdl_hook: Add title to playlist items if available
|
||||
- ytdl_hook: Set aspect ratio for anamorphic video
|
||||
- ytdl_hook: Support playlist entries without subtitles
|
||||
- ytdl_hook: add chapters by parsing video's description
|
||||
- ytdl_hook: don't add subtitles with unknown duration
|
||||
- ytdl_hook: temporarily force disable dash segments formats
|
||||
|
||||
|
||||
This listing is not complete. Check DOCS/client-api-changes.rst for a history
|
||||
of changes to the client API, and DOCS/interface-changes.rst for a history
|
||||
of changes to other user-visible interfaces.
|
||||
|
||||
A complete changelog can be seen by running `git log v0.20.0..v0.21.0`
|
||||
in the git repository or by visiting either
|
||||
https://github.com/mpv-player/mpv/compare/v0.20.0...v0.21.0 or
|
||||
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.20.0..v0.21.0
|
||||
|
||||
|
||||
Release 0.20.0
|
||||
==============
|
||||
|
||||
Options and Commands
|
||||
--------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- aspect: add --video-unscaled=downscale-big
|
||||
- player: add --image-display-duration option to control duration of image display (#3425)
|
||||
- vo_opengl: angle: new flag (dcomposition) to control DirectComposition
|
||||
- command: add sub-speed property
|
||||
|
||||
|
||||
Fixes and Minor Enhancements
|
||||
----------------------------
|
||||
|
||||
- af_lavrresample: fix error if resampler could not be recreated
|
||||
- audio: avoid missed wakeups with ab-loops
|
||||
- audio: do not apply --audio-channels if spdif passthrough is in use (#3445)
|
||||
- cache: don't use a backbuffer if the cache is as large as the file
|
||||
- command: prevent O(n^2) behaviour for playlist property
|
||||
- demux: close underlying stream if it's fully read anyway (#3456)
|
||||
- demux: fix undefined behavior with ogg metadata update (#3451)
|
||||
- player: make looping slightly more seamless
|
||||
- player: refresh very low framerate video on filter changes (#3435)
|
||||
- stream_memory: disable stream cache
|
||||
- vf_rotate: allow arbitrary rotation (#3434)
|
||||
- vo: be more trusting to estimated display FPS (#3433)
|
||||
- w32_common: use hooks to detect parent window resize
|
||||
- x11: work around mutter fullscreen issue (#2072)
|
||||
|
||||
|
||||
This listing is not complete. Check DOCS/client-api-changes.rst for a history
|
||||
of changes to the client API, and DOCS/interface-changes.rst for a history
|
||||
of changes to other user-visible interfaces.
|
||||
|
||||
A complete changelog can be seen by running `git log v0.19.0..v0.20.0`
|
||||
in the git repository or by visiting either
|
||||
https://github.com/mpv-player/mpv/compare/v0.19.0...v0.20.0 or
|
||||
http://git.srsfckn.biz/mpv/log/?qt=range&q=v0.19.0..v0.20.0
|
||||
|
||||
|
||||
Release 0.19.0
|
||||
==============
|
||||
|
||||
|
||||
@@ -6,9 +6,17 @@
|
||||
|
||||
local utils = require("mp.utils")
|
||||
|
||||
for i,name in ipairs(mp.get_property_native("property-list")) do
|
||||
function observe(name)
|
||||
mp.observe_property(name, "native", function(name, val)
|
||||
print("property '" .. name .. "' changed to '" ..
|
||||
utils.to_string(val) .. "'")
|
||||
end)
|
||||
end
|
||||
|
||||
for i,name in ipairs(mp.get_property_native("property-list")) do
|
||||
observe(name)
|
||||
end
|
||||
|
||||
for i,name in ipairs(mp.get_property_native("options")) do
|
||||
observe("options/" .. name)
|
||||
end
|
||||
@@ -1 +1 @@
|
||||
profile=pseudo-gui
|
||||
player-operation-mode=pseudo-gui
|
||||
+6
-5
@@ -151,15 +151,16 @@ for cur in ax:
|
||||
cur.addLegend(offset = (-1, 1))
|
||||
for e in G.sevents:
|
||||
cur = ax[1 if e.type == "value" else 0]
|
||||
if not cur in G.curveno:
|
||||
G.curveno[cur] = 0
|
||||
args = {'name': e.name,'antialias':True}
|
||||
color = mkColor(colors[G.curveno[cur] % len(colors)])
|
||||
if e.type == "event-signal":
|
||||
args['symbol'] = e.marker
|
||||
args['pen'] = None
|
||||
args['symbolBrush'] = pg.mkBrush(color, width=0)
|
||||
else:
|
||||
if not cur in G.curveno:
|
||||
G.curveno[cur] = 0
|
||||
args['pen'] = pg.mkPen(mkColor(colors[G.curveno[cur] % len(colors)]), width=0)
|
||||
G.curveno[cur] += 1
|
||||
args['pen'] = pg.mkPen(color, width=0)
|
||||
G.curveno[cur] += 1
|
||||
n = cur.plot([x for x,y in e.vals], [y for x,y in e.vals], **args)
|
||||
|
||||
QtGui.QApplication.instance().exec_()
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "x$LIBAV" != "xffmpeg-git" ] || [ "x$TRAVIS_OS_NAME" != "xlinux" ]; then
|
||||
# trigger build only on one of the matrix nodes
|
||||
exit;
|
||||
fi
|
||||
|
||||
if [ "x$TRAVIS_BRANCH" != "xmaster" ]; then
|
||||
# only rebuild website with pushes to master
|
||||
exit;
|
||||
fi
|
||||
|
||||
TRAVIS_COMMIT_RANGE=${TRAVIS_COMMIT_RANGE:-HEAD^..}
|
||||
if git diff --quiet --name-only --exit-code "$TRAVIS_COMMIT_RANGE" DOCS/; then
|
||||
exit;
|
||||
fi
|
||||
|
||||
body='{
|
||||
"request": {
|
||||
"branch":"master"
|
||||
}}'
|
||||
|
||||
curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Travis-API-Version: 3" \
|
||||
-H "Authorization: token $WEBSITE_TRAVIS_TOKEN" \
|
||||
-d "$body" \
|
||||
https://api.travis-ci.org/repo/mpv-player%2Fmpv.io/requests
|
||||
+4
-2
@@ -4,11 +4,14 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use warnings FATAL => 'uninitialized';
|
||||
|
||||
my $mpv = $ARGV[0] || 'mpv';
|
||||
|
||||
my @opts = parse_main_opts('--list-options', '^ (\-\-[^\s\*]*)\*?\s*(.*)');
|
||||
|
||||
die "Couldn't find any options" unless (@opts);
|
||||
|
||||
my @ao = parse_opts('--ao=help', '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @vo = parse_opts('--vo=help', '^ ([^\s\:]*)\s*: (.*)');
|
||||
|
||||
@@ -141,8 +144,7 @@ $runtime_completions
|
||||
local expl
|
||||
_tags files urls
|
||||
while _tags; do
|
||||
_requested files expl 'media file' _files -g \\
|
||||
"*.(#i)(asf|asx|avi|f4v|flac|flv|m1v|m2p|m2v|m4v|mjpg|mka|mkv|mov|mp3|mp4|mpe|mpeg|mpg|ogg|ogm|ogv|opus|qt|rm|ts|vob|wav|webm|wma|wmv|wv)(-.)" && rc=0
|
||||
_requested files expl 'media file' _files && rc=0
|
||||
if _requested urls; then
|
||||
while _next_label urls expl URL; do
|
||||
_urls "\$expl[@]" && rc=0
|
||||
|
||||
@@ -86,7 +86,7 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
struct priv *ctx = talloc_zero(NULL, struct priv);
|
||||
da->priv = ctx;
|
||||
|
||||
ctx->codec_timebase = (AVRational){0};
|
||||
ctx->codec_timebase = mp_get_codec_timebase(da->codec);
|
||||
|
||||
ctx->force_channel_map = c->force_channels;
|
||||
|
||||
@@ -104,6 +104,10 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
lavc_context->codec_id = lavc_codec->id;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MICRO >= 100
|
||||
lavc_context->pkt_timebase = ctx->codec_timebase;
|
||||
#endif
|
||||
|
||||
if (opts->downmix && mpopts->audio_output_channels.num_chmaps == 1) {
|
||||
lavc_context->request_channel_layout =
|
||||
mp_chmap_to_lavc(&mpopts->audio_output_channels.chmaps[0]);
|
||||
@@ -241,7 +245,8 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
|
||||
if (!got_frame)
|
||||
return 0;
|
||||
|
||||
double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, &priv->codec_timebase);
|
||||
double out_pts = mp_pts_from_av(MP_AVFRAME_DEC_PTS(priv->avframe),
|
||||
&priv->codec_timebase);
|
||||
|
||||
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
|
||||
if (!mpframe)
|
||||
|
||||
@@ -180,10 +180,14 @@ static void fix_audio_pts(struct dec_audio *da)
|
||||
|
||||
if (da->current_frame->pts != MP_NOPTS_VALUE) {
|
||||
double newpts = da->current_frame->pts;
|
||||
|
||||
if (da->pts != MP_NOPTS_VALUE)
|
||||
MP_STATS(da, "value %f audio-pts-err", da->pts - newpts);
|
||||
|
||||
// Keep the interpolated timestamp if it doesn't deviate more
|
||||
// than 1 ms from the real one. (MKV rounded timestamps.)
|
||||
if (da->pts == MP_NOPTS_VALUE || fabs(da->pts - newpts) > 0.001)
|
||||
da->pts = da->current_frame->pts;
|
||||
da->pts = newpts;
|
||||
}
|
||||
|
||||
if (da->pts == MP_NOPTS_VALUE && da->header->missing_timestamps)
|
||||
|
||||
+10
-4
@@ -166,10 +166,10 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
|
||||
.replaygain_data = s->replaygain_data,
|
||||
.out_pool = mp_audio_pool_create(af),
|
||||
};
|
||||
struct m_config *config = m_config_from_obj_desc(af, s->log, &desc);
|
||||
if (m_config_apply_defaults(config, name, s->opts->af_defs) < 0)
|
||||
goto error;
|
||||
if (m_config_set_obj_params(config, args) < 0)
|
||||
struct m_config *config =
|
||||
m_config_from_obj_desc_and_args(af, s->log, NULL, &desc,
|
||||
name, s->opts->af_defs, args);
|
||||
if (!config)
|
||||
goto error;
|
||||
af->priv = config->optstruct;
|
||||
|
||||
@@ -779,6 +779,12 @@ struct mp_audio *af_read_output_frame(struct af_stream *s)
|
||||
return af_dequeue_output_frame(s->last);
|
||||
}
|
||||
|
||||
void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame)
|
||||
{
|
||||
struct af_instance *af = s->last;
|
||||
MP_TARRAY_INSERT_AT(af, af->out_queued, af->num_out_queued, 0, frame);
|
||||
}
|
||||
|
||||
// Make sure the caller can change data referenced by the frame.
|
||||
// Return negative error code on failure (i.e. you can't write).
|
||||
int af_make_writeable(struct af_instance *af, struct mp_audio *frame)
|
||||
|
||||
@@ -148,6 +148,7 @@ void af_add_output_frame(struct af_instance *af, struct mp_audio *frame);
|
||||
int af_filter_frame(struct af_stream *s, struct mp_audio *frame);
|
||||
int af_output_frame(struct af_stream *s, bool eof);
|
||||
struct mp_audio *af_read_output_frame(struct af_stream *s);
|
||||
void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame);
|
||||
int af_make_writeable(struct af_instance *af, struct mp_audio *frame);
|
||||
|
||||
double af_calc_delay(struct af_stream *s);
|
||||
|
||||
@@ -99,10 +99,6 @@ static double get_delay(struct af_resample *s)
|
||||
return avresample_get_delay(s->avrctx) / (double)s->in_rate +
|
||||
avresample_available(s->avrctx) / (double)s->out_rate;
|
||||
}
|
||||
static void drop_all_output(struct af_resample *s)
|
||||
{
|
||||
while (avresample_read(s->avrctx, NULL, 1000) > 0) {}
|
||||
}
|
||||
static int get_out_samples(struct af_resample *s, int in_samples)
|
||||
{
|
||||
return avresample_get_out_samples(s->avrctx, in_samples);
|
||||
@@ -113,10 +109,6 @@ static double get_delay(struct af_resample *s)
|
||||
int64_t base = s->in_rate * (int64_t)s->out_rate;
|
||||
return swr_get_delay(s->avrctx, base) / (double)base;
|
||||
}
|
||||
static void drop_all_output(struct af_resample *s)
|
||||
{
|
||||
while (swr_drop_output(s->avrctx, 1000) > 0) {}
|
||||
}
|
||||
static int get_out_samples(struct af_resample *s, int in_samples)
|
||||
{
|
||||
#if LIBSWRESAMPLE_VERSION_MAJOR > 1 || LIBSWRESAMPLE_VERSION_MINOR >= 2
|
||||
@@ -406,8 +398,17 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_RESET:
|
||||
if (s->avrctx)
|
||||
drop_all_output(s);
|
||||
if (s->avrctx) {
|
||||
#if HAVE_LIBSWRESAMPLE
|
||||
swr_close(s->avrctx);
|
||||
if (swr_init(s->avrctx) < 0) {
|
||||
close_lavrr(af);
|
||||
return AF_ERROR;
|
||||
}
|
||||
#else
|
||||
while (avresample_read(s->avrctx, NULL, 1000) > 0) {}
|
||||
#endif
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
@@ -479,19 +480,20 @@ static void reorder_planes(struct mp_audio *mpa, int *reorder,
|
||||
static int filter_resample(struct af_instance *af, struct mp_audio *in)
|
||||
{
|
||||
struct af_resample *s = af->priv;
|
||||
struct mp_audio *out = NULL;
|
||||
|
||||
if (!s->avrctx)
|
||||
goto error;
|
||||
|
||||
int samples = get_out_samples(s, in ? in->samples : 0);
|
||||
|
||||
struct mp_audio out_format = s->pool_fmt;
|
||||
struct mp_audio *out = mp_audio_pool_get(af->out_pool, &out_format, samples);
|
||||
out = mp_audio_pool_get(af->out_pool, &out_format, samples);
|
||||
if (!out)
|
||||
goto error;
|
||||
if (in)
|
||||
mp_audio_copy_attributes(out, in);
|
||||
|
||||
if (!s->avrctx)
|
||||
goto error;
|
||||
|
||||
if (out->samples) {
|
||||
out->samples = resample_frame(s->avrctx, out, in);
|
||||
if (out->samples < 0)
|
||||
|
||||
+138
-124
@@ -28,12 +28,11 @@
|
||||
#include "af.h"
|
||||
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_pan_s
|
||||
{
|
||||
int nch; // Number of output channels; zero means same as input
|
||||
float level[AF_NCH][AF_NCH]; // Gain level for each channel
|
||||
char *matrixstr;
|
||||
}af_pan_t;
|
||||
typedef struct af_pan_s {
|
||||
int nch; // Number of output channels; zero means same as input
|
||||
float level[AF_NCH][AF_NCH]; // Gain level for each channel
|
||||
char *matrixstr;
|
||||
} af_pan_t;
|
||||
|
||||
static void set_channels(struct mp_audio *mpa, int num)
|
||||
{
|
||||
@@ -44,129 +43,17 @@ static void set_channels(struct mp_audio *mpa, int num)
|
||||
mp_audio_set_channels(mpa, &map);
|
||||
}
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
static void parse_matrix(struct af_instance *af, const char *cp)
|
||||
{
|
||||
af_pan_t* s = af->priv;
|
||||
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:
|
||||
// Sanity check
|
||||
if(!arg) return AF_ERROR;
|
||||
|
||||
af->data->rate = ((struct mp_audio*)arg)->rate;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
set_channels(af->data, s->nch ? s->nch: ((struct mp_audio*)arg)->nch);
|
||||
|
||||
if((af->data->format != ((struct mp_audio*)arg)->format) ||
|
||||
(af->data->bps != ((struct mp_audio*)arg)->bps)){
|
||||
mp_audio_set_format((struct mp_audio*)arg, af->data->format);
|
||||
return AF_FALSE;
|
||||
}
|
||||
return AF_OK;
|
||||
case AF_CONTROL_SET_PAN_LEVEL:{
|
||||
int i;
|
||||
int ch = ((af_control_ext_t*)arg)->ch;
|
||||
float* level = ((af_control_ext_t*)arg)->arg;
|
||||
if (ch >= AF_NCH)
|
||||
return AF_FALSE;
|
||||
for(i=0;i<AF_NCH;i++)
|
||||
s->level[ch][i] = level[i];
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_SET_PAN_NOUT:
|
||||
// Reinit must be called after this function has been called
|
||||
|
||||
// Sanity check
|
||||
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
|
||||
MP_ERR(af, "The number of output channels must be"
|
||||
" between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
|
||||
return AF_ERROR;
|
||||
}
|
||||
s->nch=((int*)arg)[0];
|
||||
return AF_OK;
|
||||
case AF_CONTROL_SET_PAN_BALANCE:{
|
||||
float val = *(float*)arg;
|
||||
if (s->nch)
|
||||
return AF_ERROR;
|
||||
if (af->data->nch >= 2) {
|
||||
s->level[0][0] = MPMIN(1.f, 1.f - val);
|
||||
s->level[0][1] = MPMAX(0.f, val);
|
||||
s->level[1][0] = MPMAX(0.f, -val);
|
||||
s->level[1][1] = MPMIN(1.f, 1.f + val);
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_GET_PAN_BALANCE:
|
||||
if (s->nch)
|
||||
return AF_ERROR;
|
||||
*(float*)arg = s->level[0][1] - s->level[1][0];
|
||||
return AF_OK;
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
{
|
||||
if (!c)
|
||||
return 0;
|
||||
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
|
||||
if (!l) {
|
||||
talloc_free(c);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(l, c);
|
||||
|
||||
af_pan_t* s = af->priv; // Setup for this instance
|
||||
float* in = c->planes[0]; // Input audio data
|
||||
float* out = NULL; // Output audio data
|
||||
float* end = in+c->samples*c->nch; // End of loop
|
||||
int nchi = c->nch; // Number of input channels
|
||||
int ncho = l->nch; // Number of output channels
|
||||
register int j,k;
|
||||
|
||||
out = l->planes[0];
|
||||
// Execute panning
|
||||
// FIXME: Too slow
|
||||
while(in < end){
|
||||
for(j=0;j<ncho;j++){
|
||||
register float x = 0.0;
|
||||
register float* tin = in;
|
||||
for(k=0;k<nchi;k++)
|
||||
x += tin[k] * s->level[j][k];
|
||||
out[j] = x;
|
||||
}
|
||||
out+= ncho;
|
||||
in+= nchi;
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
af_add_output_frame(af, l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af_pan_t *s = af->priv;
|
||||
int n = 0;
|
||||
int j,k;
|
||||
|
||||
int nch = s->nch;
|
||||
if(nch && AF_OK != control(af,AF_CONTROL_SET_PAN_NOUT, &nch))
|
||||
return AF_ERROR;
|
||||
|
||||
// Read pan values
|
||||
char *cp = s->matrixstr;
|
||||
j = 0; k = 0;
|
||||
while(cp && k < AF_NCH){
|
||||
int j = 0, k = 0, n;
|
||||
while (*cp && k < AF_NCH) {
|
||||
sscanf(cp, "%f%n" , &s->level[j][k], &n);
|
||||
MP_VERBOSE(af, "Pan level from channel %i to"
|
||||
" channel %i = %f\n",k,j,s->level[j][k]);
|
||||
cp =&cp[n];
|
||||
" channel %i = %f\n", k, j, s->level[j][k]);
|
||||
cp = &cp[n];
|
||||
j++;
|
||||
if(j>=nch){
|
||||
if (j >= s->nch) {
|
||||
j = 0;
|
||||
k++;
|
||||
}
|
||||
@@ -174,6 +61,133 @@ static int af_open(struct af_instance* af){
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
af_pan_t* s = af->priv;
|
||||
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:
|
||||
// Sanity check
|
||||
if (!arg)
|
||||
return AF_ERROR;
|
||||
|
||||
af->data->rate = ((struct mp_audio*)arg)->rate;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
set_channels(af->data, s->nch ? s->nch : ((struct mp_audio*)arg)->nch);
|
||||
|
||||
if ((af->data->format != ((struct mp_audio*)arg)->format) ||
|
||||
(af->data->bps != ((struct mp_audio*)arg)->bps)) {
|
||||
mp_audio_set_format((struct mp_audio*)arg, af->data->format);
|
||||
return AF_FALSE;
|
||||
}
|
||||
return AF_OK;
|
||||
case AF_CONTROL_SET_PAN_LEVEL: {
|
||||
int i;
|
||||
int ch = ((af_control_ext_t*)arg)->ch;
|
||||
float *level = ((af_control_ext_t*)arg)->arg;
|
||||
if (ch >= AF_NCH)
|
||||
return AF_FALSE;
|
||||
for (i = 0; i < AF_NCH; i++)
|
||||
s->level[ch][i] = level[i];
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_SET_PAN_NOUT:
|
||||
// Reinit must be called after this function has been called
|
||||
// Sanity check
|
||||
if (((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH) {
|
||||
MP_ERR(af, "The number of output channels must be"
|
||||
" between 1 and %i. Current value is %i\n",
|
||||
AF_NCH, ((int*)arg)[0]);
|
||||
return AF_ERROR;
|
||||
}
|
||||
s->nch = ((int*)arg)[0];
|
||||
return AF_OK;
|
||||
case AF_CONTROL_SET_PAN_BALANCE: {
|
||||
float val = *(float*)arg;
|
||||
if (s->nch)
|
||||
return AF_ERROR;
|
||||
if (af->data->nch >= 2) {
|
||||
s->level[0][0] = MPMIN(1.f, 1.f - val);
|
||||
s->level[0][1] = MPMAX(0.f, val);
|
||||
s->level[1][0] = MPMAX(0.f, -val);
|
||||
s->level[1][1] = MPMIN(1.f, 1.f + val);
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_GET_PAN_BALANCE:
|
||||
if (s->nch)
|
||||
return AF_ERROR;
|
||||
*(float*)arg = s->level[0][1] - s->level[1][0];
|
||||
return AF_OK;
|
||||
case AF_CONTROL_COMMAND: {
|
||||
char **args = arg;
|
||||
if (!strcmp(args[0], "set-matrix")) {
|
||||
parse_matrix(af, args[1]);
|
||||
return CONTROL_OK;
|
||||
} else {
|
||||
return CONTROL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
{
|
||||
if (!c)
|
||||
return 0;
|
||||
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
|
||||
if (!l) {
|
||||
talloc_free(c);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(l, c);
|
||||
|
||||
af_pan_t* s = af->priv; // Setup for this instance
|
||||
float *in = c->planes[0]; // Input audio data
|
||||
float *out = NULL; // Output audio data
|
||||
float *end = in+c->samples * c->nch; // End of loop
|
||||
int nchi = c->nch; // Number of input channels
|
||||
int ncho = l->nch; // Number of output channels
|
||||
register int j, k;
|
||||
|
||||
out = l->planes[0];
|
||||
// Execute panning
|
||||
// FIXME: Too slow
|
||||
while (in < end) {
|
||||
for (j = 0; j < ncho; j++) {
|
||||
register float x = 0.0;
|
||||
register float *tin = in;
|
||||
for (k = 0; k < nchi; k++)
|
||||
x += tin[k] * s->level[j][k];
|
||||
out[j] = x;
|
||||
}
|
||||
out += ncho;
|
||||
in += nchi;
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
af_add_output_frame(af, l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter_frame = filter_frame;
|
||||
af_pan_t *s = af->priv;
|
||||
int nch = s->nch;
|
||||
if (nch && AF_OK != control(af, AF_CONTROL_SET_PAN_NOUT, &nch))
|
||||
return AF_ERROR;
|
||||
|
||||
// Read pan values
|
||||
if (s->matrixstr)
|
||||
parse_matrix(af, s->matrixstr);
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
struct priv {
|
||||
RubberBandState rubber;
|
||||
double speed;
|
||||
double pitch;
|
||||
struct mp_audio *pending;
|
||||
bool needs_reset;
|
||||
// Estimate how much librubberband has buffered internally.
|
||||
@@ -44,6 +45,14 @@ static void update_speed(struct af_instance *af, double new_speed)
|
||||
rubberband_set_time_ratio(p->rubber, 1.0 / p->speed);
|
||||
}
|
||||
|
||||
static void update_pitch(struct af_instance *af, double new_pitch)
|
||||
{
|
||||
struct priv *p = af->priv;
|
||||
|
||||
p->pitch = new_pitch;
|
||||
rubberband_set_pitch_scale(p->rubber, p->pitch);
|
||||
}
|
||||
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
struct priv *p = af->priv;
|
||||
@@ -72,6 +81,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
}
|
||||
|
||||
update_speed(af, p->speed);
|
||||
update_pitch(af, p->pitch);
|
||||
control(af, AF_CONTROL_RESET, NULL);
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
@@ -87,6 +97,19 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
p->pending = NULL;
|
||||
p->rubber_delay = 0;
|
||||
return AF_OK;
|
||||
case AF_CONTROL_COMMAND: {
|
||||
char **args = arg;
|
||||
if (!strcmp(args[0], "set-pitch")) {
|
||||
char *endptr;
|
||||
double pitch = strtod(args[1], &endptr);
|
||||
if (*endptr || pitch < 0.01 || pitch > 100.0)
|
||||
return CONTROL_ERROR;
|
||||
update_pitch(af, pitch);
|
||||
return CONTROL_OK;
|
||||
} else {
|
||||
return CONTROL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
@@ -187,9 +210,11 @@ const struct af_info af_info_rubberband = {
|
||||
.priv_size = sizeof(struct priv),
|
||||
.priv_defaults = &(const struct priv) {
|
||||
.speed = 1.0,
|
||||
.pitch = 1.0,
|
||||
.opt_pitch = RubberBandOptionPitchHighConsistency,
|
||||
.opt_transients = RubberBandOptionTransientsMixed,
|
||||
.opt_formant = RubberBandOptionFormantPreserved,
|
||||
.opt_channels = RubberBandOptionChannelsTogether,
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_CHOICE("transients", opt_transients, 0,
|
||||
@@ -220,6 +245,7 @@ const struct af_info af_info_rubberband = {
|
||||
OPT_CHOICE("channels", opt_channels, 0,
|
||||
({"apart", RubberBandOptionChannelsApart},
|
||||
{"together", RubberBandOptionChannelsTogether})),
|
||||
OPT_DOUBLE("pitch-scale", pitch, M_OPT_RANGE, .min = 0.01, .max = 100),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
+35
-21
@@ -28,7 +28,6 @@
|
||||
#include "audio/format.h"
|
||||
#include "audio/audio.h"
|
||||
|
||||
#include "input/input.h"
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "common/msg.h"
|
||||
@@ -109,6 +108,8 @@ static bool get_desc(struct m_obj_desc *dst, int index)
|
||||
.priv_size = ao->priv_size,
|
||||
.priv_defaults = ao->priv_defaults,
|
||||
.options = ao->options,
|
||||
.global_opts = ao->global_opts,
|
||||
.legacy_prefix = ao->legacy_prefix,
|
||||
.hidden = ao->encode,
|
||||
.p = ao,
|
||||
};
|
||||
@@ -121,11 +122,15 @@ const struct m_obj_list ao_obj_list = {
|
||||
.description = "audio outputs",
|
||||
.allow_unknown_entries = true,
|
||||
.allow_trailer = true,
|
||||
.disallow_positional_parameters = true,
|
||||
};
|
||||
|
||||
static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx, char *name, char **args)
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
char *name, char **args)
|
||||
{
|
||||
assert(wakeup_cb);
|
||||
|
||||
struct MPOpts *opts = global->opts;
|
||||
struct mp_log *log = mp_log_new(NULL, global->log, "ao");
|
||||
struct m_obj_desc desc;
|
||||
@@ -139,15 +144,17 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
*ao = (struct ao) {
|
||||
.driver = desc.p,
|
||||
.probing = probing,
|
||||
.input_ctx = input_ctx,
|
||||
.global = global,
|
||||
.wakeup_cb = wakeup_cb,
|
||||
.wakeup_ctx = wakeup_ctx,
|
||||
.log = mp_log_new(ao, log, name),
|
||||
.def_buffer = opts->audio_buffer,
|
||||
.client_name = talloc_strdup(ao, opts->audio_client_name),
|
||||
};
|
||||
struct m_config *config = m_config_from_obj_desc(ao, ao->log, &desc);
|
||||
if (m_config_apply_defaults(config, name, opts->ao_defs) < 0)
|
||||
goto error;
|
||||
if (m_config_set_obj_params(config, args) < 0)
|
||||
struct m_config *config =
|
||||
m_config_from_obj_desc_and_args(ao, ao->log, global, &desc,
|
||||
name, opts->ao_defs, args);
|
||||
if (!config)
|
||||
goto error;
|
||||
ao->priv = config->optstruct;
|
||||
return ao;
|
||||
@@ -157,12 +164,12 @@ error:
|
||||
}
|
||||
|
||||
static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx, int flags,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *dev, char *name, char **args)
|
||||
{
|
||||
struct ao *ao = ao_alloc(probing, global, input_ctx, name, args);
|
||||
struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name, args);
|
||||
if (!ao)
|
||||
return NULL;
|
||||
ao->samplerate = samplerate;
|
||||
@@ -193,8 +200,9 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
|
||||
snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : "");
|
||||
talloc_free(ao);
|
||||
return ao_init(probing, global, input_ctx, encode_lavc_ctx, flags,
|
||||
samplerate, format, channels, rdevice, redirect, NULL);
|
||||
return ao_init(probing, global, wakeup_cb, wakeup_ctx,
|
||||
encode_lavc_ctx, flags, samplerate, format, channels,
|
||||
rdevice, redirect, NULL);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
@@ -244,7 +252,7 @@ static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev)
|
||||
|
||||
struct ao *ao_init_best(struct mpv_global *global,
|
||||
int init_flags,
|
||||
struct input_ctx *input_ctx,
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels)
|
||||
{
|
||||
@@ -300,8 +308,8 @@ struct ao *ao_init_best(struct mpv_global *global,
|
||||
dev = pref_dev;
|
||||
mp_verbose(log, "Using preferred device '%s'\n", dev);
|
||||
}
|
||||
ao = ao_init(probing, global, input_ctx, encode_lavc_ctx, init_flags,
|
||||
samplerate, format, channels, dev,
|
||||
ao = ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx,
|
||||
init_flags, samplerate, format, channels, dev,
|
||||
entry->name, entry->attribs);
|
||||
if (ao)
|
||||
break;
|
||||
@@ -405,8 +413,7 @@ int ao_query_and_reset_events(struct ao *ao, int events)
|
||||
static void ao_add_events(struct ao *ao, int events)
|
||||
{
|
||||
atomic_fetch_or(&ao->events_, events);
|
||||
if (ao->input_ctx)
|
||||
mp_input_wakeup(ao->input_ctx);
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
}
|
||||
|
||||
// Request that the player core destroys and recreates the AO. Fully thread-safe.
|
||||
@@ -490,7 +497,8 @@ bool ao_untimed(struct ao *ao)
|
||||
|
||||
struct ao_hotplug {
|
||||
struct mpv_global *global;
|
||||
struct input_ctx *input_ctx;
|
||||
void (*wakeup_cb)(void *ctx);
|
||||
void *wakeup_ctx;
|
||||
// A single AO instance is used to listen to hotplug events. It wouldn't
|
||||
// make much sense to allow multiple AO drivers; all sane platforms have
|
||||
// a single such audio API.
|
||||
@@ -502,12 +510,14 @@ struct ao_hotplug {
|
||||
};
|
||||
|
||||
struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
|
||||
struct input_ctx *input_ctx)
|
||||
void (*wakeup_cb)(void *ctx),
|
||||
void *wakeup_ctx)
|
||||
{
|
||||
struct ao_hotplug *hp = talloc_ptrtype(NULL, hp);
|
||||
*hp = (struct ao_hotplug){
|
||||
.global = global,
|
||||
.input_ctx = input_ctx,
|
||||
.wakeup_cb = wakeup_cb,
|
||||
.wakeup_ctx = wakeup_ctx,
|
||||
.needs_update = true,
|
||||
};
|
||||
return hp;
|
||||
@@ -560,7 +570,7 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
|
||||
if (d == &audio_out_null)
|
||||
break; // don't add unsafe/special entries
|
||||
|
||||
struct ao *ao = ao_alloc(true, hp->global, hp->input_ctx,
|
||||
struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx,
|
||||
(char *)d->name, NULL);
|
||||
if (!ao)
|
||||
continue;
|
||||
@@ -601,9 +611,13 @@ void ao_hotplug_destroy(struct ao_hotplug *hp)
|
||||
talloc_free(hp);
|
||||
}
|
||||
|
||||
static void dummy_wakeup(void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void ao_print_devices(struct mpv_global *global, struct mp_log *log)
|
||||
{
|
||||
struct ao_hotplug *hp = ao_hotplug_create(global, NULL);
|
||||
struct ao_hotplug *hp = ao_hotplug_create(global, dummy_wakeup, NULL);
|
||||
struct ao_device_list *list = ao_hotplug_get_device_list(hp);
|
||||
mp_info(log, "List of detected audio devices:\n");
|
||||
for (int n = 0; n < list->num_devices; n++) {
|
||||
|
||||
+5
-2
@@ -58,6 +58,8 @@ enum {
|
||||
AO_INIT_SAFE_MULTICHANNEL_ONLY = 1 << 1,
|
||||
// Stream silence as long as no audio is playing.
|
||||
AO_INIT_STREAM_SILENCE = 1 << 2,
|
||||
// Force exclusive mode, i.e. lock out the system mixer.
|
||||
AO_INIT_EXCLUSIVE = 1 << 3,
|
||||
};
|
||||
|
||||
typedef struct ao_control_vol {
|
||||
@@ -83,7 +85,7 @@ struct mp_audio;
|
||||
|
||||
struct ao *ao_init_best(struct mpv_global *global,
|
||||
int init_flags,
|
||||
struct input_ctx *input_ctx,
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels);
|
||||
void ao_uninit(struct ao *ao);
|
||||
@@ -106,7 +108,8 @@ void ao_hotplug_event(struct ao *ao);
|
||||
|
||||
struct ao_hotplug;
|
||||
struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
|
||||
struct input_ctx *input_ctx);
|
||||
void (*wakeup_cb)(void *ctx),
|
||||
void *wakeup_ctx);
|
||||
void ao_hotplug_destroy(struct ao_hotplug *hp);
|
||||
bool ao_hotplug_check_update(struct ao_hotplug *hp);
|
||||
const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp);
|
||||
|
||||
+65
-37
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "common/msg.h"
|
||||
#include "osdep/endian.h"
|
||||
@@ -48,6 +49,37 @@
|
||||
#include "internal.h"
|
||||
#include "audio/format.h"
|
||||
|
||||
struct ao_alsa_opts {
|
||||
char *device;
|
||||
char *mixer_device;
|
||||
char *mixer_name;
|
||||
int mixer_index;
|
||||
int resample;
|
||||
int ni;
|
||||
int ignore_chmap;
|
||||
};
|
||||
|
||||
#define OPT_BASE_STRUCT struct ao_alsa_opts
|
||||
static const struct m_sub_options ao_alsa_conf = {
|
||||
.opts = (const struct m_option[]) {
|
||||
OPT_STRING("alsa-device", device, 0, DEVICE_OPT_DEPRECATION),
|
||||
OPT_FLAG("alsa-resample", resample, 0),
|
||||
OPT_STRING("alsa-mixer-device", mixer_device, 0),
|
||||
OPT_STRING("alsa-mixer-name", mixer_name, 0),
|
||||
OPT_INTRANGE("alsa-mixer-index", mixer_index, 0, 0, 99),
|
||||
OPT_FLAG("alsa-non-interleaved", ni, 0),
|
||||
OPT_FLAG("alsa-ignore-chmap", ignore_chmap, 0),
|
||||
{0}
|
||||
},
|
||||
.defaults = &(const struct ao_alsa_opts) {
|
||||
.mixer_device = "default",
|
||||
.mixer_name = "Master",
|
||||
.mixer_index = 0,
|
||||
.ni = 0,
|
||||
},
|
||||
.size = sizeof(struct ao_alsa_opts),
|
||||
};
|
||||
|
||||
struct priv {
|
||||
snd_pcm_t *alsa;
|
||||
bool device_lost;
|
||||
@@ -61,13 +93,7 @@ struct priv {
|
||||
|
||||
snd_output_t *output;
|
||||
|
||||
char *cfg_device;
|
||||
char *cfg_mixer_device;
|
||||
char *cfg_mixer_name;
|
||||
int cfg_mixer_index;
|
||||
int cfg_resample;
|
||||
int cfg_ni;
|
||||
int cfg_ignore_chmap;
|
||||
struct ao_alsa_opts *opts;
|
||||
};
|
||||
|
||||
#define BUFFER_TIME 250000 // 250ms
|
||||
@@ -125,13 +151,13 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
|
||||
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
|
||||
snd_mixer_selem_id_set_index(sid, p->cfg_mixer_index);
|
||||
snd_mixer_selem_id_set_name(sid, p->cfg_mixer_name);
|
||||
snd_mixer_selem_id_set_index(sid, p->opts->mixer_index);
|
||||
snd_mixer_selem_id_set_name(sid, p->opts->mixer_name);
|
||||
|
||||
err = snd_mixer_open(&handle, 0);
|
||||
CHECK_ALSA_ERROR("Mixer open error");
|
||||
|
||||
err = snd_mixer_attach(handle, p->cfg_mixer_device);
|
||||
err = snd_mixer_attach(handle, p->opts->mixer_device);
|
||||
CHECK_ALSA_ERROR("Mixer attach error");
|
||||
|
||||
err = snd_mixer_selem_register(handle, NULL, NULL);
|
||||
@@ -337,8 +363,10 @@ static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
|
||||
struct mp_chmap_sel chmap_sel = {.tmp = p};
|
||||
|
||||
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps(p->alsa);
|
||||
if (!maps)
|
||||
if (!maps) {
|
||||
MP_VERBOSE(ao, "snd_pcm_query_chmaps() returned NULL\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; maps[i] != NULL; i++) {
|
||||
char aname[128];
|
||||
@@ -445,7 +473,7 @@ static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels
|
||||
|
||||
MP_VERBOSE(ao, "which we understand as: %s\n", mp_chmap_to_str(&chmap));
|
||||
|
||||
if (p->cfg_ignore_chmap) {
|
||||
if (p->opts->ignore_chmap) {
|
||||
MP_VERBOSE(ao, "user set ignore-chmap; ignoring the channel map.\n");
|
||||
} else if (af_fmt_is_spdif(ao->format)) {
|
||||
MP_VERBOSE(ao, "using spdif passthrough; ignoring the channel map.\n");
|
||||
@@ -562,11 +590,16 @@ static int try_open_device(struct ao *ao, const char *device, int mode)
|
||||
bstr dev;
|
||||
bstr_split_tok(bstr0(device), ":", &dev, &(bstr){0});
|
||||
if (bstr_equals0(dev, "default")) {
|
||||
ac3_device = append_params(tmp, "iec958", params);
|
||||
MP_VERBOSE(ao, "got error %d; opening iec fallback device '%s'\n",
|
||||
err, ac3_device);
|
||||
err = snd_pcm_open
|
||||
(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode);
|
||||
const char *const fallbacks[] = {"hdmi", "iec958", NULL};
|
||||
for (int n = 0; fallbacks[n]; n++) {
|
||||
char *ndev = append_params(tmp, fallbacks[n], params);
|
||||
MP_VERBOSE(ao, "got error %d; opening iec fallback "
|
||||
"device '%s'\n", err, ndev);
|
||||
err = snd_pcm_open
|
||||
(&p->alsa, ndev, SND_PCM_STREAM_PLAYBACK, mode);
|
||||
if (err >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
talloc_free(tmp);
|
||||
@@ -613,8 +646,8 @@ static int init_device(struct ao *ao, int mode)
|
||||
const char *device = "default";
|
||||
if (ao->device)
|
||||
device = ao->device;
|
||||
if (p->cfg_device && p->cfg_device[0])
|
||||
device = p->cfg_device;
|
||||
if (p->opts->device && p->opts->device[0])
|
||||
device = p->opts->device;
|
||||
|
||||
err = try_open_device(ao, device, mode);
|
||||
CHECK_ALSA_ERROR("Playback open error");
|
||||
@@ -639,7 +672,7 @@ static int init_device(struct ao *ao, int mode)
|
||||
|
||||
// Some ALSA drivers have broken delay reporting, so disable the ALSA
|
||||
// resampling plugin by default.
|
||||
if (!p->cfg_resample) {
|
||||
if (!p->opts->resample) {
|
||||
err = snd_pcm_hw_params_set_rate_resample(p->alsa, alsa_hwparams, 0);
|
||||
CHECK_ALSA_ERROR("Unable to disable resampling");
|
||||
}
|
||||
@@ -682,7 +715,7 @@ static int init_device(struct ao *ao, int mode)
|
||||
dump_hw_params(ao, MSGL_DEBUG, "HW params after format:\n", alsa_hwparams);
|
||||
|
||||
struct mp_chmap dev_chmap = ao->channels;
|
||||
if (af_fmt_is_spdif(ao->format) || p->cfg_ignore_chmap) {
|
||||
if (af_fmt_is_spdif(ao->format) || p->opts->ignore_chmap) {
|
||||
dev_chmap.num = 0; // disable chmap API
|
||||
} else if (dev_chmap.num == 1 && dev_chmap.speaker[0] == MP_SPEAKER_ID_FC) {
|
||||
// As yet another ALSA API inconsistency, mono is not reported correctly.
|
||||
@@ -804,7 +837,9 @@ alsa_error:
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
if (!p->cfg_ni)
|
||||
p->opts = mp_get_config_group(ao, ao->global, &ao_alsa_conf);
|
||||
|
||||
if (!p->opts->ni)
|
||||
ao->format = af_fmt_from_planar(ao->format);
|
||||
|
||||
MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version());
|
||||
@@ -1123,8 +1158,6 @@ static void list_devs(struct ao *ao, struct ao_device_list *list)
|
||||
snd_device_name_free_hint(hints);
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
|
||||
const struct ao_driver audio_out_alsa = {
|
||||
.description = "ALSA audio output",
|
||||
.name = "alsa",
|
||||
@@ -1142,20 +1175,15 @@ const struct ao_driver audio_out_alsa = {
|
||||
.wakeup = ao_wakeup_poll,
|
||||
.list_devs = list_devs,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.priv_defaults = &(const struct priv) {
|
||||
.cfg_mixer_device = "default",
|
||||
.cfg_mixer_name = "Master",
|
||||
.cfg_mixer_index = 0,
|
||||
.cfg_ni = 0,
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("device", cfg_device, 0),
|
||||
OPT_FLAG("resample", cfg_resample, 0),
|
||||
OPT_STRING("mixer-device", cfg_mixer_device, 0),
|
||||
OPT_STRING("mixer-name", cfg_mixer_name, 0),
|
||||
OPT_INTRANGE("mixer-index", cfg_mixer_index, 0, 0, 99),
|
||||
OPT_FLAG("non-interleaved", cfg_ni, 0),
|
||||
OPT_FLAG("ignore-chmap", cfg_ignore_chmap, 0),
|
||||
OPT_SUBOPT_LEGACY("device", "alsa-device"),
|
||||
OPT_SUBOPT_LEGACY("resample", "alsa-resample"),
|
||||
OPT_SUBOPT_LEGACY("mixer-device", "alsa-mixer-device"),
|
||||
OPT_SUBOPT_LEGACY("mixer-name", "alsa-mixer-name"),
|
||||
OPT_SUBOPT_LEGACY("mixer-index", "alsa-mixer-index"),
|
||||
OPT_SUBOPT_LEGACY("non-interleaved", "alsa-non-interleaved"),
|
||||
OPT_SUBOPT_LEGACY("ignore-chmap", "alsa-ignore-chmap"),
|
||||
{0}
|
||||
},
|
||||
.global_opts = &ao_alsa_conf,
|
||||
};
|
||||
@@ -143,6 +143,8 @@ static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
p->exclusive |= ao->init_flags & AO_INIT_EXCLUSIVE;
|
||||
|
||||
if (!af_fmt_is_pcm(ao->format) || p->exclusive) {
|
||||
MP_VERBOSE(ao, "redirecting to coreaudio_exclusive\n");
|
||||
ao->redirect = "coreaudio_exclusive";
|
||||
@@ -427,7 +429,9 @@ const struct ao_driver audio_out_coreaudio = {
|
||||
.priv_size = sizeof(struct priv),
|
||||
.options = (const struct m_option[]){
|
||||
OPT_FLAG("change-physical-format", change_physical_format, 0),
|
||||
OPT_FLAG("exclusive", exclusive, 0),
|
||||
OPT_FLAG("exclusive", exclusive, 0,
|
||||
.deprecation_message = "use --audio-exclusive"),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "coreaudio",
|
||||
};
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "internal.h"
|
||||
#include "audio/format.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "options/m_option.h"
|
||||
#include "common/msg.h"
|
||||
#include "audio/out/ao_coreaudio_chmap.h"
|
||||
|
||||
+42
-22
@@ -34,24 +34,48 @@
|
||||
#include "internal.h"
|
||||
#include "audio/format.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
|
||||
#include <jack/jack.h>
|
||||
|
||||
struct priv {
|
||||
jack_client_t *client;
|
||||
float jack_latency;
|
||||
char *cfg_port;
|
||||
char *cfg_client_name;
|
||||
struct jack_opts {
|
||||
char *port;
|
||||
char *client_name;
|
||||
int connect;
|
||||
int autostart;
|
||||
int stdlayout;
|
||||
};
|
||||
|
||||
#define OPT_BASE_STRUCT struct jack_opts
|
||||
static const struct m_sub_options ao_jack_conf = {
|
||||
.opts = (const struct m_option[]){
|
||||
OPT_STRING("jack-port", port, 0),
|
||||
OPT_STRING("jack-name", client_name, 0),
|
||||
OPT_FLAG("jack-autostart", autostart, 0),
|
||||
OPT_FLAG("jack-connect", connect, 0),
|
||||
OPT_CHOICE("jack-std-channel-layout", stdlayout, 0,
|
||||
({"waveext", 0}, {"any", 1})),
|
||||
{0}
|
||||
},
|
||||
.defaults = &(const struct jack_opts) {
|
||||
.client_name = "mpv",
|
||||
.connect = 1,
|
||||
},
|
||||
.size = sizeof(struct jack_opts),
|
||||
};
|
||||
|
||||
struct priv {
|
||||
jack_client_t *client;
|
||||
float jack_latency;
|
||||
int last_chunk;
|
||||
|
||||
int num_ports;
|
||||
jack_port_t *ports[MP_NUM_CHANNELS];
|
||||
|
||||
int activated;
|
||||
|
||||
struct jack_opts *opts;
|
||||
};
|
||||
|
||||
static int process(jack_nframes_t nframes, void *arg)
|
||||
@@ -77,7 +101,7 @@ connect_to_outports(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
char *port_name = (p->cfg_port && p->cfg_port[0]) ? p->cfg_port : NULL;
|
||||
char *port_name = (p->opts->port && p->opts->port[0]) ? p->opts->port : NULL;
|
||||
const char **matching_ports = NULL;
|
||||
int port_flags = JackPortIsInput;
|
||||
int i;
|
||||
@@ -144,7 +168,7 @@ static void resume(struct ao *ao)
|
||||
if (jack_activate(p->client))
|
||||
MP_FATAL(ao, "activate failed\n");
|
||||
|
||||
if (p->connect)
|
||||
if (p->opts->connect)
|
||||
connect_to_outports(ao);
|
||||
}
|
||||
}
|
||||
@@ -155,9 +179,11 @@ static int init(struct ao *ao)
|
||||
struct mp_chmap_sel sel = {0};
|
||||
jack_options_t open_options;
|
||||
|
||||
p->opts = mp_get_config_group(ao, ao->global, &ao_jack_conf);
|
||||
|
||||
ao->format = AF_FORMAT_FLOATP;
|
||||
|
||||
switch (p->stdlayout) {
|
||||
switch (p->opts->stdlayout) {
|
||||
case 0:
|
||||
mp_chmap_sel_add_waveext(&sel);
|
||||
break;
|
||||
@@ -170,10 +196,10 @@ static int init(struct ao *ao)
|
||||
goto err_chmap;
|
||||
|
||||
open_options = JackNullOption;
|
||||
if (!p->autostart)
|
||||
if (!p->opts->autostart)
|
||||
open_options |= JackNoStartServer;
|
||||
|
||||
p->client = jack_client_open(p->cfg_client_name, open_options, NULL);
|
||||
p->client = jack_client_open(p->opts->client_name, open_options, NULL);
|
||||
if (!p->client) {
|
||||
MP_FATAL(ao, "cannot open server\n");
|
||||
goto err_client_open;
|
||||
@@ -213,8 +239,6 @@ static void uninit(struct ao *ao)
|
||||
jack_client_close(p->client);
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
|
||||
const struct ao_driver audio_out_jack = {
|
||||
.description = "JACK audio output",
|
||||
.name = "jack",
|
||||
@@ -222,17 +246,13 @@ const struct ao_driver audio_out_jack = {
|
||||
.uninit = uninit,
|
||||
.resume = resume,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.priv_defaults = &(const struct priv) {
|
||||
.cfg_client_name = "mpv",
|
||||
.connect = 1,
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("port", cfg_port, 0),
|
||||
OPT_STRING("name", cfg_client_name, 0),
|
||||
OPT_FLAG("autostart", autostart, 0),
|
||||
OPT_FLAG("connect", connect, 0),
|
||||
OPT_CHOICE("std-channel-layout", stdlayout, 0,
|
||||
({"waveext", 0}, {"any", 1})),
|
||||
OPT_SUBOPT_LEGACY("port", "jack-port"),
|
||||
OPT_SUBOPT_LEGACY("name", "jack-name"),
|
||||
OPT_SUBOPT_LEGACY("autostart", "jack-autostart"),
|
||||
OPT_SUBOPT_LEGACY("connect", "jack-connect"),
|
||||
OPT_SUBOPT_LEGACY("std-channel-layout", "jack-std-channel-layout"),
|
||||
{0}
|
||||
},
|
||||
.global_opts = &ao_jack_conf,
|
||||
};
|
||||
@@ -241,4 +241,5 @@ const struct ao_driver audio_out_null = {
|
||||
OPT_CHANNELS("channel-layouts", channel_layouts, 0),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "ao-null",
|
||||
};
|
||||
+18
-2
@@ -24,6 +24,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifndef AL_FORMAT_MONO_FLOAT32
|
||||
#define AL_FORMAT_MONO_FLOAT32 0x10010
|
||||
#endif
|
||||
#ifndef AL_FORMAT_STEREO_FLOAT32
|
||||
#define AL_FORMAT_STEREO_FLOAT32 0x10011
|
||||
#endif
|
||||
#ifndef AL_FORMAT_MONO_DOUBLE_EXT
|
||||
#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012
|
||||
#endif
|
||||
#include <OpenAL/MacOSX_OALExtensions.h>
|
||||
#else
|
||||
#ifdef OPENAL_AL_H
|
||||
#include <OpenAL/alc.h>
|
||||
#include <OpenAL/al.h>
|
||||
@@ -33,6 +46,7 @@
|
||||
#include <AL/al.h>
|
||||
#include <AL/alext.h>
|
||||
#endif
|
||||
#endif // __APPLE__
|
||||
|
||||
#include "common/msg.h"
|
||||
|
||||
@@ -96,7 +110,7 @@ static int validate_device_opt(struct mp_log *log, const m_option_t *opt,
|
||||
mp_info(log, " '%s'\n", list);
|
||||
list = list + strlen(list) + 1;
|
||||
}
|
||||
return M_OPT_EXIT - 1;
|
||||
return M_OPT_EXIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -356,7 +370,9 @@ const struct ao_driver audio_out_openal = {
|
||||
.list_devs = list_devs,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt),
|
||||
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt,
|
||||
DEVICE_OPT_DEPRECATION),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "ao-openal",
|
||||
};
|
||||
@@ -246,4 +246,5 @@ const struct ao_driver audio_out_opensles = {
|
||||
OPT_INTRANGE("sample-rate", cfg_sample_rate, 0, 1000, 100000),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "opensles",
|
||||
};
|
||||
+2
-1
@@ -648,9 +648,10 @@ const struct ao_driver audio_out_oss = {
|
||||
.oss_mixer_device = PATH_DEV_MIXER,
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("device", dsp, 0),
|
||||
OPT_STRING("device", dsp, 0, DEVICE_OPT_DEPRECATION),
|
||||
OPT_STRING("mixer-device", oss_mixer_device, 0),
|
||||
OPT_STRING("mixer-channel", cfg_oss_mixer_channel, 0),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "oss",
|
||||
};
|
||||
+1
-2
@@ -152,8 +152,6 @@ static int init(struct ao *ao)
|
||||
priv->outputfilename,
|
||||
priv->waveheader ? "WAVE" : "RAW PCM", ao->samplerate,
|
||||
ao->channels.num, af_fmt_to_str(ao->format));
|
||||
MP_INFO(ao, "Info: Faster dumping is achieved with --no-video\n");
|
||||
MP_INFO(ao, "Info: To write WAVE files use --ao=pcm:waveheader (default).\n");
|
||||
|
||||
priv->fp = fopen(priv->outputfilename, priv->append ? "ab" : "wb");
|
||||
if (!priv->fp) {
|
||||
@@ -226,4 +224,5 @@ const struct ao_driver audio_out_pcm = {
|
||||
OPT_FLAG("append", append, 0),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "ao-pcm",
|
||||
};
|
||||
@@ -836,9 +836,10 @@ const struct ao_driver audio_out_pulse = {
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("host", cfg_host, 0),
|
||||
OPT_STRING("sink", cfg_sink, 0),
|
||||
OPT_STRING("sink", cfg_sink, 0, DEVICE_OPT_DEPRECATION),
|
||||
OPT_CHOICE_OR_INT("buffer", cfg_buffer, 0, 1, 2000, ({"native", 0})),
|
||||
OPT_FLAG("latency-hacks", cfg_latency_hacks, 0),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "pulse",
|
||||
};
|
||||
@@ -156,9 +156,12 @@ const struct ao_driver audio_out_rsound = {
|
||||
.resume = audio_resume,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("host", host, 0),
|
||||
OPT_STRING("port", port, 0),
|
||||
OPT_STRING("host", host, 0,
|
||||
.deprecation_message = "request --audio-device support on issue tracker"),
|
||||
OPT_STRING("port", port, 0,
|
||||
.deprecation_message = "request --audio-device support on issue tracker"),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "rsound",
|
||||
};
|
||||
|
||||
@@ -212,4 +212,5 @@ const struct ao_driver audio_out_sdl = {
|
||||
OPT_FLOAT("buflen", buflen, 0),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "sdl",
|
||||
};
|
||||
@@ -320,7 +320,9 @@ const struct ao_driver audio_out_sndio = {
|
||||
.reset = reset,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("device", dev, 0, OPTDEF_STR(SIO_DEVANY)),
|
||||
OPT_STRING("device", dev, 0, OPTDEF_STR(SIO_DEVANY),
|
||||
DEVICE_OPT_DEPRECATION),
|
||||
{0}
|
||||
},
|
||||
.legacy_prefix = "ao-sndio",
|
||||
};
|
||||
@@ -275,6 +275,8 @@ static int init(struct ao *ao)
|
||||
struct wasapi_state *state = ao->priv;
|
||||
state->log = ao->log;
|
||||
|
||||
state->opt_exclusive |= ao->init_flags & AO_INIT_EXCLUSIVE;
|
||||
|
||||
state->deviceID = wasapi_find_deviceID(ao);
|
||||
if (!state->deviceID) {
|
||||
uninit(ao);
|
||||
@@ -495,8 +497,10 @@ const struct ao_driver audio_out_wasapi = {
|
||||
.hotplug_uninit = hotplug_uninit,
|
||||
.priv_size = sizeof(wasapi_state),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_FLAG("exclusive", opt_exclusive, 0),
|
||||
OPT_STRING("device", opt_device, 0),
|
||||
OPT_FLAG("exclusive", opt_exclusive, 0,
|
||||
.deprecation_message = "use --audio-exclusive"),
|
||||
OPT_STRING("device", opt_device, 0, DEVICE_OPT_DEPRECATION),
|
||||
{NULL},
|
||||
},
|
||||
.legacy_prefix = "ao-wasapi",
|
||||
};
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "internal.h"
|
||||
#include "ao.h"
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <initguid.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "ao_wasapi.h"
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <math.h>
|
||||
#include <wchar.h>
|
||||
#include <windows.h>
|
||||
#include <initguid.h>
|
||||
#include <errors.h>
|
||||
#include <ksguid.h>
|
||||
#include <ksmedia.h>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "audio/out/ao.h"
|
||||
|
||||
/* global data used by ao.c and ao drivers */
|
||||
@@ -40,8 +40,10 @@ struct ao {
|
||||
const struct ao_driver *api; // entrypoints to the wrapper (push.c/pull.c)
|
||||
const struct ao_driver *driver;
|
||||
void *priv;
|
||||
struct mpv_global *global;
|
||||
struct encode_lavc_context *encode_lavc_ctx;
|
||||
struct input_ctx *input_ctx;
|
||||
void (*wakeup_cb)(void *ctx);
|
||||
void *wakeup_ctx;
|
||||
struct mp_log *log; // Using e.g. "[ao/coreaudio]" as prefix
|
||||
int init_flags; // AO_INIT_* flags
|
||||
bool stream_silence; // if audio inactive, just play silence
|
||||
@@ -180,6 +182,8 @@ struct ao_driver {
|
||||
int priv_size;
|
||||
const void *priv_defaults;
|
||||
const struct m_option *options;
|
||||
const struct m_sub_options *global_opts;
|
||||
const char *legacy_prefix;
|
||||
};
|
||||
|
||||
// These functions can be called by AOs.
|
||||
@@ -203,4 +207,7 @@ bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
|
||||
void ao_device_list_add(struct ao_device_list *list, struct ao *ao,
|
||||
struct ao_device_desc *e);
|
||||
|
||||
#define DEVICE_OPT_DEPRECATION \
|
||||
.deprecation_message = "use --audio-device instead"
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/threads.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "misc/ring.h"
|
||||
|
||||
/*
|
||||
@@ -151,7 +151,7 @@ int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us)
|
||||
end:
|
||||
|
||||
if (need_wakeup)
|
||||
mp_input_wakeup_nolock(ao->input_ctx);
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
|
||||
// pad with silence (underflow/paused/eof)
|
||||
for (int n = 0; n < ao->num_planes; n++)
|
||||
|
||||
+5
-3
@@ -35,7 +35,7 @@
|
||||
|
||||
#include "osdep/threads.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
|
||||
#include "audio/audio.h"
|
||||
#include "audio/audio_buffer.h"
|
||||
@@ -182,6 +182,7 @@ static int unlocked_get_space(struct ao *ao)
|
||||
struct ao_push_state *p = ao->api_priv;
|
||||
int space = mp_audio_buffer_get_write_available(p->buffer);
|
||||
if (ao->driver->get_space) {
|
||||
int align = af_format_sample_alignment(ao->format);
|
||||
// The following code attempts to keep the total buffered audio to
|
||||
// ao->buffer in order to improve latency.
|
||||
int device_space = ao->driver->get_space(ao);
|
||||
@@ -191,6 +192,7 @@ static int unlocked_get_space(struct ao *ao)
|
||||
// byte based and doesn't do proper chunked processing.
|
||||
int min_buffer = ao->buffer + 64;
|
||||
int missing = min_buffer - device_buffered - soft_buffered;
|
||||
missing = (missing + align - 1) / align * align;
|
||||
// But always keep the device's buffer filled as much as we can.
|
||||
int device_missing = device_space - soft_buffered;
|
||||
missing = MPMAX(missing, device_missing);
|
||||
@@ -305,7 +307,7 @@ static void ao_play_data(struct ao *ao)
|
||||
bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck &&
|
||||
!(flags & AOPLAY_FINAL_CHUNK);
|
||||
if (more)
|
||||
mp_input_wakeup(ao->input_ctx); // request more data
|
||||
ao->wakeup_cb(ao->wakeup_ctx); // request more data
|
||||
MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n",
|
||||
max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more);
|
||||
}
|
||||
@@ -347,7 +349,7 @@ static void *playthread(void *arg)
|
||||
}
|
||||
|
||||
if (was_playing && !p->still_playing)
|
||||
mp_input_wakeup(ao->input_ctx);
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
pthread_cond_signal(&p->wakeup); // for draining
|
||||
|
||||
if (p->still_playing && timeout > 0) {
|
||||
|
||||
+30
-2
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/log.h>
|
||||
@@ -84,6 +85,30 @@ void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Pick a "good" timebase, which will be used to convert double timestamps
|
||||
// back to fractions for passing them through libavcodec.
|
||||
AVRational mp_get_codec_timebase(struct mp_codec_params *c)
|
||||
{
|
||||
AVRational tb = {c->native_tb_num, c->native_tb_den};
|
||||
if (tb.num < 1 || tb.den < 1) {
|
||||
if (c->reliable_fps)
|
||||
tb = av_inv_q(av_d2q(c->fps, 1000000));
|
||||
if (tb.num < 1 || tb.den < 1)
|
||||
tb = AV_TIME_BASE_Q;
|
||||
}
|
||||
|
||||
// If the timebase is too coarse, raise its precision, or small adjustments
|
||||
// to timestamps done between decoder and demuxer could be lost.
|
||||
if (av_q2d(tb) > 0.001) {
|
||||
AVRational r = av_div_q(tb, (AVRational){1, 1000});
|
||||
tb.den *= (r.num + r.den - 1) / r.den;
|
||||
}
|
||||
|
||||
av_reduce(&tb.num, &tb.den, tb.num, tb.den, 1000000);
|
||||
|
||||
return tb;
|
||||
}
|
||||
|
||||
// We merely pass-through our PTS/DTS as an int64_t; libavcodec won't use it.
|
||||
union pts { int64_t i; double d; };
|
||||
|
||||
@@ -97,8 +122,10 @@ union pts { int64_t i; double d; };
|
||||
int64_t mp_pts_to_av(double mp_pts, AVRational *tb)
|
||||
{
|
||||
assert(sizeof(int64_t) >= sizeof(double));
|
||||
if (tb && tb->num > 0 && tb->den > 0)
|
||||
return mp_pts == MP_NOPTS_VALUE ? AV_NOPTS_VALUE : mp_pts / av_q2d(*tb);
|
||||
if (tb && tb->num > 0 && tb->den > 0) {
|
||||
return mp_pts == MP_NOPTS_VALUE ?
|
||||
AV_NOPTS_VALUE : llrint(mp_pts / av_q2d(*tb));
|
||||
}
|
||||
// The + 0.0 is to squash possible negative zero mp_pts, which would
|
||||
// happen to end up as AV_NOPTS_VALUE.
|
||||
return (union pts){.d = mp_pts + 0.0}.i;
|
||||
@@ -133,6 +160,7 @@ void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb)
|
||||
dst->side_data_elems = mpkt->avpacket->side_data_elems;
|
||||
if (dst->data == mpkt->avpacket->data)
|
||||
dst->buf = mpkt->avpacket->buf;
|
||||
dst->flags |= mpkt->avpacket->flags;
|
||||
}
|
||||
if (mpkt && tb && tb->num > 0 && tb->den > 0)
|
||||
dst->duration = mpkt->duration / av_q2d(*tb);
|
||||
|
||||
@@ -33,6 +33,7 @@ struct mp_log;
|
||||
int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size);
|
||||
void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st);
|
||||
void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c);
|
||||
AVRational mp_get_codec_timebase(struct mp_codec_params *c);
|
||||
void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb);
|
||||
int64_t mp_pts_to_av(double mp_pts, AVRational *tb);
|
||||
double mp_pts_from_av(int64_t av_pts, AVRational *tb);
|
||||
@@ -45,4 +46,13 @@ void mp_set_avdict(struct AVDictionary **dict, char **kv);
|
||||
void mp_avdict_print_unset(struct mp_log *log, int msgl, struct AVDictionary *d);
|
||||
int mp_set_avopts(struct mp_log *log, void *avobj, char **kv);
|
||||
|
||||
#if (LIBAVCODEC_VERSION_MICRO >= 100 && \
|
||||
LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 61, 100)) || \
|
||||
(LIBAVCODEC_VERSION_MICRO < 100 && \
|
||||
LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 0))
|
||||
#define MP_AVFRAME_DEC_PTS(frame) ((frame)->pts)
|
||||
#else
|
||||
#define MP_AVFRAME_DEC_PTS(frame) ((frame)->pkt_pts)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+3
-2
@@ -18,6 +18,7 @@
|
||||
#ifndef MPLAYER_MPCOMMON_H
|
||||
#define MPLAYER_MPCOMMON_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
@@ -64,8 +65,8 @@ enum {
|
||||
DATA_EOF = -2,
|
||||
};
|
||||
|
||||
extern const char *const mpv_version;
|
||||
extern const char *const mpv_builddate;
|
||||
extern const char mpv_version[];
|
||||
extern const char mpv_builddate[];
|
||||
|
||||
char *mp_format_time(double time, bool fractions);
|
||||
char *mp_format_time_fmt(const char *fmt, double time);
|
||||
|
||||
+19
-19
@@ -36,25 +36,25 @@
|
||||
#define OPT_BASE_STRUCT struct encode_opts
|
||||
const struct m_sub_options encode_config = {
|
||||
.opts = (const m_option_t[]) {
|
||||
OPT_STRING("o", file, CONF_GLOBAL | CONF_NOCFG | CONF_PRE_PARSE),
|
||||
OPT_STRING("of", format, CONF_GLOBAL),
|
||||
OPT_STRINGLIST("ofopts*", fopts, CONF_GLOBAL),
|
||||
OPT_FLOATRANGE("ofps", fps, CONF_GLOBAL, 0.0, 1000000.0),
|
||||
OPT_FLOATRANGE("omaxfps", maxfps, CONF_GLOBAL, 0.0, 1000000.0),
|
||||
OPT_STRING("ovc", vcodec, CONF_GLOBAL),
|
||||
OPT_STRINGLIST("ovcopts*", vopts, CONF_GLOBAL),
|
||||
OPT_STRING("oac", acodec, CONF_GLOBAL),
|
||||
OPT_STRINGLIST("oacopts*", aopts, CONF_GLOBAL),
|
||||
OPT_FLAG("oharddup", harddup, CONF_GLOBAL),
|
||||
OPT_FLOATRANGE("ovoffset", voffset, CONF_GLOBAL, -1000000.0, 1000000.0),
|
||||
OPT_FLOATRANGE("oaoffset", aoffset, CONF_GLOBAL, -1000000.0, 1000000.0),
|
||||
OPT_FLAG("ocopyts", copyts, CONF_GLOBAL),
|
||||
OPT_FLAG("orawts", rawts, CONF_GLOBAL),
|
||||
OPT_FLAG("oautofps", autofps, CONF_GLOBAL),
|
||||
OPT_FLAG("oneverdrop", neverdrop, CONF_GLOBAL),
|
||||
OPT_FLAG("ovfirst", video_first, CONF_GLOBAL),
|
||||
OPT_FLAG("oafirst", audio_first, CONF_GLOBAL),
|
||||
OPT_FLAG("ometadata", metadata, CONF_GLOBAL),
|
||||
OPT_STRING("o", file, M_OPT_FIXED | CONF_NOCFG | CONF_PRE_PARSE),
|
||||
OPT_STRING("of", format, M_OPT_FIXED),
|
||||
OPT_STRINGLIST("ofopts*", fopts, M_OPT_FIXED),
|
||||
OPT_FLOATRANGE("ofps", fps, M_OPT_FIXED, 0.0, 1000000.0),
|
||||
OPT_FLOATRANGE("omaxfps", maxfps, M_OPT_FIXED, 0.0, 1000000.0),
|
||||
OPT_STRING("ovc", vcodec, M_OPT_FIXED),
|
||||
OPT_STRINGLIST("ovcopts*", vopts, M_OPT_FIXED),
|
||||
OPT_STRING("oac", acodec, M_OPT_FIXED),
|
||||
OPT_STRINGLIST("oacopts*", aopts, M_OPT_FIXED),
|
||||
OPT_FLAG("oharddup", harddup, M_OPT_FIXED),
|
||||
OPT_FLOATRANGE("ovoffset", voffset, M_OPT_FIXED, -1000000.0, 1000000.0),
|
||||
OPT_FLOATRANGE("oaoffset", aoffset, M_OPT_FIXED, -1000000.0, 1000000.0),
|
||||
OPT_FLAG("ocopyts", copyts, M_OPT_FIXED),
|
||||
OPT_FLAG("orawts", rawts, M_OPT_FIXED),
|
||||
OPT_FLAG("oautofps", autofps, M_OPT_FIXED),
|
||||
OPT_FLAG("oneverdrop", neverdrop, M_OPT_FIXED),
|
||||
OPT_FLAG("ovfirst", video_first, M_OPT_FIXED),
|
||||
OPT_FLAG("oafirst", audio_first, M_OPT_FIXED),
|
||||
OPT_FLAG("ometadata", metadata, M_OPT_FIXED),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct encode_opts),
|
||||
|
||||
+5
-1
@@ -5,9 +5,13 @@
|
||||
// The only purpose of this is to make mpv library-safe.
|
||||
// Think hard before adding new members.
|
||||
struct mpv_global {
|
||||
struct MPOpts *opts;
|
||||
struct mp_log *log;
|
||||
struct m_config_shadow *config;
|
||||
struct mp_client_api *client_api;
|
||||
|
||||
// Using this is deprecated and should be avoided (missing synchronization).
|
||||
// Use m_config_cache to access mpv_global.config instead.
|
||||
struct MPOpts *opts;
|
||||
};
|
||||
|
||||
#endif
|
||||
+50
-22
@@ -27,12 +27,13 @@
|
||||
#include "mpv_talloc.h"
|
||||
|
||||
#include "misc/bstr.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "common/common.h"
|
||||
#include "common/global.h"
|
||||
#include "misc/ring.h"
|
||||
#include "misc/bstr.h"
|
||||
#include "options/options.h"
|
||||
#include "options/path.h"
|
||||
#include "osdep/terminal.h"
|
||||
#include "osdep/io.h"
|
||||
#include "osdep/timer.h"
|
||||
@@ -59,6 +60,8 @@ struct mp_log_root {
|
||||
int num_buffers;
|
||||
FILE *log_file;
|
||||
FILE *stats_file;
|
||||
char *log_path;
|
||||
char *stats_path;
|
||||
// --- must be accessed atomically
|
||||
/* This is incremented every time the msglevels must be reloaded.
|
||||
* (This is perhaps better than maintaining a globally accessible and
|
||||
@@ -286,6 +289,7 @@ static void write_log_file(struct mp_log *log, int lev, char *text)
|
||||
(mp_time_us() - MP_START_TIME) / 1e6,
|
||||
mp_log_levels[lev][0],
|
||||
log->verbose_prefix, text);
|
||||
fflush(root->log_file);
|
||||
}
|
||||
|
||||
static void write_msg_to_buffers(struct mp_log *log, int lev, char *text)
|
||||
@@ -457,6 +461,43 @@ void mp_msg_init(struct mpv_global *global)
|
||||
mp_msg_update_msglevels(global);
|
||||
}
|
||||
|
||||
// If opt is different from *current_path, reopen *file and update *current_path.
|
||||
// If there's an error, _append_ it to err_buf.
|
||||
// *current_path and *file are, rather trickily, only accessible under the
|
||||
// mp_msg_lock.
|
||||
static void reopen_file(char *opt, char **current_path, FILE **file,
|
||||
const char *type, struct mpv_global *global)
|
||||
{
|
||||
void *tmp = talloc_new(NULL);
|
||||
bool fail = false;
|
||||
|
||||
char *new_path = mp_get_user_path(tmp, global, opt);
|
||||
if (!new_path)
|
||||
new_path = "";
|
||||
|
||||
pthread_mutex_lock(&mp_msg_lock); // for *current_path/*file
|
||||
|
||||
char *old_path = *current_path ? *current_path : "";
|
||||
if (strcmp(old_path, new_path) != 0) {
|
||||
if (*file)
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
talloc_free(*current_path);
|
||||
*current_path = talloc_strdup(NULL, new_path);
|
||||
if (new_path[0]) {
|
||||
*file = fopen(new_path, "wb");
|
||||
fail = !*file;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mp_msg_lock);
|
||||
|
||||
if (fail)
|
||||
mp_err(global->log, "Failed to open %s file '%s'\n", type, new_path);
|
||||
|
||||
talloc_free(tmp);
|
||||
}
|
||||
|
||||
void mp_msg_update_msglevels(struct mpv_global *global)
|
||||
{
|
||||
struct mp_log_root *root = global->log->root;
|
||||
@@ -480,11 +521,14 @@ void mp_msg_update_msglevels(struct mpv_global *global)
|
||||
m_option_type_msglevels.copy(NULL, &root->msg_levels,
|
||||
&global->opts->msg_levels);
|
||||
|
||||
if (!root->log_file && opts->log_file && opts->log_file[0])
|
||||
root->log_file = fopen(opts->log_file, "wb");
|
||||
|
||||
atomic_fetch_add(&root->reload_counter, 1);
|
||||
pthread_mutex_unlock(&mp_msg_lock);
|
||||
|
||||
reopen_file(opts->log_file, &root->log_path, &root->log_file,
|
||||
"log", global);
|
||||
|
||||
reopen_file(opts->dump_stats, &root->stats_path, &root->stats_file,
|
||||
"stats", global);
|
||||
}
|
||||
|
||||
void mp_msg_force_stderr(struct mpv_global *global, bool force_stderr)
|
||||
@@ -499,8 +543,10 @@ void mp_msg_uninit(struct mpv_global *global)
|
||||
struct mp_log_root *root = global->log->root;
|
||||
if (root->stats_file)
|
||||
fclose(root->stats_file);
|
||||
talloc_free(root->stats_path);
|
||||
if (root->log_file)
|
||||
fclose(root->log_file);
|
||||
talloc_free(root->log_path);
|
||||
m_option_type_msglevels.free(&root->msg_levels);
|
||||
talloc_free(root);
|
||||
global->log = NULL;
|
||||
@@ -582,24 +628,6 @@ struct mp_log_buffer_entry *mp_msg_log_buffer_read(struct mp_log_buffer *buffer)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int mp_msg_open_stats_file(struct mpv_global *global, const char *path)
|
||||
{
|
||||
struct mp_log_root *root = global->log->root;
|
||||
int r;
|
||||
|
||||
pthread_mutex_lock(&mp_msg_lock);
|
||||
|
||||
if (root->stats_file)
|
||||
fclose(root->stats_file);
|
||||
root->stats_file = fopen(path, "wb");
|
||||
r = root->stats_file ? 0 : -1;
|
||||
|
||||
pthread_mutex_unlock(&mp_msg_lock);
|
||||
|
||||
mp_msg_update_msglevels(global);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Thread-safety: fully thread-safe, but keep in mind that the lifetime of
|
||||
// log must be guaranteed during the call.
|
||||
// Never call this from signal handlers.
|
||||
|
||||
@@ -29,7 +29,6 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
|
||||
void mp_msg_log_buffer_destroy(struct mp_log_buffer *buffer);
|
||||
struct mp_log_buffer_entry *mp_msg_log_buffer_read(struct mp_log_buffer *buffer);
|
||||
|
||||
int mp_msg_open_stats_file(struct mpv_global *global, const char *path);
|
||||
int mp_msg_find_level(const char *s);
|
||||
|
||||
extern const char *const mp_log_levels[MSGL_MAX + 1];
|
||||
|
||||
+2
-2
@@ -22,5 +22,5 @@
|
||||
#define BUILDDATE "UNKNOWN"
|
||||
#endif
|
||||
|
||||
const char *const mpv_version = "mpv " VERSION;
|
||||
const char *const mpv_builddate = BUILDDATE;
|
||||
const char mpv_version[] = "mpv " VERSION;
|
||||
const char mpv_builddate[] = BUILDDATE;
|
||||
+78
-20
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <math.h>
|
||||
@@ -28,7 +29,8 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "mpv_talloc.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/global.h"
|
||||
@@ -81,6 +83,34 @@ const demuxer_desc_t *const demuxer_list[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
struct demux_opts {
|
||||
int max_packs;
|
||||
int max_bytes;
|
||||
double min_secs;
|
||||
int force_seekable;
|
||||
double min_secs_cache;
|
||||
};
|
||||
|
||||
#define OPT_BASE_STRUCT struct demux_opts
|
||||
|
||||
const struct m_sub_options demux_conf = {
|
||||
.opts = (const struct m_option[]){
|
||||
OPT_DOUBLE("demuxer-readahead-secs", min_secs, M_OPT_MIN, .min = 0),
|
||||
OPT_INTRANGE("demuxer-max-packets", max_packs, 0, 0, INT_MAX),
|
||||
OPT_INTRANGE("demuxer-max-bytes", max_bytes, 0, 0, INT_MAX),
|
||||
OPT_FLAG("force-seekable", force_seekable, 0),
|
||||
OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct demux_opts),
|
||||
.defaults = &(const struct demux_opts){
|
||||
.max_packs = 16000,
|
||||
.max_bytes = 400 * 1024 * 1024,
|
||||
.min_secs = 1.0,
|
||||
.min_secs_cache = 10.0,
|
||||
},
|
||||
};
|
||||
|
||||
struct demux_internal {
|
||||
struct mp_log *log;
|
||||
|
||||
@@ -568,7 +598,7 @@ static bool read_packet(struct demux_internal *in)
|
||||
for (int n = 0; n < in->num_streams; n++) {
|
||||
struct demux_stream *ds = in->streams[n]->ds;
|
||||
active |= ds->active;
|
||||
read_more |= ds->active && !ds->head;
|
||||
read_more |= (ds->active && !ds->head) || ds->refreshing;
|
||||
packs += ds->packs;
|
||||
bytes += ds->bytes;
|
||||
if (ds->active && ds->last_ts != MP_NOPTS_VALUE && in->min_secs > 0 &&
|
||||
@@ -580,12 +610,12 @@ static bool read_packet(struct demux_internal *in)
|
||||
if (packs >= in->max_packs || bytes >= in->max_bytes) {
|
||||
if (!in->warned_queue_overflow) {
|
||||
in->warned_queue_overflow = true;
|
||||
MP_ERR(in, "Too many packets in the demuxer packet queues:\n");
|
||||
MP_WARN(in, "Too many packets in the demuxer packet queues:\n");
|
||||
for (int n = 0; n < in->num_streams; n++) {
|
||||
struct demux_stream *ds = in->streams[n]->ds;
|
||||
if (ds->selected) {
|
||||
MP_ERR(in, " %s/%d: %zd packets, %zd bytes\n",
|
||||
stream_type_name(ds->type), n, ds->packs, ds->bytes);
|
||||
MP_WARN(in, " %s/%d: %zd packets, %zd bytes\n",
|
||||
stream_type_name(ds->type), n, ds->packs, ds->bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,11 +632,13 @@ static bool read_packet(struct demux_internal *in)
|
||||
return false;
|
||||
}
|
||||
|
||||
double seek_pts = get_refresh_seek_pts(in);
|
||||
bool refresh_seek = seek_pts != MP_NOPTS_VALUE;
|
||||
read_more |= refresh_seek;
|
||||
|
||||
if (!read_more)
|
||||
return false;
|
||||
|
||||
double seek_pts = get_refresh_seek_pts(in);
|
||||
|
||||
// Actually read a packet. Drop the lock while doing so, because waiting
|
||||
// for disk or network I/O can take time.
|
||||
in->idle = false;
|
||||
@@ -615,7 +647,7 @@ static bool read_packet(struct demux_internal *in)
|
||||
|
||||
struct demuxer *demux = in->d_thread;
|
||||
|
||||
if (seek_pts != MP_NOPTS_VALUE) {
|
||||
if (refresh_seek) {
|
||||
MP_VERBOSE(in, "refresh seek to %f\n", seek_pts);
|
||||
demux->desc->seek(demux, seek_pts, SEEK_BACKWARD | SEEK_HR);
|
||||
}
|
||||
@@ -1031,6 +1063,7 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src)
|
||||
dst->ts_resets_possible = src->ts_resets_possible;
|
||||
dst->fully_read = src->fully_read;
|
||||
dst->start_time = src->start_time;
|
||||
dst->is_network = src->is_network;
|
||||
dst->priv = src->priv;
|
||||
}
|
||||
|
||||
@@ -1039,10 +1072,10 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src)
|
||||
dst->metadata = mp_tags_dup(dst, src->metadata);
|
||||
|
||||
if (dst->num_update_stream_tags != src->num_update_stream_tags) {
|
||||
dst->num_update_stream_tags = src->num_update_stream_tags;
|
||||
talloc_free(dst->update_stream_tags);
|
||||
dst->update_stream_tags =
|
||||
talloc_zero_array(dst, struct mp_tags *, dst->num_update_stream_tags);
|
||||
dst->num_update_stream_tags = src->num_update_stream_tags;
|
||||
}
|
||||
for (int n = 0; n < dst->num_update_stream_tags; n++) {
|
||||
talloc_free(dst->update_stream_tags[n]);
|
||||
@@ -1151,6 +1184,23 @@ static void demux_init_cuesheet(struct demuxer *demuxer)
|
||||
}
|
||||
}
|
||||
|
||||
static void demux_maybe_replace_stream(struct demuxer *demuxer)
|
||||
{
|
||||
struct demux_internal *in = demuxer->in;
|
||||
assert(!in->threading && demuxer == in->d_user);
|
||||
|
||||
if (demuxer->fully_read) {
|
||||
MP_VERBOSE(demuxer, "assuming demuxer read all data; closing stream\n");
|
||||
free_stream(demuxer->stream);
|
||||
demuxer->stream = open_memory_stream(NULL, 0); // dummy
|
||||
in->d_thread->stream = demuxer->stream;
|
||||
in->d_buffer->stream = demuxer->stream;
|
||||
|
||||
if (demuxer->desc->control)
|
||||
demuxer->desc->control(in->d_thread, DEMUXER_CTRL_REPLACE_STREAM, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
struct mp_log *log,
|
||||
const struct demuxer_desc *desc,
|
||||
@@ -1167,11 +1217,11 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
.stream = stream,
|
||||
.seekable = stream->seekable,
|
||||
.filepos = -1,
|
||||
.opts = global->opts,
|
||||
.global = global,
|
||||
.log = mp_log_new(demuxer, log, desc->name),
|
||||
.glog = log,
|
||||
.filename = talloc_strdup(demuxer, stream->url),
|
||||
.is_network = stream->is_network,
|
||||
.events = DEMUX_EVENT_ALL,
|
||||
};
|
||||
demuxer->seekable = stream->seekable;
|
||||
@@ -1179,22 +1229,24 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
!demuxer->stream->uncached_stream->seekable)
|
||||
demuxer->seekable = false;
|
||||
|
||||
struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf);
|
||||
|
||||
struct demux_internal *in = demuxer->in = talloc_ptrtype(demuxer, in);
|
||||
*in = (struct demux_internal){
|
||||
.log = demuxer->log,
|
||||
.d_thread = talloc(demuxer, struct demuxer),
|
||||
.d_buffer = talloc(demuxer, struct demuxer),
|
||||
.d_user = demuxer,
|
||||
.min_secs = demuxer->opts->demuxer_min_secs,
|
||||
.max_packs = demuxer->opts->demuxer_max_packs,
|
||||
.max_bytes = demuxer->opts->demuxer_max_bytes,
|
||||
.min_secs = opts->min_secs,
|
||||
.max_packs = opts->max_packs,
|
||||
.max_bytes = opts->max_bytes,
|
||||
.initial_state = true,
|
||||
};
|
||||
pthread_mutex_init(&in->lock, NULL);
|
||||
pthread_cond_init(&in->wakeup, NULL);
|
||||
|
||||
if (stream->uncached_stream)
|
||||
in->min_secs = MPMAX(in->min_secs, demuxer->opts->demuxer_min_secs_cache);
|
||||
in->min_secs = MPMAX(in->min_secs, opts->min_secs_cache);
|
||||
|
||||
*in->d_thread = *demuxer;
|
||||
*in->d_buffer = *demuxer;
|
||||
@@ -1225,7 +1277,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
mp_verbose(log, "Detected file format: %s\n", desc->desc);
|
||||
if (!in->d_thread->seekable)
|
||||
mp_verbose(log, "Stream is not seekable.\n");
|
||||
if (!in->d_thread->seekable && demuxer->opts->force_seekable) {
|
||||
if (!in->d_thread->seekable && opts->force_seekable) {
|
||||
mp_warn(log, "Not seekable, but enabling seeking on user request.\n");
|
||||
in->d_thread->seekable = true;
|
||||
in->d_thread->partially_seekable = true;
|
||||
@@ -1311,12 +1363,12 @@ done:
|
||||
// Convenience function: open the stream, enable the cache (according to params
|
||||
// and global opts.), open the demuxer.
|
||||
// (use free_demuxer_and_stream() to free the underlying stream too)
|
||||
// Also for some reason may close the opened stream if it's not needed.
|
||||
struct demuxer *demux_open_url(const char *url,
|
||||
struct demuxer_params *params,
|
||||
struct mp_cancel *cancel,
|
||||
struct mpv_global *global)
|
||||
{
|
||||
struct MPOpts *opts = global->opts;
|
||||
struct demuxer_params dummy = {0};
|
||||
if (!params)
|
||||
params = &dummy;
|
||||
@@ -1324,12 +1376,18 @@ struct demuxer *demux_open_url(const char *url,
|
||||
cancel, global);
|
||||
if (!s)
|
||||
return NULL;
|
||||
if (params->allow_capture)
|
||||
stream_set_capture_file(s, opts->stream_capture);
|
||||
if (params->allow_capture) {
|
||||
char *f;
|
||||
mp_read_option_raw(global, "stream-capture", &m_option_type_string, &f);
|
||||
stream_set_capture_file(s, f);
|
||||
talloc_free(f);
|
||||
}
|
||||
if (!params->disable_cache)
|
||||
stream_enable_cache(&s, &opts->stream_cache);
|
||||
stream_enable_cache_defaults(&s);
|
||||
struct demuxer *d = demux_open(s, params, global);
|
||||
if (!d) {
|
||||
if (d) {
|
||||
demux_maybe_replace_stream(d);
|
||||
} else {
|
||||
params->demuxer_failed = true;
|
||||
free_stream(s);
|
||||
}
|
||||
|
||||
+3
-1
@@ -43,6 +43,7 @@ enum demux_ctrl {
|
||||
DEMUXER_CTRL_STREAM_CTRL,
|
||||
DEMUXER_CTRL_GET_READER_STATE,
|
||||
DEMUXER_CTRL_GET_BITRATE_STATS, // double[STREAM_TYPE_COUNT]
|
||||
DEMUXER_CTRL_REPLACE_STREAM,
|
||||
};
|
||||
|
||||
struct demux_ctrl_reader_state {
|
||||
@@ -183,6 +184,7 @@ typedef struct demuxer {
|
||||
// packets is not slow either (unlike e.g. libavdevice pseudo-demuxers).
|
||||
// Typical examples: text subtitles, playlists
|
||||
bool fully_read;
|
||||
bool is_network; // opened directly from a network stream
|
||||
|
||||
// Bitmask of DEMUX_EVENT_*
|
||||
int events;
|
||||
@@ -205,7 +207,6 @@ typedef struct demuxer {
|
||||
struct mp_tags *metadata;
|
||||
|
||||
void *priv; // demuxer-specific internal data
|
||||
struct MPOpts *opts;
|
||||
struct mpv_global *global;
|
||||
struct mp_log *log, *glog;
|
||||
struct demuxer_params *params;
|
||||
@@ -219,6 +220,7 @@ typedef struct demuxer {
|
||||
// thread-safe, only the demuxer is allowed to access the stream directly.
|
||||
// You can freely use demux_stream_control() to send STREAM_CTRLs, or use
|
||||
// demux_pause() to get exclusive access to the stream.
|
||||
// Also note that the stream can get replaced if fully_read is set.
|
||||
struct stream *stream;
|
||||
} demuxer_t;
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "demux.h"
|
||||
#include "timeline.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/global.h"
|
||||
#include "options/path.h"
|
||||
#include "misc/bstr.h"
|
||||
#include "common/common.h"
|
||||
|
||||
+66
-25
@@ -35,7 +35,6 @@
|
||||
#include <libavutil/display.h>
|
||||
#include <libavutil/opt.h>
|
||||
|
||||
#include "options/options.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/tags.h"
|
||||
#include "common/av_common.h"
|
||||
@@ -45,6 +44,7 @@
|
||||
#include "stream/stream.h"
|
||||
#include "demux.h"
|
||||
#include "stheader.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "options/path.h"
|
||||
|
||||
@@ -69,22 +69,32 @@ struct demux_lavf_opts {
|
||||
char **avopts;
|
||||
int hacks;
|
||||
int genptsmode;
|
||||
char *sub_cp;
|
||||
int rtsp_transport;
|
||||
};
|
||||
|
||||
const struct m_sub_options demux_lavf_conf = {
|
||||
.opts = (const m_option_t[]) {
|
||||
OPT_INTRANGE("probesize", probesize, 0, 32, INT_MAX),
|
||||
OPT_STRING("format", format, 0),
|
||||
OPT_FLOATRANGE("analyzeduration", analyzeduration, 0, 0, 3600),
|
||||
OPT_INTRANGE("buffersize", buffersize, 0, 1, 10 * 1024 * 1024,
|
||||
OPTDEF_INT(BIO_BUFFER_SIZE)),
|
||||
OPT_FLAG("allow-mimetype", allow_mimetype, 0),
|
||||
OPT_INTRANGE("probescore", probescore, 0, 1, AVPROBE_SCORE_MAX),
|
||||
OPT_STRING("cryptokey", cryptokey, 0),
|
||||
OPT_FLAG("hacks", hacks, 0),
|
||||
OPT_CHOICE("genpts-mode", genptsmode, 0,
|
||||
OPT_INTRANGE("demuxer-lavf-probesize", probesize, 0, 32, INT_MAX),
|
||||
OPT_STRING("demuxer-lavf-format", format, 0),
|
||||
OPT_FLOATRANGE("demuxer-lavf-analyzeduration", analyzeduration, 0,
|
||||
0, 3600),
|
||||
OPT_INTRANGE("demuxer-lavf-buffersize", buffersize, 0, 1,
|
||||
10 * 1024 * 1024, OPTDEF_INT(BIO_BUFFER_SIZE)),
|
||||
OPT_FLAG("demuxer-lavf-allow-mimetype", allow_mimetype, 0),
|
||||
OPT_INTRANGE("demuxer-lavf-probescore", probescore, 0,
|
||||
1, AVPROBE_SCORE_MAX),
|
||||
OPT_STRING("demuxer-lavf-cryptokey", cryptokey, 0),
|
||||
OPT_FLAG("demuxer-lavf-hacks", hacks, 0),
|
||||
OPT_CHOICE("demuxer-lavf-genpts-mode", genptsmode, 0,
|
||||
({"lavf", 1}, {"no", 0})),
|
||||
OPT_KEYVALUELIST("o", avopts, 0),
|
||||
OPT_KEYVALUELIST("demuxer-lavf-o", avopts, 0),
|
||||
OPT_STRING("sub-codepage", sub_cp, 0),
|
||||
OPT_CHOICE("rtsp-transport", rtsp_transport, 0,
|
||||
({"lavf", 0},
|
||||
{"udp", 1},
|
||||
{"tcp", 2},
|
||||
{"http", 3})),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct demux_lavf_opts),
|
||||
@@ -95,6 +105,8 @@ const struct m_sub_options demux_lavf_conf = {
|
||||
// user is supposed to retry with larger probe sizes until a higher
|
||||
// value is reached.
|
||||
.probescore = AVPROBE_SCORE_MAX/4 + 1,
|
||||
.sub_cp = "auto",
|
||||
.rtsp_transport = 2,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -114,6 +126,7 @@ struct format_hack {
|
||||
// Do not confuse player's position estimation (position is into external
|
||||
// segment, with e.g. HLS, player knows about the playlist main file only).
|
||||
bool clear_filepos : 1;
|
||||
bool ignore_start : 1;
|
||||
};
|
||||
|
||||
#define BLACKLIST(fmt) {fmt, .ignore = true}
|
||||
@@ -137,6 +150,9 @@ static const struct format_hack format_hacks[] = {
|
||||
{"h264", .if_flags = AVFMT_NOTIMESTAMPS },
|
||||
{"hevc", .if_flags = AVFMT_NOTIMESTAMPS },
|
||||
|
||||
// Rebasing start time to 0 is very weird with ogg shoutcast streams.
|
||||
{"ogg", .ignore_start = true},
|
||||
|
||||
TEXTSUB("aqtitle"), TEXTSUB("jacosub"), TEXTSUB("microdvd"),
|
||||
TEXTSUB("mpl2"), TEXTSUB("mpsub"), TEXTSUB("pjs"), TEXTSUB("realtext"),
|
||||
TEXTSUB("sami"), TEXTSUB("srt"), TEXTSUB("stl"), TEXTSUB("subviewer"),
|
||||
@@ -158,6 +174,7 @@ static const struct format_hack format_hacks[] = {
|
||||
|
||||
typedef struct lavf_priv {
|
||||
struct stream *stream;
|
||||
bool own_stream;
|
||||
char *filename;
|
||||
struct format_hack format_hack;
|
||||
AVInputFormat *avif;
|
||||
@@ -169,6 +186,9 @@ typedef struct lavf_priv {
|
||||
int cur_program;
|
||||
char *mime_type;
|
||||
double seek_delay;
|
||||
|
||||
struct demux_lavf_opts *opts;
|
||||
double mf_fps;
|
||||
} lavf_priv_t;
|
||||
|
||||
// At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
|
||||
@@ -266,7 +286,7 @@ static void list_formats(struct demuxer *demuxer)
|
||||
static void convert_charset(struct demuxer *demuxer)
|
||||
{
|
||||
lavf_priv_t *priv = demuxer->priv;
|
||||
char *cp = demuxer->opts->sub_cp;
|
||||
char *cp = priv->opts->sub_cp;
|
||||
if (!cp || mp_charset_is_utf8(cp))
|
||||
return;
|
||||
bstr data = stream_read_complete(priv->stream, NULL, 128 * 1024 * 1024);
|
||||
@@ -286,8 +306,10 @@ static void convert_charset(struct demuxer *demuxer)
|
||||
if (conv.start)
|
||||
data = conv;
|
||||
}
|
||||
if (data.start)
|
||||
if (data.start) {
|
||||
priv->stream = open_memory_stream(data.start, data.len);
|
||||
priv->own_stream = true;
|
||||
}
|
||||
talloc_free(alloc);
|
||||
}
|
||||
|
||||
@@ -306,9 +328,8 @@ static const char *const prefixes[] =
|
||||
|
||||
static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
struct demux_lavf_opts *lavfdopts = opts->demux_lavf;
|
||||
lavf_priv_t *priv = demuxer->priv;
|
||||
struct demux_lavf_opts *lavfdopts = priv->opts;
|
||||
struct stream *s = priv->stream;
|
||||
|
||||
priv->filename = remove_prefix(s->url, prefixes);
|
||||
@@ -599,7 +620,7 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
|
||||
if (st->avg_frame_rate.num)
|
||||
sh->codec->fps = av_q2d(st->avg_frame_rate);
|
||||
if (priv->format_hack.image_format)
|
||||
sh->codec->fps = demuxer->opts->mf_fps;
|
||||
sh->codec->fps = priv->mf_fps;
|
||||
sh->codec->par_w = st->sample_aspect_ratio.num;
|
||||
sh->codec->par_h = st->sample_aspect_ratio.den;
|
||||
|
||||
@@ -666,6 +687,8 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
|
||||
if (sh->codec->lav_headers)
|
||||
mp_copy_lav_codec_headers(sh->codec->lav_headers, codec);
|
||||
#endif
|
||||
sh->codec->native_tb_num = st->time_base.num;
|
||||
sh->codec->native_tb_den = st->time_base.den;
|
||||
|
||||
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
||||
sh->default_track = true;
|
||||
@@ -727,8 +750,6 @@ static int interrupt_cb(void *ctx)
|
||||
|
||||
static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
struct demux_lavf_opts *lavfdopts = opts->demux_lavf;
|
||||
AVFormatContext *avfc;
|
||||
AVDictionaryEntry *t = NULL;
|
||||
float analyze_duration = 0;
|
||||
@@ -736,6 +757,15 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||
demuxer->priv = priv;
|
||||
priv->stream = demuxer->stream;
|
||||
|
||||
priv->opts = mp_get_config_group(priv, demuxer->global, &demux_lavf_conf);
|
||||
struct demux_lavf_opts *lavfdopts = priv->opts;
|
||||
|
||||
int index_mode;
|
||||
mp_read_option_raw(demuxer->global, "index", &m_option_type_choice,
|
||||
&index_mode);
|
||||
mp_read_option_raw(demuxer->global, "mf-fps", &m_option_type_double,
|
||||
&priv->mf_fps);
|
||||
|
||||
if (lavf_check_file(demuxer, check) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -747,7 +777,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||
parse_cryptokey(avfc, lavfdopts->cryptokey);
|
||||
if (lavfdopts->genptsmode)
|
||||
avfc->flags |= AVFMT_FLAG_GENPTS;
|
||||
if (opts->index_mode != 1)
|
||||
if (index_mode != 1)
|
||||
avfc->flags |= AVFMT_FLAG_IGNIDX;
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MICRO >= 100
|
||||
@@ -780,7 +810,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||
priv->stream->type == STREAMTYPE_AVDEVICE ||
|
||||
priv->format_hack.no_stream)
|
||||
{
|
||||
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log, opts);
|
||||
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log);
|
||||
// This might be incorrect.
|
||||
demuxer->seekable = true;
|
||||
} else {
|
||||
@@ -803,7 +833,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||
|
||||
if (matches_avinputformat_name(priv, "rtsp")) {
|
||||
const char *transport = NULL;
|
||||
switch (opts->network_rtsp_transport) {
|
||||
switch (lavfdopts->rtsp_transport) {
|
||||
case 1: transport = "udp"; break;
|
||||
case 2: transport = "tcp"; break;
|
||||
case 3: transport = "http"; break;
|
||||
@@ -855,8 +885,8 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
||||
demuxer->ts_resets_possible =
|
||||
priv->avif_flags & (AVFMT_TS_DISCONT | AVFMT_NOTIMESTAMPS);
|
||||
|
||||
demuxer->start_time = priv->avfc->start_time == AV_NOPTS_VALUE ?
|
||||
0 : (double)priv->avfc->start_time / AV_TIME_BASE;
|
||||
if (avfc->start_time != AV_NOPTS_VALUE && !priv->format_hack.ignore_start)
|
||||
demuxer->start_time = avfc->start_time / (double)AV_TIME_BASE;
|
||||
|
||||
demuxer->fully_read = priv->format_hack.fully_read;
|
||||
|
||||
@@ -908,6 +938,11 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
|
||||
#endif
|
||||
dp->pos = pkt->pos;
|
||||
dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY;
|
||||
#if LIBAVFORMAT_VERSION_MICRO >= 100 && \
|
||||
LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 50, 100)
|
||||
if (pkt->flags & AV_PKT_FLAG_DISCARD)
|
||||
MP_ERR(demux, "Edit lists are not correctly supported (FFmpeg issue).\n");
|
||||
#endif
|
||||
av_packet_unref(pkt);
|
||||
|
||||
if (priv->format_hack.clear_filepos)
|
||||
@@ -1062,6 +1097,12 @@ redo:
|
||||
av_seek_frame(priv->avfc, 0, stream_tell(priv->stream),
|
||||
AVSEEK_FLAG_BYTE);
|
||||
return DEMUXER_CTRL_OK;
|
||||
case DEMUXER_CTRL_REPLACE_STREAM:
|
||||
if (priv->own_stream)
|
||||
free_stream(priv->stream);
|
||||
priv->own_stream = false;
|
||||
priv->stream = demuxer->stream;
|
||||
return DEMUXER_CTRL_OK;
|
||||
default:
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
}
|
||||
@@ -1086,7 +1127,7 @@ static void demux_close_lavf(demuxer_t *demuxer)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (priv->stream != demuxer->stream)
|
||||
if (priv->own_stream)
|
||||
free_stream(priv->stream);
|
||||
talloc_free(priv);
|
||||
demuxer->priv = NULL;
|
||||
|
||||
+11
-4
@@ -27,6 +27,7 @@
|
||||
#include "mpv_talloc.h"
|
||||
#include "common/msg.h"
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/path.h"
|
||||
#include "misc/ctype.h"
|
||||
|
||||
@@ -304,10 +305,15 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check)
|
||||
if (!mf || mf->nr_of_files < 1)
|
||||
goto error;
|
||||
|
||||
char *force_type = demuxer->opts->mf_type;
|
||||
double mf_fps;
|
||||
char *mf_type;
|
||||
mp_read_option_raw(demuxer->global, "mf-fps", &m_option_type_double, &mf_fps);
|
||||
mp_read_option_raw(demuxer->global, "mf-type", &m_option_type_string, &mf_type);
|
||||
|
||||
const char *codec = mp_map_mimetype_to_video_codec(demuxer->stream->mime_type);
|
||||
if (!codec || (force_type && force_type[0]))
|
||||
codec = probe_format(mf, force_type, check);
|
||||
if (!codec || (mf_type && mf_type[0]))
|
||||
codec = probe_format(mf, mf_type, check);
|
||||
talloc_free(mf_type);
|
||||
if (!codec)
|
||||
goto error;
|
||||
|
||||
@@ -320,7 +326,8 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check)
|
||||
c->codec = codec;
|
||||
c->disp_w = 0;
|
||||
c->disp_h = 0;
|
||||
c->fps = demuxer->opts->mf_fps;
|
||||
c->fps = mf_fps;
|
||||
c->reliable_fps = true;
|
||||
|
||||
demux_add_sh_stream(demuxer, sh);
|
||||
|
||||
|
||||
+22
-15
@@ -43,7 +43,7 @@
|
||||
|
||||
#include "mpv_talloc.h"
|
||||
#include "common/av_common.h"
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "misc/bstr.h"
|
||||
#include "stream/stream.h"
|
||||
@@ -162,6 +162,8 @@ struct block_info {
|
||||
};
|
||||
|
||||
typedef struct mkv_demuxer {
|
||||
struct demux_mkv_opts *opts;
|
||||
|
||||
int64_t segment_start, segment_end;
|
||||
|
||||
double duration;
|
||||
@@ -179,6 +181,9 @@ typedef struct mkv_demuxer {
|
||||
mkv_index_t *indexes;
|
||||
size_t num_indexes;
|
||||
bool index_complete;
|
||||
int index_mode;
|
||||
|
||||
int edition_id;
|
||||
|
||||
struct header_elem {
|
||||
int32_t id;
|
||||
@@ -747,11 +752,10 @@ static void add_block_position(demuxer_t *demuxer, struct mkv_track *track,
|
||||
|
||||
static int demux_mkv_read_cues(demuxer_t *demuxer)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
stream_t *s = demuxer->stream;
|
||||
|
||||
if (opts->index_mode != 1 || mkv_d->index_complete) {
|
||||
if (mkv_d->index_mode != 1 || mkv_d->index_complete) {
|
||||
ebml_read_skip(demuxer->log, -1, s);
|
||||
return 0;
|
||||
}
|
||||
@@ -810,9 +814,9 @@ done:
|
||||
|
||||
static int demux_mkv_read_chapters(struct demuxer *demuxer)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
mkv_demuxer_t *mkv_d = demuxer->priv;
|
||||
stream_t *s = demuxer->stream;
|
||||
int wanted_edition = opts->edition_id;
|
||||
int wanted_edition = mkv_d->edition_id;
|
||||
uint64_t wanted_edition_uid = demuxer->matroska_data.uid.edition;
|
||||
|
||||
/* A specific edition UID was requested; ignore the user option which is
|
||||
@@ -1191,10 +1195,9 @@ static int read_deferred_element(struct demuxer *demuxer,
|
||||
|
||||
static void read_deferred_cues(demuxer_t *demuxer)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
mkv_demuxer_t *mkv_d = demuxer->priv;
|
||||
|
||||
if (mkv_d->index_complete || opts->index_mode != 1)
|
||||
if (mkv_d->index_complete || mkv_d->index_mode != 1)
|
||||
return;
|
||||
|
||||
for (int n = 0; n < mkv_d->num_headers; n++) {
|
||||
@@ -1855,7 +1858,6 @@ static int read_mkv_segment_header(demuxer_t *demuxer, int64_t *segment_end)
|
||||
static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||
{
|
||||
stream_t *s = demuxer->stream;
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
mkv_demuxer_t *mkv_d;
|
||||
int64_t start_pos;
|
||||
int64_t end_pos;
|
||||
@@ -1882,6 +1884,12 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||
mkv_d->a_skip_preroll = 1;
|
||||
mkv_d->skip_to_timecode = INT64_MIN;
|
||||
|
||||
mp_read_option_raw(demuxer->global, "index", &m_option_type_choice,
|
||||
&mkv_d->index_mode);
|
||||
mp_read_option_raw(demuxer->global, "edition", &m_option_type_choice,
|
||||
&mkv_d->edition_id);
|
||||
mkv_d->opts = mp_get_config_group(mkv_d, demuxer->global, &demux_mkv_conf);
|
||||
|
||||
if (demuxer->params && demuxer->params->matroska_was_valid)
|
||||
*demuxer->params->matroska_was_valid = true;
|
||||
|
||||
@@ -1941,7 +1949,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||
process_tags(demuxer);
|
||||
|
||||
probe_first_timestamp(demuxer);
|
||||
if (opts->demux_mkv->probe_duration)
|
||||
if (mkv_d->opts->probe_duration)
|
||||
probe_last_timestamp(demuxer, start_pos);
|
||||
|
||||
return 0;
|
||||
@@ -2730,7 +2738,6 @@ static int create_index_until(struct demuxer *demuxer, int64_t timecode)
|
||||
static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
||||
int64_t target_timecode, int flags)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
struct mkv_demuxer *mkv_d = demuxer->priv;
|
||||
struct mkv_index *index = NULL;
|
||||
|
||||
@@ -2758,9 +2765,9 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
||||
if (flags & FLAG_SUBPREROLL) {
|
||||
// Find the cluster with the highest filepos, that has a timestamp
|
||||
// still lower than min_tc.
|
||||
double secs = opts->demux_mkv->subtitle_preroll_secs;
|
||||
double secs = mkv_d->opts->subtitle_preroll_secs;
|
||||
if (mkv_d->index_has_durations)
|
||||
secs = MPMAX(secs, opts->demux_mkv->subtitle_preroll_secs_index);
|
||||
secs = MPMAX(secs, mkv_d->opts->subtitle_preroll_secs_index);
|
||||
int64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale);
|
||||
int64_t min_tc = pre < index->timecode ? index->timecode - pre : 0;
|
||||
uint64_t prev_target = 0;
|
||||
@@ -2823,7 +2830,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double seek_pts, int flags)
|
||||
int cueflags = (flags & SEEK_BACKWARD) ? FLAG_BACKWARD : 0;
|
||||
|
||||
mkv_d->subtitle_preroll = NUM_SUB_PREROLL_PACKETS;
|
||||
int preroll_opt = demuxer->opts->demux_mkv->subtitle_preroll;
|
||||
int preroll_opt = mkv_d->opts->subtitle_preroll;
|
||||
if (((flags & SEEK_HR) || preroll_opt == 1 ||
|
||||
(preroll_opt == 2 && mkv_d->index_has_durations))
|
||||
&& st_active[STREAM_SUB] && st_active[STREAM_VIDEO])
|
||||
@@ -2917,7 +2924,7 @@ static void probe_last_timestamp(struct demuxer *demuxer, int64_t start_pos)
|
||||
|
||||
// In full mode, we start reading data from the current file position,
|
||||
// which works because this function is called after headers are parsed.
|
||||
if (demuxer->opts->demux_mkv->probe_duration != 2) {
|
||||
if (mkv_d->opts->probe_duration != 2) {
|
||||
read_deferred_cues(demuxer);
|
||||
if (mkv_d->index_complete) {
|
||||
// Find last cluster that still has video packets
|
||||
@@ -2974,7 +2981,7 @@ static void probe_first_timestamp(struct demuxer *demuxer)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = demuxer->priv;
|
||||
|
||||
if (!demuxer->opts->demux_mkv->probe_start_time)
|
||||
if (!mkv_d->opts->probe_start_time)
|
||||
return;
|
||||
|
||||
struct block_info block;
|
||||
|
||||
+14
-12
@@ -32,10 +32,10 @@
|
||||
#include "mpv_talloc.h"
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "common/global.h"
|
||||
#include "demux/demux.h"
|
||||
#include "demux/timeline.h"
|
||||
#include "demux/matroska.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/options.h"
|
||||
#include "options/path.h"
|
||||
#include "misc/bstr.h"
|
||||
@@ -46,6 +46,7 @@
|
||||
struct tl_ctx {
|
||||
struct mp_log *log;
|
||||
struct mpv_global *global;
|
||||
struct MPOpts *opts;
|
||||
struct timeline *tl;
|
||||
|
||||
struct demuxer *demuxer;
|
||||
@@ -209,8 +210,7 @@ static bool check_file_seg(struct tl_ctx *ctx, char *filename, int segment)
|
||||
MP_TARRAY_APPEND(NULL, ctx->sources, ctx->num_sources, NULL);
|
||||
}
|
||||
|
||||
if (stream_wants_cache(d->stream, &ctx->global->opts->stream_cache))
|
||||
{
|
||||
if (stream_wants_cache(d->stream, ctx->opts->stream_cache)) {
|
||||
free_demuxer_and_stream(d);
|
||||
params.disable_cache = false;
|
||||
params.matroska_wanted_uids = ctx->uids; // potentially reallocated, same data
|
||||
@@ -247,7 +247,7 @@ static bool missing(struct tl_ctx *ctx)
|
||||
|
||||
static void find_ordered_chapter_sources(struct tl_ctx *ctx)
|
||||
{
|
||||
struct MPOpts *opts = ctx->global->opts;
|
||||
struct MPOpts *opts = ctx->opts;
|
||||
void *tmp = talloc_new(NULL);
|
||||
int num_filenames = 0;
|
||||
char **filenames = NULL;
|
||||
@@ -260,7 +260,7 @@ static void find_ordered_chapter_sources(struct tl_ctx *ctx)
|
||||
struct playlist *pl =
|
||||
playlist_parse_file(opts->ordered_chapters_files, ctx->global);
|
||||
talloc_steal(tmp, pl);
|
||||
for (struct playlist_entry *e = pl->first; e; e = e->next)
|
||||
for (struct playlist_entry *e = pl ? pl->first : NULL; e; e = e->next)
|
||||
MP_TARRAY_APPEND(tmp, filenames, num_filenames, e->filename);
|
||||
} else if (ctx->demuxer->stream->uncached_type != STREAMTYPE_FILE) {
|
||||
MP_WARN(ctx, "Playback source is not a "
|
||||
@@ -317,7 +317,7 @@ static int64_t add_timeline_part(struct tl_ctx *ctx,
|
||||
* early; we don't want to try seeking over a one frame gap. */
|
||||
int64_t join_diff = start - ctx->last_end_time;
|
||||
if (ctx->num_parts == 0
|
||||
|| FFABS(join_diff) > ctx->global->opts->chapter_merge_threshold * 1e6
|
||||
|| FFABS(join_diff) > ctx->opts->chapter_merge_threshold * 1e6
|
||||
|| source != ctx->timeline[ctx->num_parts - 1].source)
|
||||
{
|
||||
struct timeline_part new = {
|
||||
@@ -505,20 +505,22 @@ void build_ordered_chapter_timeline(struct timeline *tl)
|
||||
if (!demuxer->matroska_data.ordered_chapters)
|
||||
return;
|
||||
|
||||
if (!demuxer->global->opts->ordered_chapters) {
|
||||
MP_INFO(demuxer, "File uses ordered chapters, but "
|
||||
"you have disabled support for them. Ignoring.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct tl_ctx *ctx = talloc_ptrtype(tl, ctx);
|
||||
*ctx = (struct tl_ctx){
|
||||
.log = tl->log,
|
||||
.global = tl->global,
|
||||
.tl = tl,
|
||||
.demuxer = demuxer,
|
||||
.opts = mp_get_config_group(ctx, tl->global, NULL),
|
||||
};
|
||||
|
||||
if (!ctx->opts->ordered_chapters) {
|
||||
MP_INFO(demuxer, "File uses ordered chapters, but "
|
||||
"you have disabled support for them. Ignoring.\n");
|
||||
talloc_free(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
MP_INFO(ctx, "File uses ordered chapters, will build edit timeline.\n");
|
||||
|
||||
struct matroska_data *m = &demuxer->matroska_data;
|
||||
|
||||
+9
-3
@@ -22,8 +22,8 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "options/options.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demux.h"
|
||||
@@ -129,7 +129,8 @@ struct priv {
|
||||
|
||||
static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
|
||||
{
|
||||
struct demux_rawaudio_opts *opts = demuxer->opts->demux_rawaudio;
|
||||
struct demux_rawaudio_opts *opts =
|
||||
mp_get_config_group(demuxer, demuxer->global, &demux_rawaudio_conf);
|
||||
|
||||
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
|
||||
return -1;
|
||||
@@ -145,6 +146,9 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
|
||||
c->force_channels = true;
|
||||
c->samplerate = opts->samplerate;
|
||||
|
||||
c->native_tb_num = 1;
|
||||
c->native_tb_den = c->samplerate;
|
||||
|
||||
int f = opts->aformat;
|
||||
// See PCM(): sign float bits endian
|
||||
mp_set_pcm_codec(sh->codec, f & 1, f & 2, f >> 3, f & 4);
|
||||
@@ -166,7 +170,8 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
|
||||
|
||||
static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check)
|
||||
{
|
||||
struct demux_rawvideo_opts *opts = demuxer->opts->demux_rawvideo;
|
||||
struct demux_rawvideo_opts *opts =
|
||||
mp_get_config_group(demuxer, demuxer->global, &demux_rawvideo_conf);
|
||||
|
||||
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
|
||||
return -1;
|
||||
@@ -233,6 +238,7 @@ static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check)
|
||||
c->codec = decoder;
|
||||
c->codec_tag = imgfmt;
|
||||
c->fps = opts->fps;
|
||||
c->reliable_fps = true;
|
||||
c->disp_w = width;
|
||||
c->disp_h = height;
|
||||
demux_add_sh_stream(demuxer, sh);
|
||||
|
||||
+16
-8
@@ -25,15 +25,23 @@ static int demux_open_tv(demuxer_t *demuxer, enum demux_check check)
|
||||
if (check > DEMUX_CHECK_REQUEST || demuxer->stream->type != STREAMTYPE_TV)
|
||||
return -1;
|
||||
|
||||
tv_param_t *params = m_sub_options_copy(demuxer, &tv_params_conf,
|
||||
demuxer->opts->tv_params);
|
||||
struct tv_stream_params *sparams = demuxer->stream->priv;
|
||||
if (sparams->channel && sparams->channel[0]) {
|
||||
talloc_free(params->channel);
|
||||
params->channel = talloc_strdup(NULL, sparams->channel);
|
||||
tv_param_t *params = mp_get_config_group(demuxer, demuxer->global,
|
||||
&tv_params_conf);
|
||||
bstr urlparams = bstr0(demuxer->stream->path);
|
||||
bstr channel, input;
|
||||
bstr_split_tok(urlparams, "/", &channel, &input);
|
||||
if (channel.len) {
|
||||
talloc_free(params->channels);
|
||||
params->channel = bstrto0(NULL, channel);
|
||||
}
|
||||
if (input.len) {
|
||||
bstr r;
|
||||
params->input = bstrtoll(input, &r, 0);
|
||||
if (r.len) {
|
||||
MP_ERR(demuxer->stream, "invalid input: '%.*s'\n", BSTR_P(input));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (sparams->input >= 0)
|
||||
params->input = sparams->input;
|
||||
|
||||
assert(demuxer->priv==NULL);
|
||||
if(!(tvh=tv_begin(params, demuxer->log))) return -1;
|
||||
|
||||
+5
-1
@@ -74,6 +74,9 @@ struct mp_codec_params {
|
||||
struct AVCodecContext *lav_headers;
|
||||
struct AVCodecParameters *lav_codecpar;
|
||||
|
||||
// Timestamp granularity for converting double<->rational timestamps.
|
||||
int native_tb_num, native_tb_den;
|
||||
|
||||
// STREAM_AUDIO
|
||||
int samplerate;
|
||||
struct mp_chmap channels;
|
||||
@@ -84,7 +87,8 @@ struct mp_codec_params {
|
||||
|
||||
// STREAM_VIDEO
|
||||
bool avi_dts; // use DTS timing; first frame and DTS is 0
|
||||
float fps; // frames per second (set only if constant fps)
|
||||
double fps; // frames per second (set only if constant fps)
|
||||
bool reliable_fps; // the fps field is definitely not broken
|
||||
int par_w, par_h; // pixel aspect ratio (0 if unknown/square)
|
||||
int disp_w, disp_h; // display size
|
||||
int rotate; // intended display rotation, in degrees, [0, 359]
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# This file is baked into the mpv binary at compile time, and automatically
|
||||
# loaded at early initialization time. Some of the profiles are automatically
|
||||
# applied at later stages during loading.
|
||||
|
||||
[pseudo-gui]
|
||||
player-operation-mode=pseudo-gui
|
||||
|
||||
[builtin-pseudo-gui]
|
||||
terminal=no
|
||||
force-window=yes
|
||||
idle=once
|
||||
screenshot-directory=~~desktop/
|
||||
|
||||
[libmpv]
|
||||
config=no
|
||||
idle=yes
|
||||
terminal=no
|
||||
input-terminal=no
|
||||
osc=no
|
||||
ytdl=no
|
||||
input-default-bindings=no
|
||||
input-vo-keyboard=no
|
||||
stop-playback-on-init-failure=yes
|
||||
# OSX/Cocoa global input hooks
|
||||
input-appleremote=no
|
||||
input-media-keys=no
|
||||
input-app-events=no
|
||||
|
||||
[encoding]
|
||||
vo=lavc
|
||||
ao=lavc
|
||||
keep-open=no
|
||||
force-window=no
|
||||
gapless-audio=yes
|
||||
resume-playback=no
|
||||
load-scripts=no
|
||||
osc=no
|
||||
framedrop=no
|
||||
|
||||
[opengl-hq]
|
||||
scale=spline36
|
||||
cscale=spline36
|
||||
dscale=mitchell
|
||||
dither-depth=auto
|
||||
correct-downscaling=yes
|
||||
sigmoid-upscaling=yes
|
||||
deband=yes
|
||||
+2
-2
@@ -109,10 +109,10 @@
|
||||
#t add sub-pos +1 # down
|
||||
#v cycle sub-visibility
|
||||
# stretch SSA/ASS subtitles with anamorphic videos to match historical
|
||||
#V cycle ass-vsfilter-aspect-compat
|
||||
#V cycle sub-ass-vsfilter-aspect-compat
|
||||
# switch between applying no style overrides to SSA/ASS subtitles, and
|
||||
# overriding them almost completely with the normal subtitle style
|
||||
#u cycle-values ass-style-override "force" "no"
|
||||
#u cycle-values sub-ass-style-override "force" "no"
|
||||
#j cycle sub # cycle through subtitles
|
||||
#J cycle sub down # ...backwards
|
||||
#SHARP cycle audio # switch audio streams
|
||||
|
||||
+5
-3
@@ -53,9 +53,11 @@
|
||||
#ontop=yes
|
||||
|
||||
# Specify default video driver (see --vo=help for a list).
|
||||
# This one selects high quality video scaling etc. - can cause problems with
|
||||
# some drivers and GPUs.
|
||||
#vo=opengl-hq
|
||||
#vo=opengl
|
||||
|
||||
# Specify high quality video rendering preset (for OpenGL VO only)
|
||||
# Can cause performance problems with some drivers and GPUs.
|
||||
#profile=opengl-hq
|
||||
|
||||
# Force video to lock on the display's refresh rate, and change video and audio
|
||||
# speed to some degree to ensure synchronous playback - can cause problems
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ Comment[zh-CN]=播放电影和歌曲
|
||||
Comment[zh-TW]=播放電影和歌曲
|
||||
Icon=mpv
|
||||
TryExec=mpv
|
||||
Exec=mpv --profile=pseudo-gui -- %U
|
||||
Exec=mpv --player-operation-mode=pseudo-gui -- %U
|
||||
Terminal=false
|
||||
Categories=AudioVideo;Audio;Video;Player;TV;
|
||||
MimeType=application/ogg;application/x-ogg;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/m4a;audio/x-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/x-mpeg;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/ogg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg;video/x-mpeg2;video/mp4;video/msvideo;video/x-msvideo;video/ogg;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/x-fli;video/x-flv;video/x-theora;video/x-matroska;video/webm;audio/x-flac;audio/x-vorbis+ogg;video/x-ogm+ogg;audio/x-shorten;audio/x-ape;audio/x-wavpack;audio/x-tta;audio/AMR;audio/ac3;video/mp2t;audio/flac;audio/mp4;
|
||||
|
||||
+4
-2
@@ -186,8 +186,6 @@ const struct mp_cmd_def mp_cmds[] = {
|
||||
{ MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } },
|
||||
{ MP_CMD_VF_COMMAND, "vf-command", { ARG_STRING, ARG_STRING, ARG_STRING } },
|
||||
|
||||
{ MP_CMD_VO_CMDLINE, "vo-cmdline", { ARG_STRING } },
|
||||
|
||||
{ MP_CMD_SCRIPT_BINDING, "script-binding", { ARG_STRING },
|
||||
.allow_auto_repeat = true, .on_updown = true},
|
||||
|
||||
@@ -226,6 +224,10 @@ const struct mp_cmd_def mp_cmds[] = {
|
||||
{"reselect", 1})),
|
||||
}},
|
||||
|
||||
{ MP_CMD_APPLY_PROFILE, "apply-profile", {ARG_STRING } },
|
||||
|
||||
{ MP_CMD_LOAD_SCRIPT, "load-script", {ARG_STRING} },
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
+4
-3
@@ -99,9 +99,6 @@ enum mp_command_type {
|
||||
MP_CMD_VF,
|
||||
MP_CMD_VF_COMMAND,
|
||||
|
||||
/// Video output commands
|
||||
MP_CMD_VO_CMDLINE,
|
||||
|
||||
/// Internal for Lua scripts
|
||||
MP_CMD_SCRIPT_BINDING,
|
||||
MP_CMD_SCRIPT_MESSAGE,
|
||||
@@ -117,6 +114,10 @@ enum mp_command_type {
|
||||
|
||||
MP_CMD_RESCAN_EXTERNAL_FILES,
|
||||
|
||||
MP_CMD_APPLY_PROFILE,
|
||||
|
||||
MP_CMD_LOAD_SCRIPT,
|
||||
|
||||
// Internal
|
||||
MP_CMD_COMMAND_LIST, // list of sub-commands in args[0].v.p
|
||||
};
|
||||
|
||||
+110
-83
@@ -22,6 +22,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -34,7 +35,6 @@
|
||||
#include <libavutil/common.h>
|
||||
|
||||
#include "osdep/io.h"
|
||||
#include "osdep/semaphore.h"
|
||||
#include "misc/rendezvous.h"
|
||||
|
||||
#include "input.h"
|
||||
@@ -73,6 +73,7 @@ struct cmd_bind {
|
||||
};
|
||||
|
||||
struct cmd_bind_section {
|
||||
char *owner;
|
||||
struct cmd_bind *binds;
|
||||
int num_binds;
|
||||
char *section;
|
||||
@@ -96,15 +97,13 @@ struct cmd_queue {
|
||||
|
||||
struct input_ctx {
|
||||
pthread_mutex_t mutex;
|
||||
sem_t wakeup;
|
||||
struct mp_log *log;
|
||||
struct mpv_global *global;
|
||||
struct m_config_cache *opts_cache;
|
||||
struct input_opts *opts;
|
||||
|
||||
bool using_alt_gr;
|
||||
bool using_ar;
|
||||
bool using_cocoa_media_keys;
|
||||
bool win_drag;
|
||||
|
||||
// Autorepeat stuff
|
||||
short ar_state;
|
||||
@@ -146,6 +145,9 @@ struct input_ctx {
|
||||
struct cmd_queue cmd_queue;
|
||||
|
||||
struct mp_cancel *cancel;
|
||||
|
||||
void (*wakeup_cb)(void *ctx);
|
||||
void *wakeup_ctx;
|
||||
};
|
||||
|
||||
static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
|
||||
@@ -170,28 +172,30 @@ struct input_opts {
|
||||
int enable_mouse_movements;
|
||||
int vo_key_input;
|
||||
int test;
|
||||
int allow_win_drag;
|
||||
};
|
||||
|
||||
const struct m_sub_options input_config = {
|
||||
.opts = (const m_option_t[]) {
|
||||
OPT_STRING("conf", config_file, CONF_GLOBAL | M_OPT_FILE),
|
||||
OPT_INT("ar-delay", ar_delay, CONF_GLOBAL),
|
||||
OPT_INT("ar-rate", ar_rate, CONF_GLOBAL),
|
||||
OPT_PRINT("keylist", mp_print_key_list),
|
||||
OPT_PRINT("cmdlist", mp_print_cmd_list),
|
||||
OPT_FLAG("default-bindings", default_bindings, CONF_GLOBAL),
|
||||
OPT_FLAG("test", test, CONF_GLOBAL),
|
||||
OPT_INTRANGE("doubleclick-time", doubleclick_time, 0, 0, 1000),
|
||||
OPT_FLAG("right-alt-gr", use_alt_gr, CONF_GLOBAL),
|
||||
OPT_INTRANGE("key-fifo-size", key_fifo_size, CONF_GLOBAL, 2, 65000),
|
||||
OPT_FLAG("cursor", enable_mouse_movements, CONF_GLOBAL),
|
||||
OPT_FLAG("vo-keyboard", vo_key_input, CONF_GLOBAL),
|
||||
OPT_FLAG("x11-keyboard", vo_key_input, CONF_GLOBAL), // old alias
|
||||
OPT_STRING("input-conf", config_file, M_OPT_FIXED | M_OPT_FILE),
|
||||
OPT_INT("input-ar-delay", ar_delay, 0),
|
||||
OPT_INT("input-ar-rate", ar_rate, 0),
|
||||
OPT_PRINT("input-keylist", mp_print_key_list),
|
||||
OPT_PRINT("input-cmdlist", mp_print_cmd_list),
|
||||
OPT_FLAG("input-default-bindings", default_bindings, 0),
|
||||
OPT_FLAG("input-test", test, 0),
|
||||
OPT_INTRANGE("input-doubleclick-time", doubleclick_time, 0, 0, 1000),
|
||||
OPT_FLAG("input-right-alt-gr", use_alt_gr, 0),
|
||||
OPT_INTRANGE("input-key-fifo-size", key_fifo_size, 0, 2, 65000),
|
||||
OPT_FLAG("input-cursor", enable_mouse_movements, 0),
|
||||
OPT_FLAG("input-vo-keyboard", vo_key_input, 0),
|
||||
#if HAVE_COCOA
|
||||
OPT_FLAG("appleremote", use_appleremote, CONF_GLOBAL),
|
||||
OPT_FLAG("media-keys", use_media_keys, CONF_GLOBAL),
|
||||
OPT_FLAG("app-events", use_app_events, CONF_GLOBAL),
|
||||
OPT_FLAG("input-appleremote", use_appleremote, 0),
|
||||
OPT_FLAG("input-media-keys", use_media_keys, 0),
|
||||
OPT_FLAG("input-app-events", use_app_events, M_OPT_FIXED),
|
||||
#endif
|
||||
OPT_FLAG("window-dragging", allow_win_drag, 0),
|
||||
OPT_REPLACED("input-x11-keyboard", "input-vo-keyboard"),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct input_opts),
|
||||
@@ -209,7 +213,9 @@ const struct m_sub_options input_config = {
|
||||
#endif
|
||||
.default_bindings = 1,
|
||||
.vo_key_input = 1,
|
||||
.allow_win_drag = 1,
|
||||
},
|
||||
.change_flags = UPDATE_INPUT,
|
||||
};
|
||||
|
||||
static const char builtin_input_conf[] =
|
||||
@@ -845,33 +851,18 @@ static mp_cmd_t *check_autorepeat(struct input_ctx *ictx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mp_input_wait(struct input_ctx *ictx, double seconds)
|
||||
double mp_input_get_delay(struct input_ctx *ictx)
|
||||
{
|
||||
input_lock(ictx);
|
||||
double seconds = INFINITY;
|
||||
adjust_max_wait_time(ictx, &seconds);
|
||||
input_unlock(ictx);
|
||||
while (sem_trywait(&ictx->wakeup) == 0)
|
||||
seconds = -1;
|
||||
if (seconds > 0) {
|
||||
MP_STATS(ictx, "start sleep");
|
||||
struct timespec ts =
|
||||
mp_time_us_to_timespec(mp_add_timeout(mp_time_us(), seconds));
|
||||
sem_timedwait(&ictx->wakeup, &ts);
|
||||
MP_STATS(ictx, "end sleep");
|
||||
}
|
||||
}
|
||||
|
||||
void mp_input_wakeup_nolock(struct input_ctx *ictx)
|
||||
{
|
||||
// Some audio APIs discourage use of locking in their audio callback,
|
||||
// and these audio callbacks happen to call mp_input_wakeup_nolock()
|
||||
// when new data is needed. This is why we use semaphores here.
|
||||
sem_post(&ictx->wakeup);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
void mp_input_wakeup(struct input_ctx *ictx)
|
||||
{
|
||||
mp_input_wakeup_nolock(ictx);
|
||||
ictx->wakeup_cb(ictx->wakeup_ctx);
|
||||
}
|
||||
|
||||
mp_cmd_t *mp_input_read_cmd(struct input_ctx *ictx)
|
||||
@@ -996,7 +987,8 @@ bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y)
|
||||
bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y)
|
||||
{
|
||||
input_lock(ictx);
|
||||
bool r = !ictx->win_drag || test_mouse(ictx, x, y, MP_INPUT_ALLOW_VO_DRAGGING);
|
||||
bool r = !ictx->opts->allow_win_drag ||
|
||||
test_mouse(ictx, x, y, MP_INPUT_ALLOW_VO_DRAGGING);
|
||||
input_unlock(ictx);
|
||||
return r;
|
||||
}
|
||||
@@ -1021,13 +1013,19 @@ static void remove_binds(struct cmd_bind_section *bs, bool builtin)
|
||||
}
|
||||
|
||||
void mp_input_define_section(struct input_ctx *ictx, char *name, char *location,
|
||||
char *contents, bool builtin)
|
||||
char *contents, bool builtin, char *owner)
|
||||
{
|
||||
if (!name || !name[0])
|
||||
return; // parse_config() changes semantics with restrict_section==empty
|
||||
input_lock(ictx);
|
||||
// Delete:
|
||||
struct cmd_bind_section *bs = get_bind_section(ictx, bstr0(name));
|
||||
if ((!bs->owner || (owner && strcmp(bs->owner, owner) != 0)) &&
|
||||
strcmp(bs->section, "default") != 0)
|
||||
{
|
||||
talloc_free(bs->owner);
|
||||
bs->owner = talloc_strdup(bs, owner);
|
||||
}
|
||||
remove_binds(bs, builtin);
|
||||
if (contents && contents[0]) {
|
||||
// Redefine:
|
||||
@@ -1039,6 +1037,21 @@ void mp_input_define_section(struct input_ctx *ictx, char *name, char *location,
|
||||
input_unlock(ictx);
|
||||
}
|
||||
|
||||
void mp_input_remove_sections_by_owner(struct input_ctx *ictx, char *owner)
|
||||
{
|
||||
input_lock(ictx);
|
||||
struct cmd_bind_section *bs = ictx->cmd_bind_sections;
|
||||
while (bs) {
|
||||
if (bs->owner && owner && strcmp(bs->owner, owner) == 0) {
|
||||
mp_input_disable_section(ictx, bs->section);
|
||||
remove_binds(bs, false);
|
||||
remove_binds(bs, true);
|
||||
}
|
||||
bs = bs->next;
|
||||
}
|
||||
input_unlock(ictx);
|
||||
}
|
||||
|
||||
static bool bind_matches_key(struct cmd_bind *bind, int num_keys, const int *keys)
|
||||
{
|
||||
if (bind->num_keys != num_keys)
|
||||
@@ -1195,22 +1208,23 @@ done:
|
||||
return r;
|
||||
}
|
||||
|
||||
struct input_ctx *mp_input_init(struct mpv_global *global)
|
||||
struct input_ctx *mp_input_init(struct mpv_global *global,
|
||||
void (*wakeup_cb)(void *ctx),
|
||||
void *wakeup_ctx)
|
||||
{
|
||||
|
||||
struct input_ctx *ictx = talloc_ptrtype(NULL, ictx);
|
||||
*ictx = (struct input_ctx){
|
||||
.global = global,
|
||||
.opts = talloc_zero(ictx, struct input_opts), // replaced later
|
||||
.ar_state = -1,
|
||||
.log = mp_log_new(ictx, global->log, "input"),
|
||||
.mouse_section = "default",
|
||||
.opts_cache = m_config_cache_alloc(ictx, global, &input_config),
|
||||
.wakeup_cb = wakeup_cb,
|
||||
.wakeup_ctx = wakeup_ctx,
|
||||
};
|
||||
|
||||
if (sem_init(&ictx->wakeup, 0, 0)) {
|
||||
MP_FATAL(ictx, "mpv doesn't work on systems without POSIX semaphores.\n");
|
||||
abort();
|
||||
}
|
||||
ictx->opts = ictx->opts_cache->opts;
|
||||
|
||||
mpthread_mutex_init_recursive(&ictx->mutex);
|
||||
|
||||
@@ -1221,13 +1235,45 @@ struct input_ctx *mp_input_init(struct mpv_global *global)
|
||||
return ictx;
|
||||
}
|
||||
|
||||
void mp_input_load(struct input_ctx *ictx)
|
||||
static void reload_opts(struct input_ctx *ictx, bool shutdown)
|
||||
{
|
||||
struct input_opts *input_conf =
|
||||
m_sub_options_copy(ictx, &input_config, ictx->global->opts->input_opts);
|
||||
m_config_cache_update(ictx->opts_cache);
|
||||
|
||||
talloc_free(ictx->opts);
|
||||
ictx->opts = input_conf;
|
||||
#if HAVE_COCOA
|
||||
struct input_opts *opts = ictx->opts;
|
||||
|
||||
if (ictx->using_ar != (opts->use_appleremote && !shutdown)) {
|
||||
ictx->using_ar = !ictx->using_ar;
|
||||
if (ictx->using_ar) {
|
||||
cocoa_init_apple_remote();
|
||||
} else {
|
||||
cocoa_uninit_apple_remote();
|
||||
}
|
||||
}
|
||||
|
||||
if (ictx->using_cocoa_media_keys != (opts->use_media_keys && !shutdown)) {
|
||||
ictx->using_cocoa_media_keys = !ictx->using_cocoa_media_keys;
|
||||
if (ictx->using_cocoa_media_keys) {
|
||||
cocoa_init_media_keys();
|
||||
} else {
|
||||
cocoa_uninit_media_keys();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp_input_update_opts(struct input_ctx *ictx)
|
||||
{
|
||||
input_lock(ictx);
|
||||
reload_opts(ictx, false);
|
||||
input_unlock(ictx);
|
||||
}
|
||||
|
||||
void mp_input_load_config(struct input_ctx *ictx)
|
||||
{
|
||||
input_lock(ictx);
|
||||
|
||||
reload_opts(ictx, false);
|
||||
|
||||
// "Uncomment" the default key bindings in etc/input.conf and add them.
|
||||
// All lines that do not start with '# ' are parsed.
|
||||
@@ -1240,8 +1286,8 @@ void mp_input_load(struct input_ctx *ictx)
|
||||
}
|
||||
|
||||
bool config_ok = false;
|
||||
if (input_conf->config_file)
|
||||
config_ok = parse_config_file(ictx, input_conf->config_file, true);
|
||||
if (ictx->opts->config_file && ictx->opts->config_file[0])
|
||||
config_ok = parse_config_file(ictx, ictx->opts->config_file, true);
|
||||
if (!config_ok) {
|
||||
// Try global conf dir
|
||||
void *tmp = talloc_new(NULL);
|
||||
@@ -1251,32 +1297,17 @@ void mp_input_load(struct input_ctx *ictx)
|
||||
talloc_free(tmp);
|
||||
}
|
||||
|
||||
if (input_conf->use_alt_gr) {
|
||||
ictx->using_alt_gr = true;
|
||||
}
|
||||
|
||||
#if HAVE_COCOA
|
||||
if (input_conf->use_app_events) {
|
||||
if (ictx->opts->use_app_events)
|
||||
cocoa_start_event_monitor();
|
||||
}
|
||||
|
||||
if (input_conf->use_appleremote) {
|
||||
cocoa_init_apple_remote();
|
||||
ictx->using_ar = true;
|
||||
}
|
||||
|
||||
if (input_conf->use_media_keys) {
|
||||
cocoa_init_media_keys();
|
||||
ictx->using_cocoa_media_keys = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ictx->win_drag = ictx->global->opts->allow_win_drag;
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
if (ictx->global->opts->input_file && *ictx->global->opts->input_file)
|
||||
mp_input_pipe_add(ictx, ictx->global->opts->input_file);
|
||||
#endif
|
||||
|
||||
input_unlock(ictx);
|
||||
}
|
||||
|
||||
static void clear_queue(struct cmd_queue *queue)
|
||||
@@ -1293,21 +1324,14 @@ void mp_input_uninit(struct input_ctx *ictx)
|
||||
if (!ictx)
|
||||
return;
|
||||
|
||||
#if HAVE_COCOA
|
||||
if (ictx->using_ar) {
|
||||
cocoa_uninit_apple_remote();
|
||||
}
|
||||
|
||||
if (ictx->using_cocoa_media_keys) {
|
||||
cocoa_uninit_media_keys();
|
||||
}
|
||||
#endif
|
||||
input_lock(ictx);
|
||||
reload_opts(ictx, true);
|
||||
input_unlock(ictx);
|
||||
|
||||
close_input_sources(ictx);
|
||||
clear_queue(&ictx->cmd_queue);
|
||||
talloc_free(ictx->current_down_cmd);
|
||||
pthread_mutex_destroy(&ictx->mutex);
|
||||
sem_destroy(&ictx->wakeup);
|
||||
talloc_free(ictx);
|
||||
}
|
||||
|
||||
@@ -1320,7 +1344,10 @@ void mp_input_set_cancel(struct input_ctx *ictx, struct mp_cancel *cancel)
|
||||
|
||||
bool mp_input_use_alt_gr(struct input_ctx *ictx)
|
||||
{
|
||||
return ictx->using_alt_gr;
|
||||
input_lock(ictx);
|
||||
bool r = ictx->opts->use_alt_gr;
|
||||
input_unlock(ictx);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct mp_cmd *mp_input_parse_cmd(struct input_ctx *ictx, bstr str,
|
||||
|
||||
+14
-9
@@ -196,9 +196,13 @@ void mp_input_disable_all_sections(struct input_ctx *ictx);
|
||||
// builtin: create as builtin section; this means if the user defines bindings
|
||||
// using "{name}", they won't be ignored or overwritten - instead,
|
||||
// they are preferred to the bindings defined with this call
|
||||
// owner: string ID of the client which defined this, or NULL
|
||||
// If the section already exists, its bindings are removed and replaced.
|
||||
void mp_input_define_section(struct input_ctx *ictx, char *name, char *location,
|
||||
char *contents, bool builtin);
|
||||
char *contents, bool builtin, char *owner);
|
||||
|
||||
// Remove all sections that have been defined by the given owner.
|
||||
void mp_input_remove_sections_by_owner(struct input_ctx *ictx, char *owner);
|
||||
|
||||
// Define where on the screen the named input section should receive.
|
||||
// Setting a rectangle of size 0 unsets the mouse area.
|
||||
@@ -219,22 +223,23 @@ bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y);
|
||||
|
||||
// Initialize the input system
|
||||
struct mpv_global;
|
||||
struct input_ctx *mp_input_init(struct mpv_global *global);
|
||||
struct input_ctx *mp_input_init(struct mpv_global *global,
|
||||
void (*wakeup_cb)(void *ctx),
|
||||
void *wakeup_ctx);
|
||||
|
||||
// Load config, options, and devices.
|
||||
void mp_input_load(struct input_ctx *ictx);
|
||||
void mp_input_load_config(struct input_ctx *ictx);
|
||||
|
||||
void mp_input_update_opts(struct input_ctx *ictx);
|
||||
|
||||
void mp_input_uninit(struct input_ctx *ictx);
|
||||
|
||||
// Sleep for the given amount of seconds, until mp_input_wakeup() is called,
|
||||
// or new input arrives. seconds<=0 returns immediately.
|
||||
void mp_input_wait(struct input_ctx *ictx, double seconds);
|
||||
// Return number of seconds until the next autorepeat event will be generated.
|
||||
// Returns INFINITY if no autorepeated key is active.
|
||||
double mp_input_get_delay(struct input_ctx *ictx);
|
||||
|
||||
// Wake up sleeping input loop from another thread.
|
||||
void mp_input_wakeup(struct input_ctx *ictx);
|
||||
|
||||
void mp_input_wakeup_nolock(struct input_ctx *ictx);
|
||||
|
||||
// Used to asynchronously abort playback. Needed because the core still can
|
||||
// block on network in some situations.
|
||||
struct mp_cancel;
|
||||
|
||||
+9
-5
@@ -20,6 +20,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -97,6 +98,11 @@ static void *client_thread(void *p)
|
||||
{
|
||||
pthread_detach(pthread_self());
|
||||
|
||||
// We don't use MSG_NOSIGNAL because the moldy fruit OS doesn't support it.
|
||||
struct sigaction sa = { .sa_handler = SIG_IGN, .sa_flags = SA_RESTART };
|
||||
sigfillset(&sa.sa_mask);
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
int rc;
|
||||
|
||||
struct client_arg *arg = p;
|
||||
@@ -118,15 +124,11 @@ static void *client_thread(void *p)
|
||||
};
|
||||
|
||||
fcntl(arg->client_fd, F_SETFL, fcntl(arg->client_fd, F_GETFL, 0) | O_NONBLOCK);
|
||||
mpv_suspend(arg->client);
|
||||
|
||||
while (1) {
|
||||
rc = poll(fds, 2, 0);
|
||||
if (rc == 0) {
|
||||
mpv_resume(arg->client);
|
||||
if (rc == 0)
|
||||
rc = poll(fds, 2, -1);
|
||||
mpv_suspend(arg->client);
|
||||
}
|
||||
if (rc < 0) {
|
||||
MP_ERR(arg, "Poll error\n");
|
||||
continue;
|
||||
@@ -337,6 +339,8 @@ static void *ipc_thread(void *p)
|
||||
goto done;
|
||||
}
|
||||
|
||||
MP_VERBOSE(arg, "Listening to IPC socket.\n");
|
||||
|
||||
int client_num = 0;
|
||||
|
||||
struct pollfd fds[2] = {
|
||||
|
||||
+3
-5
@@ -222,7 +222,6 @@ static void *client_thread(void *p)
|
||||
MP_VERBOSE(arg, "Client connected\n");
|
||||
|
||||
mpv_set_wakeup_callback(arg->client, wakeup_cb, wakeup_event);
|
||||
mpv_suspend(arg->client);
|
||||
|
||||
// Do the first read operation on the pipe
|
||||
if ((ioerr = async_read(arg->client_h, buf, 4096, &ol))) {
|
||||
@@ -233,11 +232,8 @@ static void *client_thread(void *p)
|
||||
while (1) {
|
||||
HANDLE handles[] = { wakeup_event, ol.hEvent };
|
||||
int n = WaitForMultipleObjects(2, handles, FALSE, 0);
|
||||
if (n == WAIT_TIMEOUT) {
|
||||
mpv_resume(arg->client);
|
||||
if (n == WAIT_TIMEOUT)
|
||||
n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||
mpv_suspend(arg->client);
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case WAIT_OBJECT_0: // wakeup_event
|
||||
@@ -381,6 +377,8 @@ static void *ipc_thread(void *p)
|
||||
goto done;
|
||||
}
|
||||
|
||||
MP_VERBOSE(arg, "Listening to IPC pipe.\n");
|
||||
|
||||
while (1) {
|
||||
DWORD err = ConnectNamedPipe(server, &ol) ? 0 : GetLastError();
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
#include <io.h>
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "osdep/io.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
+58
-20
@@ -135,10 +135,6 @@ extern "C" {
|
||||
* (used through libass), ALSA, FFmpeg, and possibly more.
|
||||
* - The FPU precision must be set at least to double precision.
|
||||
* - On Windows, mpv will call timeBeginPeriod(1).
|
||||
* - On UNIX, every mpv_initialize() call will block SIGPIPE. This is done
|
||||
* because FFmpeg makes unsafe use of OpenSSL and GnuTLS, which can raise
|
||||
* this signal under certain circumstances. Once these libraries (or FFmpeg)
|
||||
* are fixed, libmpv will not block the signal anymore.
|
||||
* - On memory exhaustion, mpv will kill the process.
|
||||
*
|
||||
* Encoding of filenames
|
||||
@@ -215,7 +211,7 @@ extern "C" {
|
||||
* relational operators (<, >, <=, >=).
|
||||
*/
|
||||
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
|
||||
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 22)
|
||||
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 23)
|
||||
|
||||
/**
|
||||
* Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with.
|
||||
@@ -370,10 +366,11 @@ const char *mpv_client_name(mpv_handle *ctx);
|
||||
* and needs to be initialized to be actually used with most other API
|
||||
* functions.
|
||||
*
|
||||
* Most API functions will return MPV_ERROR_UNINITIALIZED in the uninitialized
|
||||
* state. You can call mpv_set_option() (or mpv_set_option_string() and other
|
||||
* variants) to set initial options. After this, call mpv_initialize() to start
|
||||
* the player, and then use e.g. mpv_command() to start playback of a file.
|
||||
* Some API functions will return MPV_ERROR_UNINITIALIZED in the uninitialized
|
||||
* state. You can call mpv_set_property() (or mpv_set_property_string() and
|
||||
* other variants, and before mpv 0.21.0 mpv_set_option() etc.) to set initial
|
||||
* options. After this, call mpv_initialize() to start the player, and then use
|
||||
* e.g. mpv_command() to start playback of a file.
|
||||
*
|
||||
* The point of separating handle creation and actual initialization is that
|
||||
* you can configure things which can't be changed during runtime.
|
||||
@@ -401,7 +398,7 @@ const char *mpv_client_name(mpv_handle *ctx);
|
||||
* options.
|
||||
*
|
||||
* The mpv command line parser is not available through this API, but you can
|
||||
* set individual options with mpv_set_option(). Files for playback must be
|
||||
* set individual options with mpv_set_property(). Files for playback must be
|
||||
* loaded with mpv_command() or others.
|
||||
*
|
||||
* Note that you should avoid doing concurrent accesses on the uninitialized
|
||||
@@ -422,6 +419,17 @@ mpv_handle *mpv_create(void);
|
||||
* This function needs to be called to make full use of the client API if the
|
||||
* client API handle was created with mpv_create().
|
||||
*
|
||||
* Only the following options require to be set _before_ mpv_initialize():
|
||||
* - options which are only read at initialization time:
|
||||
* - config
|
||||
* - config-dir
|
||||
* - input-conf
|
||||
* - load-scripts
|
||||
* - script
|
||||
* - player-operation-mode
|
||||
* - input-app-events (OSX)
|
||||
* - all encoding mode options
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
int mpv_initialize(mpv_handle *ctx);
|
||||
@@ -492,10 +500,6 @@ mpv_handle *mpv_create_client(mpv_handle *ctx, const char *name);
|
||||
* possible that some options were successfully set even if any of these errors
|
||||
* happen.
|
||||
*
|
||||
* The same restrictions as with mpv_set_option() apply: some options can't
|
||||
* be set outside of idle or uninitialized state, and many options don't
|
||||
* take effect immediately.
|
||||
*
|
||||
* @param filename absolute path to the config file on the local filesystem
|
||||
* @return error code
|
||||
*/
|
||||
@@ -518,6 +522,11 @@ int mpv_load_config_file(mpv_handle *ctx, const char *filename);
|
||||
* mpv_suspend() is not allowed.
|
||||
*
|
||||
* Calling this on an uninitialized player (see mpv_create()) will deadlock.
|
||||
*
|
||||
* @deprecated This function, as well as mpv_resume(), are deprecated, and
|
||||
* will stop doing anything soon. Their semantics were never
|
||||
* well-defined, and their usefulness is extremely limited. The
|
||||
* calls will remain stubs in order to keep ABI compatibility.
|
||||
*/
|
||||
void mpv_suspend(mpv_handle *ctx);
|
||||
|
||||
@@ -778,16 +787,36 @@ void mpv_free_node_contents(mpv_node *node);
|
||||
* works in uninitialized state (see mpv_create()), and in some cases in at
|
||||
* runtime.
|
||||
*
|
||||
* Changing options at runtime does not always work. For some options, attempts
|
||||
* to change them simply fails. Many other options may require reloading the
|
||||
* file for changes to take effect. In general, you should prefer calling
|
||||
* mpv_set_property() to change settings during playback, because the property
|
||||
* mechanism guarantees that changes take effect immediately.
|
||||
*
|
||||
* Using a format other than MPV_FORMAT_NODE is equivalent to constructing a
|
||||
* mpv_node with the given format and data, and passing the mpv_node to this
|
||||
* function.
|
||||
*
|
||||
* Note: this is semi-deprecated. For most purposes, this is not needed anymore.
|
||||
* Starting with mpv version 0.21.0 (version 1.23) most options can be set
|
||||
* with mpv_set_property() (and related functions), and even before
|
||||
* mpv_initialize(). In some obscure corner cases, using this function
|
||||
* to set options might still be required (see below, and also section
|
||||
* "Inconsistencies between options and properties" on the manpage). Once
|
||||
* these are resolved, the option setting functions might be fully
|
||||
* deprecated.
|
||||
*
|
||||
* The following options still need to be set either _before_
|
||||
* mpv_initialize() with mpv_set_property() (or related functions), or
|
||||
* with mpv_set_option() (or related functions) at any time:
|
||||
* - options shadowed by deprecated properties:
|
||||
* - demuxer (property deprecated in 0.21.0)
|
||||
* - idle (property deprecated in 0.21.0)
|
||||
* - fps (property deprecated in 0.21.0)
|
||||
* - cache (property deprecated in 0.21.0)
|
||||
* - length (property deprecated in 0.10.0)
|
||||
* - audio-samplerate (property deprecated in 0.10.0)
|
||||
* - audio-channels (property deprecated in 0.10.0)
|
||||
* - audio-format (property deprecated in 0.10.0)
|
||||
* - deprecated options shadowed by properties:
|
||||
* - chapter (option deprecated in 0.21.0)
|
||||
* - playlist-pos (option deprecated in 0.21.0)
|
||||
* The deprecated properties will be removed in mpv 0.22.0.
|
||||
*
|
||||
* @param name Option name. This is the same as on the mpv command line, but
|
||||
* without the leading "--".
|
||||
* @param format see enum mpv_format.
|
||||
@@ -893,6 +922,15 @@ int mpv_command_node_async(mpv_handle *ctx, uint64_t reply_userdata,
|
||||
* mpv_node with the given format and data, and passing the mpv_node to this
|
||||
* function. (Before API version 1.21, this was different.)
|
||||
*
|
||||
* Note: starting with mpv 0.21.0 (client API version 1.23), this can be used to
|
||||
* set options in general. It even can be used before mpv_initialize()
|
||||
* has been called. If called before mpv_initialize(), setting properties
|
||||
* not backed by options will result in MPV_ERROR_PROPERTY_UNAVAILABLE.
|
||||
* In some cases, properties and options still conflict. In these cases,
|
||||
* mpv_set_property() accesses the options before mpv_initialize(), and
|
||||
* the properties after mpv_initialize(). These conflicts will be removed
|
||||
* in mpv 0.22.0. See mpv_set_option() for further remarks.
|
||||
*
|
||||
* @param name The property name. See input.rst for a list of properties.
|
||||
* @param format see enum mpv_format.
|
||||
* @param[in] data Option value.
|
||||
|
||||
@@ -190,6 +190,29 @@ extern "C" {
|
||||
* In previous libmpv releases, this used "GL_MP_D3D_interfaces" and
|
||||
* "glMPGetD3DInterface". This is deprecated; use glMPGetNativeDisplay instead
|
||||
* (the semantics are 100% compatible).
|
||||
*
|
||||
* Windowing system interop on RPI
|
||||
* -------------------------------
|
||||
*
|
||||
* The RPI uses no proper interop, but hardware overlays instead. To place the
|
||||
* overlay correctly, you can communicate the window parameters as follows to
|
||||
* libmpv. gl->MPGetNativeDisplay("MPV_RPI_WINDOW") return an array of type int
|
||||
* with the following 4 elements:
|
||||
* 0: display number (default 0)
|
||||
* 1: layer number of the GL layer - video will be placed in the layer
|
||||
* directly below (default: 0)
|
||||
* 2: absolute x position of the GL context (default: 0)
|
||||
* 3: absolute y position of the GL context (default: 0)
|
||||
* The (x,y) position must be the absolute screen pixel position of the
|
||||
* top/left pixel of the dispmanx layer used for the GL context. If you render
|
||||
* to a FBO, the position must be that of the final position of the FBO
|
||||
* contents on screen. You can't transform or scale the video other than what
|
||||
* mpv will render to the video overlay. The defaults are suitable for
|
||||
* rendering the video at fullscreen.
|
||||
* The parameters are checked on every draw by calling MPGetNativeDisplay and
|
||||
* checking the values in the returned array for changes. The returned array
|
||||
* must remain valid until the libmpv render function returns; then it can be
|
||||
* deallocated by the API user.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <QList>
|
||||
#include <QHash>
|
||||
#include <QSharedPointer>
|
||||
#include <QMetaType>
|
||||
|
||||
#include <mpv/client.h>
|
||||
|
||||
@@ -227,6 +228,8 @@ struct node_autofree {
|
||||
* Return the given property as mpv_node converted to QVariant, or QVariant()
|
||||
* on error.
|
||||
*
|
||||
* @deprecated use get_property() instead
|
||||
*
|
||||
* @param name the property name
|
||||
*/
|
||||
static inline QVariant get_property_variant(mpv_handle *ctx, const QString &name)
|
||||
@@ -240,6 +243,8 @@ static inline QVariant get_property_variant(mpv_handle *ctx, const QString &name
|
||||
|
||||
/**
|
||||
* Set the given property as mpv_node converted from the QVariant argument.
|
||||
|
||||
* @deprecated use set_property() instead
|
||||
*/
|
||||
static inline int set_property_variant(mpv_handle *ctx, const QString &name,
|
||||
const QVariant &v)
|
||||
@@ -250,6 +255,8 @@ static inline int set_property_variant(mpv_handle *ctx, const QString &name,
|
||||
|
||||
/**
|
||||
* Set the given option as mpv_node converted from the QVariant argument.
|
||||
*
|
||||
* @deprecated use set_property() instead
|
||||
*/
|
||||
static inline int set_option_variant(mpv_handle *ctx, const QString &name,
|
||||
const QVariant &v)
|
||||
@@ -261,6 +268,8 @@ static inline int set_option_variant(mpv_handle *ctx, const QString &name,
|
||||
/**
|
||||
* mpv_command_node() equivalent. Returns QVariant() on error (and
|
||||
* unfortunately, the same on success).
|
||||
*
|
||||
* @deprecated use command() instead
|
||||
*/
|
||||
static inline QVariant command_variant(mpv_handle *ctx, const QVariant &args)
|
||||
{
|
||||
@@ -272,7 +281,94 @@ static inline QVariant command_variant(mpv_handle *ctx, const QVariant &args)
|
||||
return node_to_variant(&res);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to return error codes wrapped in QVariant for functions which
|
||||
* return QVariant.
|
||||
*
|
||||
* You can use get_error() or is_error() to extract the error status from a
|
||||
* QVariant value.
|
||||
*/
|
||||
struct ErrorReturn
|
||||
{
|
||||
/**
|
||||
* enum mpv_error value (or a value outside of it if ABI was extended)
|
||||
*/
|
||||
int error;
|
||||
|
||||
ErrorReturn() : error(0) {}
|
||||
explicit ErrorReturn(int err) : error(err) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the mpv error code packed into a QVariant, or 0 (success) if it's not
|
||||
* an error value.
|
||||
*
|
||||
* @return error code (<0) or success (>=0)
|
||||
*/
|
||||
static inline int get_error(const QVariant &v)
|
||||
{
|
||||
if (!v.canConvert<ErrorReturn>())
|
||||
return 0;
|
||||
return v.value<ErrorReturn>().error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the QVariant carries a mpv error code.
|
||||
*/
|
||||
static inline bool is_error(const QVariant &v)
|
||||
{
|
||||
return get_error(v) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given property as mpv_node converted to QVariant, or QVariant()
|
||||
* on error.
|
||||
*
|
||||
* @param name the property name
|
||||
* @return the property value, or an ErrorReturn with the error code
|
||||
*/
|
||||
static inline QVariant get_property(mpv_handle *ctx, const QString &name)
|
||||
{
|
||||
mpv_node node;
|
||||
int err = mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node);
|
||||
if (err < 0)
|
||||
return QVariant::fromValue(ErrorReturn(err));
|
||||
node_autofree f(&node);
|
||||
return node_to_variant(&node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given property as mpv_node converted from the QVariant argument.
|
||||
*
|
||||
* @return mpv error code (<0 on error, >= 0 on success)
|
||||
*/
|
||||
static inline int set_property(mpv_handle *ctx, const QString &name,
|
||||
const QVariant &v)
|
||||
{
|
||||
node_builder node(v);
|
||||
return mpv_set_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node());
|
||||
}
|
||||
|
||||
/**
|
||||
* mpv_command_node() equivalent.
|
||||
*
|
||||
* @param args command arguments, with args[0] being the command name as string
|
||||
* @return the property value, or an ErrorReturn with the error code
|
||||
*/
|
||||
static inline QVariant command(mpv_handle *ctx, const QVariant &args)
|
||||
{
|
||||
node_builder node(args);
|
||||
mpv_node res;
|
||||
int err = mpv_command_node(ctx, node.node(), &res);
|
||||
if (err < 0)
|
||||
return QVariant::fromValue(ErrorReturn(err));
|
||||
node_autofree f(&res);
|
||||
return node_to_variant(&res);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(mpv::qt::ErrorReturn)
|
||||
|
||||
#endif
|
||||
@@ -291,6 +291,11 @@ bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags)
|
||||
if (strcasecmp(cp, "UTF-8-BROKEN") == 0)
|
||||
return bstr_sanitize_utf8_latin1(NULL, buf);
|
||||
|
||||
// Force CP949 over EUC-KR since iconv distinguishes them and
|
||||
// EUC-KR causes error on CP949 encoded data
|
||||
if (strcasecmp(cp, "EUC-KR") == 0)
|
||||
cp = "CP949";
|
||||
|
||||
iconv_t icdsc;
|
||||
if ((icdsc = iconv_open("UTF-8", cp)) == (iconv_t) (-1)) {
|
||||
if (flags & MP_ICONV_VERBOSE)
|
||||
|
||||
+132
-73
@@ -28,19 +28,31 @@ struct mp_dispatch_queue {
|
||||
struct mp_dispatch_item *head, *tail;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
int suspend_requested;
|
||||
bool suspended;
|
||||
void (*wakeup_fn)(void *wakeup_ctx);
|
||||
void *wakeup_ctx;
|
||||
// This lock grant access to the target thread's state during suspend mode.
|
||||
// During suspend mode, the target thread is blocked in the function
|
||||
// mp_dispatch_queue_process(), however this function may be processing
|
||||
// dispatch queue items. This lock serializes the dispatch queue processing
|
||||
// and external mp_dispatch_lock() calls.
|
||||
// Invariant: can be held only while suspended==true, and suspend_requested
|
||||
// must be >0 (unless mp_dispatch_queue_process() locks it). In particular,
|
||||
// suspend mode must not be left while the lock is held.
|
||||
pthread_mutex_t exclusive_lock;
|
||||
// Make mp_dispatch_queue_process() exit if it's idle.
|
||||
bool interrupted;
|
||||
// The target thread is blocked by mp_dispatch_queue_process(). Note that
|
||||
// mp_dispatch_lock() can set this from true to false to keep the thread
|
||||
// blocked (this stops if from processing other dispatch items, and from
|
||||
// other threads to return from mp_dispatch_lock(), making it an exclusive
|
||||
// lock).
|
||||
bool idling;
|
||||
// A mp_dispatch_lock() call is requesting an exclusive lock.
|
||||
bool lock_request;
|
||||
// Used to block out threads calling mp_dispatch_queue_process() while
|
||||
// they're externall locked via mp_dispatch_lock().
|
||||
// We could use a simple counter (increment it instead of adding a frame,
|
||||
// also increment it when locking), but with this we can perform some
|
||||
// minimal debug checks.
|
||||
struct lock_frame *frame;
|
||||
};
|
||||
|
||||
struct lock_frame {
|
||||
struct lock_frame *prev;
|
||||
pthread_t thread;
|
||||
pthread_t locked_thread;
|
||||
bool locked;
|
||||
};
|
||||
|
||||
struct mp_dispatch_item {
|
||||
@@ -55,11 +67,11 @@ static void queue_dtor(void *p)
|
||||
{
|
||||
struct mp_dispatch_queue *queue = p;
|
||||
assert(!queue->head);
|
||||
assert(!queue->suspend_requested);
|
||||
assert(!queue->suspended);
|
||||
assert(!queue->idling);
|
||||
assert(!queue->lock_request);
|
||||
assert(!queue->frame);
|
||||
pthread_cond_destroy(&queue->cond);
|
||||
pthread_mutex_destroy(&queue->lock);
|
||||
pthread_mutex_destroy(&queue->exclusive_lock);
|
||||
}
|
||||
|
||||
// A dispatch queue lets other threads run callbacks in a target thread.
|
||||
@@ -76,7 +88,6 @@ struct mp_dispatch_queue *mp_dispatch_create(void *ta_parent)
|
||||
struct mp_dispatch_queue *queue = talloc_ptrtype(ta_parent, queue);
|
||||
*queue = (struct mp_dispatch_queue){0};
|
||||
talloc_set_destructor(queue, queue_dtor);
|
||||
pthread_mutex_init(&queue->exclusive_lock, NULL);
|
||||
pthread_mutex_init(&queue->lock, NULL);
|
||||
pthread_cond_init(&queue->cond, NULL);
|
||||
return queue;
|
||||
@@ -111,6 +122,10 @@ static void mp_dispatch_append(struct mp_dispatch_queue *queue,
|
||||
// Wake up the main thread; note that other threads might wait on this
|
||||
// condition for reasons, so broadcast the condition.
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
// No wakeup callback -> assume mp_dispatch_queue_process() needs to be
|
||||
// interrupted instead.
|
||||
if (!queue->wakeup_fn)
|
||||
queue->interrupted = true;
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
if (queue->wakeup_fn)
|
||||
queue->wakeup_fn(queue->wakeup_ctx);
|
||||
@@ -170,24 +185,47 @@ void mp_dispatch_run(struct mp_dispatch_queue *queue,
|
||||
}
|
||||
|
||||
// Process any outstanding dispatch items in the queue. This also handles
|
||||
// suspending or locking the target thread.
|
||||
// suspending or locking the this thread from another thread via
|
||||
// mp_dispatch_lock().
|
||||
// The timeout specifies the minimum wait time. The actual time spent in this
|
||||
// function can be much higher if the suspending/locking functions are used, or
|
||||
// if executing the dispatch items takes time. On the other hand, this function
|
||||
// can return much earlier than the timeout due to sporadic wakeups.
|
||||
// It is also guaranteed that if at least one queue item was processed, the
|
||||
// function will return as soon as possible, ignoring the timeout. This
|
||||
// simplifies users, such as re-checking conditions before waiting. (It will
|
||||
// still process the remaining queue items, and wait for unsuspend.)
|
||||
// Note that this will strictly return only after:
|
||||
// - timeout has passed,
|
||||
// - all queue items were processed,
|
||||
// - the possibly acquired lock has been released
|
||||
// It's possible to cancel the timeout by calling mp_dispatch_interrupt().
|
||||
void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout)
|
||||
{
|
||||
int64_t wait = timeout > 0 ? mp_add_timeout(mp_time_us(), timeout) : 0;
|
||||
struct lock_frame frame = {
|
||||
.thread = pthread_self(),
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
queue->suspended = true;
|
||||
// Wake up thread which called mp_dispatch_suspend().
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
while (queue->head || queue->suspend_requested || wait > 0) {
|
||||
if (queue->head) {
|
||||
frame.prev = queue->frame;
|
||||
queue->frame = &frame;
|
||||
// Logically, the queue is idling if the target thread is blocked in
|
||||
// mp_dispatch_queue_process() doing nothing, so it's not possible to call
|
||||
// it again. (Reentrant calls via callbacks temporarily reset the field.)
|
||||
assert(!queue->idling);
|
||||
queue->idling = true;
|
||||
// Wake up thread which called mp_dispatch_lock().
|
||||
if (queue->lock_request)
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
while (1) {
|
||||
if (queue->lock_request || queue->frame != &frame || frame.locked) {
|
||||
// Block due to something having called mp_dispatch_lock(). This
|
||||
// is either a lock "acquire" (lock_request=true), or a lock in
|
||||
// progress, with the possibility the thread which called
|
||||
// mp_dispatch_lock() is now calling mp_dispatch_queue_process()
|
||||
// (the latter means we must ignore any queue state changes,
|
||||
// until it has been unlocked again).
|
||||
pthread_cond_wait(&queue->cond, &queue->lock);
|
||||
if (queue->frame == &frame && !frame.locked)
|
||||
assert(queue->idling);
|
||||
} else if (queue->head) {
|
||||
struct mp_dispatch_item *item = queue->head;
|
||||
queue->head = item->next;
|
||||
if (!queue->head)
|
||||
@@ -195,66 +233,50 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout)
|
||||
item->next = NULL;
|
||||
// Unlock, because we want to allow other threads to queue items
|
||||
// while the dispatch item is processed.
|
||||
// At the same time, exclusive_lock must be held to protect the
|
||||
// thread's user state.
|
||||
// At the same time, we must prevent other threads from returning
|
||||
// from mp_dispatch_lock(), which is done by idling=false.
|
||||
queue->idling = false;
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
pthread_mutex_lock(&queue->exclusive_lock);
|
||||
|
||||
item->fn(item->fn_data);
|
||||
pthread_mutex_unlock(&queue->exclusive_lock);
|
||||
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
assert(!queue->idling);
|
||||
queue->idling = true;
|
||||
// Wakeup mp_dispatch_run(), also mp_dispatch_lock().
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
if (item->asynchronous) {
|
||||
talloc_free(item);
|
||||
} else {
|
||||
item->completed = true;
|
||||
// Wakeup mp_dispatch_run()
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
}
|
||||
} else if (wait > 0 && !queue->interrupted) {
|
||||
struct timespec ts = mp_time_us_to_timespec(wait);
|
||||
if (pthread_cond_timedwait(&queue->cond, &queue->lock, &ts))
|
||||
wait = 0;
|
||||
} else {
|
||||
if (wait > 0) {
|
||||
struct timespec ts = mp_time_us_to_timespec(wait);
|
||||
pthread_cond_timedwait(&queue->cond, &queue->lock, &ts);
|
||||
} else {
|
||||
pthread_cond_wait(&queue->cond, &queue->lock);
|
||||
}
|
||||
}
|
||||
wait = 0;
|
||||
}
|
||||
queue->suspended = false;
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
// Set the target thread into suspend mode: in this mode, the thread will enter
|
||||
// mp_dispatch_queue_process(), process any outstanding dispatch items, and
|
||||
// wait for new items when done (instead of exiting the process function).
|
||||
// Multiple threads can enter suspend mode at the same time. Suspend mode is
|
||||
// not a synchronization mechanism; it merely makes sure the target thread does
|
||||
// not leave mp_dispatch_queue_process(), even if it's done. mp_dispatch_lock()
|
||||
// can be used for exclusive access.
|
||||
void mp_dispatch_suspend(struct mp_dispatch_queue *queue)
|
||||
{
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
queue->suspend_requested++;
|
||||
while (!queue->suspended) {
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
if (queue->wakeup_fn)
|
||||
queue->wakeup_fn(queue->wakeup_ctx);
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
if (queue->suspended)
|
||||
break;
|
||||
pthread_cond_wait(&queue->cond, &queue->lock);
|
||||
}
|
||||
}
|
||||
queue->idling = false;
|
||||
assert(!frame.locked);
|
||||
assert(queue->frame == &frame);
|
||||
queue->frame = frame.prev;
|
||||
queue->interrupted = false;
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
// Undo mp_dispatch_suspend().
|
||||
void mp_dispatch_resume(struct mp_dispatch_queue *queue)
|
||||
// If the queue is inside of mp_dispatch_queue_process(), make it return as
|
||||
// soon as all work items have been run, without waiting for the timeout. This
|
||||
// does not make it return early if it's blocked by a mp_dispatch_lock().
|
||||
// If mp_dispatch_queue_process() is called in a reentrant way (including the
|
||||
// case where another thread calls mp_dispatch_lock() and then
|
||||
// mp_dispatch_queue_process()), this affects only the "topmost" invocation.
|
||||
void mp_dispatch_interrupt(struct mp_dispatch_queue *queue)
|
||||
{
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
assert(queue->suspended);
|
||||
assert(queue->suspend_requested > 0);
|
||||
queue->suspend_requested--;
|
||||
if (queue->suspend_requested == 0)
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
queue->interrupted = true;
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
@@ -265,13 +287,50 @@ void mp_dispatch_resume(struct mp_dispatch_queue *queue)
|
||||
// and the mutex behavior applies to this function only.
|
||||
void mp_dispatch_lock(struct mp_dispatch_queue *queue)
|
||||
{
|
||||
mp_dispatch_suspend(queue);
|
||||
pthread_mutex_lock(&queue->exclusive_lock);
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
// First grab the queue lock. Something else could be holding the lock.
|
||||
while (queue->lock_request)
|
||||
pthread_cond_wait(&queue->cond, &queue->lock);
|
||||
queue->lock_request = true;
|
||||
// And now wait until the target thread gets "trapped" within the
|
||||
// mp_dispatch_queue_process() call, which will mean we get exclusive
|
||||
// access to the target's thread state.
|
||||
while (!queue->idling) {
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
if (queue->wakeup_fn)
|
||||
queue->wakeup_fn(queue->wakeup_ctx);
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
if (queue->idling)
|
||||
break;
|
||||
pthread_cond_wait(&queue->cond, &queue->lock);
|
||||
}
|
||||
assert(queue->lock_request);
|
||||
assert(queue->frame); // must be set if idling
|
||||
assert(!queue->frame->locked); // no recursive locking on the same level
|
||||
// "Lock".
|
||||
queue->frame->locked = true;
|
||||
queue->frame->locked_thread = pthread_self();
|
||||
// Reset state for recursive mp_dispatch_queue_process() calls.
|
||||
queue->lock_request = false;
|
||||
queue->idling = false;
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
// Undo mp_dispatch_lock().
|
||||
void mp_dispatch_unlock(struct mp_dispatch_queue *queue)
|
||||
{
|
||||
pthread_mutex_unlock(&queue->exclusive_lock);
|
||||
mp_dispatch_resume(queue);
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
// Must be called atfer a mp_dispatch_lock().
|
||||
assert(queue->frame);
|
||||
assert(queue->frame->locked);
|
||||
assert(pthread_equal(queue->frame->locked_thread, pthread_self()));
|
||||
// "Unlock".
|
||||
queue->frame->locked = false;
|
||||
// This must have been set to false during locking (except temporarily
|
||||
// during recursive mp_dispatch_queue_process() calls).
|
||||
assert(!queue->idling);
|
||||
queue->idling = true;
|
||||
// Wakeup mp_dispatch_queue_process(), and maybe other mp_dispatch_lock()s.
|
||||
pthread_cond_broadcast(&queue->cond);
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
}
|
||||
+1
-2
@@ -15,8 +15,7 @@ void mp_dispatch_enqueue_autofree(struct mp_dispatch_queue *queue,
|
||||
void mp_dispatch_run(struct mp_dispatch_queue *queue,
|
||||
mp_dispatch_fn fn, void *fn_data);
|
||||
void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout);
|
||||
void mp_dispatch_suspend(struct mp_dispatch_queue *queue);
|
||||
void mp_dispatch_resume(struct mp_dispatch_queue *queue);
|
||||
void mp_dispatch_interrupt(struct mp_dispatch_queue *queue);
|
||||
void mp_dispatch_lock(struct mp_dispatch_queue *queue);
|
||||
void mp_dispatch_unlock(struct mp_dispatch_queue *queue);
|
||||
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#include "node.h"
|
||||
|
||||
// Init a node with the given format. If parent is not NULL, it is set as
|
||||
// parent allocation according to m_option_type_node rules (which means
|
||||
// the mpv_node_list allocs are used for chaining the TA allocations).
|
||||
// format == MPV_FORMAT_NONE will simply initialize it with all-0.
|
||||
void node_init(struct mpv_node *dst, int format, struct mpv_node *parent)
|
||||
{
|
||||
// Other formats need to be initialized manually.
|
||||
assert(format == MPV_FORMAT_NODE_MAP || format == MPV_FORMAT_NODE_ARRAY ||
|
||||
format == MPV_FORMAT_FLAG || format == MPV_FORMAT_INT64 ||
|
||||
format == MPV_FORMAT_DOUBLE || format == MPV_FORMAT_NONE);
|
||||
|
||||
void *ta_parent = NULL;
|
||||
if (parent) {
|
||||
assert(parent->format == MPV_FORMAT_NODE_MAP ||
|
||||
parent->format == MPV_FORMAT_NODE_ARRAY);
|
||||
ta_parent = parent->u.list;
|
||||
}
|
||||
|
||||
*dst = (struct mpv_node){ .format = format };
|
||||
if (format == MPV_FORMAT_NODE_MAP || format == MPV_FORMAT_NODE_ARRAY)
|
||||
dst->u.list = talloc_zero(ta_parent, struct mpv_node_list);
|
||||
}
|
||||
|
||||
// Add an entry to a MPV_FORMAT_NODE_ARRAY.
|
||||
// m_option_type_node memory management rules apply.
|
||||
struct mpv_node *node_array_add(struct mpv_node *dst, int format)
|
||||
{
|
||||
struct mpv_node_list *list = dst->u.list;
|
||||
assert(dst->format == MPV_FORMAT_NODE_ARRAY && dst->u.list);
|
||||
MP_TARRAY_GROW(list, list->values, list->num);
|
||||
node_init(&list->values[list->num], format, dst);
|
||||
return &list->values[list->num++];
|
||||
}
|
||||
|
||||
// Add an entry to a MPV_FORMAT_NODE_MAP. Keep in mind that this does
|
||||
// not check for already existing entries under the same key.
|
||||
// m_option_type_node memory management rules apply.
|
||||
struct mpv_node *node_map_add(struct mpv_node *dst, const char *key, int format)
|
||||
{
|
||||
assert(key);
|
||||
|
||||
struct mpv_node_list *list = dst->u.list;
|
||||
assert(dst->format == MPV_FORMAT_NODE_MAP && dst->u.list);
|
||||
MP_TARRAY_GROW(list, list->values, list->num);
|
||||
MP_TARRAY_GROW(list, list->keys, list->num);
|
||||
list->keys[list->num] = talloc_strdup(list, key);
|
||||
node_init(&list->values[list->num], format, dst);
|
||||
return &list->values[list->num++];
|
||||
}
|
||||
|
||||
// Add a string entry to a MPV_FORMAT_NODE_MAP. Keep in mind that this does
|
||||
// not check for already existing entries under the same key.
|
||||
// m_option_type_node memory management rules apply.
|
||||
void node_map_add_string(struct mpv_node *dst, const char *key, const char *val)
|
||||
{
|
||||
assert(val);
|
||||
|
||||
struct mpv_node *entry = node_map_add(dst, key, MPV_FORMAT_NONE);
|
||||
entry->format = MPV_FORMAT_STRING;
|
||||
entry->u.string = talloc_strdup(dst->u.list, val);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#ifndef MP_MISC_NODE_H_
|
||||
#define MP_MISC_NODE_H_
|
||||
|
||||
#include "libmpv/client.h"
|
||||
|
||||
void node_init(struct mpv_node *dst, int format, struct mpv_node *parent);
|
||||
struct mpv_node *node_array_add(struct mpv_node *dst, int format);
|
||||
struct mpv_node *node_map_add(struct mpv_node *dst, const char *key, int format);
|
||||
void node_map_add_string(struct mpv_node *dst, const char *key, const char *val);
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
#include <libavutil/common.h>
|
||||
#include <assert.h>
|
||||
#include "mpv_talloc.h"
|
||||
#include "osdep/atomics.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "ring.h"
|
||||
|
||||
struct mp_ring {
|
||||
|
||||
+601
-280
File diff suppressed because it is too large.
Load diff
+107
-31
@@ -19,6 +19,7 @@
|
||||
#define MPLAYER_M_CONFIG_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "misc/bstr.h"
|
||||
@@ -37,10 +38,13 @@ struct mp_log;
|
||||
|
||||
// Config option
|
||||
struct m_config_option {
|
||||
bool is_generated : 1; // Automatically added ("no-" options)
|
||||
bool is_hidden : 1; // Does not show up in help
|
||||
bool is_set_from_cmdline : 1; // Set by user from command line
|
||||
bool is_set_from_config : 1; // Set by a config file
|
||||
bool is_set_locally : 1; // Has a backup entry
|
||||
bool warning_was_printed : 1;
|
||||
int16_t shadow_offset; // Offset into m_config_shadow.data
|
||||
int16_t group; // Index into m_config.groups
|
||||
const char *name; // Full name (ie option-subopt)
|
||||
const struct m_option *opt; // Option description
|
||||
void *data; // Raw value of the option
|
||||
@@ -74,10 +78,33 @@ typedef struct m_config {
|
||||
int (*includefunc)(void *ctx, char *filename, int flags);
|
||||
void *includefunc_ctx;
|
||||
|
||||
// Can intercept option write accesses.
|
||||
int (*option_set_callback)(void *ctx, struct m_config_option *co,
|
||||
void *data, int flags);
|
||||
void *option_set_callback_cb;
|
||||
|
||||
// Notification after an option was successfully written to.
|
||||
// Uses flags as set in UPDATE_OPTS_MASK.
|
||||
void (*option_change_callback)(void *ctx, struct m_config_option *co,
|
||||
int flags);
|
||||
void *option_change_callback_ctx;
|
||||
|
||||
// For the command line parser
|
||||
int recursion_depth;
|
||||
|
||||
bool subopt_deprecation_warning;
|
||||
|
||||
void *optstruct; // struct mpopts or other
|
||||
|
||||
int shadow_size;
|
||||
|
||||
// List of m_sub_options instances.
|
||||
// Index 0 is the top-level and is always present.
|
||||
struct m_config_group *groups;
|
||||
int num_groups;
|
||||
|
||||
// Thread-safe shadow memory; only set for the main m_config.
|
||||
struct m_config_shadow *shadow;
|
||||
} m_config_t;
|
||||
|
||||
// Create a new config object.
|
||||
@@ -94,8 +121,9 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
|
||||
size_t size, const void *defaults,
|
||||
const struct m_option *options);
|
||||
|
||||
// (Warning: new object references config->log and others.)
|
||||
struct m_config *m_config_dup(void *talloc_ctx, struct m_config *config);
|
||||
// Creates "backup" shadow memory for use with m_config_cache. Sets it on
|
||||
// mpv_global. Expected to be called at early init on the main m_config.
|
||||
void m_config_create_shadow(struct m_config *config);
|
||||
|
||||
struct m_config *m_config_from_obj_desc(void *talloc_ctx, struct mp_log *log,
|
||||
struct m_obj_desc *desc);
|
||||
@@ -104,12 +132,9 @@ struct m_config *m_config_from_obj_desc_noalloc(void *talloc_ctx,
|
||||
struct mp_log *log,
|
||||
struct m_obj_desc *desc);
|
||||
|
||||
int m_config_set_obj_params(struct m_config *conf, char **args);
|
||||
|
||||
// Search for the object with the given name in the defaults list, and apply
|
||||
// its parameters.
|
||||
int m_config_apply_defaults(struct m_config *config, const char *name,
|
||||
struct m_obj_settings *defaults);
|
||||
struct m_config *m_config_from_obj_desc_and_args(void *ta_parent,
|
||||
struct mp_log *log, struct mpv_global *global, struct m_obj_desc *desc,
|
||||
const char *name, struct m_obj_settings *defaults, char **args);
|
||||
|
||||
// Make sure the option is backed up. If it's already backed up, do nothing.
|
||||
// All backed up options can be restored with m_config_restore_backups().
|
||||
@@ -131,10 +156,11 @@ enum {
|
||||
M_SETOPT_PRESERVE_CMDLINE = 32, // Don't set if already marked as FROM_CMDLINE
|
||||
M_SETOPT_NO_FIXED = 64, // Reject M_OPT_FIXED options
|
||||
M_SETOPT_NO_PRE_PARSE = 128, // Reject M_OPT_PREPARSE options
|
||||
M_SETOPT_NO_OVERWRITE = 256, // Skip options marked with FROM_*
|
||||
};
|
||||
|
||||
// Flags for safe option setting during runtime.
|
||||
#define M_SETOPT_RUNTIME (M_SETOPT_NO_FIXED | M_SETOPT_NO_PRE_PARSE)
|
||||
#define M_SETOPT_RUNTIME M_SETOPT_NO_FIXED
|
||||
|
||||
// Set the named option to the given string.
|
||||
// flags: combination of M_SETOPT_* flags (0 for normal operation)
|
||||
@@ -157,11 +183,15 @@ static inline int m_config_set_option0(struct m_config *config,
|
||||
return m_config_set_option(config, bstr0(name), bstr0(param));
|
||||
}
|
||||
|
||||
// Similar to m_config_set_option_ext(), but set as data in its native format.
|
||||
// The type data points to is as in co->opt
|
||||
int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
|
||||
void *data, int flags);
|
||||
|
||||
void m_config_mark_co_flags(struct m_config_option *co, int flags);
|
||||
|
||||
int m_config_set_option_raw_direct(struct m_config *config,
|
||||
struct m_config_option *co,
|
||||
void *data, int flags);
|
||||
|
||||
// Similar to m_config_set_option_ext(), but set as data using mpv_node.
|
||||
struct mpv_node;
|
||||
int m_config_set_option_node(struct m_config *config, bstr name,
|
||||
@@ -171,17 +201,14 @@ int m_config_set_option_node(struct m_config *config, bstr name,
|
||||
int m_config_parse_suboptions(struct m_config *config, char *name,
|
||||
char *subopts);
|
||||
|
||||
|
||||
/* Get the option matching the given name.
|
||||
* \param config The config object.
|
||||
* \param name The option's 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_raw(const struct m_config *config,
|
||||
struct bstr name);
|
||||
struct m_config_option *m_config_get_co(const struct m_config *config,
|
||||
struct bstr name);
|
||||
|
||||
int m_config_get_co_count(struct m_config *config);
|
||||
struct m_config_option *m_config_get_co_index(struct m_config *config, int index);
|
||||
|
||||
// Return the n-th option by position. n==0 is the first option. If there are
|
||||
// less than (n + 1) options, return NULL.
|
||||
const char *m_config_get_positional_option(const struct m_config *config, int n);
|
||||
@@ -193,13 +220,18 @@ const char *m_config_get_positional_option(const struct m_config *config, int n)
|
||||
// Returns: error code (<0), or number of expected params (0, 1)
|
||||
int m_config_option_requires_param(struct m_config *config, bstr name);
|
||||
|
||||
// Notify m_config_cache users that the option has (probably) changed its value.
|
||||
void m_config_notify_change_co(struct m_config *config,
|
||||
struct m_config_option *co);
|
||||
|
||||
bool m_config_is_in_group(struct m_config *config,
|
||||
const struct m_sub_options *group,
|
||||
struct m_config_option *co);
|
||||
|
||||
// Return all (visible) option names as NULL terminated string list.
|
||||
char **m_config_list_options(void *ta_parent, const struct m_config *config);
|
||||
|
||||
/* Print a list of all registered options.
|
||||
* \param config The config object.
|
||||
*/
|
||||
void m_config_print_option_list(const struct m_config *config);
|
||||
void m_config_print_option_list(const struct m_config *config, const char *name);
|
||||
|
||||
|
||||
/* Find the profile with the given name.
|
||||
@@ -211,6 +243,10 @@ struct m_profile *m_config_get_profile0(const struct m_config *config,
|
||||
char *name);
|
||||
struct m_profile *m_config_get_profile(const struct m_config *config, bstr name);
|
||||
|
||||
// Apply and clear the default profile - it's the only profile that new config
|
||||
// files do not simply append to (for configfile parser).
|
||||
void m_config_finish_default_profile(struct m_config *config, int flags);
|
||||
|
||||
/* Get the profile with the given name, creating it if necessary.
|
||||
* \param config The config object.
|
||||
* \param arg The profile's name.
|
||||
@@ -247,13 +283,53 @@ int m_config_set_profile_option(struct m_config *config, struct m_profile *p,
|
||||
*/
|
||||
int m_config_set_profile(struct m_config *config, char *name, int flags);
|
||||
|
||||
void *m_config_alloc_struct(void *talloc_ctx,
|
||||
const struct m_sub_options *subopts);
|
||||
struct mpv_node m_config_get_profiles(struct m_config *config);
|
||||
|
||||
// Create a copy of the struct ptr, described by opts.
|
||||
// "opts" must live until the struct is free'd.
|
||||
// Freeing the struct frees all members.
|
||||
void *m_sub_options_copy(void *talloc_ctx, const struct m_sub_options *opts,
|
||||
const void *ptr);
|
||||
// This can be used to create and synchronize per-thread option structs,
|
||||
// which then can be read without synchronization. No concurrent access to
|
||||
// the cache itself is allowed.
|
||||
struct m_config_cache {
|
||||
// The struct as indicated by m_config_cache_alloc's group parameter.
|
||||
void *opts;
|
||||
|
||||
// Internal.
|
||||
struct m_config_shadow *shadow;
|
||||
struct m_config *shadow_config;
|
||||
long long ts;
|
||||
int group;
|
||||
};
|
||||
|
||||
// Create a mirror copy from the global options.
|
||||
// ta_parent: parent for the returned allocation
|
||||
// global: option data source
|
||||
// group: the option group to return. This can be NULL for the global option
|
||||
// struct (MPOpts), or m_sub_options used in a certain OPT_SUBSTRUCT()
|
||||
// item.
|
||||
struct m_config_cache *m_config_cache_alloc(void *ta_parent,
|
||||
struct mpv_global *global,
|
||||
const struct m_sub_options *group);
|
||||
|
||||
// Update the options in cache->opts to current global values. Return whether
|
||||
// there was an update notification at all (which may or may not indicate that
|
||||
// some options have changed).
|
||||
// Keep in mind that while the cache->opts pointer does not change, the option
|
||||
// data itself will (e.g. string options might be reallocated).
|
||||
bool m_config_cache_update(struct m_config_cache *cache);
|
||||
|
||||
// Like m_config_cache_alloc(), but return the struct (m_config_cache->opts)
|
||||
// directly, with no way to update the config.
|
||||
// Warning: does currently not set the child as its own talloc root, which
|
||||
// means the only way to free the struct is by freeing ta_parent.
|
||||
void *mp_get_config_group(void *ta_parent, struct mpv_global *global,
|
||||
const struct m_sub_options *group);
|
||||
|
||||
|
||||
// Read a single global option in a thread-safe way. For multiple options,
|
||||
// use m_config_cache. The option must exist and match the provided type (the
|
||||
// type is used as a sanity check only). Performs semi-expensive lookup.
|
||||
void mp_read_option_raw(struct mpv_global *global, const char *name,
|
||||
const struct m_option_type *type, void *dst);
|
||||
|
||||
struct m_config *mp_get_root_config(struct mpv_global *global);
|
||||
|
||||
#endif /* MPLAYER_M_CONFIG_H */
|
||||
+63
-132
@@ -133,14 +133,6 @@ 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) == 0 || VAL(val) == 1)
|
||||
return 0;
|
||||
VAL(val) = 0;
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
static int parse_flag(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param, void *dst)
|
||||
{
|
||||
@@ -202,7 +194,6 @@ const m_option_type_t m_option_type_flag = {
|
||||
.print = print_flag,
|
||||
.copy = copy_opt,
|
||||
.add = add_flag,
|
||||
.clamp = clamp_flag,
|
||||
.set = flag_set,
|
||||
.get = flag_get,
|
||||
};
|
||||
@@ -243,45 +234,6 @@ const m_option_type_t m_option_type_store = {
|
||||
.set = store_set,
|
||||
};
|
||||
|
||||
// Same for float types
|
||||
|
||||
#undef VAL
|
||||
#define VAL(x) (*(float *)(x))
|
||||
|
||||
static int parse_store_float(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param, void *dst)
|
||||
{
|
||||
if (param.len == 0) {
|
||||
if (dst)
|
||||
VAL(dst) = opt->max;
|
||||
return 0;
|
||||
} else {
|
||||
mp_err(log, "Invalid parameter for %.*s flag: %.*s\n",
|
||||
BSTR_P(name), BSTR_P(param));
|
||||
return M_OPT_DISALLOW_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
static int store_float_set(const m_option_t *opt, void *dst, struct mpv_node *src)
|
||||
{
|
||||
if (src->format != MPV_FORMAT_FLAG)
|
||||
return M_OPT_UNKNOWN;
|
||||
if (!src->u.flag)
|
||||
return M_OPT_INVALID;
|
||||
VAL(dst) = opt->max;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_float_store = {
|
||||
// can only be activated
|
||||
.name = "Flag",
|
||||
.size = sizeof(float),
|
||||
.flags = M_OPT_TYPE_OPTIONAL_PARAM,
|
||||
.parse = parse_store_float,
|
||||
.copy = copy_opt,
|
||||
.set = store_float_set,
|
||||
};
|
||||
|
||||
// Integer
|
||||
|
||||
#undef VAL
|
||||
@@ -336,14 +288,6 @@ static int parse_longlong(struct mp_log *log, const m_option_t *opt,
|
||||
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;
|
||||
@@ -475,7 +419,6 @@ const m_option_type_t m_option_type_int = {
|
||||
.copy = copy_opt,
|
||||
.add = add_int,
|
||||
.multiply = multiply_int,
|
||||
.clamp = clamp_int,
|
||||
.set = int_set,
|
||||
.get = int_get,
|
||||
};
|
||||
@@ -488,7 +431,6 @@ const m_option_type_t m_option_type_int64 = {
|
||||
.copy = copy_opt,
|
||||
.add = add_int64,
|
||||
.multiply = multiply_int64,
|
||||
.clamp = clamp_int64,
|
||||
.set = int64_set,
|
||||
.get = int64_get,
|
||||
};
|
||||
@@ -546,21 +488,6 @@ const char *m_opt_choice_str(const struct m_opt_choice_alternatives *choices,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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(struct mp_log *log, const struct m_option *opt,
|
||||
struct bstr name, struct bstr param, void *dst)
|
||||
{
|
||||
@@ -750,7 +677,6 @@ const struct m_option_type m_option_type_choice = {
|
||||
.print = print_choice,
|
||||
.copy = copy_opt,
|
||||
.add = add_choice,
|
||||
.clamp = clamp_choice,
|
||||
.set = choice_set,
|
||||
.get = choice_get,
|
||||
};
|
||||
@@ -894,7 +820,8 @@ static int clamp_double(const m_option_t *opt, void *val)
|
||||
v = opt->min;
|
||||
r = M_OPT_OUT_OF_RANGE;
|
||||
}
|
||||
if (!isfinite(v)) {
|
||||
// (setting max/min to INFINITY/-INFINITY is allowed)
|
||||
if (!isfinite(v) && v != opt->max && v != opt->min) {
|
||||
v = opt->min;
|
||||
r = M_OPT_OUT_OF_RANGE;
|
||||
}
|
||||
@@ -921,22 +848,8 @@ static int parse_double(struct mp_log *log, const m_option_t *opt,
|
||||
return M_OPT_INVALID;
|
||||
}
|
||||
|
||||
if (opt->flags & M_OPT_MIN)
|
||||
if (tmp_float < opt->min) {
|
||||
mp_err(log, "The %.*s option must be >= %f: %.*s\n",
|
||||
BSTR_P(name), opt->min, BSTR_P(param));
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (opt->flags & M_OPT_MAX)
|
||||
if (tmp_float > opt->max) {
|
||||
mp_err(log, "The %.*s option must be <= %f: %.*s\n",
|
||||
BSTR_P(name), opt->max, BSTR_P(param));
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (!isfinite(tmp_float)) {
|
||||
mp_err(log, "The %.*s option must be a finite number: %.*s\n",
|
||||
if (clamp_double(opt, &tmp_float) < 0) {
|
||||
mp_err(log, "The %.*s option is out of range: %.*s\n",
|
||||
BSTR_P(name), BSTR_P(param));
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
}
|
||||
@@ -990,11 +903,7 @@ static int double_set(const m_option_t *opt, void *dst, struct mpv_node *src)
|
||||
} else {
|
||||
return M_OPT_UNKNOWN;
|
||||
}
|
||||
if ((opt->flags & M_OPT_MIN) && val < opt->min)
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
if ((opt->flags & M_OPT_MAX) && val > opt->max)
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
if (!isfinite(val))
|
||||
if (clamp_double(opt, &val) < 0)
|
||||
return M_OPT_OUT_OF_RANGE;
|
||||
*(double *)dst = val;
|
||||
return 1;
|
||||
@@ -1016,7 +925,6 @@ const m_option_type_t m_option_type_double = {
|
||||
.print = print_double,
|
||||
.pretty_print = print_double_f3,
|
||||
.copy = copy_opt,
|
||||
.clamp = clamp_double,
|
||||
.add = add_double,
|
||||
.multiply = multiply_double,
|
||||
.set = double_set,
|
||||
@@ -1026,14 +934,6 @@ const m_option_type_t m_option_type_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(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param, void *dst)
|
||||
{
|
||||
@@ -1095,7 +995,30 @@ const m_option_type_t m_option_type_float = {
|
||||
.copy = copy_opt,
|
||||
.add = add_float,
|
||||
.multiply = multiply_float,
|
||||
.clamp = clamp_float,
|
||||
.set = float_set,
|
||||
.get = float_get,
|
||||
};
|
||||
|
||||
static int parse_float_aspect(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param, void *dst)
|
||||
{
|
||||
if (bstr_equals0(param, "no")) {
|
||||
if (dst)
|
||||
VAL(dst) = 0.0f;
|
||||
return 1;
|
||||
}
|
||||
return parse_float(log, opt, name, param, dst);
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_aspect = {
|
||||
.name = "Aspect",
|
||||
.size = sizeof(float),
|
||||
.parse = parse_float_aspect,
|
||||
.print = print_float,
|
||||
.pretty_print = print_float_f3,
|
||||
.copy = copy_opt,
|
||||
.add = add_float,
|
||||
.multiply = multiply_float,
|
||||
.set = float_set,
|
||||
.get = float_get,
|
||||
};
|
||||
@@ -1192,12 +1115,10 @@ static void free_str(void *src)
|
||||
const m_option_type_t m_option_type_string = {
|
||||
.name = "String",
|
||||
.size = sizeof(char *),
|
||||
.flags = M_OPT_TYPE_DYNAMIC,
|
||||
.parse = parse_str,
|
||||
.print = print_str,
|
||||
.copy = copy_str,
|
||||
.free = free_str,
|
||||
.clamp = clamp_str,
|
||||
.set = str_set,
|
||||
.get = str_get,
|
||||
};
|
||||
@@ -1503,7 +1424,7 @@ const m_option_type_t m_option_type_string_list = {
|
||||
*/
|
||||
.name = "String list",
|
||||
.size = sizeof(char **),
|
||||
.flags = M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
|
||||
.flags = M_OPT_TYPE_ALLOW_WILDCARD,
|
||||
.parse = parse_str_list,
|
||||
.print = print_str_list,
|
||||
.copy = copy_str_list,
|
||||
@@ -1539,7 +1460,6 @@ static int parse_str_append_list(struct mp_log *log, const m_option_t *opt,
|
||||
const m_option_type_t m_option_type_string_append_list = {
|
||||
.name = "String list",
|
||||
.size = sizeof(char **),
|
||||
.flags = M_OPT_TYPE_DYNAMIC,
|
||||
.parse = parse_str_append_list,
|
||||
.print = print_str_list,
|
||||
.copy = copy_str_list,
|
||||
@@ -1653,7 +1573,6 @@ static int keyvalue_list_get(const m_option_t *opt, void *ta_parent,
|
||||
const m_option_type_t m_option_type_keyvalue_list = {
|
||||
.name = "Key/value list",
|
||||
.size = sizeof(char **),
|
||||
.flags = M_OPT_TYPE_DYNAMIC,
|
||||
.parse = parse_keyvalue_list,
|
||||
.print = print_keyvalue_list,
|
||||
.copy = copy_str_list,
|
||||
@@ -1720,7 +1639,6 @@ static int set_msglevels(const m_option_t *opt, void *dst,
|
||||
const m_option_type_t m_option_type_msglevels = {
|
||||
.name = "Output verbosity levels",
|
||||
.size = sizeof(char **),
|
||||
.flags = M_OPT_TYPE_DYNAMIC,
|
||||
.parse = parse_msglevels,
|
||||
.print = print_keyvalue_list,
|
||||
.copy = copy_str_list,
|
||||
@@ -2186,7 +2104,7 @@ static int parse_imgfmt(struct mp_log *log, const m_option_t *opt,
|
||||
mp_info(log, " %s", list[i]);
|
||||
mp_info(log, "\n");
|
||||
talloc_free(list);
|
||||
return M_OPT_EXIT - 1;
|
||||
return M_OPT_EXIT;
|
||||
}
|
||||
|
||||
unsigned int fmt = mp_imgfmt_from_name(param, true);
|
||||
@@ -2257,7 +2175,7 @@ static int parse_afmt(struct mp_log *log, const m_option_t *opt,
|
||||
for (int i = 1; i < AF_FORMAT_COUNT; i++)
|
||||
mp_info(log, " %s", af_fmt_to_str(i));
|
||||
mp_info(log, "\n");
|
||||
return M_OPT_EXIT - 1;
|
||||
return M_OPT_EXIT;
|
||||
}
|
||||
|
||||
int fmt = 0;
|
||||
@@ -2301,7 +2219,7 @@ static int parse_channels(struct mp_log *log, const m_option_t *opt,
|
||||
mp_info(log, "\nOther values:\n"
|
||||
" auto-safe\n");
|
||||
}
|
||||
return M_OPT_EXIT - 1;
|
||||
return M_OPT_EXIT;
|
||||
}
|
||||
|
||||
bool auto_safe = bstr_equals0(param, "auto-safe");
|
||||
@@ -2483,7 +2401,6 @@ const m_option_type_t m_option_type_time = {
|
||||
.pretty_print = pretty_print_time,
|
||||
.copy = copy_opt,
|
||||
.add = add_double,
|
||||
.clamp = clamp_double,
|
||||
.set = time_set,
|
||||
.get = time_get,
|
||||
};
|
||||
@@ -2731,17 +2648,21 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst,
|
||||
// without '=' sets a flag, or whether it's a positional argument.
|
||||
static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name,
|
||||
struct m_config *config, bstr name, bstr val,
|
||||
int flags, int *nold, bstr *out_name, bstr *out_val)
|
||||
int flags, bool nopos,
|
||||
int *nold, bstr *out_name, bstr *out_val)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!config)
|
||||
return 0; // skip
|
||||
if (!config) {
|
||||
*out_name = name; // preserve args for opengl-hq legacy handling
|
||||
*out_val = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// va.start != NULL => of the form name=val (not positional)
|
||||
// If it's just "name", and the associated option exists and is a flag,
|
||||
// don't accept it as positional argument.
|
||||
if (val.start || m_config_option_requires_param(config, name) == 0) {
|
||||
if (val.start || m_config_option_requires_param(config, name) == 0 || nopos) {
|
||||
r = m_config_set_option_ext(config, name, val, flags);
|
||||
if (r < 0) {
|
||||
if (r == M_OPT_UNKNOWN) {
|
||||
@@ -2749,7 +2670,7 @@ static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name,
|
||||
BSTR_P(opt_name), BSTR_P(obj_name), BSTR_P(name));
|
||||
return M_OPT_UNKNOWN;
|
||||
}
|
||||
if (r > M_OPT_EXIT)
|
||||
if (r != M_OPT_EXIT)
|
||||
mp_err(log, "Option %.*s: "
|
||||
"Error while parsing %.*s parameter %.*s (%.*s)\n",
|
||||
BSTR_P(opt_name), BSTR_P(obj_name), BSTR_P(name),
|
||||
@@ -2775,7 +2696,7 @@ static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name,
|
||||
}
|
||||
r = m_config_set_option_ext(config, bstr0(opt), val, flags);
|
||||
if (r < 0) {
|
||||
if (r > M_OPT_EXIT)
|
||||
if (r != M_OPT_EXIT)
|
||||
mp_err(log, "Option %.*s: "
|
||||
"Error while parsing %.*s parameter %s (%.*s)\n",
|
||||
BSTR_P(opt_name), BSTR_P(obj_name), opt, BSTR_P(val));
|
||||
@@ -2797,7 +2718,7 @@ static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name,
|
||||
// desc is optional.
|
||||
static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name,
|
||||
struct bstr name, struct bstr *pstr,
|
||||
struct m_config *config, int flags,
|
||||
struct m_config *config, int flags, bool nopos,
|
||||
struct m_obj_desc *desc, char ***ret)
|
||||
{
|
||||
int nold = 0;
|
||||
@@ -2818,8 +2739,8 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name,
|
||||
goto exit;
|
||||
if (bstr_equals0(fname, "help"))
|
||||
goto print_help;
|
||||
r = get_obj_param(log, opt_name, name, config, fname, fval, flags, &nold,
|
||||
&fname, &fval);
|
||||
r = get_obj_param(log, opt_name, name, config, fname, fval, flags,
|
||||
nopos, &nold, &fname, &fval);
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
@@ -2850,12 +2771,12 @@ print_help: ;
|
||||
if (config) {
|
||||
if (desc->print_help)
|
||||
desc->print_help(log);
|
||||
m_config_print_option_list(config);
|
||||
m_config_print_option_list(config, "*");
|
||||
} else {
|
||||
mp_warn(log, "Option %.*s: item %.*s doesn't exist.\n",
|
||||
BSTR_P(opt_name), BSTR_P(name));
|
||||
}
|
||||
r = M_OPT_EXIT - 1;
|
||||
r = M_OPT_EXIT;
|
||||
|
||||
exit:
|
||||
free_str_list(&args);
|
||||
@@ -2874,6 +2795,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt,
|
||||
char **plist = NULL;
|
||||
struct m_obj_desc desc;
|
||||
bstr label = {0};
|
||||
bool nopos = list->disallow_positional_parameters;
|
||||
|
||||
if (bstr_eatstart0(pstr, "@")) {
|
||||
if (!bstr_split_tok(*pstr, ":", &label, pstr)) {
|
||||
@@ -2909,7 +2831,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt,
|
||||
struct m_config *config = m_config_from_obj_desc_noalloc(NULL, log, &desc);
|
||||
bstr s = bstr0(desc.init_options);
|
||||
m_obj_parse_sub_config(log, opt, str, &s, config,
|
||||
M_SETOPT_CHECK_ONLY, NULL, &plist);
|
||||
M_SETOPT_CHECK_ONLY, nopos, NULL, &plist);
|
||||
assert(s.len == 0);
|
||||
talloc_free(config);
|
||||
}
|
||||
@@ -2919,7 +2841,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt,
|
||||
if (!skip)
|
||||
config = m_config_from_obj_desc_noalloc(NULL, log, &desc);
|
||||
r = m_obj_parse_sub_config(log, opt, str, pstr, config,
|
||||
M_SETOPT_CHECK_ONLY, &desc,
|
||||
M_SETOPT_CHECK_ONLY, nopos, &desc,
|
||||
_ret ? &plist : NULL);
|
||||
talloc_free(config);
|
||||
if (r < 0)
|
||||
@@ -3051,7 +2973,7 @@ static int parse_obj_settings_list(struct mp_log *log, const m_option_t *opt,
|
||||
}
|
||||
}
|
||||
mp_info(log, "\n");
|
||||
return M_OPT_EXIT - 1;
|
||||
return M_OPT_EXIT;
|
||||
}
|
||||
|
||||
if (op == OP_CLR) {
|
||||
@@ -3301,7 +3223,7 @@ static int get_obj_settings_list(const m_option_t *opt, void *ta_parent,
|
||||
const m_option_type_t m_option_type_obj_settings_list = {
|
||||
.name = "Object settings list",
|
||||
.size = sizeof(m_obj_settings_t *),
|
||||
.flags = M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
|
||||
.flags = M_OPT_TYPE_ALLOW_WILDCARD,
|
||||
.parse = parse_obj_settings_list,
|
||||
.print = print_obj_settings_list,
|
||||
.copy = copy_obj_settings_list,
|
||||
@@ -3422,7 +3344,6 @@ static int node_get(const m_option_t *opt, void *ta_parent,
|
||||
const m_option_type_t m_option_type_node = {
|
||||
.name = "Complex",
|
||||
.size = sizeof(struct mpv_node),
|
||||
.flags = M_OPT_TYPE_DYNAMIC,
|
||||
.parse = parse_node,
|
||||
.print = print_node,
|
||||
.copy = copy_node,
|
||||
@@ -3438,3 +3359,13 @@ const m_option_type_t m_option_type_alias = {
|
||||
const m_option_type_t m_option_type_removed = {
|
||||
.name = "removed",
|
||||
};
|
||||
|
||||
static int parse_dummy(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param, void *dst)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
const m_option_type_t m_option_type_subopt_legacy = {
|
||||
.name = "legacy suboption",
|
||||
.parse = parse_dummy,
|
||||
};
|
||||
+69
-42
@@ -38,7 +38,6 @@ struct mpv_node;
|
||||
// Simple types
|
||||
extern const m_option_type_t m_option_type_flag;
|
||||
extern const m_option_type_t m_option_type_store;
|
||||
extern const m_option_type_t m_option_type_float_store;
|
||||
extern const m_option_type_t m_option_type_int;
|
||||
extern const m_option_type_t m_option_type_int64;
|
||||
extern const m_option_type_t m_option_type_intpair;
|
||||
@@ -62,7 +61,9 @@ extern const m_option_type_t m_option_type_color;
|
||||
extern const m_option_type_t m_option_type_geometry;
|
||||
extern const m_option_type_t m_option_type_size_box;
|
||||
extern const m_option_type_t m_option_type_channels;
|
||||
extern const m_option_type_t m_option_type_aspect;
|
||||
extern const m_option_type_t m_option_type_node;
|
||||
extern const m_option_type_t m_option_type_subopt_legacy;
|
||||
|
||||
// Used internally by m_config.c
|
||||
extern const m_option_type_t m_option_type_alias;
|
||||
@@ -129,6 +130,12 @@ struct m_obj_desc {
|
||||
// Set by m_obj_list_find(). If the requested name is an old alias, this
|
||||
// is set to the old name (while the name field uses the new name).
|
||||
const char *replaced_name;
|
||||
// For convenience: these are added as global command-line options.
|
||||
const struct m_sub_options *global_opts;
|
||||
// Evil hack to essentially force-move .options to global_opts. All options
|
||||
// will be added as global options with the given prefix, and using
|
||||
// sub-options will be treated as deprecated and redirected.
|
||||
const char *legacy_prefix;
|
||||
};
|
||||
|
||||
// Extra definition needed for \ref m_option_type_obj_settings_list options.
|
||||
@@ -142,6 +149,8 @@ struct m_obj_list {
|
||||
// Allow unknown entries, for which a dummy entry is inserted, and whose
|
||||
// options are skipped and ignored.
|
||||
bool allow_unknown_entries;
|
||||
// This helps with confusing error messages if unknown flag options are used.
|
||||
bool disallow_positional_parameters;
|
||||
};
|
||||
|
||||
// Find entry by name
|
||||
@@ -182,6 +191,9 @@ struct m_sub_options {
|
||||
const struct m_option *opts;
|
||||
size_t size;
|
||||
const void *defaults;
|
||||
// Change flags passed to mp_option_change_callback() if any option that is
|
||||
// directly or indirectly part of this group is changed.
|
||||
int change_flags;
|
||||
};
|
||||
|
||||
#define CONF_TYPE_FLAG (&m_option_type_flag)
|
||||
@@ -207,7 +219,6 @@ struct m_sub_options {
|
||||
union m_option_value {
|
||||
int flag; // not the C type "bool"!
|
||||
int store;
|
||||
float float_store;
|
||||
int int_;
|
||||
int64_t int64;
|
||||
int intpair[2];
|
||||
@@ -291,13 +302,6 @@ struct m_option_type {
|
||||
// to the valid value range of the option.
|
||||
void (*multiply)(const m_option_t *opt, void *val, double f);
|
||||
|
||||
// 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);
|
||||
|
||||
// Set the option value in dst to the contents of src.
|
||||
// (If the option is dynamic, the old value in *dst has to be freed.)
|
||||
// Return values:
|
||||
@@ -359,30 +363,45 @@ struct m_option {
|
||||
// The option is forbidden in config files.
|
||||
#define M_OPT_NOCFG (1 << 2)
|
||||
|
||||
// This option can't be set per-file when used with struct m_config.
|
||||
#define M_OPT_GLOBAL (1 << 4)
|
||||
|
||||
// Can not be freely changed at runtime (normally, all options can be changed,
|
||||
// even if the settings don't get effective immediately). Note that an option
|
||||
// might still change even if this is set, e.g. via properties or per-file
|
||||
// options.
|
||||
#define M_OPT_FIXED (1 << 5)
|
||||
#define M_OPT_FIXED (1 << 3)
|
||||
|
||||
// The option should be set during command line pre-parsing
|
||||
#define M_OPT_PRE_PARSE (1 << 6)
|
||||
#define M_OPT_PRE_PARSE (1 << 4)
|
||||
|
||||
// The option expects a file name (or a list of file names)
|
||||
#define M_OPT_FILE (1 << 11)
|
||||
#define M_OPT_FILE (1 << 5)
|
||||
|
||||
// Logging-related option - used to update log/terminal settings eagerly
|
||||
#define M_OPT_TERM (1 << 12)
|
||||
// Do not add as property.
|
||||
#define M_OPT_NOPROP (1 << 6)
|
||||
|
||||
// The following are also part of the M_OPT_* flags, and are used to update
|
||||
// certain groups of options.
|
||||
#define UPDATE_OPT_FIRST (1 << 7)
|
||||
#define UPDATE_TERM (1 << 7) // terminal options
|
||||
#define UPDATE_RENDERER (1 << 8) // mainly vo_opengl options
|
||||
#define UPDATE_VIDEOPOS (1 << 9) // video position (panscan etc.)
|
||||
#define UPDATE_OSD (1 << 10) // related to OSD rendering
|
||||
#define UPDATE_BUILTIN_SCRIPTS (1 << 11) // osc/ytdl
|
||||
#define UPDATE_IMGPAR (1 << 12) // video image params overrides
|
||||
#define UPDATE_INPUT (1 << 13) // mostly --input-* options
|
||||
#define UPDATE_AUDIO (1 << 14) // --audio-channels etc.
|
||||
#define UPDATE_PRIORITY (1 << 15) // --priority (Windows-only)
|
||||
#define UPDATE_SCREENSAVER (1 << 16) // --stop-screensaver
|
||||
#define UPDATE_OPT_LAST (1 << 16)
|
||||
|
||||
// All bits between _FIRST and _LAST (inclusive)
|
||||
#define UPDATE_OPTS_MASK \
|
||||
(((UPDATE_OPT_LAST << 1) - 1) & ~(unsigned)(UPDATE_OPT_FIRST - 1))
|
||||
|
||||
// These are kept for compatibility with older code.
|
||||
#define CONF_MIN M_OPT_MIN
|
||||
#define CONF_MAX M_OPT_MAX
|
||||
#define CONF_RANGE M_OPT_RANGE
|
||||
#define CONF_NOCFG M_OPT_NOCFG
|
||||
#define CONF_GLOBAL (M_OPT_GLOBAL | M_OPT_FIXED)
|
||||
#define CONF_PRE_PARSE M_OPT_PRE_PARSE
|
||||
|
||||
// These flags are used to describe special parser capabilities or behavior.
|
||||
@@ -403,19 +422,11 @@ struct m_option {
|
||||
*/
|
||||
#define M_OPT_TYPE_ALLOW_WILDCARD (1 << 1)
|
||||
|
||||
// Dynamic data type.
|
||||
/** This flag indicates that the data is dynamically allocated (m_option::p
|
||||
* points to a pointer). It enables a little hack in the \ref Config which
|
||||
* replaces the initial value of such variables with a dynamic copy in case
|
||||
* the initial value is statically allocated (pretty common with strings).
|
||||
*/
|
||||
#define M_OPT_TYPE_DYNAMIC (1 << 2)
|
||||
|
||||
// The parameter is optional and by default no parameter is preferred. If
|
||||
// ambiguous syntax is used ("--opt value"), the command line parser will
|
||||
// assume that the argument takes no parameter. In config files, these
|
||||
// options can be used without "=" and value.
|
||||
#define M_OPT_TYPE_OPTIONAL_PARAM (1 << 3)
|
||||
#define M_OPT_TYPE_OPTIONAL_PARAM (1 << 2)
|
||||
|
||||
///////////////////////////// Parser flags /////////////////////////////////
|
||||
|
||||
@@ -424,8 +435,7 @@ struct m_option {
|
||||
// On success parsers return a number >= 0.
|
||||
//
|
||||
// To indicate that MPlayer should exit without playing anything,
|
||||
// parsers return M_OPT_EXIT minus the number of parameters they
|
||||
// consumed: \ref M_OPT_EXIT or \ref M_OPT_EXIT-1.
|
||||
// parsers return M_OPT_EXIT.
|
||||
//
|
||||
// On error one of the following (negative) error codes is returned:
|
||||
|
||||
@@ -449,8 +459,6 @@ struct m_option {
|
||||
#define M_OPT_PARSER_ERR -6
|
||||
|
||||
// Returned when MPlayer should exit. Used by various help stuff.
|
||||
/** M_OPT_EXIT must be the lowest number on this list.
|
||||
*/
|
||||
#define M_OPT_EXIT -7
|
||||
|
||||
char *m_option_strerror(int code);
|
||||
@@ -577,10 +585,6 @@ extern const char m_option_path_separator;
|
||||
OPT_GENERAL(int, optname, varname, flags, .max = value, \
|
||||
.type = &m_option_type_store)
|
||||
|
||||
#define OPT_FLOAT_STORE(optname, varname, flags, value) \
|
||||
OPT_GENERAL(float, optname, varname, flags, .max = value, \
|
||||
.type = &m_option_type_float_store)
|
||||
|
||||
#define OPT_STRINGLIST(...) \
|
||||
OPT_GENERAL(char**, __VA_ARGS__, .type = &m_option_type_string_list)
|
||||
|
||||
@@ -622,10 +626,11 @@ extern const char m_option_path_separator;
|
||||
#define OPT_STRING(...) \
|
||||
OPT_GENERAL(char*, __VA_ARGS__, .type = &m_option_type_string)
|
||||
|
||||
#define OPT_SETTINGSLIST(optname, varname, flags, objlist) \
|
||||
#define OPT_SETTINGSLIST(optname, varname, flags, objlist, ...) \
|
||||
OPT_GENERAL(m_obj_settings_t*, optname, varname, flags, \
|
||||
.type = &m_option_type_obj_settings_list, \
|
||||
.priv = (void*)MP_EXPECT_TYPE(const struct m_obj_list*, objlist))
|
||||
.priv = (void*)MP_EXPECT_TYPE(const struct m_obj_list*, objlist), \
|
||||
__VA_ARGS__)
|
||||
|
||||
#define OPT_IMAGEFORMAT(...) \
|
||||
OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_type_imgfmt)
|
||||
@@ -682,6 +687,9 @@ extern const char m_option_path_separator;
|
||||
#define OPT_TRACKCHOICE(name, var) \
|
||||
OPT_CHOICE_OR_INT(name, var, 0, 0, 8190, ({"no", -2}, {"auto", -1}))
|
||||
|
||||
#define OPT_ASPECT(...) \
|
||||
OPT_GENERAL(float, __VA_ARGS__, .type = &m_option_type_aspect)
|
||||
|
||||
#define OPT_STRING_VALIDATE_(optname, varname, flags, validate_fn, ...) \
|
||||
OPT_GENERAL(char*, optname, varname, flags, __VA_ARGS__, \
|
||||
.priv = MP_EXPECT_TYPE(m_opt_string_validate_fn, validate_fn))
|
||||
@@ -690,7 +698,7 @@ extern const char m_option_path_separator;
|
||||
|
||||
#define OPT_PRINT(optname, fn) \
|
||||
{.name = optname, \
|
||||
.flags = M_OPT_FIXED | M_OPT_GLOBAL | M_OPT_NOCFG | M_OPT_PRE_PARSE, \
|
||||
.flags = M_OPT_FIXED | M_OPT_NOCFG | M_OPT_PRE_PARSE, \
|
||||
.type = &m_option_type_print_fn, \
|
||||
.priv = MP_EXPECT_TYPE(m_opt_print_fn, fn), \
|
||||
.offset = -1}
|
||||
@@ -706,13 +714,32 @@ extern const char m_option_path_separator;
|
||||
.type = &m_option_type_subconfig, \
|
||||
.priv = (void*)&subconf)
|
||||
|
||||
// If "--name" was removed, but "--newname" has the same semantics.
|
||||
// Same as above, but for legacy suboption usage, which have no associated
|
||||
// field (no actual data anywhere).
|
||||
#define OPT_SUBSTRUCT_LEGACY(optname, subconf) \
|
||||
{.name = optname, .offset = -1, .type = &m_option_type_subconfig, \
|
||||
.priv = (void*)&subconf}
|
||||
|
||||
// Provide a another name for the option.
|
||||
#define OPT_ALIAS(optname, newname) \
|
||||
{.name = optname, .type = &m_option_type_alias, .priv = newname, \
|
||||
.offset = -1}
|
||||
|
||||
// If "--optname" was removed, but "--newname" has the same semantics.
|
||||
// It will be redirected, and a warning will be printed on first use.
|
||||
#define OPT_REPLACED(optname, newname) \
|
||||
{.name = optname, .type = &m_option_type_alias, .priv = newname, .offset = -1}
|
||||
{.name = optname, .type = &m_option_type_alias, .priv = newname, \
|
||||
.deprecation_message = "", .offset = -1}
|
||||
|
||||
// "--name" doesn't exist, but inform the user about a replacement with msg.
|
||||
// "--optname" doesn't exist, but inform the user about a replacement with msg.
|
||||
#define OPT_REMOVED(optname, msg) \
|
||||
{.name = optname, .type = &m_option_type_removed, .priv = msg, .offset = -1}
|
||||
{.name = optname, .type = &m_option_type_removed, .priv = msg, \
|
||||
.deprecation_message = "", .offset = -1}
|
||||
|
||||
// Redirect a suboption (e.g. from --vo) to a global option. The redirection
|
||||
// is handled as a special case instead of being applied automatically.
|
||||
#define OPT_SUBOPT_LEGACY(optname, globalname) \
|
||||
{.name = optname, .type = &m_option_type_subopt_legacy, .priv = globalname, \
|
||||
.offset = -1}
|
||||
|
||||
#endif /* MPLAYER_M_OPTION_H */
|
||||
+14
-11
@@ -36,8 +36,8 @@
|
||||
#include "common/msg.h"
|
||||
#include "common/common.h"
|
||||
|
||||
static struct m_property *m_property_list_find(const struct m_property *list,
|
||||
const char *name)
|
||||
struct m_property *m_property_list_find(const struct m_property *list,
|
||||
const char *name)
|
||||
{
|
||||
for (int n = 0; list && list[n].name; n++) {
|
||||
if (strcmp(list[n].name, name) == 0)
|
||||
@@ -115,6 +115,11 @@ int m_property_do(struct mp_log *log, const struct m_property *prop_list,
|
||||
M_PROPERTY_NOT_IMPLEMENTED)
|
||||
return r;
|
||||
// Fallback to m_option
|
||||
r = m_property_do(log, prop_list, name, M_PROPERTY_GET_CONSTRICTED_TYPE,
|
||||
&opt, ctx);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
assert(opt.type);
|
||||
if (!opt.type->add)
|
||||
return M_PROPERTY_NOT_IMPLEMENTED;
|
||||
if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0)
|
||||
@@ -124,16 +129,14 @@ int m_property_do(struct mp_log *log, const struct m_property *prop_list,
|
||||
m_option_free(&opt, &val);
|
||||
return r;
|
||||
}
|
||||
case M_PROPERTY_GET_CONSTRICTED_TYPE: {
|
||||
if ((r = do_action(prop_list, name, action, arg, ctx)) >= 0)
|
||||
return r;
|
||||
if ((r = do_action(prop_list, name, M_PROPERTY_GET_TYPE, arg, ctx)) >= 0)
|
||||
return r;
|
||||
return M_PROPERTY_NOT_IMPLEMENTED;
|
||||
}
|
||||
case M_PROPERTY_SET: {
|
||||
if (!log)
|
||||
return M_PROPERTY_ERROR;
|
||||
m_option_copy(&opt, &val, arg);
|
||||
r = opt.type->clamp ? opt.type->clamp(&opt, arg) : 0;
|
||||
m_option_free(&opt, &val);
|
||||
if (r != 0) {
|
||||
mp_err(log, "Property '%s': invalid value.\n", name);
|
||||
return M_PROPERTY_ERROR;
|
||||
}
|
||||
return do_action(prop_list, name, M_PROPERTY_SET, arg, ctx);
|
||||
}
|
||||
case M_PROPERTY_GET_NODE: {
|
||||
|
||||
@@ -48,6 +48,12 @@ enum mp_property_action {
|
||||
// arg: char**
|
||||
M_PROPERTY_PRINT,
|
||||
|
||||
// Like M_PROPERTY_GET_TYPE, but get a type that is compatible to the real
|
||||
// type, but reflect practical limits, such as runtime-available values.
|
||||
// This is mostly used for "UI" related things.
|
||||
// (Example: volume property.)
|
||||
M_PROPERTY_GET_CONSTRICTED_TYPE,
|
||||
|
||||
// Switch the property up/down by a given value.
|
||||
// If unimplemented, the property wrapper uses the property type as
|
||||
// fallback.
|
||||
@@ -128,6 +134,9 @@ struct m_property {
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct m_property *m_property_list_find(const struct m_property *list,
|
||||
const char *name);
|
||||
|
||||
// Access a property.
|
||||
// action: one of m_property_action
|
||||
// ctx: opaque value passed through to property implementation
|
||||
|
||||
+305
-228
@@ -25,6 +25,7 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -39,6 +40,7 @@
|
||||
#include "stream/stream.h"
|
||||
#include "video/csputils.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/image_writer.h"
|
||||
#include "sub/osd.h"
|
||||
#include "audio/filter/af.h"
|
||||
#include "audio/decode/dec_audio.h"
|
||||
@@ -46,6 +48,10 @@
|
||||
#include "player/command.h"
|
||||
#include "stream/stream.h"
|
||||
|
||||
#if HAVE_DRM
|
||||
#include "video/out/drm_common.h"
|
||||
#endif
|
||||
|
||||
extern const char mp_help_text[];
|
||||
|
||||
static void print_version(struct mp_log *log)
|
||||
@@ -71,7 +77,10 @@ extern const struct m_sub_options vd_lavc_conf;
|
||||
extern const struct m_sub_options ad_lavc_conf;
|
||||
extern const struct m_sub_options input_config;
|
||||
extern const struct m_sub_options encode_config;
|
||||
extern const struct m_sub_options image_writer_conf;
|
||||
extern const struct m_sub_options gl_video_conf;
|
||||
extern const struct m_sub_options ao_alsa_conf;
|
||||
|
||||
extern const struct m_sub_options demux_conf;
|
||||
|
||||
extern const struct m_obj_list vf_obj_list;
|
||||
extern const struct m_obj_list af_obj_list;
|
||||
@@ -81,6 +90,7 @@ extern const struct m_obj_list ao_obj_list;
|
||||
const struct m_opt_choice_alternatives mp_hwdec_names[] = {
|
||||
{"no", HWDEC_NONE},
|
||||
{"auto", HWDEC_AUTO},
|
||||
{"yes" , HWDEC_AUTO},
|
||||
{"auto-copy", HWDEC_AUTO_COPY},
|
||||
{"vdpau", HWDEC_VDPAU},
|
||||
{"videotoolbox",HWDEC_VIDEOTOOLBOX},
|
||||
@@ -92,41 +102,185 @@ const struct m_opt_choice_alternatives mp_hwdec_names[] = {
|
||||
{"d3d11va", HWDEC_D3D11VA},
|
||||
{"d3d11va-copy",HWDEC_D3D11VA_COPY},
|
||||
{"rpi", HWDEC_RPI},
|
||||
{"rpi-copy", HWDEC_RPI_COPY},
|
||||
{"mediacodec", HWDEC_MEDIACODEC},
|
||||
{"cuda", HWDEC_CUDA},
|
||||
{"cuda-copy", HWDEC_CUDA_COPY},
|
||||
{"crystalhd", HWDEC_CRYSTALHD},
|
||||
{0}
|
||||
};
|
||||
|
||||
static const struct m_sub_options screenshot_conf = {
|
||||
.opts = image_writer_opts,
|
||||
.size = sizeof(struct image_writer_opts),
|
||||
.defaults = &image_writer_opts_defaults,
|
||||
};
|
||||
|
||||
#define OPT_BASE_STRUCT struct mp_cache_opts
|
||||
|
||||
const struct m_sub_options stream_cache_conf = {
|
||||
.opts = (const struct m_option[]){
|
||||
OPT_CHOICE_OR_INT("cache", size, 0, 32, 0x7fffffff,
|
||||
({"no", 0},
|
||||
{"auto", -1},
|
||||
{"yes", -2})),
|
||||
OPT_CHOICE_OR_INT("cache-default", def_size, 0, 32, 0x7fffffff,
|
||||
({"no", 0})),
|
||||
OPT_INTRANGE("cache-initial", initial, 0, 0, 0x7fffffff),
|
||||
OPT_INTRANGE("cache-seek-min", seek_min, 0, 0, 0x7fffffff),
|
||||
OPT_INTRANGE("cache-backbuffer", back_buffer, 0, 0, 0x7fffffff),
|
||||
OPT_STRING("cache-file", file, M_OPT_FILE),
|
||||
OPT_INTRANGE("cache-file-size", file_max, 0, 0, 0x7fffffff),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct mp_cache_opts),
|
||||
.defaults = &(const struct mp_cache_opts){
|
||||
.size = -1,
|
||||
.def_size = 75000,
|
||||
.initial = 0,
|
||||
.seek_min = 500,
|
||||
.back_buffer = 75000,
|
||||
.file_max = 1024 * 1024,
|
||||
},
|
||||
};
|
||||
|
||||
#undef OPT_BASE_STRUCT
|
||||
#define OPT_BASE_STRUCT struct mp_vo_opts
|
||||
|
||||
static const m_option_t mp_vo_opt_list[] = {
|
||||
OPT_SETTINGSLIST("vo", video_driver_list, 0, &vo_obj_list, ),
|
||||
OPT_SETTINGSLIST("vo-defaults", vo_defs, 0, &vo_obj_list,
|
||||
.deprecation_message = "deprecated, use global options"),
|
||||
OPT_CHOICE_C("hwdec-preload", hwdec_preload_api, 0, mp_hwdec_names),
|
||||
OPT_SUBSTRUCT("sws", sws_opts, sws_conf, 0),
|
||||
OPT_FLAG("taskbar-progress", taskbar_progress, 0),
|
||||
OPT_FLAG("ontop", ontop, 0),
|
||||
OPT_FLAG("border", border, 0),
|
||||
OPT_FLAG("fit-border", fit_border, 0),
|
||||
OPT_FLAG("on-all-workspaces", all_workspaces, 0),
|
||||
OPT_GEOMETRY("geometry", geometry, 0),
|
||||
OPT_SIZE_BOX("autofit", autofit, 0),
|
||||
OPT_SIZE_BOX("autofit-larger", autofit_larger, 0),
|
||||
OPT_SIZE_BOX("autofit-smaller", autofit_smaller, 0),
|
||||
OPT_DOUBLE("window-scale", window_scale, CONF_RANGE, .min = 0.001, .max = 100),
|
||||
OPT_FLAG("force-window-position", force_window_position, 0),
|
||||
OPT_STRING("x11-name", winname, 0),
|
||||
OPT_FLOATRANGE("monitoraspect", force_monitor_aspect, 0, 0.0, 9.0),
|
||||
OPT_FLOATRANGE("monitorpixelaspect", monitor_pixel_aspect, 0, 0.2, 9.0),
|
||||
OPT_FLAG("fullscreen", fullscreen, 0),
|
||||
OPT_ALIAS("fs", "fullscreen"),
|
||||
OPT_FLAG("native-keyrepeat", native_keyrepeat, 0),
|
||||
OPT_FLOATRANGE("panscan", panscan, UPDATE_VIDEOPOS, 0.0, 1.0),
|
||||
OPT_FLOATRANGE("video-zoom", zoom, UPDATE_VIDEOPOS, -20.0, 20.0),
|
||||
OPT_FLOATRANGE("video-pan-x", pan_x, UPDATE_VIDEOPOS, -3.0, 3.0),
|
||||
OPT_FLOATRANGE("video-pan-y", pan_y, UPDATE_VIDEOPOS, -3.0, 3.0),
|
||||
OPT_FLOATRANGE("video-align-x", align_x, UPDATE_VIDEOPOS, -1.0, 1.0),
|
||||
OPT_FLOATRANGE("video-align-y", align_y, UPDATE_VIDEOPOS, -1.0, 1.0),
|
||||
OPT_CHOICE("video-unscaled", unscaled, UPDATE_VIDEOPOS,
|
||||
({"no", 0}, {"yes", 1}, {"downscale-big", 2})),
|
||||
OPT_INT64("wid", WinID, 0),
|
||||
OPT_CHOICE_OR_INT("screen", screen_id, 0, 0, 32,
|
||||
({"default", -1})),
|
||||
OPT_CHOICE_OR_INT("fs-screen", fsscreen_id, 0, 0, 32,
|
||||
({"all", -2}, {"current", -1})),
|
||||
OPT_FLAG("fs-black-out-screens", fs_black_out_screens, 0),
|
||||
OPT_FLAG("keepaspect", keepaspect, UPDATE_VIDEOPOS),
|
||||
OPT_FLAG("keepaspect-window", keepaspect_window, 0),
|
||||
#if HAVE_X11
|
||||
OPT_CHOICE("x11-netwm", x11_netwm, 0,
|
||||
({"auto", 0}, {"no", -1}, {"yes", 1})),
|
||||
OPT_CHOICE("x11-bypass-compositor", x11_bypass_compositor, 0,
|
||||
({"no", 0}, {"yes", 1}, {"fs-only", 2}, {"never", 3})),
|
||||
#endif
|
||||
#if HAVE_WIN32
|
||||
OPT_STRING("vo-mmcss-profile", mmcss_profile, 0),
|
||||
#endif
|
||||
#if HAVE_DRM
|
||||
OPT_STRING_VALIDATE("drm-connector", drm_connector_spec,
|
||||
0, drm_validate_connector_opt),
|
||||
OPT_INT("drm-mode", drm_mode_id, 0),
|
||||
#endif
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
const struct m_sub_options vo_sub_opts = {
|
||||
.opts = mp_vo_opt_list,
|
||||
.size = sizeof(struct mp_vo_opts),
|
||||
.defaults = &(const struct mp_vo_opts){
|
||||
.video_driver_list = NULL,
|
||||
.monitor_pixel_aspect = 1.0,
|
||||
.screen_id = -1,
|
||||
.fsscreen_id = -1,
|
||||
.panscan = 0.0f,
|
||||
.keepaspect = 1,
|
||||
.keepaspect_window = 1,
|
||||
.taskbar_progress = 1,
|
||||
.border = 1,
|
||||
.fit_border = 1,
|
||||
.WinID = -1,
|
||||
.window_scale = 1.0,
|
||||
.x11_bypass_compositor = 2,
|
||||
.mmcss_profile = "Playback",
|
||||
.fullscreen = HAVE_RPI ? 1 : 0,
|
||||
},
|
||||
};
|
||||
|
||||
#undef OPT_BASE_STRUCT
|
||||
#define OPT_BASE_STRUCT struct dvd_opts
|
||||
|
||||
const struct m_sub_options dvd_conf = {
|
||||
.opts = (const struct m_option[]){
|
||||
OPT_STRING("dvd-device", device, M_OPT_FILE),
|
||||
OPT_INT("dvd-speed", speed, 0),
|
||||
OPT_INTRANGE("dvd-angle", angle, 0, 1, 99),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct dvd_opts),
|
||||
.defaults = &(const struct dvd_opts){
|
||||
.angle = 1,
|
||||
},
|
||||
};
|
||||
|
||||
#undef OPT_BASE_STRUCT
|
||||
#define OPT_BASE_STRUCT struct MPOpts
|
||||
|
||||
const m_option_t mp_opts[] = {
|
||||
// handled in command line pre-parser (parse_commandline.c)
|
||||
{"v", CONF_TYPE_STORE, CONF_GLOBAL | CONF_NOCFG, .offset = -1},
|
||||
{"v", CONF_TYPE_STORE, M_OPT_FIXED | CONF_NOCFG, .offset = -1},
|
||||
{"playlist", CONF_TYPE_STRING, CONF_NOCFG | M_OPT_MIN | M_OPT_FIXED | M_OPT_FILE,
|
||||
.min = 1, .offset = -1},
|
||||
{"{", CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
|
||||
{"}", CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
|
||||
|
||||
// handled in m_config.c
|
||||
{ "include", CONF_TYPE_STRING, M_OPT_FIXED | M_OPT_FILE, .offset = -1},
|
||||
{ "profile", CONF_TYPE_STRING_LIST, M_OPT_FIXED, .offset = -1},
|
||||
{ "include", CONF_TYPE_STRING, M_OPT_FILE, .offset = -1},
|
||||
{ "profile", CONF_TYPE_STRING_LIST, 0, .offset = -1},
|
||||
{ "show-profile", CONF_TYPE_STRING, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
|
||||
{ "list-options", CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
|
||||
OPT_FLAG("list-properties", property_print_help,
|
||||
CONF_NOCFG | M_OPT_FIXED | M_OPT_NOPROP),
|
||||
|
||||
OPT_CHOICE("player-operation-mode", operation_mode,
|
||||
M_OPT_FIXED | M_OPT_PRE_PARSE | M_OPT_NOPROP,
|
||||
({"cplayer", 0}, {"pseudo-gui", 1})),
|
||||
|
||||
OPT_FLAG("shuffle", shuffle, 0),
|
||||
|
||||
// ------------------------- common options --------------------
|
||||
OPT_FLAG("quiet", quiet, CONF_GLOBAL),
|
||||
OPT_FLAG_STORE("really-quiet", verbose, CONF_GLOBAL | CONF_PRE_PARSE, -10),
|
||||
OPT_FLAG("terminal", use_terminal, CONF_GLOBAL | CONF_PRE_PARSE | M_OPT_TERM),
|
||||
OPT_GENERAL(char**, "msg-level", msg_levels, CONF_GLOBAL|CONF_PRE_PARSE |
|
||||
M_OPT_TERM, .type = &m_option_type_msglevels),
|
||||
OPT_STRING("dump-stats", dump_stats, CONF_GLOBAL | CONF_PRE_PARSE),
|
||||
OPT_FLAG("msg-color", msg_color, CONF_GLOBAL | CONF_PRE_PARSE | M_OPT_TERM),
|
||||
OPT_STRING("log-file", log_file, CONF_GLOBAL | CONF_PRE_PARSE | M_OPT_FILE),
|
||||
OPT_FLAG("msg-module", msg_module, CONF_GLOBAL | M_OPT_TERM),
|
||||
OPT_FLAG("msg-time", msg_time, CONF_GLOBAL | M_OPT_TERM),
|
||||
OPT_FLAG("quiet", quiet, 0),
|
||||
OPT_FLAG_STORE("really-quiet", verbose,
|
||||
M_OPT_FIXED | CONF_PRE_PARSE | M_OPT_NOPROP, -10),
|
||||
OPT_FLAG("terminal", use_terminal, CONF_PRE_PARSE | UPDATE_TERM),
|
||||
OPT_GENERAL(char**, "msg-level", msg_levels, CONF_PRE_PARSE | UPDATE_TERM,
|
||||
.type = &m_option_type_msglevels),
|
||||
OPT_STRING("dump-stats", dump_stats, UPDATE_TERM | CONF_PRE_PARSE),
|
||||
OPT_FLAG("msg-color", msg_color, CONF_PRE_PARSE | UPDATE_TERM),
|
||||
OPT_STRING("log-file", log_file, CONF_PRE_PARSE | M_OPT_FILE | UPDATE_TERM),
|
||||
OPT_FLAG("msg-module", msg_module, UPDATE_TERM),
|
||||
OPT_FLAG("msg-time", msg_time, UPDATE_TERM),
|
||||
#ifdef _WIN32
|
||||
OPT_CHOICE("priority", w32_priority, 0,
|
||||
OPT_CHOICE("priority", w32_priority, UPDATE_PRIORITY,
|
||||
({"no", 0},
|
||||
{"realtime", REALTIME_PRIORITY_CLASS},
|
||||
{"high", HIGH_PRIORITY_CLASS},
|
||||
@@ -135,68 +289,39 @@ const m_option_t mp_opts[] = {
|
||||
{"belownormal", BELOW_NORMAL_PRIORITY_CLASS},
|
||||
{"idle", IDLE_PRIORITY_CLASS})),
|
||||
#endif
|
||||
OPT_FLAG("config", load_config, CONF_GLOBAL | CONF_PRE_PARSE),
|
||||
OPT_FLAG("config", load_config, M_OPT_FIXED | CONF_PRE_PARSE),
|
||||
OPT_STRING("config-dir", force_configdir,
|
||||
CONF_GLOBAL | CONF_NOCFG | CONF_PRE_PARSE),
|
||||
OPT_STRINGLIST("reset-on-next-file", reset_options, M_OPT_GLOBAL),
|
||||
M_OPT_FIXED | CONF_NOCFG | CONF_PRE_PARSE),
|
||||
OPT_STRINGLIST("reset-on-next-file", reset_options, 0),
|
||||
|
||||
#if HAVE_LUA
|
||||
OPT_STRINGLIST("script", script_files, CONF_GLOBAL | M_OPT_FILE),
|
||||
OPT_KEYVALUELIST("script-opts", script_opts, M_OPT_GLOBAL),
|
||||
OPT_FLAG("osc", lua_load_osc, CONF_GLOBAL),
|
||||
OPT_FLAG("ytdl", lua_load_ytdl, CONF_GLOBAL),
|
||||
OPT_STRING("ytdl-format", lua_ytdl_format, CONF_GLOBAL),
|
||||
OPT_KEYVALUELIST("ytdl-raw-options", lua_ytdl_raw_options, CONF_GLOBAL),
|
||||
OPT_FLAG("load-scripts", auto_load_scripts, CONF_GLOBAL),
|
||||
OPT_STRINGLIST("script", script_files, M_OPT_FIXED | M_OPT_FILE),
|
||||
OPT_KEYVALUELIST("script-opts", script_opts, 0),
|
||||
OPT_FLAG("osc", lua_load_osc, UPDATE_BUILTIN_SCRIPTS),
|
||||
OPT_FLAG("ytdl", lua_load_ytdl, UPDATE_BUILTIN_SCRIPTS),
|
||||
OPT_STRING("ytdl-format", lua_ytdl_format, 0),
|
||||
OPT_KEYVALUELIST("ytdl-raw-options", lua_ytdl_raw_options, 0),
|
||||
OPT_FLAG("load-scripts", auto_load_scripts, M_OPT_FIXED),
|
||||
#endif
|
||||
|
||||
// ------------------------- stream options --------------------
|
||||
|
||||
OPT_CHOICE_OR_INT("cache", stream_cache.size, 0, 32, 0x7fffffff,
|
||||
({"no", 0},
|
||||
{"auto", -1},
|
||||
{"yes", -2})),
|
||||
OPT_CHOICE_OR_INT("cache-default", stream_cache.def_size, 0, 32, 0x7fffffff,
|
||||
({"no", 0})),
|
||||
OPT_INTRANGE("cache-initial", stream_cache.initial, 0, 0, 0x7fffffff),
|
||||
OPT_INTRANGE("cache-seek-min", stream_cache.seek_min, 0, 0, 0x7fffffff),
|
||||
OPT_INTRANGE("cache-backbuffer", stream_cache.back_buffer, 0, 0, 0x7fffffff),
|
||||
OPT_STRING("cache-file", stream_cache.file, M_OPT_FILE),
|
||||
OPT_INTRANGE("cache-file-size", stream_cache.file_max, 0, 0, 0x7fffffff),
|
||||
OPT_SUBSTRUCT("", stream_cache, stream_cache_conf, 0),
|
||||
|
||||
#if HAVE_DVDREAD || HAVE_DVDNAV
|
||||
OPT_STRING("dvd-device", dvd_device, M_OPT_FILE),
|
||||
OPT_INT("dvd-speed", dvd_speed, 0),
|
||||
OPT_INTRANGE("dvd-angle", dvd_angle, 0, 1, 99),
|
||||
OPT_SUBSTRUCT("", dvd_opts, dvd_conf, 0),
|
||||
#endif /* HAVE_DVDREAD */
|
||||
OPT_INTPAIR("chapter", chapterrange, 0),
|
||||
OPT_INTPAIR("chapter", chapterrange, 0, .deprecation_message = "instead of "
|
||||
"--chapter=A-B use --start=#A --end=#B+1"),
|
||||
OPT_CHOICE_OR_INT("edition", edition_id, 0, 0, 8190,
|
||||
({"auto", -1})),
|
||||
#if HAVE_LIBBLURAY
|
||||
OPT_STRING("bluray-device", bluray_device, M_OPT_FILE),
|
||||
OPT_INTRANGE("bluray-angle", bluray_angle, 0, 0, 999),
|
||||
#endif /* HAVE_LIBBLURAY */
|
||||
|
||||
OPT_STRINGLIST("http-header-fields", network_http_header_fields, 0),
|
||||
OPT_STRING("user-agent", network_useragent, 0),
|
||||
OPT_STRING("referrer", network_referrer, 0),
|
||||
OPT_FLAG("cookies", network_cookies_enabled, 0),
|
||||
OPT_STRING("cookies-file", network_cookies_file, M_OPT_FILE),
|
||||
OPT_CHOICE("rtsp-transport", network_rtsp_transport, 0,
|
||||
({"lavf", 0},
|
||||
{"udp", 1},
|
||||
{"tcp", 2},
|
||||
{"http", 3})),
|
||||
OPT_FLAG("tls-verify", network_tls_verify, 0),
|
||||
OPT_STRING("tls-ca-file", network_tls_ca_file, M_OPT_FILE),
|
||||
OPT_STRING("tls-cert-file", network_tls_cert_file, M_OPT_FILE),
|
||||
OPT_STRING("tls-key-file", network_tls_key_file, M_OPT_FILE),
|
||||
OPT_DOUBLE("network-timeout", network_timeout, M_OPT_MIN, .min = 0),
|
||||
|
||||
// ------------------------- demuxer options --------------------
|
||||
|
||||
OPT_CHOICE_OR_INT("frames", play_frames, M_OPT_FIXED, 0, INT_MAX,
|
||||
({"all", -1})),
|
||||
OPT_CHOICE_OR_INT("frames", play_frames, 0, 0, INT_MAX, ({"all", -1})),
|
||||
|
||||
OPT_REL_TIME("start", play_start, 0),
|
||||
OPT_REL_TIME("end", play_end, 0),
|
||||
@@ -207,13 +332,16 @@ const m_option_t mp_opts[] = {
|
||||
OPT_TIME("ab-loop-a", ab_loop[0], 0, .min = MP_NOPTS_VALUE),
|
||||
OPT_TIME("ab-loop-b", ab_loop[1], 0, .min = MP_NOPTS_VALUE),
|
||||
|
||||
OPT_CHOICE_OR_INT("playlist-pos", playlist_pos, 0, 0, INT_MAX, ({"no", -1})),
|
||||
OPT_CHOICE_OR_INT("playlist-start", playlist_pos, 0, 0, INT_MAX,
|
||||
({"auto", -1}, {"no", -1})),
|
||||
|
||||
OPT_FLAG("pause", pause, M_OPT_FIXED),
|
||||
OPT_FLAG("pause", pause, 0),
|
||||
OPT_CHOICE("keep-open", keep_open, 0,
|
||||
({"no", 0},
|
||||
{"yes", 1},
|
||||
{"always", 2})),
|
||||
OPT_DOUBLE("image-display-duration", image_display_duration,
|
||||
M_OPT_RANGE, 0, INFINITY),
|
||||
|
||||
OPT_CHOICE("index", index_mode, 0, ({"default", 1}, {"recreate", 0})),
|
||||
|
||||
@@ -225,9 +353,9 @@ const m_option_t mp_opts[] = {
|
||||
OPT_TRACKCHOICE("ff-aid", stream_id_ff[STREAM_AUDIO]),
|
||||
OPT_TRACKCHOICE("ff-vid", stream_id_ff[STREAM_VIDEO]),
|
||||
OPT_TRACKCHOICE("ff-sid", stream_id_ff[STREAM_SUB]),
|
||||
OPT_FLAG_STORE("no-sub", stream_id[0][STREAM_SUB], 0, -2),
|
||||
OPT_FLAG_STORE("no-video", stream_id[0][STREAM_VIDEO], 0, -2),
|
||||
OPT_FLAG_STORE("no-audio", stream_id[0][STREAM_AUDIO], 0, -2),
|
||||
OPT_ALIAS("sub", "sid"),
|
||||
OPT_ALIAS("video", "vid"),
|
||||
OPT_ALIAS("audio", "aid"),
|
||||
OPT_STRINGLIST("alang", stream_lang[STREAM_AUDIO], 0),
|
||||
OPT_STRINGLIST("slang", stream_lang[STREAM_SUB], 0),
|
||||
|
||||
@@ -252,13 +380,6 @@ const m_option_t mp_opts[] = {
|
||||
OPT_STRING("audio-demuxer", audio_demuxer_name, 0),
|
||||
OPT_STRING("sub-demuxer", sub_demuxer_name, 0),
|
||||
OPT_FLAG("demuxer-thread", demuxer_thread, 0),
|
||||
OPT_DOUBLE("demuxer-readahead-secs", demuxer_min_secs, M_OPT_MIN, .min = 0),
|
||||
OPT_INTRANGE("demuxer-max-packets", demuxer_max_packs, 0, 0, INT_MAX),
|
||||
OPT_INTRANGE("demuxer-max-bytes", demuxer_max_bytes, 0, 0, INT_MAX),
|
||||
|
||||
OPT_FLAG("force-seekable", force_seekable, 0),
|
||||
|
||||
OPT_DOUBLE("cache-secs", demuxer_min_secs_cache, M_OPT_MIN, .min = 0),
|
||||
OPT_FLAG("cache-pause", cache_pausing, 0),
|
||||
|
||||
OPT_DOUBLE("mf-fps", mf_fps, 0),
|
||||
@@ -278,12 +399,11 @@ const m_option_t mp_opts[] = {
|
||||
|
||||
// force video/audio rate:
|
||||
OPT_DOUBLE("fps", force_fps, CONF_MIN, .min = 0),
|
||||
OPT_INTRANGE("audio-samplerate", force_srate, 0, 1000, 16*48000),
|
||||
OPT_CHANNELS("audio-channels", audio_output_channels, 0),
|
||||
OPT_AUDIOFORMAT("audio-format", audio_output_format, 0),
|
||||
OPT_FLAG("audio-normalize-downmix", audio_normalize, 0),
|
||||
OPT_DOUBLE("speed", playback_speed, M_OPT_RANGE | M_OPT_FIXED,
|
||||
.min = 0.01, .max = 100.0),
|
||||
OPT_INTRANGE("audio-samplerate", force_srate, UPDATE_AUDIO, 1000, 16*48000),
|
||||
OPT_CHANNELS("audio-channels", audio_output_channels, UPDATE_AUDIO),
|
||||
OPT_AUDIOFORMAT("audio-format", audio_output_format, UPDATE_AUDIO),
|
||||
OPT_FLAG("audio-normalize-downmix", audio_normalize, UPDATE_AUDIO),
|
||||
OPT_DOUBLE("speed", playback_speed, M_OPT_RANGE, .min = 0.01, .max = 100.0),
|
||||
|
||||
OPT_FLAG("audio-pitch-correction", pitch_correction, 0),
|
||||
|
||||
@@ -292,10 +412,10 @@ const m_option_t mp_opts[] = {
|
||||
|
||||
// ------------------------- codec/vfilter options --------------------
|
||||
|
||||
OPT_SETTINGSLIST("af-defaults", af_defs, 0, &af_obj_list),
|
||||
OPT_SETTINGSLIST("af*", af_settings, 0, &af_obj_list),
|
||||
OPT_SETTINGSLIST("vf-defaults", vf_defs, 0, &vf_obj_list),
|
||||
OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list),
|
||||
OPT_SETTINGSLIST("af-defaults", af_defs, 0, &af_obj_list, ),
|
||||
OPT_SETTINGSLIST("af*", af_settings, 0, &af_obj_list, ),
|
||||
OPT_SETTINGSLIST("vf-defaults", vf_defs, 0, &vf_obj_list, ),
|
||||
OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list, ),
|
||||
|
||||
OPT_CHOICE("deinterlace", deinterlace, 0,
|
||||
({"auto", -1},
|
||||
@@ -310,28 +430,24 @@ const m_option_t mp_opts[] = {
|
||||
OPT_FLAG("ad-spdif-dtshd", dtshd, 0),
|
||||
|
||||
OPT_CHOICE_C("hwdec", hwdec_api, 0, mp_hwdec_names),
|
||||
OPT_CHOICE_C("hwdec-preload", vo.hwdec_preload_api, 0, mp_hwdec_names),
|
||||
OPT_STRING("hwdec-codecs", hwdec_codecs, 0),
|
||||
#if HAVE_VIDEOTOOLBOX_HWACCEL
|
||||
OPT_IMAGEFORMAT("videotoolbox-format", videotoolbox_format, 0),
|
||||
#endif
|
||||
|
||||
OPT_SUBSTRUCT("sws", vo.sws_opts, sws_conf, 0),
|
||||
|
||||
// -1 means auto aspect (prefer container size until aspect change)
|
||||
// 0 means square pixels
|
||||
OPT_FLOATRANGE("video-aspect", movie_aspect, 0, -1.0, 10.0),
|
||||
OPT_FLOAT_STORE("no-video-aspect", movie_aspect, 0, 0.0),
|
||||
OPT_CHOICE("video-aspect-method", aspect_method, 0,
|
||||
OPT_ASPECT("video-aspect", movie_aspect, UPDATE_IMGPAR, -1.0, 10.0),
|
||||
OPT_CHOICE("video-aspect-method", aspect_method, UPDATE_IMGPAR,
|
||||
({"hybrid", 0}, {"bitstream", 1}, {"container", 2})),
|
||||
|
||||
OPT_CHOICE("field-dominance", field_dominance, 0,
|
||||
OPT_CHOICE("field-dominance", field_dominance, UPDATE_IMGPAR,
|
||||
({"auto", -1}, {"top", 0}, {"bottom", 1})),
|
||||
|
||||
OPT_SUBSTRUCT("vd-lavc", vd_lavc_params, vd_lavc_conf, 0),
|
||||
OPT_SUBSTRUCT("ad-lavc", ad_lavc_params, ad_lavc_conf, 0),
|
||||
|
||||
OPT_SUBSTRUCT("demuxer-lavf", demux_lavf, demux_lavf_conf, 0),
|
||||
OPT_SUBSTRUCT("", demux_lavf, demux_lavf_conf, 0),
|
||||
OPT_SUBSTRUCT("demuxer-rawaudio", demux_rawaudio, demux_rawaudio_conf, 0),
|
||||
OPT_SUBSTRUCT("demuxer-rawvideo", demux_rawvideo, demux_rawvideo_conf, 0),
|
||||
OPT_SUBSTRUCT("demuxer-mkv", demux_mkv, demux_mkv_conf, 0),
|
||||
@@ -343,82 +459,76 @@ const m_option_t mp_opts[] = {
|
||||
OPT_PATHLIST("audio-file-paths", audiofile_paths, 0),
|
||||
OPT_STRING_APPEND_LIST("external-file", external_files, M_OPT_FILE),
|
||||
OPT_FLAG("autoload-files", autoload_files, 0),
|
||||
OPT_STRING("sub-codepage", sub_cp, 0),
|
||||
OPT_FLOAT("sub-delay", sub_delay, 0),
|
||||
OPT_FLOAT("sub-fps", sub_fps, 0),
|
||||
OPT_FLOAT("sub-speed", sub_speed, 0),
|
||||
OPT_FLAG("sub-visibility", sub_visibility, 0),
|
||||
OPT_FLAG("sub-forced-only", forced_subs_only, 0),
|
||||
OPT_FLAG("stretch-dvd-subs", stretch_dvd_subs, 0),
|
||||
OPT_FLAG("stretch-image-subs-to-screen", stretch_image_subs, 0),
|
||||
OPT_FLOAT("sub-delay", sub_delay, UPDATE_OSD),
|
||||
OPT_FLOAT("sub-fps", sub_fps, UPDATE_OSD),
|
||||
OPT_FLOAT("sub-speed", sub_speed, UPDATE_OSD),
|
||||
OPT_FLAG("sub-visibility", sub_visibility, UPDATE_OSD),
|
||||
OPT_FLAG("sub-forced-only", forced_subs_only, UPDATE_OSD),
|
||||
OPT_FLAG("stretch-dvd-subs", stretch_dvd_subs, UPDATE_OSD),
|
||||
OPT_FLAG("stretch-image-subs-to-screen", stretch_image_subs, UPDATE_OSD),
|
||||
OPT_FLAG("sub-fix-timing", sub_fix_timing, 0),
|
||||
OPT_CHOICE("sub-auto", sub_auto, 0,
|
||||
({"no", -1}, {"exact", 0}, {"fuzzy", 1}, {"all", 2})),
|
||||
OPT_CHOICE("audio-file-auto", audiofile_auto, 0,
|
||||
({"no", -1}, {"exact", 0}, {"fuzzy", 1}, {"all", 2})),
|
||||
OPT_INTRANGE("sub-pos", sub_pos, 0, 0, 100),
|
||||
OPT_FLOATRANGE("sub-gauss", sub_gauss, 0, 0.0, 3.0),
|
||||
OPT_FLAG("sub-gray", sub_gray, 0),
|
||||
OPT_INTRANGE("sub-pos", sub_pos, UPDATE_OSD, 0, 100),
|
||||
OPT_FLOATRANGE("sub-gauss", sub_gauss, UPDATE_OSD, 0.0, 3.0),
|
||||
OPT_FLAG("sub-gray", sub_gray, UPDATE_OSD),
|
||||
OPT_FLAG("sub-ass", ass_enabled, 0),
|
||||
OPT_FLOATRANGE("sub-scale", sub_scale, 0, 0, 100),
|
||||
OPT_FLOATRANGE("ass-line-spacing", ass_line_spacing, 0, -1000, 1000),
|
||||
OPT_FLAG("sub-use-margins", sub_use_margins, 0),
|
||||
OPT_FLAG("ass-force-margins", ass_use_margins, 0),
|
||||
OPT_FLAG("ass-vsfilter-aspect-compat", ass_vsfilter_aspect_compat, 0),
|
||||
OPT_CHOICE("ass-vsfilter-color-compat", ass_vsfilter_color_compat, 0,
|
||||
OPT_FLOATRANGE("sub-scale", sub_scale, UPDATE_OSD, 0, 100),
|
||||
OPT_FLOATRANGE("sub-ass-line-spacing", ass_line_spacing, UPDATE_OSD, -1000, 1000),
|
||||
OPT_FLAG("sub-use-margins", sub_use_margins, UPDATE_OSD),
|
||||
OPT_FLAG("sub-ass-force-margins", ass_use_margins, UPDATE_OSD),
|
||||
OPT_FLAG("sub-ass-vsfilter-aspect-compat", ass_vsfilter_aspect_compat, UPDATE_OSD),
|
||||
OPT_CHOICE("sub-ass-vsfilter-color-compat", ass_vsfilter_color_compat, UPDATE_OSD,
|
||||
({"no", 0}, {"basic", 1}, {"full", 2}, {"force-601", 3})),
|
||||
OPT_FLAG("ass-vsfilter-blur-compat", ass_vsfilter_blur_compat, 0),
|
||||
OPT_FLAG("sub-ass-vsfilter-blur-compat", ass_vsfilter_blur_compat, UPDATE_OSD),
|
||||
OPT_FLAG("embeddedfonts", use_embedded_fonts, 0),
|
||||
OPT_STRINGLIST("ass-force-style", ass_force_style_list, 0),
|
||||
OPT_STRING("ass-styles", ass_styles_file, M_OPT_FILE),
|
||||
OPT_CHOICE("ass-hinting", ass_hinting, 0,
|
||||
OPT_STRINGLIST("sub-ass-force-style", ass_force_style_list, UPDATE_OSD),
|
||||
OPT_STRING("sub-ass-styles", ass_styles_file, M_OPT_FILE),
|
||||
OPT_CHOICE("sub-ass-hinting", ass_hinting, UPDATE_OSD,
|
||||
({"none", 0}, {"light", 1}, {"normal", 2}, {"native", 3})),
|
||||
OPT_CHOICE("ass-shaper", ass_shaper, 0,
|
||||
OPT_CHOICE("sub-ass-shaper", ass_shaper, UPDATE_OSD,
|
||||
({"simple", 0}, {"complex", 1})),
|
||||
OPT_CHOICE("ass-style-override", ass_style_override, 0,
|
||||
OPT_CHOICE("sub-ass-style-override", ass_style_override, UPDATE_OSD,
|
||||
({"no", 0}, {"yes", 1}, {"force", 3}, {"signfs", 4}, {"strip", 5})),
|
||||
OPT_FLAG("sub-scale-by-window", sub_scale_by_window, 0),
|
||||
OPT_FLAG("sub-scale-with-window", sub_scale_with_window, 0),
|
||||
OPT_FLAG("ass-scale-with-window", ass_scale_with_window, 0),
|
||||
OPT_FLAG("osd-bar", osd_bar_visible, 0),
|
||||
OPT_FLOATRANGE("osd-bar-align-x", osd_bar_align_x, 0, -1.0, +1.0),
|
||||
OPT_FLOATRANGE("osd-bar-align-y", osd_bar_align_y, 0, -1.0, +1.0),
|
||||
OPT_FLOATRANGE("osd-bar-w", osd_bar_w, 0, 1, 100),
|
||||
OPT_FLOATRANGE("osd-bar-h", osd_bar_h, 0, 0.1, 50),
|
||||
OPT_FLAG("sub-scale-by-window", sub_scale_by_window, UPDATE_OSD),
|
||||
OPT_FLAG("sub-scale-with-window", sub_scale_with_window, UPDATE_OSD),
|
||||
OPT_FLAG("sub-ass-scale-with-window", ass_scale_with_window, UPDATE_OSD),
|
||||
OPT_FLAG("osd-bar", osd_bar_visible, UPDATE_OSD),
|
||||
OPT_FLOATRANGE("osd-bar-align-x", osd_bar_align_x, UPDATE_OSD, -1.0, +1.0),
|
||||
OPT_FLOATRANGE("osd-bar-align-y", osd_bar_align_y, UPDATE_OSD, -1.0, +1.0),
|
||||
OPT_FLOATRANGE("osd-bar-w", osd_bar_w, UPDATE_OSD, 1, 100),
|
||||
OPT_FLOATRANGE("osd-bar-h", osd_bar_h, UPDATE_OSD, 0.1, 50),
|
||||
OPT_SUBSTRUCT("osd", osd_style, osd_style_conf, 0),
|
||||
OPT_SUBSTRUCT("sub-text", sub_text_style, sub_style_conf, 0),
|
||||
OPT_SUBSTRUCT("sub", sub_style, sub_style_conf, 0),
|
||||
OPT_FLAG("sub-clear-on-seek", sub_clear_on_seek, 0),
|
||||
OPT_INTRANGE("teletext-page", teletext_page, 0, 1, 999),
|
||||
|
||||
//---------------------- libao/libvo options ------------------------
|
||||
OPT_SETTINGSLIST("vo", vo.video_driver_list, 0, &vo_obj_list),
|
||||
OPT_SETTINGSLIST("vo-defaults", vo.vo_defs, 0, &vo_obj_list),
|
||||
OPT_SETTINGSLIST("ao", audio_driver_list, 0, &ao_obj_list),
|
||||
OPT_SETTINGSLIST("ao-defaults", ao_defs, 0, &ao_obj_list),
|
||||
OPT_STRING("audio-device", audio_device, 0),
|
||||
OPT_STRING("audio-client-name", audio_client_name, 0),
|
||||
OPT_SETTINGSLIST("ao", audio_driver_list, 0, &ao_obj_list, ),
|
||||
OPT_SETTINGSLIST("ao-defaults", ao_defs, 0, &ao_obj_list,
|
||||
.deprecation_message = "deprecated, use global options"),
|
||||
OPT_STRING("audio-device", audio_device, UPDATE_AUDIO),
|
||||
OPT_FLAG("audio-exclusive", audio_exclusive, UPDATE_AUDIO),
|
||||
OPT_STRING("audio-client-name", audio_client_name, UPDATE_AUDIO),
|
||||
OPT_FLAG("audio-fallback-to-null", ao_null_fallback, 0),
|
||||
OPT_FLAG("audio-stream-silence", audio_stream_silence, 0),
|
||||
OPT_FLOATRANGE("audio-wait-open", audio_wait_open, 0, 0, 60),
|
||||
OPT_CHOICE("force-window", force_vo, 0,
|
||||
({"no", 0}, {"yes", 1}, {"immediate", 2})),
|
||||
OPT_FLAG("taskbar-progress", vo.taskbar_progress, 0),
|
||||
OPT_FLAG("ontop", vo.ontop, M_OPT_FIXED),
|
||||
OPT_FLAG("border", vo.border, M_OPT_FIXED),
|
||||
OPT_FLAG("fit-border", vo.fit_border, M_OPT_FIXED),
|
||||
OPT_FLAG("on-all-workspaces", vo.all_workspaces, M_OPT_FIXED),
|
||||
|
||||
OPT_FLAG("window-dragging", allow_win_drag, CONF_GLOBAL),
|
||||
|
||||
OPT_CHOICE("softvol", softvol, 0,
|
||||
({"no", SOFTVOL_NO},
|
||||
{"yes", SOFTVOL_YES},
|
||||
{"auto", SOFTVOL_AUTO})),
|
||||
{"auto", SOFTVOL_AUTO}),
|
||||
.deprecation_message = "no replacement"),
|
||||
OPT_FLOATRANGE("volume-max", softvol_max, 0, 100, 1000),
|
||||
// values <0 for volume and mute are legacy and ignored
|
||||
OPT_FLOATRANGE("volume", softvol_volume, 0, -1, 1000),
|
||||
OPT_CHOICE("mute", softvol_mute, 0,
|
||||
({"auto", -1},
|
||||
{"no", 0},
|
||||
({"no", 0},
|
||||
{"auto", 0},
|
||||
{"yes", 1})),
|
||||
OPT_CHOICE("gapless-audio", gapless_audio, 0,
|
||||
({"no", 0},
|
||||
@@ -428,62 +538,24 @@ const m_option_t mp_opts[] = {
|
||||
.min = 0, .max = 10),
|
||||
OPT_FLOATRANGE("balance", balance, 0, -1, 1),
|
||||
|
||||
OPT_GEOMETRY("geometry", vo.geometry, 0),
|
||||
OPT_SIZE_BOX("autofit", vo.autofit, 0),
|
||||
OPT_SIZE_BOX("autofit-larger", vo.autofit_larger, 0),
|
||||
OPT_SIZE_BOX("autofit-smaller", vo.autofit_smaller, 0),
|
||||
OPT_FLOATRANGE("window-scale", vo.window_scale, 0, 0.001, 100),
|
||||
OPT_FLAG("force-window-position", vo.force_window_position, 0),
|
||||
// vo name (X classname) and window title strings
|
||||
OPT_STRING("x11-name", vo.winname, 0),
|
||||
OPT_STRING("title", wintitle, 0),
|
||||
OPT_STRING("force-media-title", media_title, 0),
|
||||
// set aspect ratio of monitor - useful for 16:9 TV-out
|
||||
OPT_FLOATRANGE("monitoraspect", vo.force_monitor_aspect, 0, 0.0, 9.0),
|
||||
OPT_FLOATRANGE("monitorpixelaspect", vo.monitor_pixel_aspect, 0, 0.2, 9.0),
|
||||
// start in fullscreen mode:
|
||||
OPT_FLAG("fullscreen", vo.fullscreen, M_OPT_FIXED),
|
||||
OPT_FLAG("fs", vo.fullscreen, M_OPT_FIXED),
|
||||
OPT_FLAG("native-keyrepeat", vo.native_keyrepeat, M_OPT_FIXED),
|
||||
OPT_FLOATRANGE("panscan", vo.panscan, 0, 0.0, 1.0),
|
||||
OPT_FLOATRANGE("video-zoom", vo.zoom, 0, -20.0, 20.0),
|
||||
OPT_FLOATRANGE("video-pan-x", vo.pan_x, 0, -3.0, 3.0),
|
||||
OPT_FLOATRANGE("video-pan-y", vo.pan_y, 0, -3.0, 3.0),
|
||||
OPT_FLOATRANGE("video-align-x", vo.align_x, 0, -1.0, 1.0),
|
||||
OPT_FLOATRANGE("video-align-y", vo.align_y, 0, -1.0, 1.0),
|
||||
OPT_FLAG("video-unscaled", vo.unscaled, 0),
|
||||
OPT_FLAG("force-rgba-osd-rendering", force_rgba_osd, 0),
|
||||
OPT_CHOICE_OR_INT("video-rotate", video_rotate, 0, 0, 359,
|
||||
OPT_CHOICE_OR_INT("video-rotate", video_rotate, UPDATE_IMGPAR, 0, 359,
|
||||
({"no", -1})),
|
||||
OPT_CHOICE_C("video-stereo-mode", video_stereo_mode, 0, mp_stereo3d_names),
|
||||
OPT_CHOICE_C("video-stereo-mode", video_stereo_mode, UPDATE_IMGPAR,
|
||||
mp_stereo3d_names),
|
||||
|
||||
OPT_CHOICE_OR_INT("cursor-autohide", cursor_autohide_delay, 0,
|
||||
0, 30000, ({"no", -1}, {"always", -2})),
|
||||
OPT_FLAG("cursor-autohide-fs-only", cursor_autohide_fs, 0),
|
||||
OPT_FLAG("stop-screensaver", stop_screensaver, 0),
|
||||
|
||||
OPT_INT64("wid", vo.WinID, 0),
|
||||
#if HAVE_X11
|
||||
OPT_CHOICE("x11-netwm", vo.x11_netwm, 0,
|
||||
({"auto", 0}, {"no", -1}, {"yes", 1})),
|
||||
OPT_CHOICE("x11-bypass-compositor", vo.x11_bypass_compositor, 0,
|
||||
({"no", 0}, {"yes", 1}, {"fs-only", 2}, {"never", 3})),
|
||||
#endif
|
||||
#if HAVE_WIN32
|
||||
OPT_STRING("vo-mmcss-profile", vo.mmcss_profile, M_OPT_FIXED),
|
||||
#endif
|
||||
OPT_FLAG("stop-screensaver", stop_screensaver, UPDATE_SCREENSAVER),
|
||||
|
||||
OPT_STRING("heartbeat-cmd", heartbeat_cmd, 0,
|
||||
.deprecation_message = "use Lua scripting instead"),
|
||||
OPT_FLOAT("heartbeat-interval", heartbeat_interval, CONF_MIN, 0),
|
||||
|
||||
OPT_CHOICE_OR_INT("screen", vo.screen_id, 0, 0, 32,
|
||||
({"default", -1})),
|
||||
|
||||
OPT_CHOICE_OR_INT("fs-screen", vo.fsscreen_id, 0, 0, 32,
|
||||
({"all", -2}, {"current", -1})),
|
||||
|
||||
OPT_FLAG("fs-black-out-screens", vo.fs_black_out_screens, 0),
|
||||
OPT_INTRANGE("brightness", gamma_brightness, 0, -100, 100),
|
||||
OPT_INTRANGE("saturation", gamma_saturation, 0, -100, 100),
|
||||
OPT_INTRANGE("contrast", gamma_contrast, 0, -100, 100),
|
||||
@@ -491,15 +563,13 @@ const m_option_t mp_opts[] = {
|
||||
OPT_INTRANGE("gamma", gamma_gamma, 0, -100, 100),
|
||||
OPT_CHOICE_C("video-output-levels", video_output_levels, 0,
|
||||
mp_csp_levels_names),
|
||||
OPT_FLAG("keepaspect", vo.keepaspect, 0),
|
||||
OPT_FLAG("keepaspect-window", vo.keepaspect_window, 0),
|
||||
|
||||
OPT_FLAG("use-filedir-conf", use_filedir_conf, 0),
|
||||
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_FLAG("osd-fractions", osd_fractions, 0),
|
||||
OPT_FLOATRANGE("osd-scale", osd_scale, 0, 0, 100),
|
||||
OPT_FLOATRANGE("osd-scale", osd_scale, UPDATE_OSD, 0, 100),
|
||||
OPT_FLAG("osd-scale-by-window", osd_scale_by_window, 0),
|
||||
|
||||
OPT_DOUBLE("sstep", step_sec, CONF_MIN, 0),
|
||||
@@ -532,6 +602,7 @@ const m_option_t mp_opts[] = {
|
||||
OPT_FLAG("save-position-on-quit", position_save_on_quit, 0),
|
||||
OPT_FLAG("write-filename-in-watch-later-config", write_filename_in_watch_later_config, 0),
|
||||
OPT_FLAG("ignore-path-in-watch-later-config", ignore_path_in_watch_later_config, 0),
|
||||
OPT_STRING("watch-later-directory", watch_later_directory, 0),
|
||||
|
||||
OPT_FLAG("ordered-chapters", ordered_chapters, 0),
|
||||
OPT_STRING("ordered-chapters-files", ordered_chapters_files, M_OPT_FILE),
|
||||
@@ -585,29 +656,37 @@ const m_option_t mp_opts[] = {
|
||||
OPT_STRING("osd-msg2", osd_msg[1], 0),
|
||||
OPT_STRING("osd-msg3", osd_msg[2], 0),
|
||||
|
||||
OPT_FLAG("video-osd", video_osd, 0),
|
||||
|
||||
OPT_CHOICE("idle", player_idle_mode, 0,
|
||||
({"no", 0},
|
||||
{"once", 1},
|
||||
{"yes", 2})),
|
||||
|
||||
OPT_FLAG("input-terminal", consolecontrols, CONF_GLOBAL),
|
||||
OPT_FLAG("input-terminal", consolecontrols, UPDATE_TERM),
|
||||
|
||||
OPT_STRING("input-file", input_file, M_OPT_FILE | M_OPT_GLOBAL),
|
||||
OPT_STRING("input-ipc-server", ipc_path, M_OPT_FILE),
|
||||
OPT_STRING("input-file", input_file, M_OPT_FILE | UPDATE_INPUT),
|
||||
OPT_STRING("input-ipc-server", ipc_path, M_OPT_FILE | UPDATE_INPUT),
|
||||
|
||||
OPT_SUBSTRUCT("screenshot", screenshot_image_opts, image_writer_conf, 0),
|
||||
OPT_SUBSTRUCT("screenshot", screenshot_image_opts, screenshot_conf, 0),
|
||||
OPT_STRING("screenshot-template", screenshot_template, 0),
|
||||
OPT_STRING("screenshot-directory", screenshot_directory, 0),
|
||||
|
||||
OPT_SUBSTRUCT("input", input_opts, input_config, 0),
|
||||
OPT_SUBSTRUCT("", input_opts, input_config, 0),
|
||||
|
||||
OPT_PRINT("list-properties", property_print_help),
|
||||
OPT_PRINT("list-protocols", stream_print_proto_list),
|
||||
OPT_PRINT("help", print_help),
|
||||
OPT_PRINT("h", print_help),
|
||||
OPT_PRINT("version", print_version),
|
||||
OPT_PRINT("V", print_version),
|
||||
|
||||
OPT_SUBSTRUCT("", vo, vo_sub_opts, 0),
|
||||
OPT_SUBSTRUCT("", demux_opts, demux_conf, 0),
|
||||
|
||||
#if HAVE_GL
|
||||
OPT_SUBSTRUCT("", gl_video_opts, gl_video_conf, 0),
|
||||
#endif
|
||||
|
||||
#if HAVE_ENCODING
|
||||
OPT_SUBSTRUCT("", encode_opts, encode_config, 0),
|
||||
#endif
|
||||
@@ -658,7 +737,6 @@ const m_option_t mp_opts[] = {
|
||||
OPT_REPLACED("ss", "start"),
|
||||
OPT_REPLACED("stop-xscreensaver", "stop-screensaver"),
|
||||
OPT_REPLACED("sub-fuzziness", "sub-auto"),
|
||||
OPT_REPLACED("sub", "sub-file"),
|
||||
OPT_REPLACED("subcp", "sub-codepage"),
|
||||
OPT_REPLACED("subdelay", "sub-delay"),
|
||||
OPT_REPLACED("subfile", "sub-file"),
|
||||
@@ -690,6 +768,35 @@ const m_option_t mp_opts[] = {
|
||||
OPT_REPLACED("media-title", "force-media-title"),
|
||||
OPT_REPLACED("input-unix-socket", "input-ipc-server"),
|
||||
OPT_REPLACED("softvol-max", "volume-max"),
|
||||
OPT_REMOVED("bluray-angle", "this didn't do anything for a few releases"),
|
||||
OPT_REPLACED("playlist-pos", "playlist-start"),
|
||||
OPT_REPLACED("sub-text-font", "sub-font"),
|
||||
OPT_REPLACED("sub-text-font-size", "sub-font-size"),
|
||||
OPT_REPLACED("sub-text-color", "sub-color"),
|
||||
OPT_REPLACED("sub-text-border-color", "sub-border-color"),
|
||||
OPT_REPLACED("sub-text-shadow-color", "sub-shadow-color"),
|
||||
OPT_REPLACED("sub-text-back-color", "sub-back-color"),
|
||||
OPT_REPLACED("sub-text-border-size", "sub-border-size"),
|
||||
OPT_REPLACED("sub-text-shadow-offset", "sub-shadow-offset"),
|
||||
OPT_REPLACED("sub-text-spacing", "sub-spacing"),
|
||||
OPT_REPLACED("sub-text-margin-x", "sub-margin-x"),
|
||||
OPT_REPLACED("sub-text-margin-y", "sub-margin-y"),
|
||||
OPT_REPLACED("sub-text-align-x", "sub-align-x"),
|
||||
OPT_REPLACED("sub-text-align-y", "sub-align-y"),
|
||||
OPT_REPLACED("sub-text-blur", "sub-blur"),
|
||||
OPT_REPLACED("sub-text-bold", "sub-bold"),
|
||||
OPT_REPLACED("sub-text-italic", "sub-italic"),
|
||||
OPT_REPLACED("ass-line-spacing", "sub-ass-line-spacing"),
|
||||
OPT_REPLACED("ass-force-margins", "sub-ass-force-margins"),
|
||||
OPT_REPLACED("ass-vsfilter-aspect-compat", "sub-ass-vsfilter-aspect-compat"),
|
||||
OPT_REPLACED("ass-vsfilter-color-compat", "sub-ass-vsfilter-color-compat"),
|
||||
OPT_REPLACED("ass-vsfilter-blur-compat", "sub-ass-vsfilter-blur-compat"),
|
||||
OPT_REPLACED("ass-force-style", "sub-ass-force-style"),
|
||||
OPT_REPLACED("ass-styles", "sub-ass-styles"),
|
||||
OPT_REPLACED("ass-hinting", "sub-ass-hinting"),
|
||||
OPT_REPLACED("ass-shaper", "sub-ass-shaper"),
|
||||
OPT_REPLACED("ass-style-override", "sub-ass-style-override"),
|
||||
OPT_REPLACED("ass-scale-with-window", "sub-ass-scale-with-window"),
|
||||
|
||||
{0}
|
||||
};
|
||||
@@ -709,32 +816,16 @@ const struct MPOpts mp_default_opts = {
|
||||
.audio_buffer = 0.2,
|
||||
.audio_device = "auto",
|
||||
.audio_client_name = "mpv",
|
||||
.vo = {
|
||||
.video_driver_list = NULL,
|
||||
.monitor_pixel_aspect = 1.0,
|
||||
.screen_id = -1,
|
||||
.fsscreen_id = -1,
|
||||
.panscan = 0.0f,
|
||||
.keepaspect = 1,
|
||||
.keepaspect_window = 1,
|
||||
.taskbar_progress = 1,
|
||||
.border = 1,
|
||||
.fit_border = 1,
|
||||
.WinID = -1,
|
||||
.window_scale = 1.0,
|
||||
.x11_bypass_compositor = 2,
|
||||
.mmcss_profile = "Playback",
|
||||
},
|
||||
.allow_win_drag = 1,
|
||||
.wintitle = "${?media-title:${media-title}}${!media-title:No file} - mpv",
|
||||
.heartbeat_interval = 30.0,
|
||||
.stop_screensaver = 1,
|
||||
.cursor_autohide_delay = 1000,
|
||||
.gamma_gamma = 1000,
|
||||
.gamma_brightness = 1000,
|
||||
.gamma_contrast = 1000,
|
||||
.gamma_saturation = 1000,
|
||||
.gamma_hue = 1000,
|
||||
.gamma_gamma = 0,
|
||||
.gamma_brightness = 0,
|
||||
.gamma_contrast = 0,
|
||||
.gamma_saturation = 0,
|
||||
.gamma_hue = 0,
|
||||
.video_osd = 1,
|
||||
.osd_level = 1,
|
||||
.osd_duration = 1000,
|
||||
.osd_bar_align_y = 0.5,
|
||||
@@ -747,6 +838,7 @@ const struct MPOpts mp_default_opts = {
|
||||
.sub_use_margins = 1,
|
||||
.ass_scale_with_window = 0,
|
||||
.sub_scale_with_window = 1,
|
||||
.teletext_page = 100,
|
||||
#if HAVE_LUA
|
||||
.lua_load_osc = 1,
|
||||
.lua_load_ytdl = 1,
|
||||
@@ -765,22 +857,8 @@ const struct MPOpts mp_default_opts = {
|
||||
.load_config = 1,
|
||||
.position_resume = 1,
|
||||
.autoload_files = 1,
|
||||
.stream_cache = {
|
||||
.size = -1,
|
||||
.def_size = 75000,
|
||||
.initial = 0,
|
||||
.seek_min = 500,
|
||||
.back_buffer = 75000,
|
||||
.file_max = 1024 * 1024,
|
||||
},
|
||||
.demuxer_max_packs = 16000,
|
||||
.demuxer_max_bytes = 400 * 1024 * 1024,
|
||||
.demuxer_thread = 1,
|
||||
.demuxer_min_secs = 1.0,
|
||||
.network_rtsp_transport = 2,
|
||||
.network_timeout = 0.0,
|
||||
.hls_bitrate = INT_MAX,
|
||||
.demuxer_min_secs_cache = 10.0,
|
||||
.cache_pausing = 1,
|
||||
.chapterrange = {-1, -1},
|
||||
.ab_loop = {MP_NOPTS_VALUE, MP_NOPTS_VALUE},
|
||||
@@ -796,6 +874,7 @@ const struct MPOpts mp_default_opts = {
|
||||
.play_frames = -1,
|
||||
.rebase_start_time = 1,
|
||||
.keep_open = 0,
|
||||
.image_display_duration = 1.0,
|
||||
.stream_id = { { [STREAM_AUDIO] = -1,
|
||||
[STREAM_VIDEO] = -1,
|
||||
[STREAM_SUB] = -1, },
|
||||
@@ -828,16 +907,14 @@ const struct MPOpts mp_default_opts = {
|
||||
.ass_shaper = 1,
|
||||
.use_embedded_fonts = 1,
|
||||
.sub_fix_timing = 1,
|
||||
.sub_cp = "auto",
|
||||
.screenshot_template = "mpv-shot%n",
|
||||
|
||||
.hwdec_api = HAVE_RPI ? HWDEC_RPI : 0,
|
||||
.hwdec_codecs = "h264,vc1,wmv3,hevc,mpeg2video,vp9",
|
||||
.videotoolbox_format = IMGFMT_NV12,
|
||||
|
||||
.index_mode = 1,
|
||||
|
||||
.dvd_angle = 1,
|
||||
|
||||
.mf_fps = 1.0,
|
||||
|
||||
.display_tags = (char **)(const char*[]){
|
||||
|
||||
Loaded 100 of 233 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user