Compare commits

...
521 Commits
Author SHA1 Message Date
sfan5 70b991749d Release 0.32.0 2020-01-26 21:31:54 +01:00
wm4 bc1c024ae0 lua: stop setting bogus package path
Scripts are not supposed to be able to "import" anything from mpv's
scripts directory, because all these files are loaded by mpv itself.
2020-01-26 15:28:51 +01:00
James Ross-Gowan 80423e5b55 w32_common: support minimized and maximized properties
Add support for setting window-minimized and window-maximized in
Windows. The minimized and maximized state can be set independently.
When the window is minimized, the value of window-maximized will
determine whether the window is restored to the maximized state or not.

Changing state is done with ShowWindow(), which has commands that change
the window state and activate it (eg. SW_RESTORE) and commands that
change the window state without activating it (eg. SW_SHOWNOACTIVATE.)
It would be nice if we could use commands that don't activate the
window, so scripts could change the window state in the backrgound
without bringing it to the foreground, but there are some problems with
that. There is no command to maximize a window without activating it, so
SW_MAXIMIZE is used instead.  Also, restoring a window from minimize
without activating it seems buggy. On my Windows 10 1909 PC, it always
moves the window to the back of the z-order. SW_RESTORE is used instead
of SW_SHOWNOACTIVATE because of this.

This also changes the way the window is initially shown. Previously, the
window was made visible as a consequence of the SWP_SHOWWINDOW flag in
the first call to SetWindowPos. In order to set the initial minimized or
maximized state of the window, the window is shown with the ShowWindow
function instead, where the ShowWindow command is determined by whether
the window should be initially maximized or minimized.

Even when showing the window normally, we should still call ShowWindow
with the SW_SHOW command instead of using SetWindowPos, since the first
call a process makes to ShowWindow(SW_SHOW) has special behaviour
where it uses the show command in the process' STARTUPINFO instead of
the command passed to the function, which should fix #5724.

Note: While changes to window-minimized while in fullscreen mode should
work as expected, changing window-maximized while in fullscreen does not
work and won't result in the window changing state, even after leaving
fullscreen. For this to work correctly, the fullscreen logic needs to be
changed to apply the new maximized state on leaving fullscreen.

Fixes: #5724
Fixes: #7351
2020-01-26 15:36:12 +02:00
wm4 48880d827d player: fix minor coding style issue 2020-01-26 14:29:48 +01:00
Chris Down 1ae17074bd player: check if file is URL before attempting to get mtime
I noticed an oversight when using ytdl-hook -- if the path is a URL, we
try to `stat()` it, which obviously doesn't work. To mitigate that,
don't check or update mtimes for URLs.
2020-01-26 14:28:31 +01:00
wm4 b316534902 stream_lavf: remove version from user agent 2020-01-26 14:24:47 +01:00
der richter dd14d06835 mac: change Report Issue menu link to the new choose template page 2020-01-26 14:02:32 +01:00
der richter 1dea80d3fd cocoa-cb: add pinch to resize window gesture
the event returns a delta ratio so we can just add it to the current
window-scale.

Adds support for #3214
2020-01-26 12:33:47 +01:00
der richter 2aa4186a25 cocoa-cb: never set a window size smaller than the set minSize
this prevents a vanishing window if the size is set too small.
2020-01-26 12:33:47 +01:00
der richter 44f6e79439 travis: don't send notifications for forks 2020-01-26 12:12:22 +01:00
der richter e2c59b4177 cocoa-cb: fix race condition on quit
it was possible for mouse events to be triggered when the core was
already being shut down. to prevent this properly close and remove the
window and additional remove the reference to MPVHelper object.
2020-01-26 12:12:22 +01:00
der richter 3275cd04b7 cocoa-cb: add support for forcing the dedicated GPU for rendering
this deprecates the old cocoa backend only option and moves it to the
general macos ones. add support for the new option in the cocoa-cb
layer creation and use the new option in the olde cocoa backend.

Fixes #7272
2020-01-26 12:12:22 +01:00
der richter 465f48fb0c cocoa-cb: don't set App icon when called from bundle
due to the bundle config the icon is set automatically via the bundle
system mechanisms. this also makes it possible to set the icon to a
custom one with the standard macOS copy paste method via the file info
dialogue.

Fixes #6874
2020-01-26 12:12:22 +01:00
der richter 695d850412 mac: report playback state to the MediaPlayer Command Center
some system logic for the global media key events depends on the right
playback state. set the state properly to prevent more breakages in the
future.
2020-01-26 12:09:55 +01:00
der richter 3d16ab1a31 mac: add support for PLAYONLY and PAUSEONLY key codes to MediaPlayer
Fixes #7365
2020-01-26 12:09:55 +01:00
der richter 77d42d5532 input: add new PLAYONLY and PAUSEONLY MP_KEY key codes
since the old PLAY and PAUSE key codes cycle through the pause property,
the new key codes only explicitly set the pause property.
2020-01-26 12:09:55 +01:00
wm4 ae0520cafc client API: document srand() use 2020-01-21 17:07:40 +01:00
wm4 1ea145a9a1 player: make failure to load scripts non-fatal again
Restore the behavior from a few commits ago. I decided that it's strange
that this is fatal, since e.g. config file errors are also non-fatal.
2020-01-20 19:58:51 +01:00
wm4 65f3c7453d stream_libarchive: more broken garbage
Why the fuck am I even bothering with this crap?
2020-01-20 19:58:51 +01:00
wm4 3ef0754102 Revert "stream_libarchive: remove "old" rar volume pattern"
This reverts commit 1b0129c414.

It turns out most of the files affected by the idiotic use-case actually
use this old naming pattern, which I hoped was unused.

This means for now we'll always assume .rar files are multi-part (until
proven otherwise), but the following commit tries to fix this.
2020-01-20 19:58:51 +01:00
der richter e666546910 github: rename Bug to Issue and slightly change the question template 2020-01-20 10:12:40 +01:00
wm4 da913998d3 input: fix cycle 2nd argument stringification
Triggered the fallback code that formatted the argument as "(NULL)".
2020-01-19 20:53:26 +01:00
wm4 90c11fa729 stream_libarchive: do not require leading / in archive URLs
The / was added some time ago, because it simplifies some other things.
But there is actually no reason to reject old URLs.
2020-01-19 19:26:51 +01:00
wm4 00cdda2ae8 scripting: make player error when attempting to load unknown scripts
It's ridiculous that --script=something.dumb does not cause an error.
Make it error, and extend this behavior to the scripts/ sub-dir in the
mpv config dir.
2020-01-19 19:25:54 +01:00
wm4 ee7be62dbc player: write watch-later config even for unseekable streams
I think there was a user complaint that this does not restore the
playlist position.

There's no reason not to save the "state" for unseekable streams; what
we probably don't want is to make restoring trying to issue a seek. So
just don't save the position. (Although we probably could anyway, since
seek requests on unseekable streams are ignored now.)

Fixes: issue number forgotten, if it even exists.
2020-01-17 15:26:16 +01:00
wm4 ad1ae64251 f_autoconvert: remove subfmt conversion BS
This was used to convert e.g. P010 to NV12 within the filter chain,
which hopefully a thing that is not needed anymore. (And has been dead
code since the ANGLE "RGB" interop code was removed.)
2020-01-17 15:19:05 +01:00
wm4 044996e112 f_hwtransfer: extend vaapi whitelist with some working formats
Notably, BGR0, which is the only additional format listed as supported
by the texture mapper, results in broken colors. This is most likely not
a mpv issue, so the whitelist fulfils its purpose.
2020-01-17 15:13:23 +01:00
wm4 a500608845 f_hwtransfer: minor debug logging improvement 2020-01-17 15:10:36 +01:00
wm4 7ed6b5f44d vo_gpu: hwdec_vaapi: set correct hw_imgfmt value
As documented on struct mp_hwdec_ctx, hw_imgfmt specifies the hardware
surface wrapper format for which supported_formats is valid. If this was
not set, f_hwtransfer ignored supported_formats, and assumed all formats
were supported.
2020-01-17 15:08:46 +01:00
Avi Halachmi (:avih) 40832773c1 osc: more frequent cache updates: from 10% diff to 5% or 5s
Cache display updates, especially when it's bigger than few minute,
could have been be very infrequent to the point that one is not sure
if it updates at all.

Reduce the 10% change-threshold to 5% and add another threshold of 5s.
2020-01-14 13:15:48 +02:00
Philip Langdale 3259494d9e bash completion: only generate option list when needed
Right now we are generating the fully option list before doing
anything else. That makes filename completion significantly slower
than it was before, for no gain. It's easy to only generate the
option list when it's actually needed.

I also know I could additionally cache the option list across
invocations, but I'm not doing that yet to make testing easier.
2020-01-13 17:12:25 -08:00
Philip Langdale 4d51660195 osc: usability improvements for pseudo-csd title bar
There are two improvements here:

1) Correct the right-side padding on the title box. This was messed
   up previously because I was passing the title box width when I
   should be passing the x coordinate. I've also increased the
   spacing to separate the title from the window controls more
   clearly.

2) I'ved added a mouse tracking area over the title bar so that the
   osc doesn't disappear if you hover over the title box. This didn't
   work previously because the input area only covers the actual
   window controls. The implementation here is simplified in that
   it's only a mouse area and not an input area. This is enough to
   keep the osc visible, but it won't stop the mouse pointer
   disappearing. Fixing that requires a full input area which, for
   now, I will say isn't worth the effort.
2020-01-13 16:25:34 -08:00
Philip Langdale 9f7c271087 osc: when fullscreened, un-maximise window control should un-fullscreen
It's a bit unintuitive today when you use the un-maximise control
while fullscreened. Depending on the VO in use, this might silently
change the maximise state without any visible effect, or it might
do nothing. It's less surprising if the control exits the fullscreen
state.

Note that the exact behaviour is still VO dependent. If the window
was maximised before being fullscreened, it might exit fullscreen
back to maximised or back to regular window mode.

I thought about trying to explicitly control that behaviour but
it makes the osc code weird and probably wouldn't work all the time.
2020-01-12 08:43:19 -08:00
Dudemanguy a870145fb9 wayland: support maximize/minimize on startup
Allow the --window-maximized and --window-minimized flags to actually
work when the player is started on wayland. If the compositor doesn't
support maximization or minimization, then these options just do
nothing.
2020-01-12 16:12:09 +00:00
dudemanguy b8a42cc41c wayland: unscrew up cursors
Fixes #7345

There was a multitude of issues with cursor handling in wayland and
behavior seemed to vary for strange reasons across compositors and also
bad things were being done in wayland_common. The problem is complicated
and involved fullscreen states being set incorrectly under certain
instances and so on. The best solution is to just remove most of the
extra cruft. In handle_toplevel_config, instead of automatically
assuming is_fullscreen and is_maximized are false, we should use
whatever value is currently set vo_opts which matters when we initially
launch the window.
2020-01-12 01:54:41 +00:00
dudemanguy 6cb3d024c8 Revert "options: move cursor autohiding opts to mp_vo_opts"
This reverts commit 65a317436d.
2020-01-12 01:54:41 +00:00
wm4 63bf362d11 f_hwtransfer: move format fields to private struct
A user can barely do anything useful with it, and there are no users
which access these anyway, so private is better.
2020-01-12 01:47:42 +01:00
wm4 68292a2780 f_hwtransfer: restructure and error properly on broken cases
I think the previous code didn't consider the situation if the input
format was not any of the upload formats. It then could have possibly
tried to upload the wrong format (and not sure what the underlying APIs
do with it).

Take care of this, also improve logging, and change it such that
mp_hwupload_find_upload_format() does not unnecessarily change the state
(although it doesn't really matter).
2020-01-12 01:43:21 +01:00
wm4 a3f220ba44 f_autoconvert: usw f_hwtransfer properly
With the recent change how f_hwtransfer could select formats, it's
possible that the upload_fmts list contains formats that are never
selected, and the filter would have failed.

The way it works now is that f_hwtransfer gets to select the format
(which honestly doesn't make sense, but whatever), and f_autoconvert
gets only a single format.

It would be more ideal if f_hwtransfer provided a list of possible input
formats, but that's absurdly too complex for now. Maybe I'll change it
back at some later point, but I expect this shit to be in a perpetual
state of complexity and brokenness.
2020-01-12 01:33:02 +01:00
wm4 4b168bcda3 input: escape command parameters when logging
Some complex commands (like commands generated by scripts to define key
bindings or the OSD overlay command) contain new lines, which "corrupts"
logging.

Fix this by escaping the parameters C-style. Abuse the JSON writer for
this, which already has code to vaguely produce C-style escapes.

At first I considered stripping the quotes, but then I thought it's
actually a good idea to leave them in, as it makes things clearer.

Follows an idea by avih.
2020-01-12 01:04:33 +01:00
wm4 b947bfcf1f f_hwtransfer: slightly better logging 2020-01-11 22:46:04 +01:00
wm4 7555e2a42a f_hwtransfer: whitelist vaapi formats that actually appear to work
(Oh yes, we could have skipped all the complexity, and hardcoded the
cases that work in the first place. This wouldn't be an issue if FFmpeg
or libva exported correct information. Also possible that FFmpeg's
filter chain does not allow to do this correctly in the first place,
since filters expose next to no meta information about what hw formats
etc. they need.)

Note that uploading yuv420p to a nv12 vaapi surface actually works, but
the blacklist excludes it. So this might get a bit slower. I'm not
bothering with this case because it's rarely needed, and the blacklist
specification would become a bit more complex if you had to specify
sw/upload format pairs.

Fixes: #7350
2020-01-11 22:45:42 +01:00
wm4 a009b57c77 f_hwtransfer: change order in which hwdec upload formats are considered
Basically, instead of trusting the upload format, and picking the first
sw format that has a desired upload format, trust the sw format. So now
we pick the sw format first, and then select from the set of upload
formats supported by it.

This is probably more straightforward, and works around a crash with
vaapi:

  mpv 8bit.mkv --vf=format=vaapi --gpu-hwdec-interop=all

(Forces vaapi upload if hw decoding is not enabled.)

Unfortunately, this still does not work, because vaapi, FFmpeg, the VO
interop code, or all of them are doing something stupid. In particular,
this picks the yuv420p sw format, which doesn't really exist despiter
advertised (???????????????????????????????????????), and simply breaks.

See: #7350
2020-01-11 22:29:53 +01:00
wm4 a3ddddff3a vaapi: reduce log levels further
Try to exclude mostly uninteresting information from verbose logging,
but still include it in debug logging.
2020-01-11 16:35:30 +01:00
wm4 f23dcfef82 vo_gpu: hwdec_vaapi: silence warning during probing
hwdec_vaapi tries to probe all available surface formats in advance. For
that, we iterate over _all_ profiles in an attempt to collect possible
surface formats. This means we try profiles we normally wouldn't use for
decoding or filtering, and which could be "unrelated" services.

It seems some drivers report at least one profile, for which
vaQueryConfigEntrypoints() fails (because the profile is not supported;
not sure why it lists it, then). So turn the error message into a
verbose message to avoid confusing output.

Fixes: #7347
2020-01-11 16:35:30 +01:00
Dudemanguy cfceaec266 wayland: don't set cursor before pointer id
This shouldn't really matter, but it's probably best to avoid.
vo_wayland_control would execute set_cursor_visibility while wl->pointer
existed but it didn't check if wl->pointer_id existed. So
wl_pointer_set_cursor would be set to a null surface with an id of 0.
Instead, just wait until we have an actual, non-zero pointer id so that
the cursor is set with the correct, actual id and not a fictious 0 id.
This ensures that the pointer isn't set until it enters the wl_surface
which is what we want.
2020-01-11 00:05:21 -06:00
Philip Langdale 8b85b40b2f bash completion: add initial implementation of bash completion
While we've had a zsh completion script for a while, we haven't had
one for bash. This one is reasonably comprehensive, although there are
improvements one could imagine for certain options.
2020-01-09 12:07:05 -08:00
der richter 28609cc498 cocoa-cb: don't active window when minimized or hidden on file change
Fixes #7195
2020-01-09 20:41:44 +01:00
der richter ea9f9af76c github: add several issue templates and a warning to not ignore them 2020-01-09 20:20:35 +01:00
der richter e6c9e33a31 cocoa-cb: add runtime dpi change and use proper fallback for initial dpi
at the time of the initial dpi query the window is not instantiated yet.
we use a proper fallback in that case, eg the target configured screen
or the main screen if none is set.

also change some weird oversight and a small optimisation.
2020-01-09 19:13:42 +01:00
wm4 7bb3f53cf5 command, vo: add a mechanism for runtime DPI scale changes
Follow up to commit a58585d5e0. It turned out that the OSX backend
needs this.
2020-01-09 19:13:42 +01:00
der richter 57f9de7b53 travis: update macOS images and make building faster
don't build our own ffmpeg anymore and instead use the bottled version
from homebrew. update the newest macOS image. also handle macOS 10.12
as a legacy OS since homebrew and Apple stopped supporting it.
nevertheless it's helpful to build on that version since it's the last
version we support building on. it's a bit special since we have to pin
the homebrew-core version to a previous one where all the bottles for
macOS 10.12 are still available, otherwise it would build nearly
everything from source and that would take ages. also start caching the
homebrew cache folder for downloads.
2020-01-09 19:11:38 +01:00
wm4 363048077f client API: fix property notification from non-playloop sources
This code assumed that the function is only called from the playloop
itself (and since property notification is done at the end of it, i.e.
before sleeping, it obviously would not have needed to wake up the
core).

But this function is actually called from some comments (such as
playlist-move), so this assumption was incorrect. Use the same method as
the other function.

Untested.

Fixes: #7339 (probably)
2020-01-09 18:16:41 +01:00
wm4 3a9f0f537f client API: change event mask to event number in one place
Cosmetic change. Slightly more convenient/readable.
2020-01-09 18:12:10 +01:00
wm4 33e999de82 stream_libarchive: fix unnecessarily opening all volumes on opening
Seems like I'm still not done with rar playback stuff...

It turns out the reason for archive_read_open1() opening all volumes had
nothing to do with libarchive's rar code, but was a consequence of how
multi volume support is implemented in libarchive, and due to the fact
that we enabled archive_read_support_format_zip_seekable() (through
archive_read_support_format_zip()).

The seekable zip format will seek to the end of the file and search for
a zip "header" there. It could possibly be considered a libarchive bug
that it does that even if it's fairly sure that it's a RAR file.

We already do probing on a small buffer read from the start of the file
(i.e. not giving libarchive a way to seek the stream before we think
it's an archive), but that does not help, since libarchive needs to
probe _again_. libarchive does not seem to provide a function to query
the format (no archive_read_get_format()). Which seems quite strange,
but at least I didn't find one.

This commit works this around by doing some manual rar/zip probing. We
could have gone only with rar probing. But detecting zip separately
allows us to avoid that stream_libarchive seeks to the end during early
probing. This is an additional bonus on top of "fixing" multi volume
rar.

The zip probing is from archive_read_format_zip_streamable_bid(). The
rar signature is the common prefix of the rar and rar5 formats in
libarchive (presumably the RAR fixed header parts without version).

If the demuxer seeks to the end of the rar entry, this will still open
all volumes; I'm not sure whether the old/removed rar code in mpv could
handle this better.

See: #7182
2020-01-09 02:25:13 +01:00
Avi Halachmi (:avih) 5e0875c9e0 js: use osd-dimentions for mp.get_osd_{size,margins}
This matches lua's 11b9315b but with the lagacy field names which the
js code used previously.

Currently the property always returns an object (with dummy/last/null
field values if there are no dimensions), but the code is ready for
a future case where it might return null if there are no dimensions - at
which case it will forward the null, breaking backward compatibility for
a better API.
2020-01-08 11:49:49 +02:00
wm4 f612de1712 vo_gpu: fix crash if dither texture fails to allocate
Theoretically possible (and quite unlikely due to the small texture
size). The code was originally written with the assumption that texture
allocations can't fail, and it was never updated out of laziness.
Untested.
2020-01-08 03:45:17 +01:00
wm4 1c83ded3b0 osc: don't delay updates on resize
The idea is that if the player is resized, we do not delay redrawing
(which is normally done to limit the redraw rate to something
reasonable).

Not sure if this even does anything. For one, reacting to osd-dimensions
changes is cleaner than just polling the screen size with the next tick
event, and hoping that resizes generate tick events for whatever
logically unrelated reasons.
2020-01-08 02:37:12 +01:00
wm4 4a65c22c50 osd: fix possible misses of osd-dimensions property updates
check_obj_resize() in sub/osd.c calls mp_client_broadcast_event(), which
calls notify_property_events(). This is pretty unexpected, because
check_obj_resize() may be called from the VO thread. While that's sort
of awful, it seems to be OK locking-wise. But it breaks an assumption in
notify_property_events() that the core doesn't need to be woken up,
which could possibly lead to a missed/delayed property update (although
rather unlikely).

Fix this by explicitly waking up the core when it's called from the OSD
code.
2020-01-08 02:31:18 +01:00
wm4 a58585d5e0 command: cache display-hidpi-scale property
This is a gross hack for the shitty design of how VO properties are
handled (which was fine with MPlayer, but became increasingly a shit tub
with mpv's VO thread).

The problem here is that console.lua reads display-hidpi-scale on every
render, but which may take a long time for video timing and vsync
blocking. It will also block the core, making osc.lua unable to react to
window resizing quickly enough.

This should be solved by not using the "classic" blocking VOCTRL
mechanism, and instead side-stepping it with something that doesn't
require any waiting (like for example the "fullscreen" property does).

But this require more thinking and work my "brain" can handle at the
moment. So for now add a shitty hack that will cause a lot of problems,
and which will have to be replaced later. Most importantly, it'll break
theoretic support for multiple screens with different DPI, or runtime
DPI changes. Possibly could affect the Cocoa backend; the X11 isn't
dynamic enough by nature, and other backends do not implement this.
2020-01-08 02:16:45 +01:00
wm4 7ce41cda05 command: remove outdated MP_EVENT_WIN_STATE entries
These properties are handled very differently now, and being in that
list did pretty much nothing.
2020-01-08 02:01:49 +01:00
wm4 11b9315b3f lua: use new OSD property
See previous commit.

A nice side-effect is that mp.get_osd_margins() is not a special
Lua-only thing anymore. I didn't test whether this function still works
as expected, though.
2020-01-08 00:16:58 +01:00
wm4 db9048f21a command: add osd-dimensions property
This "bundles" all OSD properties. It also makes some previously
Lua-only values available (Lua has mp.get_osd_margins(), unsure if
anything uses it).

The main intention is actually to allow retrieving all fields in an
"atomic" way. (Could introduce a mechanism on the level of the mpv
client API to do this, but doing ti ad-hoc all the time like this commit
is easier.)
2020-01-08 00:16:01 +01:00
wm4 d3cef97ad3 options: change option parsing when using a single dash
Addresses dumb things like accidentally overwriting a media file with
e.g. "mpv --log-file test.mkv" (when the user thought that --log-file
was a flag option, when it actually takes a filename). This example will
now print an error. It still works with "-log-file overwritten.mkv", but
prints a warning.

Not sure if I'm being too careful or not "radical" enough. In any case,
both the syntax that stops working and the syntax that produces a
warning now have been discouraged and were called legacy for almost a
decade.
2020-01-07 23:08:45 +01:00
wm4 5b56be0e91 build: fix minimum libarchive version
Seems like 3.3.3 was not correct and too early.

Fixes: #7334
2020-01-07 22:31:35 +01:00
Dave bcc921bd2f manpage: explain deprecated usage of multiple items with *-add 2020-01-07 18:13:12 +01:00
Dave 343bf8a9ac DOCS/encoding.rst: remove deprecated usage of multiple items with *-add
4a084c0df8 deprecated multiple -add items
with d3e3bd4307 explicitly warning against
this usage.
2020-01-07 18:13:12 +01:00
wm4 28650e116a stream_libarchive: enable anger management
Well that was too much misery when trying to deal with an idiotic
feature, so it had to be compensated for.
Replace insults with proper explanation, libarchive sort of isn't guilty
in the first place, and their format support is pretty good all things
considered.
2020-01-07 15:32:27 +01:00
Dudemanguy 9eb399193e wayland: don't exit the option loop
More than one option may change at the same time so don't break out of
this loop.
2020-01-04 22:02:36 +00:00
wm4 d26b5daf3e command: make sub-step command actually apply sub-delay change properly
The change was not propagated to the OSD/subtitle code, since that still
uses an "old" method. Change it so that the propagation is actually
performed.

(One could argue the OSD/subtitle code should use other ways to update
the options, but that would probably be more effort for now.)
2020-01-04 21:12:29 +01:00
wm4 1b0129c414 stream_libarchive: remove "old" rar volume pattern
This turned every "normal" .rar filename into a multi-volume one
accidentally. Since the detection is purely by filename (due to lack of
support by libarchive I guess), it causes the nasty message added in the
previous commit to appear for every .rar file. Just drop it.
2020-01-04 20:49:00 +01:00
wm4 119bad4daa stream_libarchive: add annoying message regarding multi-volume archives
I'm done.
2020-01-04 20:00:43 +01:00
wm4 1b283f6b60 libarchive: some shitty hack to make opening slightly faster
See manpage additions. The libarchive behavior mentioned in the last
paragraph there is technically unrelated, but makes this new option
mostly pointless.

See: #7182
2020-01-04 19:56:09 +01:00
wm4 4231ce6f5f stream_libarchive: log each opened volume
To annoy the user.
2020-01-04 19:48:55 +01:00
wm4 5016a1e4a6 demux: add per-demuxer sub-options
Until now, they were all just added to options.c (e.g. demux_mkv_conf).
This adds a mechanism which can be used to add future options in a
(very) slightly more elegant way.
2020-01-04 19:47:36 +01:00
wm4 8150b8552b options: add mechanism to add sub-options from component lists
There are a lot of ad-hoc component lists in mpv: for example the stream
and demuxer lists. It doesn't seem to make sense to add any abstractions
around it since they are completely trivial and have very specific
probing mechanisms and so on, so they will remain ad-hoc.

This commits add a way to let these add arbitrary per-component options,
without giving up the ad-hoc way, and without having to dump them into
options.c with lots of ifdeffery (like it was done until now).

Also see next commit.
2020-01-04 19:45:50 +01:00
wm4 4419d29bb0 stream_libarchive: remove unnecessary string list of volumes
Just add the entries as volumes directly.
2020-01-04 19:31:08 +01:00
wm4 04bde06095 stream_libarchive: some more hacks to improve multi-volume archives
Instead of opening every volume on start just to see if it's there, all
all volumes that could possibly exist, and "handle" it on opening. This
requires working around some of libarchive's amazing stupidity and using
some empirically determined behavior. Will possibly break if libarchive
changes some of this behavior.

See: #7182
2020-01-04 18:59:23 +01:00
wm4 657ce1b15c stream_libarchive: enable rar5 support
We whitelist formats (and not all of them). RAR v5 is a separated format
entry for inexplicable reasons. (It's a separate implementation, but who
really wants to support only either of the rar formats?)

I'm not sure if it was libarchive 3.3.3. Their git history is absolutely
chaotic. These people do not know how to use git. I couldn't be bothered
to dig deeper.
2020-01-04 17:15:09 +01:00
wm4 99700bc52c demux_edl: restore relative path resolution
Playing e.g. "dir/f.edl" should make all non-absolute paths in f.edl
relative to "dir".

Commit 0e98b2ad8e accidentally broke this.
2020-01-02 23:31:02 +01:00
Philip Langdale daa125cb45 osc: reset input handling state on a change in visibility mode
Currently, the activation and deactivation of input handling is done
inside the render() loop, but this does not run when the osc mode is
`never` - which does make sense.

That means that if you are cycling the visibility mode, the input
state will be whatever it was at the time of the mode change. And,
as our modes are ordered `auto` -> `always` -> `never`, the input
state will be enabled when you cycle to `never`.

There are various ways you can imagine fixing this, and in this
change I propose we reset the input state to disabled on a mode
change, and then let render() re-enable input if that's appropriate.

Fixes #7298.
2020-01-02 07:32:57 -08:00
Dudemanguy 5feee11e43 wayland: disable by default for gnome
It turns out that gnome wayland still has very serious issues that make
it unusable for playback with mpv. Other compositors mostly behave fine
(Plasma is just missing feature but it's not seriously broken), so GNOME
gets the special honor of having a warning printed out. The only
solution for GNOME users at this time of writing is to either use the
Xorg session or use another wayland compositor.
2020-01-01 20:27:54 +00:00
Dudemanguy 7d08491cd9 Revert "vo_gpu: move wayland below X11 in autoprobe order"
This reverts commit a6d8e9b7ff.
2020-01-01 20:27:54 +00:00
wm4 934f8e1026 Bump copyright year
Merry Christmas or whatever it fucking is now.
2019-12-31 17:10:46 +01:00
wm4 3b6c4e7be1 demux: make track switching instant with certain mpegts files
When switching tracks, the data for the new track is missing by the
amount of data prefetched. This is because all demuxers return
interleaved data, and you can't just seek the switched track alone.
Normally, this would mean that the new track simply gets no data for a
while (e.g. silence if it's an audio track). To avoid this, mpv performs
a special "refresh seek" in the demuxer, which tries to resume demuxing
from an earlier position, in a way that does not disrupt decoding for
the non-changed tracks. (Could write a lot about the reasons for doing
something so relatively complex, and the alternatives and their
weaknesses, but let's not.)

This requires that the demuxer can tell whether a packet after a seek
was before or after a previously demuxed packet, sort of like an unique
ID. The code can use the byte position (pos) and the DTS for this. The
DTS is normally strictly monotonically increasing, the position in most
sane file formats too (notably not mp4, in theory).

The file at hand had DTS==NOPTS packets (which is fine, usually this
happens when PTS can be used instead, but the demux.c code structure
doesn't make it easy to use this), and pos==-1 at the same time. The
latter is what libavformat likes to return when the packet was produced
by a "parser" (or in other words, packets were split or reassembled),
and the packet has no real file position. That means the refresh seek
mechanism has no packet position and can't work.

Fix this by making up a pseudo-position if it's missing. This needs to
set the same value every time, which is why it does not work for
keyframe packets (which, by definition, could be a seek target).

Fixes: #7306 (sort of)
2019-12-31 00:17:46 +01:00
Chris Down b721f9d095 configfiles: Fix utime retcode check
In final fixups for #7139 it seems I managed to screw up utime error
checks. Everything still works, but we MP_WARN when we don't need to.
2019-12-31 00:17:07 +01:00
wm4 fcf0b80dc9 player: make unpausing directly after seek work with --keep-open
When using --keep-open, and the end of the file is reached, the player's
"pause" property is set to true. Attempting to set it to false reverts
it back to true immediately. That's how it's designed, for better or
worse.

Running "seek -10 ; set pause no" did not work, because the seek is
first queued and pause is unset, but then the decoding functions
determine that EOF is still a thing, and "mpctx->stop_play =
AT_END_OF_FILE;" is set again. handle_keep_open() then sets pause again.
Only then the seek is actually run.

Fix this by not setting stop_play if a seek is queued.
2019-12-30 17:40:21 +01:00
wm4 a6d8e9b7ff vo_gpu: move wayland below X11 in autoprobe order
I'm sick of mpv being accused of not doing it right.
You can't do it right on Wayland? Long live X11.

Fixes: #7307
2019-12-30 13:12:33 +01:00
Philip Langdale 5fcad696a9 manpage: update discussion of nvidia hardware acceleration
The text here has become somewhat outdated over the years, and it's
worth updating to reflect the current situation.
2019-12-29 15:09:46 -08:00
Philip Langdale 9c05be8999 video: cuda: add explicit context creation for copy hwaccels
In the distant past, the cuviddec backed copy hwaccel could be
configured directly using lavc options. However, since that time,
we gained support for automatic hw ctx creation which ended up
bypassing the lavc options.

Rather than trying to find a way to pass those options again, a
better idea is to make the 'cuda-decode-device' option, used by
the interop hwaccels, work for the copy hwaccels too.

And that's pretty simple: we have to add a create function that
checks the option and passes it on to ffmpeg.

Note that this does require a slight re-jig to the configuration
flags, as we now have a scenario where we want to build with support
for the cuda copy hwaccels but not the interop ones. So we need
a distinct configuration flag for that combination.

Fixes #7295.
2019-12-29 14:32:47 -08:00
wm4 f0d0822595 demux: fix --stream-record runtime change handling
Well, if that wasn't particularly dumb.
2019-12-29 20:18:35 +01:00
der richter 0737d842b0 build: actually remove MediaPlayer sources from build when disabled
a small oversight on my side when i added the new flag to fix an include
problem for the vo_sub_opts struct.
2019-12-29 18:43:58 +01:00
Philip Langdale 49cbc5017c vo_gpu: hwdec_vaegl: remove support for old-style interop
In vaapi 1.1.0 (which confusingly is libva release 2.1.0), they
introduced a new surface export API that is more efficient, and
we've been supporting that and the old API ever since (Feb 2018).

If we drop support for the old API, we can do some fairly nice cleanup
of the code.

Note that the pkgconfig entries are explicitly versioned by the API
version and not the library version. I confirmed the upstream pkgconfig
files.
2019-12-28 14:31:34 -08:00
Philip Langdale eb852dc50c vo_gpu: hwdec_vdpau: remove direct_mode
As we are less and less interested in vpdpau, with nvdec and vaapi
being better choices in general on nvidia and AMD respectively, we
might consider removing direct_mode, where we bypass the vdpau
mixer and work directly with yuv textures. Normally, working with
yuv textures would be great, but vdpau built in an assumption that
all frames are delivered as separate fields, causing us to have
to re-interleave them.

nvidia then introduces a new OpenGL extension that can return the
yuv frames as frames, but we can't just unconditionally switch to
that as we'd want to keep supporting older hardware where the drivers
are no longer getting new features. The end result is that we
wouldn't be able to get rid of the old code paths.

Removing direct_mode means we always use the mixer, and work with
rgba frame textures. There are some theoretical limitations to
this, but in practice they probably don't matter much - unsupported
colourspaces don't matter because without 10bit decoding support,
we can't use them anyway, and apparently we're not doing separate
chroma scaling these days, so scaling the rbga doesn't really lose
anything (and the vdpau hq scaling option remains available).
2019-12-28 14:31:06 -08:00
wm4 5a26150717 command: add a playlist-unshuffle command
Has a number of restrictions.

See: #2491, #7294
2019-12-28 21:32:15 +01:00
wm4 582f3f7cc0 playlist: change from linked list to an array
Although a linked list was ideal at first, there are cases where it
sucks, and became increasingly awkward (with the mpv command API
preferring integer indexes to access the list). In future, we probably
want to add more playlist-related functionality, so better change it to
an array now.

An array isn't always ideal either. Since playlist entries are still
separate objects (because in some cases you need a stable "iterator" to
it), but you still need to efficiently get the next/previous playlist
entry, there's a pl_index field, that needs to be maintained. E.g.
adding an entry at the start of the playlist => update the pl_index
field for all other entries. Well, it's not really worth to do something
more complicated to avoid these things.

This commit is probably buggy as shit. It's not like I bothered to test
everything. That's _your_ role.
2019-12-28 21:32:15 +01:00
wm4 4564a22d13 ta: add another funny macro 2019-12-28 21:32:15 +01:00
wm4 65337c032f ta: document funny macros 2019-12-28 21:32:15 +01:00
der richter e2c6919da0 travis: fix python3 for macOS machines
python3 couldn't be set up as system default because it was blocked by
the old python2.
2019-12-28 21:10:08 +01:00
Oliver Freyermuth 1571276d64 stream_dvb: Remove implicit fallthroughs and consistify debug messages.
The code is more explicit now and less confusing,
and debug messages for the channel parsing for the several delivery systems
are now more similar.
2019-12-28 19:16:07 +01:00
James Ross-Gowan c4600394d4 w32_common: remove implicit fallthrough
GCC 9.2 warns about this. It was always a bit sketchy, so get rid of it.
VK_F10 generates WM_SYSKEYDOWN, so it only needs to be handled in the
WM_SYSKEYDOWN case.
2019-12-29 02:30:31 +11:00
Sai Ke WANG 01de2a9bd5 lua: fix mp.file_info for large files
`size` field with `unsigned int` was truncated to 4GB

Signed-off-by: wm4 <wm4@nowhere>
2019-12-28 14:34:32 +01:00
sfan5 13b8363c47 Update VERSION 2019-12-28 12:11:35 +01:00
sfan5 091aa96c4d Release 0.31.0 2019-12-28 12:07:07 +01:00
wm4 499a41ea35 DOCS/tech-overview.txt: some more blabla
This file is only complete once it contains the entire mpv source code
in English form.
2019-12-28 10:09:28 +01:00
wm4 025e77eaf1 audio: react to --ao and --audio-buffer runtime changes
Before this commit, runtime changes were only applied if something else
caused audio to be reinitialized. Now setting them reinitializes audio
explicitly.
2019-12-27 17:56:22 +01:00
wm4 0c0c373844 m_option: fix runtime changing of --audio-channels
This option type, used by --audio-channels, had a completely broken
m_option_type.equal implementation, and thus reacted incorrectly to
runtime option changes.

Broken since commit b16cea750f.
2019-12-27 17:44:33 +01:00
wm4 2a7e17fe4e DOCS/tech-overview.txt: add lots of irrelevant blabla
Thought it might be useful to document some of these things, instead of
explaining them over and over again. But I can guarantee that nobody
will ever read all this. (Independent of its quality and completeness.)
2019-12-27 17:09:47 +01:00
der richter 1caa653f2d cocoa-cb: force redraw when screen or size changes
in certain circumstances the video was not redrawn even when the size
or the backing scale factor changed. this could lead to a lower
resolution output than intended.

now it redraws the video when screen properties or the window size
changes.
2019-12-24 21:51:24 +01:00
der richter d9e13f42b8 cocoa-cb: implement hidpi scale reporting 2019-12-24 21:51:24 +01:00
wm4 8e9644761a console: add a basic help command
It's not really great. But I think it's good enough to save someone
who's lost. Most importantly, it should become obvious _what_ the
console expects (input commands), and how to exit it.

Would be nice if we could show some documentation, or give a link to
documentation, but that's out of scope and/or not easy.

I considered implementing the "help" command as builtin command in
command.c. On the other hand, this could not show console.lua specific
help, so I implemented it in console.lua. The ad-hoc command parsing
(that sort-of mirrors mpv input command syntax) for the "help" command
is probably the worst part of this.
2019-12-24 16:08:04 +01:00
wm4 1d2fcb9227 console: do not strip leading spaces
As suggested by TheAMM and avih.
2019-12-24 16:04:00 +01:00
wm4 029bb593e7 command: extend command-list output
Add some very basic information about arguments.
2019-12-24 16:03:16 +01:00
wm4 b6d7d246fe manpage: fix example in --hwdec section 2019-12-24 16:02:49 +01:00
wm4 b9084dfd47 stats: do not use "tick" event
It's deprecated. The new solution works almost exactly the same way
(since the still existing internal tick event triggers vsync-jitter
change command), though as far as API usage goes, it's somewhat
questionable. (The comment is meant to discourage anyone trying to copy
the idea for external scripts.)
2019-12-24 16:02:24 +01:00
Niklas Haas f868052872 build: force bootstrap.py to use python3
The script fails running successfully with python2.
2019-12-24 12:22:36 +01:00
wm4 2636bbbf33 osc: redraw on visibility option runtime changes
This affects behavior when using the "del" default key binding.
Sometimes, setting visibility to always did not draw it correctly. This
probably fixes it.
2019-12-24 09:50:08 +01:00
wm4 67650446b5 vd_lavc: remove hwdec-by-default special case for RPI 2019-12-24 09:24:56 +01:00
wm4 380f01567d vd_lavc: more hwdec autoselect nonsense
Add an "auto-safe" mode, mostly triggered by Ubuntu's nonsense to force
hwdec=vaapi in the global config file in their mpv package. But to be
honest it's probably something more people want.

This is implemented as explicit whitelist. On Windows, HEVC/Intel is
sometimes broken, but it's still whitelisted, and in theory we'd need a
detailed whitelist of device names etc. (like for example browsers tend
to do). On OSX, videotoolbox is a pretty bad choice, but unfortunately
the only one, so it's whitelisted too. There may be a larger number of
hwdec wrappers that work anyway, and I'm for example ignoring Android.
2019-12-24 09:24:22 +01:00
der richter e7add205d8 build: fix build with disabled swift and Media Player
when swift is disabled some headers are not included. one of them is the
options/options.h header that is needed for the vo_sub_opts struct. we
include it to fix the build without swift.

the second problem is the build time check for the macOS 10.12.2
features or more specific the Media Player support. since it is a swift
feature we can not use it when swift is disabled. add a separate
Media Player check that also depends on swift and use that new
preprocessor variable as a build time check instead.

Fixes #7282
2019-12-23 23:44:20 +01:00
Avi Halachmi (:avih) 9f2fda7d85 js: support mp.create_osd_overlay (match 07287262)
The legacy mp.set_osd_ass(...) is still supported (but also still
undocumented) as a wrapper for the new mp.create_osd_overlay(...).
2019-12-23 17:52:34 +02:00
Avi Halachmi (:avih) 5a74bf5f95 js: batch key bindings updates (match 96932fe7)
Implemented using one-time idle observer (i.e. setTimeout), to avoid
additional function call(back) every time the event loop enters idle.

The lua mp.flush_key_bindings() is also available, also undocumented.
2019-12-23 17:52:34 +02:00
Nicolas F 7ed70f925b osc: add option to disable santa hat
A minority of users have expressed a dislike of hats, calling them
"cancer [that] don't belong in software" describing the people who add
them as "shitty circlejerks" and "chucklefuck."

While I personally disagree with those opinions, it's probably easier
to let them have it their way. For that reason this adds the option
`greenandgrumpy` to the osc, which allows users to disable the hat.
2019-12-23 16:38:41 +01:00
wm4 091ee9d770 lua: fix guard against division by 0
This was incorrectly converted from the original C code. Change it to
what the original code used.
2019-12-23 16:10:06 +01:00
wm4 d951a7f021 lua: fix passing non-integers to mp.set_osd_ass()
libass uses integers for PlayResX/Y, so the osd-overlay command also
does. Lua (pre-5.3) does not have an integer type, but the command
interface makes a difference anyway. If you pass a Lua number with a
fractional part to an integer parameter (using mp.command_native()), it
will result in an error and complain about incompatible types.

I think that's fine, but since this behavior extends to
mp.set_osd_ass(), this is a compatibility problem.

Fix this by explicitly coercing the resolution parameters to integer
numbers.
2019-12-23 13:23:10 +01:00
wm4 86d24b069b osc: set an arbitrary high Z-order
The main reason for this is just to make show the OSC always above
console.lua, instead of a random order.

(And this is also the only reason osc.lua was changed to the new API.
The old API could have been extended, but lets not.)
2019-12-23 12:06:33 +01:00
wm4 490b3ba007 osc: use new overlay API
This tries to avoid the update() call if nothing changed. This brings it
more into line with the old code (the osd-overlay command simply does
not skip the update if nothing changed). I don't know whether this
matters; most likely not. Normally, code should try to avoid redundant
updates on its own, so it's not the job of the command. However, for the
OSC we simply want to reduce the differences.
2019-12-23 11:48:16 +01:00
wm4 0728726251 client API, lua: add new API for setting OSD overlays
Lua scripting has an undocumented mp.set_osd_ass() function, which is
used by osc.lua and console.lua. Apparently, 3rd party scripts also use
this. It's probably time to make this a public API.

The Lua implementation just bypassed the libmpv API. To make it usable
by any type of client, turn it into a command, "osd-overlay".

There's already a "overlay-add". Ignore it (although the manpage admits
guiltiness). I don't really want to deal with that old command. Its main
problem is that it uses global IDs, while I'd like to avoid that scripts
mess with each others overlays (whether that is accidentally or
intentionally). Maybe "overlay-add" can eventually be merged into
"osd-overlay", but I'm too lazy to do that now.

Scripting now uses the commands. There is a helper to manage OSD
overlays. The helper is very "thin"; I only want to force script authors
to use the ID allocation, which may help with putting multiple scripts
into a single .lua file without causing conflicts (basically, avoiding
singletons within a script's environment). The old set_osd_ass() is
emulated with the new API.

The JS scripting wrapper also provides a set_osd_ass() function, which
calls internal mpv API. Comment that part (to keep it compiling), but
I'm leaving it to @avih to finish the change.
2019-12-23 11:44:24 +01:00
wm4 96932fe77c lua: batch-update key bindings
Lua scripting implements key bindings by defining an input section with
all the bindings in it. Every add_key_binding() call ran a mpv command
to update this section. This caused a lot of spam at debug log levels.

Reduce the spam and more it efficient by batching updates into a single
mpv command when the script becomes inactive. This is pretty simple,
because there's already the concept of idle handlers.

This requires that the script actually goes to sleep, which might not
happen in various extremely bogus corner cases, such as polling the mpv
message queue with active waiting. Just don't do that.
2019-12-23 11:17:01 +01:00
wm4 346c651de3 manpage: document that --vo=xv breaks "boxvideo"
(OK, maybe a bit redundant, since vo=xv breaks a lot of stuff.)
2019-12-23 11:11:24 +01:00
wm4 36da3325a3 demux: stop setting dummy stream on demux_close_stream()
Demuxers can call demux_close_stream() to close the underlying stream if
it's not needed anymore. (Useful to release "heavy" resources like FDs
and sockets. Plus merely keeping a file open can have visible side
effects such as inability to unmount a filesystem or, on Windows, to do
anything with the file.)

Until now, this set demuxer->stream to a dummy stream, because most code
used to assume that the stream field is non-NULL. But this requirement
disappeared (in some cases, the stream field is already NULL), so stop
doing that. demux_lavf.c, one of the demuxers which calls this function,
still had some of this, though.
2019-12-23 11:09:42 +01:00
wm4 af6652004d stream_concat, stream_memory: more stream_origin stuff
Make concat streams use the "worst" origin of its parts, which may or
may not be what makes sense. stream_memory has no natural way to do
this, so just add a vague comment.
2019-12-23 11:03:44 +01:00
wm4 ba45b67370 bstr: remove unused bstr_splitlines() function 2019-12-23 11:01:56 +01:00
wm4 cd09ea92be demux_mf: use stream API to open list files
mf:// has an obscure feature that lets you pass a list of filenames
separated by newlines. Who knows whether anyone is using that. It opened
these listfiles with fopen(), so the recent stream origin bullshit
doesn't operate on it. Fix this by using the mpv internal stream API
instead. Unfortunately there is no fgets(), so write an ad-hoc one. (An
implementation of line reading via "stream" is still in demux_playlist,
but it's better to keep it quarantined there.)
2019-12-23 11:01:29 +01:00
TheAMM 6d93e4cb22 osc: display Santa hat for idle logo in December
During the 12th month (checked during script initialization), draw a Santa hat
on top of the idle message's logo.
Slightly refactors and optimizes the drawing process as well: reorder original
logo layers and remove redundant holes in them, use a shared line prefix
to clear the style and set start position.

Signed-off-by: wm4 <wm4@nowhere>
2019-12-23 01:45:34 +01:00
wm4 0eabc6614a client API: deprecate tick event
This is conceptually outdated and should not exist. This affects Lua
scripting and JSON IPC too.
2019-12-22 14:37:28 +01:00
Avi Halachmi (:avih) b670838b3d js: read_options: on_update: don't re-read the config file
Now that 00af718a made the lua read_options behavior much more similar
to the js behavior, the main difference was that lua does not re-read
the config file at on_update (but it does re-apply its stored content)
while js did re-read it.

Now the js on_update also does not re-read the config file and instead
applies its stored original content.

This is slightly hacky by adding an undocumented optional 4th argument
to read_options which allows overriding the config file content.
2019-12-22 14:51:13 +02:00
wm4 3267bcd210 console: reduce border size
This looks better if the ASS canvas size is used to scale according to
HiDPI factor (instead of font size).
2019-12-22 12:52:36 +01:00
wm4 b899504862 osc: use video margins only if OSC is visible
Looks awkward otherwise. This means that even if boxvideo is enabled,
nothing gets "boxed" if the OSC is set to auto-hide.
2019-12-22 12:50:29 +01:00
wm4 6bf1a83057 osc: cleanup boxvideo margin handling
Make sure it gets properly reinitialized when needed. This is especially
useful now that the OSC reacts to runtime option changes, which can
change the layout too.

This may call set_property_number() on the margin properties more often
now, but since redundant option changes are ignored now, this shouldn't
have any too bad effects.
2019-12-22 12:44:26 +01:00
wm4 12843dcea1 osc: full reinit on runtime option changes
Fuck it, just let's just reinit everything.

On a side note, the changelist parameter provided by read_options()
(here "list") is now unused. But it's not hard to provide and might be
useful for other stuff. So don't remove it from the generic
read_options() code.
2019-12-22 12:32:50 +01:00
wm4 00af718a9e lua: change runtime option change behavior
As described in the manpage changes. This makes more sense than the
previous approach, where options could "unexpectedly" stick. Although
this is still a somewhat arbitrary policy (ask many people and you'd get
a number of different expectations on what should happen), I think that
it reflects what mpv's builtin stuff does.

All the copying is annoying, but let's just hope nobody is stupid enough
to change these properties per video frame or something equally
ridiculous.
2019-12-22 12:30:53 +01:00
wm4 9e15e3ad8f demux: remove debug abort()
WHAT THE FUCK

Fixes: #7279
2019-12-22 04:57:18 +01:00
Niklas Haas 2a70140ba8 vo_gpu: vulkan: set allow_suboptimal when possible
This was added in libplacebo v1.29.0 and allows making resizes slightly
smoother for clients that already handle resize events (such as mpv).
2019-12-22 03:55:07 +01:00
Nicolas F 93a6308bb7 video/out/x11: add fs-screen fallback
Apparently there are two different options for controlling which
screen an mpv window goes onto: --fs-screen and --screen. The former
explicitly only controls which screen a fullscreened window goes onto,
but does not appear to actually care about this option at runtime for
X11, so pressing f will always fullscreen to the screen mpv is currently
on. This means the option is of questionable usefulness for starters.

Making it worse, if you use --screen=1 --fs, mpv will actually fullscreen
on screen 0, because --fs-screen isn't set. Instead of doing that, fall
back to whatever --screen is set to.
2019-12-22 02:33:48 +01:00
Abdullah Alansari e6bdd94cb2 command: fix confusing displayed aspect-ratio
For example, when a user switches the aspect-ratio display `16:9`
instead of `1.778` and `Original` instead of `-1.000`.
2019-12-22 02:32:50 +01:00
Avi Halachmi (:avih) 71ddb22b39 js: read_options: support on_update (match 478a321d)
This is a bit different than the lua code: on script-opts change it
simply re-applies the conf-file and script-opts to the options object,
and if this results in any changed value at options then on_update is
called with the changelist as argument.

This allows a value to revert back to the conf-file value if the
matching script-opts key had a different value and then got deleted.
It also guarantees to call back whenever the options object is
modified, which the lua code doesn't do (e.g. if the caller changed
a value and the observer changed it back - it won't detect a change).
2019-12-21 14:57:10 +02:00
wm4 05fb6f906d osc: cosmetics: remove some excessive whitespace 2019-12-20 14:25:56 +01:00
wm4 b439588172 osc: react to script-opts runtime changes
With special attention to changing osc-visibility. Untested, although
osc-visibility works (it's pretty much equivalent to the key binding, so
there is not much interesting going on).

Somewhat inspired by code posted by github user CogentRedTester.

Fixes: #4513
2019-12-20 14:24:36 +01:00
wm4 478a321dcc lua: add a helper for runtime script option changes
A script can use this to easily get runtime updates. (Even if
script-opts is sort of clunky.)
2019-12-20 14:21:16 +01:00
wm4 db1e28f175 osc: rearrange hidetimeout/visibiltiy handling
The way how this modifies and backups/restores user option values is a
bit of a problem for runtime option changing.

Clean this up a little. Now cycling the visibility updates the user
option value, but always to "valid" values (unlike hidetimeout used to
be used). If the user option value is changed externally (enabled by a
later commit), it'll be cleanly overwritten.
2019-12-20 13:44:59 +01:00
wm4 70c5401952 osc: move windowcontrols option code to the right place
There doesn't seem to be a reason why it was where it was. It should be
in validate_user_opts(), which will be important for runtime changing
too.
2019-12-20 13:21:49 +01:00
wm4 7338e3d8fe manpage: add osc and console default keys to keyboard control section
Although they were not undocumented, they were hidden away in the
respective manpage sections. It's a good idea to add them to the main
keyboard bindings overview too. stats.lua also did this.
2019-12-20 13:00:39 +01:00
wm4 05cd4c9e08 console: use hidpi scale reporting
I decided to factor this into the user's scale option (instead of
somehow using it as default if the user has not specified it), because
it makes the option handling simpler, and won't break things like
per-screen DPI if the user only wants to scale the console font by a
factor.
2019-12-20 13:00:39 +01:00
wm4 ac474631c1 x11: implement hidpi scale reporting
(X11 does not support different per-screen DPI (or only via hacks), so
this is pretty simple. If other backends are going to implement this,
then they should send VO_EVENT_WIN_STATE if the DPI for the mpv window
changes by moving it to another screen or such.)
2019-12-20 13:00:39 +01:00
wm4 8e620c8e76 command: add property returning hidpi scale 2019-12-20 13:00:39 +01:00
wm4 8448fe0b62 demux: add an option to control tag charset
Fucking gross that you need this in almost-2020.

Fixes: #7255
2019-12-20 13:00:39 +01:00
wm4 0e98b2ad8e edl: accept arbitrary paths
Until now, .edl files accepted only "simple" filenames, i.e. no relative
or absolute paths, no URLs. Now that the origin bullshit is a bit
cleaned up and enforced in the EDL code, there's absolutely no reason to
keep this.

The new code behaves somewhat similar to playlists. (Although playlists
are special because they're not truly recursively opened.)
2019-12-20 13:00:39 +01:00
wm4 1cb9e7efb8 stream, demux: redo origin policy thing
mpv has a very weak and very annoying policy that determines whether a
playlist should be used or not. For example, if you play a remote
playlist, you usually don't want it to be able to read local filesystem
entries. (Although for a media player the impact is small I guess.)

It's weak and annoying as in that it does not prevent certain cases
which could be interpreted as bad in some cases, such as allowing
playlists on the local filesystem to reference remote URLs. It probably
barely makes sense, but we just want to exclude some other "definitely
not a good idea" things, all while playlists generally just work, so
whatever.

The policy is:
- from the command line anything is played
- local playlists can reference anything except "unsafe" streams
  ("unsafe" means special stream inputs like libavfilter graphs)
- remote playlists can reference only remote URLs
- things like "memory://" and archives are "transparent" to this

This commit does... something. It replaces the weird stream flags with a
slightly clearer "origin" value, which is now consequently passed down
and used everywhere. It fixes some deviations from the described policy.

I wanted to force archives to reference only content within them, but
this would probably have been more complicated (or required different
abstractions), and I'm too lazy to figure it out, so archives are now
"transparent" (playlists within archives behave the same outside).

There may be a lot of bugs in this.

This is unfortunately a very noisy commit because:
- every stream open call now needs to pass the origin
- so does every demuxer open call (=> params param. gets mandatory)
- most stream were changed to provide the "origin" value
- the origin value needed to be passed along in a lot of places
- I was too lazy to split the commit

Fixes: #7274
2019-12-20 13:00:39 +01:00
wm4 572c32abbe libarchive: prefix entry names in archive URLs with '/'
This has the advantage that playlists within the archive will work as
expected, because demux_playlist will correctly join the archive base
URL and entry name. Before this change, it could skip before the "|",
resulting in a broken URL.
2019-12-20 08:35:08 +01:00
wm4 505cab9c15 osc: fix a comment 2019-12-20 00:53:42 +01:00
wm4 99cc13e3d1 osc: fade out if paused and mouse position is outside of OSC
This broke with the recent changes since tick() is not called regularly
anymore in paused mode. Add an explicit timer for this.
2019-12-19 22:43:22 +01:00
wm4 69fb2ddbc7 osc: fix crash when toggling visibility
The previous osc.lua related commit removed this function, and trying to
call it crashed the OSC. Just remove the call.
2019-12-19 22:10:09 +01:00
Avi Halachmi (:avih) 3460a7b696 js: support shared script properties (match 7e4819e7) 2019-12-19 16:23:19 +02:00
Avi Halachmi (:avih) 4fc5cd32d0 js: require: allow custom module search paths via mp.module_paths 2019-12-19 16:23:19 +02:00
Avi Halachmi (:avih) 3d2e30d764 DOCS: js: minor update for modules/require 2019-12-19 16:23:19 +02:00
wm4 c4ae7d8203 osc: don't run update_margins() every frame
This is something recent that also caused per frame log spam, because it
tried to update the margins every frame.
2019-12-19 12:53:37 +01:00
wm4 3ed96cca88 command: reduce OSC/stats log spam
For some inexplicable reason, the OSC runs the expand-text command a
_lot_. This command is logged at the log file default log level, so the
log file can quickly fill up with these messages. It directly violates
the mpv logging policy: per-frame (or similarly common) log messages
should not be enabled by default for the log file.

stats.lua uses the show-text command for some reason (instead of
creating its own OSD layer).

Explicitly reduce the log level for expand-text and some other commands.
Also reduce the log level for commands triggered by mouse movement.

The previous commit also contributed some to reduce log spam.

Fixes: #4771
2019-12-19 12:52:13 +01:00
wm4 48f906249e osc: use property notifications and a timer instead of "tick" events
Traditionally, the OSC used mpv's "tick" event, which was approximately
sent once per video frame. It didn't try to track any other state, and
just updated everything.

This is sort of a problem in many corner cases and non-corner cases. For
example, it would eat CPU in the paused state (probably to some degree
also the mpv core's fault), or would waste power or even throw errors
("event queue overflows") on high FPS video.

Change this to not using the tick event. Instead, react to a number of
property change events. Rate-limit actual redrawing with a timer; the
next update cannot happen sooner than the hardcoded 30ms OSC frame
duration. This has also the effect that multiple successive updates are
(mostly) coalesced.

This means the OSC won't eat your CPU when the player is fucking paused.
(It'll still update if e.g. the cache is growing, though.) There is some
potential for bugs whenever it uses properties that are not explicitly
observed. (In theory we could easily change this to a reactive concept
to avoid such things, but whatever.)
2019-12-19 12:41:01 +01:00
wm4 ce9d2c9f8e client API: remove comment about error status
mpv_event_property (for property observation) actually never sets an
error status. You cannot distinguish between unavailable properties and
properties which returned an error. Not sure if it ever did.
2019-12-19 11:21:30 +01:00
wm4 b054abe7fc manpage: lua: mention what happens on unavailable properties
Kind of as big one if the user unexpectedly gets nil instead of a value.
2019-12-19 11:19:15 +01:00
wm4 2c5cb2c53f client API: rewrite property observation (again)
I intend to rewrite this code approximately every 2 months.

Last time, I did this in commit d66eb93e5d (and 065c307e8e and
b2006eeb74). It was intended to remove the roundabout synchronous
thread "ping pong" when observing properties. At first, the original
async. code was replaced with some nice mostly synchronous code. But
then an async. code path had to be added for vo_libmpv, and finally the
sync. code was dropped because it broke in other obscure cases (like the
Objective-C Cocoa backend).

Try again. This time, update properties entirely on the main thread.
Updates get batched out on every playloop iteration. (At first I wanted
it to make it every time the player goes to sleep, but that might starve
API clients if the playloop get saturated.) One nice thing is that
clients only get woken up once all changed events have been sent, which
might reduce overhead.

While this sounds simple, it's not. The main problem is that reading
properties must not block the client API, i.e. no client API locks can
be held while reading the property. Maybe eventually we can avoid this
requirement, but currently it's just a fact. This means we have to
iterate over all clients and then over all properties (of each client),
all while releasing all locks when updating a property. Solve this by
rechecking on each iteration whether the list changed, and if so,
aborting the iteration and redo it "next time".

High risk change, expect bugs such as crashes and missing property
updates.
2019-12-19 11:11:51 +01:00
wm4 f719b63840 options: fix incorrect deprecation message
Passing multiple items to a key/value option is OK, only for -add
suffixed options it's deprecated.
2019-12-19 01:17:01 +01:00
wm4 7142214243 options: fix UB/crash in key/values parser
keyvalue_list_find_key() was called on a "partially" constructed list,
because the terminating NULL was added only later. Didn't I say this
code is cursed?

Fixes: #7273
2019-12-18 18:44:21 +01:00
wm4 09ea3a424f console: adjust position to OSC
See previous commit.
2019-12-18 09:04:15 +01:00
wm4 4787eb594a osc: make margins available
This is for console.lua (see next commit). The idea is that console.lua
can adjust its offset to the bottom of the window by the height of the
OSC.

If the OSC is not set to permanently visible, export no margins, because
it would look weird to move the console depending on the mouse movement.
2019-12-18 09:03:32 +01:00
wm4 7e4819e705 command, lua: add a way to share data between scripts
Very primitive and dumb, but fulfils its purpose for the next commits.

I chose this specific implementation because it has the lowest footprint
in command.c, without resorting to crazy hacks such as sending messages
between scripts (which would be hard to coordinate especially on
startup).
2019-12-18 08:58:49 +01:00
wm4 6ab013cbdd command: make change-list work with pure properties too
Until now, it only worked on options. Useful for the next commit.
2019-12-18 07:50:48 +01:00
wm4 11d35b72a6 x11: fix X property out of bounds memory reads
The size overflow check was inverted: instead of allowing reading only
the first dst_size bytes of the property, it allowed copying past the
property buffer (as returned by xlib). xlib doesn't return the size of
the buffer in bytes, so it has to be computed and checked manually.

Wouldn't it be great if C allowed me to write the overflow check in a
readable way, so it doesn't trick me into writing dumb security bugs?

Relying on X security is even dumber than creating a X security bug,
though, so this was not a real problem. But I found that one specific
call tried to read more than what the property provided, so reduce that.

Also, len*ib obviously can't overflow, so there's an additional layer of
dumb to this whole thing.

While we're at dumb things, why the hell does xlib use "long" for 32 bit
types. It's a god damn pain.
2019-12-18 07:12:53 +01:00
wm4 5f74ed5828 options: deprecate -del for list options
I never liked that these used integer indexes. -remove should have
existed from the start. This deprecation is yet another empty threat,
though.
2019-12-18 06:57:24 +01:00
wm4 9b9307ea9f options: fix filter list comparison (again)
This was completely broken: it compared the first item of the filter
list only. Apparently I forgot that this is a list. This probably broke
aspects of runtime filter changing probably since commit  b16cea750f.

Fix this, and remove some redundant code from obj_settings_equals().
Which is not the same as m_obj_settings_equal(), so rename it to make
confusing them harder. (obj_setting_match() has these very weird label
semantics that should probably just be killed. Or not.)
2019-12-18 06:49:48 +01:00
wm4 0a1588d39b options: add -remove action to list options
Actually I wanted this for key/value lists only, but add it to the
others for consistency too. (For vf/af it barely makes even sense, but
anyway.)
2019-12-18 06:31:39 +01:00
wm4 8bdedf9062 options: make keys in key/value lists unique
I don't even know anymore whether this was intended or not. Certain use
cases for the "-o" options might require this. These options are for
passing general FFmpeg options. These are translated to av_opt_set()
calls, which may or may not accumulate the option values on multiple
calls with the same option name (how should I know?).

Anyway, it seems crazy to allow non-unique keys, so make them unique.

The ad-hoc nature of the option code makes this wonderfully complicated
(when I wrote that this code is cursed, I meant it). In combination with
lazy testing, it probably means there are lots of bugs here.
2019-12-18 06:03:39 +01:00
wm4 d3e3bd4307 options: increase consistency between list options and document them
Whenever I deal with this, I have to look at the code to make sense of
this. And beyond that, there are some strange inconsistencies. (I think
this code is cursed. It always was, and maybe always will be.)

Although the manpage claimed that using multiple items for -add etc. is
deprecated, string list options didn't warn against it. So add the
warning, and add something in the changelog (even though nobody will
ever read this).

The manpage mentioned --vf-append, but this didn't even exist. So add
it, I guess. We encourage using -append for the other option types, so
for consistency, it should work on filter options. (And I already
tricked me into believing it existed when I mentioned it in the
manpage.)

Make the "operations" table separate for all option types, and mention
the option type on every single of the top-level list options.
2019-12-18 05:32:02 +01:00
wm4 bd96b97170 vd_lavc: add gross workaround for nvdec/libavcodec broken API issue
libavcodec's nvdec wrapper can return invalid frames, that do not have
any data fields set. This is not allowed by the API, but why would they
follow their own API?

Add a workaround to specifically detect this situation. In practice,
this should fall back to software decoding if it happens too often in a
row. (But single errors are still tolerated, because I don't know why.)

Untested due to lack of hardware from the regrettable graphics company.

Better do this here than deal with the moronic project we unfortunately
depend on.

See: #7185
2019-12-18 01:56:50 +01:00
wm4 06c9c38199 f_lavfi: add gross workaround for af_dynaudnorm bug
Better do this here than deal with the moronic project we unfortunately
depend on.

The workaround is generic; unknown whether it works correctly with
multi-input/output filters or filter graphs. It assumes that if all
inputs are EOF, and all outputs are EAGAIN, the bug happened.

This is pretty tricky, because anything could happen. Any time some form
of progress is made, the got_eagain state needs to be reset, because the
filter pad's state could have changed.
2019-12-18 01:44:20 +01:00
der richter 0b9bc6f180 cocoa-cb: report fullscreen state for legacy fullscreen
report the fs screen state when the fullscreen is externally triggered
for the legacy fullscreen.
2019-12-17 23:48:13 +01:00
wm4 2a4d7c4aa8 command, vo: remove old option change notification mechanisms
These all have been replaced recently.

There was a leftover in window.swift. It couldn't have done anything
useful in the current state of the code, so drop these lines.
2019-12-17 23:18:17 +01:00
wm4 13dff3073d client API: remove some dead code
This was for the "suspend" API, which has been removed (turned into
stubs) a long time ago.
2019-12-17 23:11:15 +01:00
wm4 e75d28effd command: slightly simplify input-ipc-server change detection/init
The generic change detection now handles this just as well.

The way how this function is manually called at init is slightly gross.
Make that part slightly more explicit to hopefully avoid confusion.
2019-12-17 23:06:10 +01:00
Jan Ekström df7d5a1689 video/w32_common: follow updates to the border option instead of VOCTRL_BORDER 2019-12-18 00:02:49 +02:00
Jan Ekström 6554db47ab video/w32_common: follow updates to the ontop option instead of VOCTRL_ONTOP 2019-12-18 00:02:49 +02:00
Jan Ekström ee75908134 video/w32_common: move minimized state signaling to where it happens
WM_SIZE is the message we receive from which we can infer if we got
minimized or not.
2019-12-18 00:02:49 +02:00
Jan Ekström 8200304768 video/w32_common: switch full screening to options cache
* Instead of following VOCTRL_FULLSCREEN, check for option changes.
* Instead of signaling VO_EVENT_FULLSCREEN_STATE, update the cached
  option structure and have it propagated to the origin.

Additionally, gets rid of all the straight usage of the VO options
structure.

Done in a similar style to the Wayland common file, where in case
of reading the value, the "payload" from cache is utilized.
2019-12-18 00:02:49 +02:00
wm4 0bf0efd6d3 demux_edl: fix reusing segment source files
EDL files can have multiple segments taken from the same source file. In
this case, the source file is supposed to be opened only once. This
stopped working, and it created a new demuxer instance for every single
segment entry. This made it slow and made it use much more memory than
needed.

This was because it tried to iterate over the array of source files, but
the array count (num_parts) was only set to a non-0 value later. Fix
this by maintaining the count correctly.

In addition, the actual code for checking whether a source can be reused
(in open_source()) regressed and stopped working correctly. d->stream
could be NULL. Use demuxer.filename instead; I'm not entirely sure
whether this is always correct, but fortunately we have a distributed
almost-AI driven test suite (called "users") which will probably find
and report such cases.

Probably broke with commit a09396ee60 or something close, but didn't
check closer.

Fixes: #7267
2019-12-17 01:57:42 +01:00
wm4 65e9139764 x11: fix --hidpi-window-scale=no on hidpi screens
In this combination, the [current-]window-scale properties still
incorrectly applied scaling.

For some reason, vo_calc_window_geometry2() handled this option
(basically ignored the dpi_scale parameter passed to it), but since the
DPI compensation for window-scale is implemented in x11_common.c, we
need to check and honor this option here too. (What a mess.)
2019-12-16 21:45:46 +01:00
wm4 5d9aa72f25 msg: fix "terminal-default" logging mode
console.lua uses "terminal-default" logging, which is supposed to return
all messages logged to the terminal to the API. Internally, this is
translated to MP_LOG_BUFFER_MSGL_TERM, which is MSGL_MAX+1, because it's
not an actual log level (blame C for not having proper sum types or
something).

Unfortunately, this unintentionally raised the internal log level to
MSGL_MAX+1. It still functioned as intended, because log messages were
simply filtered at a "later" point. But it led to every message being
formatted even if not needed. More importantly, it made mp_msg_test()
pointless (code calls this to avoid logging in "expensive" cases and if
the messages would just get discarded). Also, this broke libplacebo
logging, because the code to map the log messages did not expect a level
higher than MSGL_MAX (mp_msg_level() returned MSGL_MAX+1 too).

Fix this by not letting the dummy level value be used as log level.
Messages at terminal log level will always make it to the inner log
message dispatcher function (i.e. mp_msg_va() will call
write_msg_to_buffers()), so log buffers which use the dummy log level
don't need to adjust the actual log level at all.
2019-12-16 21:31:54 +01:00
wm4 d07b7f068d command: change "window-scale" property behavior
This is similar to the "edition" change.

I considered making this go through deprecation, but didn't have a good
idea how to do that. Maybe it's fine, because this is pretty obscure.
But it might break some API users/scripts (it certainly broke
stats.lua), and all I have to say is sorry for that.
2019-12-16 02:32:17 +01:00
wm4 9800855895 x11: scale window-scale by DPI
"window-scale" is 1.0 by default; however, x11 implicitly set that to
2.0 on hidpi screens. This made the default 2.0, which was inconsistent
with the option. The "window-scale" property jumped from 1.0 to 2.0 when
a window was created.

Avoid this by factoring the DPI into the window-scale. This makes the
UNFS_WINDOW_SIZE return a virtual size; since this value is used for the
window-scale property only, this is fine and has no further
consequences. (Originally, this was possibly meant to be used for other
purposes, but I'm perfectly fine with redoing this again should that
ever happen.)

This changes user-visible behavior, and it's as if setting window-scale
multiplies its argument by 2 suddenly. Hopefully no user will get angry.
2019-12-16 02:22:51 +01:00
wm4 1d482e42cb command: remove unnecessary mute property implementation
This only added the CONSTRICTED_TYPE thing, but it works correctly
without.
2019-12-16 01:54:06 +01:00
wm4 de0f9b9f2d m_option: clamp integer before adding a value
This is for the previous commit, and should affect behavior with the
special M_PROPERTY_GET_CONSTRICTED_TYPE mechanism only. The effect is
that cycling the "edition" property, if the option is set to "auto",
will change to the second edition instead of the first.

Normally, option values must always be within their range, so this
should not affect anything else. M_PROPERTY_GET_CONSTRICTED_TYPE is
sort-of fine with this kind of behavior.

If this affects any other M_PROPERTY_GET_CONSTRICTED_TYPE users
neqatively, I will revert the change.
2019-12-16 01:52:52 +01:00
wm4 aa5f234b43 command: change "edition" property behavior
See manpage/changelog changes.

The purpose of this change is to removes another case of inconsistent
property behavior. At first I wanted to make this go through deprecation
before making a technically incompatible change, but then I considered
this feature too obscure as that anyone would care.
2019-12-16 01:47:06 +01:00
wm4 76a92fd30b player: avoid underrun wakeup loop
The VO underrun detection (just a weak heuristic) added in commit f26dfb
flagged the underrun state every time it was checked, and since the
check happened in every playloop iteration, this caused the playloop to
wake up itself on every iteration. It burned an entire core while in
this state.

Fix this by flagging this condition only once (as it should be), and
requiring that a frame is displayed to trigger it again. This makes it
work similar as the audio underrun check.

The bug report referenced below says --demuxer-thread=no avoided this.
This is because the demuxer layer doesn't do proper underrun reporting
if the reader thread is disabled.

Fixes: #7259
2019-12-16 01:15:43 +01:00
wm4 31eb2f9f33 build: downgrade EGL requirement from 1.5 to 1.4
With the previous commit, there's no need for 1.5 anymore. And in fact,
it's just too dangerous to rely on 1.5 because of all the EGL craziness.
For example, you might get a 1.5 EGL system library, but a driver might
still give you 1.4 at runtime. If you assume that you can call 1.5
functions, you will probably get random crashes in this case. What a
cursed API. (The same problem exists with EGL 1.3, but fortunately
nothing seems to use that anymore. We can just ignore that problem.)
2019-12-16 00:37:18 +01:00
wm4 e1586585b4 vo_gpu: opengl: make it work with EGL 1.4
This tries to deal with the crazy EGL situation. The summary is:

- using eglGetDisplay() with multiple windowing platforms doesn't really
  work, but Mesa had an awful hack for it
- this hack can be disabled at build time, and some distros sometimes
  accidentally or intentionally do so
- Mesa will probably eventually disable it by default
- we switched to eglGetPlatformDisplay(), but this requires EGL 1.5
- the very regrettable graphics company (also known as Nvidia) ships
  drivers (for old hardware I think) that are EGL 1.4 only
- that means even though we "require" EGL 1.5 and link against it, the
  runtime EGL may be 1.4
- trying to run mpv there crashes in the dynamic linker
- so we have to go through some more awful compatibility hacks

This commit tries to do it "properly", but using EGL 1.4 as base. The
plaform selection mechanism is a messy extension there, which got
elevated to core API in 1.5 (but OF COURSE in incompatible ways).

I'm not sure whether the EGL 1.5 code path (by parsing the EGL_VERSION)
is really needed, but if you ask me, it feels slightly saner not to rely
on an EGL 1.4 kludge forever. But maybe this is just an instance of
self-harm, since they will most likely never drop or not provide this
API.

Also, unlike before, we actually check the extension string for the
individual platform extensions, because who knows, some EGL
implementations might curse us if we pass unknown platform parameters.
(But actually, the more I think about this, the more bullshit it is.)

X11 and Wayland were the only ones trying to call eglGetPlatformDisplay,
so they're the only ones which are adjusted in this commit.

Unfortunately, correct function of this commit is unconfirmed. It's
possible that it crashes with the old drivers mentioned above.

Why didn't they solve it like this:

struct native_display {
    int platform_type;
    void *native_display;
};

Could have kept eglGetDisplay() without all the obnoxious extension BS.
2019-12-16 00:25:51 +01:00
wm4 4ae43a1c40 vd_lavc: fix broken assert()
This assert() sometimes triggered (and still triggers) with lavc API
bugs. It tries to check that at least 1 plane is set to a non-NULL
value. Obviously, a valid frame returned by successful decoding should
never have it.

The problem is that some hwdecs use integer surface IDs cast to a
pointer. Recently, it happened that newer Intel drivers started using
surface ID 0 under certain circumstances (for unknown reasons), which
triggers this assert.

Just get rid of it.

For the sake of #7185, add an assert() specifically for nvdec. That
failure needs to be further analyzed, is probably a FFmpeg bug, and
without this assert() would just crash somewhere further down the video
chain.

Fixes: #7261
2019-12-15 23:40:11 +01:00
wm4 2c6d42e704 vo_gpu: x11egl: log EGL config ID
Somewhat useful for debugging.
2019-12-15 23:33:23 +01:00
wm4 8e08a2ec97 vd_lavc: simplify decode return error checking
This code checked AVFrame.buf[0] instead of the decode return code to
see whether a frame was decoded. This is sort of suspicious; while I
think that the lavc API actually guarantees it, it's not intuitive
anyway. In addition, the code was unnecessarily roundabout.

Replace it with a proper error code check. Remove the other error return
(that was, or should have been, redundant before). The no-frame path is
now cleanly separated. Add an assert on the frame-returned path; if this
fails, lavc violated its own API.
2019-12-15 22:26:39 +01:00
der richter a32db637b5 mac: replace old event tap for media key support with MediaPlayer
the old event tap has several problems, like no proper priority support
or having to set accessibility permissions for mpv or the terminal.

it is now replaced by the new MediaPlayer which has proper priority
support and isn't as greedy as previously. this only includes Media Key
support and not any of the other features included in the MediaPlayer
framework, like proper Now Playing data (only set dummy data for now).
this is only available on macOS 10.12.2 and higher.

also removes some unnecessary redefines.

Fixes #6389
2019-12-15 20:07:31 +01:00
der richter 8a6ee7fe94 mac: remove Apple Remote support
the Apple Remote has long been deprecated and abandoned by Apple.
current macs don't come with support for it anymore. support might be
re-added with the next commit.
2019-12-15 20:07:31 +01:00
der richter 1eb6cbd093 cocoa-cb: fix freeing of macos_opts config group
using the MPContext as ta parent was a bad idea and shouldn't be done in
any circumstances there because it only supposed to be for internal
usage. this had the undesired effect that the options group was freed
but still used since the MPContext is freed afterwards.

instead manually free options group.
2019-12-15 20:07:11 +01:00
der richter f21a980e37 cocoa-cb: update and add more options to use new options handling
this updates and add the maximized, minimized, keepaspect and ontop
options to use the new options handling
2019-12-15 20:07:11 +01:00
der richter c8cc203735 cocoa-cb: use m_config_cache and new VOCTRL for option handling
this removes the direct access of the mp_vo_opts stuct via the vo struct
and replaces it with the m_config_cache usage. this updates the
fullscreen and window-minimized property via m_config_cache_write_opt
instead of the old mechanism via VOCTRL and event flagging. also use the
new VOCTRL_VO_OPTS_CHANGED event for fullscreen and border changes.
2019-12-15 20:07:11 +01:00
wm4 e5676a67ee DOCS/contribute.md: fix a typo 2019-12-15 16:33:58 +01:00
wm4 0de881fa72 DOCS/contribute.md: should -> must
People somehow think "should" makes things optional, even though the
wording was merely trying to account for the exception of the rule. I
guess this means programming documents should sound like we're running a
police state (which is also the ultimate outcome of all technological
development, if you weren't aware).

See: #7248
2019-12-15 14:58:51 +01:00
Philip Sequeira a6cb92c74a zsh completion: fix handling of aliases that are listed without --
Pretty sure they used to all have --, but I guess it was changed at some
point. More incentive to do this completion stuff in a more structured
way.
2019-12-15 14:17:00 +01:00
Philip Sequeira 0198bc13a1 zsh completion: use actual POSIX-compatible regex for whitespace
\s and \S aren't actually part of the spec, but it seems glibc supports
them anyway so I didn't notice when originally testing. This fixes the
script on Apple's libc and probably others that adhere more closely to
the spec.

The most direct replacement for \s would have been [[:space:]], but we
only expect to see spaces and tabs, so might as well just do that. Also
could have used [[:blank:]], which is basically a locale-aware version
of [ \t], but mpv isn't going to output anything but ASCII spaces and
tabs, so let's avoid unnecessary complexity and stick with the ASCII
literals.
2019-12-15 14:17:00 +01:00
Philip Sequeira a921c0628e zsh completion: actually make pcre optional
It was supposed to be optional already, but I misunderstood how the
re_match_pcre option worked. If it's set, it will try to use PCRE
matching whether it's available or not (and blow up if it's not). So,
first try to load the module it'll use, and only set the option if that
works.

Fixes #7240.
2019-12-15 14:17:00 +01:00
Down Thomas 698a6a2747 osxbundle: simplify process_libraries() to eliminate leafs()
Instead of traversing across leafs() which can lead to an infinite
loop issue with cross-linked libraries, use the dictionary
(libs_dict) created by libraries() to create a set (libs_set) of
every unique library. Every value in libs_dict is also a key in
libs_dict, so every unique library linked to mpv will be a key in
libs_dict. Use set() on libs_dict to return a set of the keys from
libs_dict, and remove binary from the set so that a duplicate of
the binary is not added to the libs directory.

Iterate over libs_set to bundle dylibs while using the libs_dict
to determine which install_names to change.
2019-12-15 12:33:25 +01:00
wm4 2dbe33ce83 DOCS: mention that mpv doesn't build with MSVC
And troll Microsoft slightly while we're at it. But is it trolling if
it's the truth?

The level of C99 support in MSVC is probably a bit better than most
people think, but it's by far not adequate. We need a bit of either C11
or GNU extensions too, and rely on some MinGW helpers (that look like
they're provided by MS, except they're not).
2019-12-14 16:05:54 +01:00
wm4 aab0116e7d player: fix an outdated comment
The client API doesn't use input_ctx anymore, and the "wakeup" flag is
gone (if it even existed at all).
2019-12-14 14:18:40 +01:00
wm4 1f1d2d5f49 player: move point at which queued seeks are applied
Do it after decoding etc., but before waiting for input. This seems to
make more sense, because whether a queued seek can be applied depends on
the playback state. So it sounds like a good idea to apply the seek
first thing, but it's a bad idea to go to sleep if there's still a
queued seek pending (that couldn't be processed earlier).

Also add an empty line before mp_wait_events(); it doesn't really have
to do with the filter bullshit.
2019-12-14 14:18:10 +01:00
wm4 57fbc9cd76 player: make repeated hr-seeks past EOF trigger EOF as expected
If you have a normal file with audio and video, and keep "spamming"
forward hr-seeks, the player just kept showing the last video frame
instead of exiting or playing the next file. This started happening
since commit 6bcda94cb. Although not a bug per se, it was odd, and very
user-noticable.

The main problem was that the pending seek command was processed before
the EOF was "noticed". Processing the command reset everything, so the
player did not terminate playback, but repeated the seek.

This commit restores the old behavior.

For one, it makes video return the correct status (video.c). The
parameter is a bit ugly, but better than duplicating the logic or having
another MPContext field. (As a minor detail, setting r=VD_EOF makes sure
have_new_frame() returns true, rather than going through another
iteration or whatever the hell will happen instead, which would clobber
logical_eof.)

Another thing is making the seek logic actually wait until the seek
outcome has been determined if audio is also active. Audio needs to wait
for video in order to get the video seek target position. (Which in turn
is because hr-seek still "snaps" to video frames. You can't seek in
between two frames, so audio can't just use the seek target, but always
has to wait on the timestamp of the video frame. This has other
disadvantages and is a misdesign, but not something I'll fix today.)

In theory, this might make hr-seeks less responsive, because it needs to
fully decode/filter the audio too, but in practice most time is spent on
video, which had to be fully decoded before this change. (In general,
hr-seek could probably just show a random frame when a queued hr-seek
overrides the current hr-seek, which would probably lead to a better
user experience, but that's out of scope.)

Fixes: #7206
2019-12-14 14:17:16 +01:00
wm4 23c5965d47 player: cosmetically restructure a small function
No actual functional changes. Just preparation for the next commit, to
reduce its diff.
2019-12-14 14:15:57 +01:00
wm4 ad2cda343b player: add comment to clarify FFmpeg ABI handling
Don't patch it out.
2019-12-13 13:22:46 +01:00
Philip Langdale 2a0a595e37 osc: set the wrap style for the title shown with window controls
I missed adding this when defining the style used for the video
title in the window control bar. The default behaviour is to wrap,
but we want to cut the title off when we run out of space.
2019-12-12 13:12:16 -08:00
wm4 19bd69e5e3 cocoa_common: remove deprecated VOCTRLs/VO_EVENTs
See commit 4e4252f916 and the following as an example how this would
have to be done if done properly.

Since I'm unable to test on OSX, and nobody is interested in fixing this
code (including myself, actually), just remove the deprecated
definitions to make sure the code still builds. This will break runtime
switching of fullscreen, ontop, border. (The way the minimized state is
reported was also deprecated, but commit 40c2f2eeb0 already broke it
anyway.)
2019-12-12 19:56:03 +01:00
wm4 22e4aac9fa wayland: remove unnecessary VO_EVENT_FULLSCREEN_STATE
This is needed and used only for VOCTRL_GET_FULLSCREEN, which the
wayland code got rid of.
2019-12-12 14:47:52 +01:00
wm4 aee413d246 manpage: fix --vulkan-async-compute default value
Seems like this was silently changed to enabled by default on the change
to libplacebo, without adjusting the manpage. Fix the documented
default.

Also add a comment about Nvidia; see referenced issue.

Fixes: #7245
2019-12-12 12:46:59 +01:00
wm4 cc746c9508 vo_gpu: x11egl: cleanup EGL correctly
...probably.

The EGL backend had a strange problem: when recreating the window, EGL
surface creation sometimes mysteriously failed. For example, keeping the
"_" key down (cycles video by default) destroys and recreates the window
in rapid succession, which will often enough show the "Could not create
EGL surface!" message.

This was puzzling because due to mpv's architecture, the X11 Window and
even the X11 Display were fully destroyed, the thread on which they ran
was destroyed, and then everything was recreated. There shouldn't have
been any state that could make subsequent EGL initialization fail.

It turns out mpv forgot to free EGLSurfaces in the x11 code. EGL is a
pretty crazy API (full of thread local and global state with weird
lifetime requirements), and for example it seems EGLDisplay cannot be
explicitly released, but apparently implicitly dies when the native
display is closed (at least EGL 1.5 claims eglTerminate() does _not_
invalidate the display, only certain objects linked to it). It appears
that Mesa still referenced at least EGLSurface in some form, and either
some pointer or some X11 ID was dangling, and when it randomly matched
when eglCreateWindowSurface() was called, it failed.

Fix this by calling eglTerminate(), which supposedly destroys (or rather
unreferences) contexts and surfaces created from the display (but
absurdly not the display itself).

Now why can't you just destroy the display? If it's implicitly
invalidated, why can't it just call eglTerminate() implicitly when this
happens? Did Mesa do something wrong when they somehow didn't
automatically remove the dangling object (so I could claim not to be
responsible for the bug)? Who the fuck knows, and I'm too tired to
figure this out (both because it's late, and because I'm tired of this
EGL crap API).

Still not sure if the code is correct now. I think EGL was designed to
maximize implementation and API-use complications. How else could you
possibly come up with something like the EGLDisplay life cycle? Or am I
just making a fuss? Anyway, fuck EGL, fuck computers, fuck technology.

Fixes: #7129
2019-12-12 01:50:05 +01:00
Philip Langdale db3754d8d6 osc: use custom symbols for window controls
I was recently informed that unicode has official symbols for
window controls, and I put together a change to use them, which
worked, as long as a suitable font was installed. However, it's
not that hard to get a normal system that lacks an appropriate
font, and libass wants to print warnings if the symbols aren't
in the default font, which will almost always be true.

So, I gave up and added the symbols to the custom osd font that
we already have. This ensures they are always available, and
that they are aligned consistently on all platforms.

I took the symbols from the `symbola` font, as this has a suitable
licence and the symbols look nice enough.

Symbola Licence:

    Fonts are free for any use; they may be opened, edited,
    modified, regenerated, packaged and redistributed.

Finally, as we now have access to an un-maximize symbol, I added
logic to use it when the window is maximized.
2019-12-11 13:53:10 -08:00
wm4 59cdfe50b2 rpi: destroy fullscreen change handling
Get rid of the legacy VOCTRL (which will be removed later). I'm not sure
what exactly fullscreen was supposed to do (toggling between using the
entire display, and what --geometry forced?), but I don't care, just get
rid of the VOCTRL. PRs to fix regressions caused by this will be
accepted, but personally I don't care since this is excessively fringe
and obscure.
2019-12-11 18:50:37 +01:00
wm4 b6fa63b01e vo_sdl: use new fullscreen change mechanism
Like the other backends. (Looks relatively convoluted, because it only
uses the fullscreen legacy VOCTRL, none of the others.)
2019-12-11 18:47:57 +01:00
wm4 c84460f61f build: add -Wimplicit-fallthrough
This warning seems to be designed well. It doesn't seem to warn on
fallthrough-only case statements, so it's compatible to well written
code.

stream_dvdnav.c had an obscure bug in inactive code, fix it.
stream_dvb.c is the only place where it intentionally falls through, I
guess I'll just leave it alone.
2019-12-11 17:28:47 +01:00
dudemanguy c68251a3a7 wayland: adjust hidden state detection
The wayland backend needs to keep track of whether or not a window is
hidden for presentation time. There is no presentation feedback when a
window is hidden which means we shouldn't be sending information to the
vo_sync_info structure (i.e. just leave it all at -1). This seemed to
work fine, but recent changes to presentation time in one notable
compositor (Sway; it was probably always broken in Weston actually)
changed the presentation time behavior.

For reasons that aren't clear, there is a greater than 16.666ms delay
between the first presentation time event and the second presentation
time event (compositor latency?) when you switch back to an mpv window
after it is hidden for long enough (a few seconds). When using
presentation time, this causes mpv to feed in some bad values in its
vsync timing mechanism thus causing the A/V desync spike as described in
issue #7223.

This solution is not really ideal. It would be better if the
presentation time events received by the compositors did not have the
aforementioned inconsistency. However since this occurs in both Sway and
Weston and clients can't really fight compositors in wayland-world,
here's a reasonable enough workaround. Basically, just add a slight
delay before we start feeding information into the vo_sync_info again.
We already do this when the window is hidden, so it's not a huge leap.

The delay chosen here is arbitrary, and it basically just recycles the
same parameters used to detect if a window is hidden. If
vo_wayland_wait_frame times out 60 times in a row (or whatever your
monitor's refresh rate is), then we assume the window is hidden. This is
a pretty safe assumption; something has to be terribly wrong for you to
miss 60 vblanks in a row while a window is on the screen.

In this case, we basically just do the reverse of that. If mpv receives
60 frame callbacks in a row (or whatever your monitor's refresh rate
is), then it assumes the window is not hidden. Previously, as soon as it
received 1 frame callback it was declared not hidden. Essentially,
there's just 1 second of delay after reshowing a window before the
presentation time statistics are used again. This should be more than
enough time to skip over the weird inconsistent behavior presentation
time behavior and avoid the A/V desync spike.

Fixes #7223
2019-12-10 17:55:43 +00:00
Philip Langdale 59b0fec508 osc: explicitly re-init the osc on a change in border visibility
I had previously wondered whether to do this, but in my testing
with x11 and wayland, the osc was being re-inited on a border
toggle already so I didn't add it.

However, on win32, things are different and there is no re-init
when toggling borders. I belive this is because the active window
size doesn't change in anyway, while on x11/wayland, toggling the
border actually changes the window size - and that trigger a re-init.

So, let's just be explicit and request a re-init when the border
is toggled.
2019-12-09 21:02:17 -08:00
James Ross-Gowan b3b2cc44fa console.lua: add this script
Merged from mpv-repl git repo commit 5ea2bf64f9c239f0326b02. Some
changes were made on top of it:

- Tabs were converted to 4 spaces indentation (plus some manual
  indentation fixes in some places).
- All user-visible mentions of "repl" were renamed to "console".
- The README was converted to a manpage (with heavy changes, some
  additions taken from stats.rst; rossy converted the key bindings
  table to RST).
- The method to change the default key binding was changed.
- Change minor detail about "font" default value setting (not a
  functional change).
- Integrate into the player as builtin script, including an option to
  prevent loading it.

Above changes and commit message done by wm4.

Signed-off-by: wm4 <wm4@nowhere>
2019-12-08 02:46:44 +01:00
Anton Kindestam b2b15d4e6e vo_drm: replace drmModeAddFB usage with drmModeAddFB2
drmModeAddFB is legacy, and might not pick the pixel format you
expect, depending on your driver. Use drmModeAddFB2 which specifies
this explicitly using a fourcc.
2019-12-07 19:23:58 +01:00
Anton Kindestam d5cabf7348 drm: avoid division by 0 in drm_pflip_cb with bad drivers
Seems like some drivers only increment msc every other page flip when
running in interlaced mode (I'm looking at you nouveau). I.e. it seems
to be incremented at the frame rate, rather than the field rate.
Obviously we can't work with this, so shame the driver and bail.

On intel this isn't an issue, as msc is incremented at field rate
there.

This means presentation feedback won't work correctly in interlaced
modes with those drivers, but who in their right mind uses an
interlaced mode these days, anyway?
2019-12-07 18:34:25 +01:00
sfan5 83b742df77 drm_common: fix display FPS estimation for interlaced modes 2019-12-07 16:44:27 +01:00
sfan5 376e57ee7b vo_drm: fix potentially broken capability check
If the capability is available it may still be 0 to signal absence of support.
2019-12-07 16:44:27 +01:00
sfan5 823f52f91f drm_common: log more useful things 2019-12-07 16:44:27 +01:00
wm4 b36e8569a1 lua: make later key bindings always have higher priority
Later calls to mp.add_key_binding() should take priority over previous
calls with the same key. Until now, the order was random (due to using
table pairs() iteration order).

Do this by simply sorting by a counter that is never reset. Since
input.c also gives later bindings priority, this works out.

Calling mp.remove_key_binding() on a newer binding makes an older still
existing binding with the same key active again. New bindings override
older ones, but do not overwrite them. I think these are good semantics
for most use cases.

(Note that the Lua code cannot determine whether two bindings use the
same key. Keys are strings, and two different strings could refer to the
same key. The code does not have access to input.c's key name
normalization, so it cannot compare them.)
2019-12-07 14:53:33 +01:00
wm4 855a4779ae filters: move prefix check from f_lavfi.c to user_filters.c
It's user_filters.c which allows the "lavfi-" prefix to distinguish
libavfilter filters from mpv builtin filters. f_lavfi.c is a layer
below, and strictly passes anything it gets to libavfilter. So the
correct place for this is in user_filters.c, which also has the code for
stripping the prefix in the normal filter instantiation code.
2019-12-07 14:19:11 +01:00
wm4 d90d5ee1a0 vo_gpu: hwdec_vaapi_gl: use gl_check_extension() instead of strstr()
In theory, using strstr() to search for extensions is a bad idea,
because some extension names might be prefixes for other names, so you
could get false positives. gl_check_extension() avoids this case.

It's not clear whether this is really needed; maybe not. Surely the EGL
committee is aware of these practices (many GL clients do this, which is
why it's widely considered bad practice), and would avoid defining new
extension names which contain existing names as sub-strings, but
whatever.
2019-12-07 14:16:30 +01:00
wm4 16b9c4c952 vo_gpu: hwdec_vaapi_gl: do not include eglext.h
Adding an ifdef mess to deal with insufficient system headers is kind of
a mess. It's easier to just provide the definitions manually. This sucks
a bit too, but it's the approach we've been using with OpenGL headers in
general, and I think that worked pretty well.
2019-12-07 14:04:43 +01:00
wm4 3cabd11f9b vo_gpu: hwdec_vaapi_gl: add missing PLANE3 defines as well
On systems whose EGL headers do not define these extensions, the build
still failed due to missing ..._PLANE3_... defines. Although we supplied
missing EGL_LINUX_DMA_BUF_EXT defines manually, the PLANE3 ones are
actually from a separate extension, which explains why they were not
added to the fallback defines in the first place.

Add them, now it builds without the eglext.h include.

See #6838.
2019-12-07 14:01:10 +01:00
wm4 23289a452f command: fix unintended reset of filters
Since the recent option changes (probably b16cea750f), using the "vf"
or "af" commands to change the filter chain did not write the option
value correctly. This led to the option value being reset the next time
an option changed.

This happened because the new option value was not copied to the
m_config_cache's internal storage. So on the next option update, it
looked like the option value changed, because the user-side value was
different from the internal value. It was copied back, which meant the
original option value was reinstated, and the previous "vf"/"af" command
was undone.

Fix this by using the correct way to store the option value. This also
takes care of property change notification (because the function is
specifically separate from m_config_cache_write_opt() to do that), so
remove the old call.

Fixes: #7220
2019-12-06 19:27:45 +01:00
wm4 b0c9f582ad player: loadfile overrides previous stop command
Both the "stop" and "loadfile" commands are asynchronous. "stop" starts
terminating playback, which used to be done in the same playloop
iteration, but now it may take longer, so a "loadfile" command can be
received while this is going on. (Possible that it used to work if the
second command was issued at least in the next playloop iteration.)

Make the "loadfile" override the "stop" mode, so the next file will be
played, instead of quitting or going into idle mode.

Unlike the referenced bug report claims, this has nothing to do with
IPC.

Fixes: #7225
2019-12-06 19:21:14 +01:00
wm4 13fe87f66b build: fix zimg message in configure output
It's useful as software scaler in general, not just that video filter.
2019-12-06 19:16:30 +01:00
ekisu 02d8d4e3ef f_lavfi: mp_lavfi_is_usable: check for "lavfi-" prefix
Without this, adding filters with the prefix would fail, and some
filters that have conflicting names with mpv ones were unusable.
2019-12-06 19:12:57 +01:00
dudemanguy 122bbb9ff4 DOCS: fix wayland-frame-wait offset value range
It actually goes down to -500 not -100.
2019-12-05 14:35:23 -06:00
wm4 000c045aa8 vo: redraw dropped frame if paused between queuing and drawing frame
When frame-stepping with display-sync mode enabled in high framerate
video, the frame was sometimes not redrawn correctly. Only the first OSD
interaction (or something similar) made it visible.

In this case, the core schedules many frames as dropped (because it's
ignorant of pausing/frame-stepping, as in theory the player is _not_
paused during frame-stepping, only at the end of it). There's a race
between the VO rendering the queued frame, and the core calling
vo_set_paused() after it has queued the frame. If the latter happens
first, the existing logic to redraw the previous dropped frame does
things correctly. If the former happens, the frame is not redrawn
automatically, but will be redrawn on the next user input (or if OSD is
enabled, and the pause state change updates it, which leads to an
immediate redraw).

Fix this by never actually dropping a frame in paused mode. The request
by the core to drop it is simply ignored.

Maybe this could be done slightly nicer by updating the pause state with
the VO atomically. Then we wouldn't have the frame drop counter going up
either (it's actually dropped, but then redrawn; but I doubt any user,
or me in a few weeks, would understand this). But I'm not really
interested in polishing this by increasing the complexity of the
frame-step code.
2019-12-04 23:55:42 +01:00
Remita Amine c23b3ac53a README: fix typo 2019-12-04 16:20:40 +01:00
Philip Langdale 353e4efdef osc: rework window control configuration to add auto mode
To aid in discoverability, and to address the most common case
directly, I'm adding an 'auto' mode for the window controls. In
this case, we will show the controls if there is no window border
and hide them if there are borders. This also respects the option
being toggled at runtime.

To ensure that it works in the wayland case, I've also made sure
that the wayland code explicitly forces the option to false if
decoration support is missing.

Based on feedback, I've split the config in two, with one option
for whether controls are active, and one for alignment. These are
new enough that we can get away with ignoring compatibility.
2019-12-04 09:32:25 +08:00
Philip Langdale f8689eff6d osc: ensure that window control show/hide zone is handled dynamically
As preparation for adding the auto mode for window controls, we need
to make sure that the controls can be successfully toggled at runtime,
rather than only being able to configure them once at startup. Right
now, there is a problem with the handling of the show/hide zone for
the window controls.

The previous fix for #7212 was to avoid registering the input mapping
for the window control show/hide zone. If there is no input mapping,
then there is no input, and the zone is a no-op, even if it exists.
But this only happens at startup. After that point, the input mapping
doesn't exist and cannot be turned on.

In this change, I'm switching the approach; we now go back to always
registering the input mapping, and instead, we zero out the show/hide
zone if window controls are disabled, and set its size appropriately
if they are enabled.
2019-12-04 09:32:25 +08:00
dudemanguy 7f300a00e9 wayland: fix cursor behavior on an edge case
This small regression was introduced by #7216. Previously, the wayland
backend used a trick which kept track of the previous fullscreen state
and used that logic for showing the cursor. Since vo_opts now keeps
track of the current fullscreen state, most of this stopped being
neccessary.

However, there was one edge case where the cursor didn't
behave the same: passing a fullscreen flag for the inital window. The
cursor would initially be visible here which is not desirable. This can
be remedied pretty easily by just setting the cursor visiblity to false
if the pointer entry event occurs on fullscreen. The only thing we need
to do is to make sure that the autohide delay isn't completely disabled
(i.e. the cursor is always visible). Hence the need for the previous
commit.
2019-12-04 00:47:05 +00:00
dudemanguy 65a317436d options: move cursor autohiding opts to mp_vo_opts
Certain backends (i.e. wayland) will need to do special things with the
mouse. It makes sense to expose the values of these options to them, so
they can behave correctly.
2019-12-04 00:47:05 +00:00
wm4 fd28be400c sd_lavc: add a hack ontop of another hack to fix completely fucked file
Do what we do best in multimedia: add conflicting hacks on top of other
hacks, that fix a single sample, and may break other ones.

In this case, it only happens if the file is most likely already broken
(subtitle bounding boxes go outside of the subtitle "canvas"), so it's
OK. The file still looks broken (and, in fact, the file is completely
fucking broken), but you can see the subtitles.

But in summary, this is not actually something I should have bothered
about.

I noticed that MPlayer shows the subtitles "correctly", but this is only
because they have a hack that extends subtitles with small resolution to
a larger hardcoded resolution. This hack was removed from mpv, because
it broke some completely legitimate files. As another really funny fact,
MPlayer's default video output (vdpau) appears to display this file
correctly, but only because it handles narrow aspect ratios (that extend
the height instead of the width) incorrectly. It extends the height, but
leaves the video with 1:1 aspect ratio at the top. It seems to repeat
the last video line. (-vo xv and -vo gl show it correctly, i.e.
stretched like mpv, by the way.) For some reason, the sample file at
hand is extended with black, so the subtitles are rendered into a black
area below the video, which is almost reasonable. So, MPlayer may
display this file "correctly", but in fact it only happens to do so
because of 1 hack that breaks legitimate files, and 1 bug. What the
fuck.

Fixes: #7218 (sort of)
2019-12-03 22:33:45 +01:00
wm4 e5b016b7bf player: don't apply weird timestamp tolerance on backstep
Hr-seek has some sort of tolerance against timestamps, where it allows
for up to 5ms deviation. This means it can work only for videos with up
to 200 FPS framerate. There were complains about how it doesn't work
with videos beyond some high fps. (1000 was mentioned, although that
sounds more like it's about the limit that .mkv has.)

I suspect this is because otherwise, it might be hard to hit a timestamp
with --start, which specifies timestamps as integer, and thus will most
likely never represent a timestamp exactly. Another part of the problem
is that mpv uses 64 bit floats for timestamps, so fractional parts are
never represented exactly. (Both the "tolerance" and using floats for
timestamps were things introduced before my time.)

Anyway, in the backstep case, we can be relatively sure that the
timestamp will be exact (as in, the same unmodified value that was
returned by the filter chain), so we can make an exception for that, in
order to fix backstep.

Untested. (For that you have users.)

May help with #7208.
2019-12-03 21:43:32 +01:00
wm4 d60bbd86e3 demux_lavf: export demuxer_id for more formats which have it
See previous commit. libavformat exports this information as AVStream.id
field.

The big problem is that the libavformat field is simply 0 if it's
unknown (i.e. the demuxer never sets it). So it needs to remain a
whitelist. Just add more formats which are known to have a meaningful
ID.

I considered exporting IDs for all formats, and then either leaving the
values as they are, or filtering duplicate values (and choosing
arbitrary but unique different IDs). But then again, I think it's sort
of mpv's job to filter FFmpeg's absurd bullshit API, and it should make
an effort to hide it rather than to reflect it.

See: #7211
2019-12-03 21:15:40 +01:00
wm4 370ed5777c demux: do not make up demuxer_id
The demuxer_id (exported in as "src-id" property) is supposed to be the
native stream ID, as it exists in the file, or -1 if that does not exist
(actually any negative value), or if it is unknown.

Until now, an ID was made up if it was missing. That seems like strange
non-sense, and I can't find the reason why it was done. But it was
probably for convenience by the EDL stuff or so.

Stop doing this. Fortunately, the src-id property was documented as
being unavailable if the ID is not known. Even the code for this was
present, it was just inactive until now. Extend input.rst with some
explanations.

Also fixing 3 other places where negative demuxer_id was ignored or
avoided.
2019-12-03 21:04:53 +01:00
Philip Langdale b6f605285c wayland: update remaining legacy VOCTRL usage to options
The remaining legacy VOCTRLs are for the fullscreen and border
properties. For fullscreen this largely just replacing the private
state field with the vo option but there are small semantic
differences that we need to be careful of.

For the border setting, it's trivial as we don't have external
mechanisms for changing the state, but I also can't test it as
I'm not using a compositor that supports it.
2019-12-02 14:14:09 +00:00
Philip Langdale 193b6fd8dd osc: don't show error if windowcontrols=yes
I always intended for this to be accepted and mean "right" but I
made it show an error for any value that's not explicitly
recognised (while considering all unrecognised values to mean "right").

So let's explicitly recognise "yes".
2019-12-02 11:04:43 +08:00
Dudemanguy 7da15ca9bd osc: don't always set window control keybindings
Only set the window control keybindings if the window control option is
actually enabled. Fixes #7212.
2019-12-01 17:23:02 -06:00
Philip Langdale 61b8e1d436 wayland: update Maximize and Minimize handling to use new options
I wanted to get this done quickly as I introduced the new VOCTRL
behaviour for minimize and maximize and it was immediately made
legacy, so best to purge it before anyone gets confused.

I did not sort out fullscreen as that's more involved and not something
I've educated myself about yet. But I did replace the VOCTRL_FULLSCREEN
usage with the new option change mechanism as that seemed simple
enough.
2019-12-01 09:39:51 +08:00
wm4 78f1629a53 vf_gpu: render subtitles
Pretty annoying affair. The vo_gpu code could of course not trigger
rendering from filters yet, so it needed to be extended. Also, this uses
some icky stuff made for vf_sub (and this was the reason I marked vf_sub
as deprecated), so everything is terrible.
2019-11-30 18:09:31 +01:00
wm4 6a88e7463e build: require at least GL 2.0 headers for GLX
The previous hack for fixing #7201 requires this, but it wasn't checked.
It's easy to check, so do it. (Yes, we could just have required OpenGL
3.2 headers and skipped the earlier fix.)

For #7201.
2019-11-30 17:37:56 +01:00
wm4 cd9fe3a843 m_config: remove change callback before unintialization
We don't want m_config uninitialization to call random change callbacks.
This happens at the end of mp_destroy(), when almost everything else is
already destroyed, and the change callbacks would probably trigger UB
all over the place.

The change callbacks could be trigger by m_config_restore_backups(),
which is just used as a cheap way to free the remaining state. The worst
is that this depends on which options may still have been part of this
"backup" state, which depends on user input.

Probably never a practical problem, since the backup state is most
likely guaranteed to be empty before uninit is performed, but still.
2019-11-30 17:33:29 +01:00
wm4 fa9a1ff0a0 vo_gpu: opengl: add hack for ancient Mesa/GLX
glx.h recursively includes gl.h, and there is no way to prevent this.
Old Mesa defines some GL symbols, but not all which mpv needs. In
particular, one user who was too lazy to update his ancient Ubuntu and
preferred to bother us with obscure bug reports, had Mesa headers which
did not define GL 3.2, so GLsync was not defined.

All in all I still think the idea of providing the GL API definitions
ourselves was a good idea; just GLX should have been isolated better.
But isolating GLX now is too much effort.

Not sure why I'm bothering with this at all.

Fixes: #7201 (unconfirmed)
2019-11-30 13:38:28 +01:00
Philip Langdale 8614cb38d9 osc: ensure the window-controls mouse area is initially zero sized
This is necessary to avoid breaking input behaviour in the 'idle'
state when not playing a video. Otherwise, the mouse area starts off
covering the whole window and blocks normal input.
2019-11-30 19:56:30 +08:00
Avi Halachmi (:avih) b67d124dc0 js: mp.add_key_binding: allow false-y name (match 311cc5b)
This is in addition to the allowed omission of name and/or flags (as
documented).
2019-11-30 12:23:47 +02:00
Avi Halachmi (:avih) abf6b22abd lua: unbreak mp.add_key_binding(key, fn)
Commit 311cc5b6 added the ability use flags while omitting name, but
broke the case where both name and flags are omitted.

Now omitting either name or flags or both works as documented.
2019-11-30 12:06:22 +02:00
Philip Langdale 2750ca597c osc: fix typo wsc_geo -> wc_geo 2019-11-30 09:14:49 +08:00
Philip Langdale 971dbcc21c osc: apply boxvideo margins to the window controls
It seems logical to account for the window controls if `boxvideo`
is in use (which has the effect of reducing the size of the video
so that the osc is not covering the video).
2019-11-30 08:56:29 +08:00
wm4 cb7048700f filters: fix incorrect #if for vf_gpu
This didn't match what is in wscript_build.py. Also, it should work on
non-X11 platforms... probably. (The condition is convoluted and almost
nonsensical, but the offscreen context creation needs to be cleaned up
anyway as soon as other backends, e.g. for win32, are added.)
2019-11-30 01:13:37 +01:00
wm4 0e376150a6 command: remove property change notification from property dispatcher
Properties should handle this themselves. This basically sent redundant
notifications. I found only two places where the "proper" notification
was missing.
2019-11-30 01:07:24 +01:00
wm4 464a045ed8 command: merge two functions
Due to recent changes, it makes no sense anymore to keep them separate.
2019-11-30 00:56:23 +01:00
wm4 56b06907a6 command: remove another unneeded hack
Now that the option-to-property bridge is gone, this is not needed
anymore. It always took the "silent" path.

Also, at least as of before this commit, this didn't correctly print a
warning when accessing a deprecated option as property. This was because
m_config_get_co_raw() was used, which intentionally does not print any
warnings, so switch to the non-raw one. (Affects only options that have
.deprecation_message set.)
2019-11-30 00:50:31 +01:00
wm4 90df6c79c9 vf_gpu: add video filter using vo_gpu's renderer
Probably pretty useless in this form (see: the wall of warnings), but
someone wanted this.

I think this should be useful to perform some automated tests, maybe.

Fixes: #7194
2019-11-29 20:37:11 +01:00
wm4 053297b1ca vo_gpu: opengl: do not free "GL" sub-allocations
This function always expects the GL struct pointer to be a talloc
allocation. So far so bad. But the terrible thing is that _lots_ of code
in mpv didn't quite get this (including the code which introduced the
way it is used this way). For example, in context_glx.c you see this:

struct priv {
    GL gl;
    ...

GL is not a talloc allocation, but since it's at the start of a talloc
allocation, it works anyway. So far so bad. But the really terrible
thing is that mpgl_load_functions2() calls talloc_free_children() on the
GL pointer, which means that all of priv's. This would be unintentional
and could create dangling pointers. And this happens at the about 1
dozen of callers. I'm amazed it didn't broke yet anywhere.

Removing this anti-pattern with making GL "implicitly" a talloc
allocation would be too much effort at this point. So just manually free
the only allocation that the function attached to GL.
2019-11-29 20:23:27 +01:00
wm4 1ccb049d3b osc: fix operation when window controls are disabled
It seems this area is simply not defined when window controls are
disabled, so ipairs() will crash on it.
2019-11-29 16:00:21 +01:00
wm4 3f7556baef x11: implement unminimization
This appears to work with IceWM.
2019-11-29 14:27:27 +01:00
Philip Langdale 2b4c867505 osc: handle deadzone and barmargin for window controls
I missed these due to only testing with my personal osc config.

The deadzone needs to be correctly handled for the window controls,
or they will fail to appear when the mouse is close to or over them.

In the process of doing that, I realised that the controls should
respect the barmargin, if set. This is because the controls should
remain aligned when layout=topbar and as the control bar is top
aligned, it should be equally affected if the user needs to set
the barmargin.

I also fixed a mistake in trying to the use the mpv-osd-symbols font
for the window controls.
2019-11-29 13:56:58 +01:00
wm4 d520258ffb x11: handle maximize/minimize with new option stuff
Should restore full functionality.

The initial state setting is a bit shoddy (instead of setting the
properties before map, we use the WM commands to change it after, so you
will see the normal window state for a moment; the WM commands do not
work on unmapped windows, so fixing this would require more code).
2019-11-29 13:56:58 +01:00
wm4 40c2f2eeb0 command: change window-minimized/window-maximized to options
Unfortunately, this breaks window state reporting for all VOs which
supported it. This can be fixed later (for x11 in the next commit).
2019-11-29 13:56:58 +01:00
wm4 d37e461eab x11: add change notification for --on-all-workspaces
Not particularly important and nobody asked for this, but demonstrates
how such things can be easily done now.
2019-11-29 13:56:58 +01:00
wm4 893f76045f x11: handle some more options with new option stuff 2019-11-29 13:56:58 +01:00
wm4 4e4252f916 x11: use new option stuff to implement fullscreen
- remove VOCTRL_FULLSCREEN and VOCTRL_GET_FULLSCREEN
- have your own m_config_cache for the fullscreen option
  (vo->opts_cache cannot be used because you lose per-option change
  notifications, and it'd be a mess anyway)
- use VOCTRL_VO_OPTS_CHANGED to update it
  (it's used for convenience)
- when updating it, check for the fullscreen option
  (wasn't sure how to do it best; currently, it compares the raw
  option pointers, but this could be changed)
- do not send VO_EVENT_FULLSCREEN_STATE on FS change
- instead write the option on FS change
  (assign in opt. struct + m_config_cache_write_opt)
2019-11-29 13:56:58 +01:00
wm4 b16cea750f player: change m_config to use new option handling mechanisms
Instead of making m_config a special-case, it more or less uses the
underlying m_config_cache/m_config_shadow APIs properly. This makes the
player core a (relatively) equivalent user of the core option API. In
particular, this means that other threads can change core options with
m_config_cache_write_opt() calls (before this commit, this merely led to
diverging option values).

An important change is that before this commit, mpctx->opts contained
the "master copy" of all option data. Now it's just another copy of the
option data, and the shadow copy is considered the master. This is why
whenever mpctx->opts is written, the change needs to be copied to the
master (thus why this commits add a bunch of m_config_notify... calls).

If another thread (e.g. a VO) changes an option, async_change_cb is now
invoked, which funnels the change notification through the player's
layers.

The new self_notification parameter on mp_option_change_callback is so
that m_config_notify... doesn't trigger recursion, and it's used in
cases where the change was already "processed". It's still needed to
trigger libmpv property updates. (I considered using an extra
m_config_cache for that, but it'd only cause problems with no
advantages.)

I think the recent changes actually forgot to send libmpv property
updates in some cases. This should fix this anyway. In some cases,
property updates are reworked, and the potential for bugs should be
lower (probably).

The primary point of this change is to allow external updates, for
example by a VO writing the fullscreen option if the window state is
changed by the window manager (rather than mpv changing it). This is not
used yet, but the following commits will.
2019-11-29 12:49:15 +01:00
wm4 5e2658c981 m_config: make m_config_cache_write_opt() check/return changes
Goes in line with the recent changes to always checking for option value
changes. The player core will use this to determine whether it should
send additional change events.
2019-11-29 12:37:41 +01:00
wm4 1cb085a82e options: get rid of GLOBAL_CONFIG hack
Just an implementation detail that can be cleaned up now. Internally,
m_config maintains a tree of m_sub_options structs, except for the root
it was not defined explicitly. GLOBAL_CONFIG was a hack to get access to
it anyway. Define it explicitly instead.
2019-11-29 12:14:43 +01:00
wm4 5083db91eb m_config: untangle new and old code somewhat
The original MPlayer m_config was essentially only responsible for
handling some command line parsing details, handling profiles, and
file-local options. And then there's the new mpv stuff (that stuff was
regretfully written by me), which is mostly associated with making
things thread-safe (includes things like making it all library-safe,
instead of stuffing all option data into global variables).

This commit tries to separate them some more. For example,
m_config_shadow (the thread-safe thing) now does not need access to
m_config anymore. m_config can hopefully be reduced to handling only the
"old" mplayer-derived mechanisms.
2019-11-29 12:14:43 +01:00
wm4 f73881fa10 m_config: allow writing options through m_config_cache
This will allow any other threads to write to the global option data in
a safe way.

The typical example for this is the fullscreen option, which needs to be
written by VO (or even some other thing running completely separate from
the main thread). We have a complicated and annoying contraption which
gets the value updated on the main thread, and this function will help
get rid of it.

As of this commit, this doesn't really work yet, because he main thread
uses its own weird copy of the option data.
2019-11-29 12:14:43 +01:00
wm4 591494b271 m_config: add fine-grained option reporting mechanism
This adds m_config_cache_get_next_changed() and the change_flags field
in m_config_cache. Both can be used to determine whether specific
options changed (rather than the entire sub-group).

Not sure if I'm very happy with that. The former rather compact
update_options() is now a bit of a mess, because it needs to be
incremental. m_config_cache_get_next_changed() will not be too nice to
use, and change_flags still relies on global "allocation" of change
flags (see UPDATE_* defines in m_option.h). If C weren't such a
primitive language that smells like grandpa, it would be nice to define
per-option change callbacks or so.

This compares options by value to determine whether they have changed.
This makes it slower in theory, but in practice it probably doesn't
matter (options are rarely changed after initialization). The
alternative would have been per-option change counters (wastes too much
memory; not a practical problem but too ugly), or keep all
m_config_caches in a global list and have bitmaps with per-option change
bits (sounds complicated). I guess the current way is OK.

Technically, this changes semantics slightly by ignoring setting an
option to the same value. Technically this wasn't a no-op, although the
effect was almost almost no-op. Some code would actually become cleaner
by ignoring such redundant change events, and them being no-op is
probably also what the user would normally assume.
2019-11-29 12:14:43 +01:00
wm4 1e6c57d4e4 m_config: move stuff around
Create a separate struct for internal fields of m_config_cache, so API
users can't just mess with stuff they shouldn't access.

Move the ts field out of m_config_data, so we don't need unnecessary
atomics in one case.

This is just preparation, and shouldn't change any behavior.
2019-11-29 12:14:43 +01:00
wm4 5b5d163a6a atomic: add mp_atomic_uint64 2019-11-29 12:14:43 +01:00
wm4 0cd612530c m_option: remove an outdated ancient comment
The exact type name (m_obj_list_t) was removed in 2013. I don't think
this stub comment helps much with understanding this complicated thing
anyway (this code is for the --vf/--af options, and makes up almost half
of m_option.c).
2019-11-29 12:14:43 +01:00
wm4 f95cdb2e97 f_output_chain: use m_option_equal()
This is used to detect whether any filters were changed. This code was
essentially ported to m_option.c.

One possible difference is how the old code did name comparison. It did
not actually compare the name (!?!?), so this might change behavior,
hopefully to the better.
2019-11-29 12:14:43 +01:00
wm4 6d82c04dca command: use m_option_equal()
No more converting the option values to a string to compare it.
2019-11-29 12:14:43 +01:00
wm4 63270ff898 m_option: add option comparison
Looks like this will be needed for fine-grained option change
notifications. There are some other parts in the player which implement
parts of this.
2019-11-29 12:14:43 +01:00
Philip Langdale 82735d1287 man/osc: fix typo 2019-11-29 18:21:35 +08:00
Philip Langdale c13d6da4d4 x11: implement minimize and maximize related VOCTRLs
This allows the pseudo client side decorations to be used under x11,
which might be desirable when running in border=no mode.
2019-11-29 18:21:19 +08:00
Philip Langdale a220f08648 osc: implement pseudo client side decorations via OSC
Today, if window decorations are not present, either because they were
disabled, or because the platform doesn't support them
(eg: gnome-shell on wayland), there are no window controls, meaning it
is not possible to minimize/maximize/close a window without knowing
keyboard shortcuts.

While you can imagine various ways of offering client side decorations,
it is attractive to consider using OSC because that is functionality
that we already have.

The main work here is defining a separate input area from the main
OSC box with its own buttons, etc.

While we could probably handle auto-detection based on whether
decorations are present or not, it's manually controlled for now.

The window control logic is mostly disconnected from the OSC itself,
except in the case of the `topbar` layout, where there has to be
coordination so that the controls don't get drawn on top of each other.

I had to do fine-positioning of the buttons based on the font on
my system, so don't be surprised if it looks wrong elsewhere.

You could also argue that window controls should be unscaled, even
if the main OSC box is scaled, but I've not tried to do this.
2019-11-29 16:56:20 +08:00
Philip Langdale 901b3dddb0 wayland: implement minimize and maximize related VOCTRLs
We primarily care about pseudo-decorations for wayland, where
the compositor may not support server-side decorations. So let's
implement the minimize and maximize commands and return the
maximized window state.
2019-11-29 16:56:20 +08:00
Philip Langdale c2bd3b1ecc command: add window-maximized and make window-minimized settable
If we want to implement window pseudo-decorations via OSC, we need a
way to tell the vo to minimize and maximize the window. Today, we have
minimized as a read-only property, and no property for maximized.

Let's made minimized settable and add a maximized property to go with
it. In turn, that requires us to add VOCTRLs for minimizing or
maximizing a window, and an additional WIN_STATE to indicate a
maximized window.
2019-11-29 16:56:20 +08:00
Philip Langdale f3c2f1f6aa wayland: restore window geometry after un-maximize
At least with gnome-shell (I know, I know), the compositor does
not provide the old window size when leaving the maximized state.
Instead, we get a toplevel_config event with a 0x0 size and no
additional states.

Today, we already save the window geometry to restore it when leaving
the fullscreen state, so we just need a small change for it to
kick in for leaving the maximized state. If I read this correctly,
we'll still respect the size passed by a compositor that actually
provides the old size.
2019-11-29 16:56:20 +08:00
Philip Langdale 5e3eb03ecf wayland: make the edge grab zone width user configurable
Rather than hard-coding the edge grab zone width, we can make it
user configurable. It seems worthwhile to have separate configs
for pointer and touch usage as the defaults should be different,
and a user might have both input methods in use.
2019-11-29 16:56:20 +08:00
Philip Langdale 4c179a27c2 wayland: add grab zone for resizing window with mouse
Today, we support resizing wayland windows when we detect a touch
event in a defined grab zone. As part of implementing
pseudo-decorations, we should have equivalent functionality for
mouse input. And if we detect support for actual decorations we
will not activate the grab zone as the decorations will provide this.
2019-11-29 16:56:20 +08:00
wm4 f09570664f DOCS/interface-changes.rst: more details about track property changes
Another subtle thing that should be mentioned. May or may not matter to
someone.
2019-11-27 20:47:43 +01:00
wm4 db3b5c9309 x11_common: don't use vo->opts directly
Use x11->opts instead of vo->opts. This doesn't matter currently, and
x11->opts is actually set to vo->opts. However, there's a chance that
either option access changes, or that the way backends integrate with
struct vo changes. This is just a preemptive change to make this less of
a mess, and it's generally a good idea to reduce accesses to struct vo
anyway.
2019-11-27 20:30:13 +01:00
wm4 7c6570402b options: remove options-to-property bridge
The previous bunch of commits made this unnecessary, so this should be
a purely internal change with no user impact.

This may or may not open the way to future improvements. Even if not,
at least the property/option interaction should now be much less buggy.
2019-11-25 20:29:43 +01:00
wm4 78bb1586d3 command: shuffle around even more crap
Convert some remaining properties to work without the option-to-property
bridge. Behavior shouldn't change (except for the corner case that it
tries to reapply the new state when setting a property, while it used to
ignore redundant sets).

As it is the case with many of these changes, much of the code is not in
its final proper state yet, but is rather a temporary workaround. For
example, these "VO flag" properties should just be fully handled in the
VO backend. (Currently, the config or VO layers don't provide enough
mechanism yet as that all the backends like x11, win32, etc. could be
changed yet, but that's another refactoring mess for another time.)

Now nothing relies on this option-to-property bridge anymore, which
opens the way to even more refactoring, which eventually may result in
tiny improvements for the end user.
2019-11-25 20:29:43 +01:00
wm4 fba7c69b8a command: change vid/aid/sid property behavior slightly
Again in line with the option-to-property bridge changes. As usual, this
causes subtle behavior changes, which may affect some users.
2019-11-25 20:29:43 +01:00
wm4 37ac43847e options: pre-check filter names when using vf/af libavfilter bridge
Until now, using a filter not in mpv's builtin filter list would assume
it's a libavfilter filter. If it wasn't, the option value was still
accepted, but creating the filter simply failed. But since this happens
after option parsing, so the result is confusing.

Improve this slightly by checking filter names. This will reject truly
unknown filters at option parsing time. Unfortunately, this still does
not check filter arguments. This would be much more complex, because
you'd have to create a dummy filter graph and allocate the filter. Maybe
another time.
2019-11-25 20:29:42 +01:00
wm4 13afc2150b command: change af/vf property behavior wrt. filter creation failures
The behavior is slightly different in a messy way. The change is in line
with the option-to-property bridge removal mentioned some commits ago
and thus is deemed necessary.
2019-11-25 01:16:03 +01:00
wm4 f5daae12ff command: remove redundant reinit_filters() call on filter change failure
This attempted to restore the old filter chain if setting a new one at
runtime failed. This is not needed anymore, because changing the filter
chain is done in a "transactional" way now.
2019-11-25 01:05:53 +01:00
wm4 5af9fefff6 f_output_chain: fix possible crash when changing filters
When changing filters at runtime (vf/af commands/properties), this could
crash due to a NULL pointer access. The code for comparing the old and
new option values (to detect changes) was simply buggy.
2019-11-25 01:04:38 +01:00
wm4 d123af34b5 m_config: discourage mp_read_option_raw()
This function is dangerous, because it disables the already basic/week
type checking the option system has at all. I'm tend towards thinking
that all of its uses should be replaced.
2019-11-25 00:52:30 +01:00
wm4 3a2dc8b22e command, options: deprecate old --display-fps behavior
See changelog and manpage changes.

(So much effort to fix an ancient dumb mistake for an option nobody
should use anyway.)
2019-11-25 00:47:53 +01:00
wm4 c26e80d0fd command: shuffle some crap around
This is preparation to get rid of the option-to-property bridge
(mp_on_set_option). This is a pretty insane thing that redirects
accesses to options to properties. It was needed in the ever ongoing
transition from something to... something else.

A good example for the need of this bridge is applying profiles at
runtime. This obviously goes through the config parser, but should also
make all changes effective, for which traditionally the property layer
is used.

There isn't much left that needs this bridge. This commit changes a
bunch of options (which also have a property implementation) to use
option change notifications instead. Many of the properties are still
left, but perform unrelated functions like OSD formatting.

This should be mostly compatible. There may be some subtle behavior
changes. For example, "hwdec" and "record-file" do not check for changes
anymore before applying them, so writing the current value to them
suddenly does something, while it was ignored before.

DVB changes untested, but should work.
2019-11-25 00:26:36 +01:00
wm4 9249887641 manpage: remove audio-file etc. caveat description
These properties actually were removed/replaced, so there is no conflict
with the options of the same name anymore. For example, there is no
"audio-file" property anymore, but you still can set "audio-files" (and
--audio-file simply maps to --audio-files-append).
2019-11-24 22:47:32 +01:00
wm4 e2e6bb496e options: remove deprecated --playlist-pos alias
This causes problems because it has the same name as a property which
behaves differently.
2019-11-24 22:39:47 +01:00
wm4 c1acb1afe1 input: use array instead of linked list for sections
Shouldn't change behavior.
2019-11-23 15:00:48 +01:00
wm4 311cc5b611 lua: make add_key_binding() rotate optional arguments correctly
add_key_binding() makes the name argument optional (in weird Lua
fashion), which did not work if there were additional arguments. So
there is no way to avoid specifying a name while passing a rp argument.
Fix this, declare this way of skipping the argument as deprecated, and
allow passing name=nil as the preferred way to skip the name argument.
2019-11-23 14:40:00 +01:00
wm4 66a46cba89 input: remove potential minor memory leak 2019-11-23 14:14:19 +01:00
Niklas Haas b31f2f6cb9 vo_gpu: fix infinite scaler reinit spam
Handling the window with this function makes no sense, since windows
and kernels are not the same thing and don't share the same option list.

The only reason it's done is to make sure the char* points at the static
string rather than the dynamically allocated one, which we can do
manually in this function. Rewrite a bit for clarity/quality.
2019-11-23 11:46:52 +01:00
wm4 2dc6b27ee7 input: export input.conf comments ot input-bindings property
This is supposed to turn input.conf comments into inline documentation.
Whether this will be useful depends on whether there'll be a script
using this field.

This changes a small aspect of input.conf parsing fundamentally: this
attempts to strip comments/whitespace from the command string, which
will later be used to generate the command when a key binding is
executed. This should not have any negative effects, but there could be
unknown bugs. (For some reason, every command is parsed when input.conf
is parsed, but it still only stores the string for the command. I guess
that saves some minor amount of memory.)
2019-11-23 01:18:49 +01:00
wm4 f379cf0bf8 command, input: add input-bindings property
Read-only information about all bindings. Somewhat hoping someone can
make a nice GUI-like overlay thing for it, which provides information
about mapped keys.
2019-11-23 01:18:49 +01:00
wm4 251069d9ea command: add command-list property 2019-11-23 01:18:49 +01:00
wm4 6e0e39b79f input: change mp_cmd.original from bstr to cstr
No reason to have this as bstr, just makes everything more complex.

Also clear mp_cmd.sender when it's copied. Otherwise it would be a
dangling pointer. Apparently it's never set to non-NULL in this
situation, but this is cleaner anyway.
2019-11-23 01:18:49 +01:00
Aman Gupta dbb5dd7c33 demux_lavf: log packet read errors
Signed-off-by: Aman Gupta <aman@tmm1.net>
2019-11-22 12:56:46 -08:00
wm4 033af5390f input: make MP_INPUT_RELEASE_ALL a pseudo-key
Should be without consequences. I think this is less trouble, because
code frequently wants to add/remove bits for modifiers and key state
from key codes, and with this change you can't accidentally break it by
testing or removing bits from the old -1 value.
2019-11-22 01:19:00 +01:00
wm4 4a90da4e1d msg: show how many messages were dropped
Although repl.lua will probably not use this.
2019-11-22 01:15:08 +01:00
wm4 65a531b8e4 msg: drop old instead of new messages on overflow
It did that because there was no other way. It used a lock-free ring
buffer, which does not support this. Use a "manual" ring buffer with
explicit locks instead, and drop messages from the start.

(We could have continued to use mp_ring, but it was already too late,
and although mp_ring is fine, using it for types other than bytes looked
awkward, and writing a ring buffer yet again seemed nicer. At least it's
not C++, where mp_ring would have been a template, and everything would
have looked like shit soup no matter what.)
2019-11-22 01:15:08 +01:00
wm4 53477ffc4b msg: fix missing wakeup callback in terminal-default log level
In the referenced commit, I forgot about this part, and a client which
tried to use this was actually not woken up when needed.

(Also why the hell does the subject line of that commit say "removed"?)

Fixes: 8c2d73f112
2019-11-22 01:15:08 +01:00
wm4 21f2468d67 input: add text produced by key to script key events
Particularly for "any_unicode" mappings, so they don't have to
special-case keys like '#' and ' ', which are normally mapped to
symbolic names for input.conf reasons. (Though admittedly, this is a
pretty minor thing, since API users could map these manually.)
2019-11-22 01:15:08 +01:00
wm4 eab5457e47 manpage: correct "complex" key binding description
The key is never nil if it's invoked through the normal input path. The
key name could be "" if mp_cmd.key_name==NULL. This should not happen,
but there's no strong guarantee in input.c that it cannot happen, so
whatever.
2019-11-22 01:15:08 +01:00
wm4 a394d9e3ae manpage: improve "complex" key binding list of table entries 2019-11-22 01:15:08 +01:00
wm4 0a6c09b96f input: introduce a pseudo key name that grabs all text input
The intended target for this is the mpv.repl script, which manually
added every single ASCII key as a separate key binding. This provides a
simpler mechanism, that will catch any kind of text input.

Due to its special nature, explicitly do not give a guarantee for
compatibility; thus the warning in input.rst.
2019-11-22 01:15:08 +01:00
wm4 a098e98198 input: fix ineffective mp_msg_test call
This was supposed not to go through key lookup if the message wasn't
going to be output, but for whatever reason the log levels were
mismatched.
2019-11-22 01:15:07 +01:00
Avi Halachmi (:avih) 67fef2b152 js: complex key binding: use key_name like the docs say 2019-11-20 16:55:21 +02:00
Avi Halachmi (:avih) 14971424b9 js: report key name for "complex" key bindings - match b08c8f50 2019-11-20 16:28:49 +02:00
Avi Halachmi (:avih) da13a3b231 lua: complex key binding: use key_name like the docs say 2019-11-20 16:28:49 +02:00
Chris Down e143966a76 player: Optionally validate st_mtime when restoring playback state
I often watch sporting events. On many occasions I get files with the
same filename for each session. For example, for F1 I might have the
following directory structure:

    F1/
        FP1.mkv
        FP2.mkv
        FP3.mkv
        Qualification.mkv
        Race.mkv

Since usually one simply watches one race after the other, I usually
just rsync the new event's files over the old ones, so, for example,
Race.mkv will be replaced from the file for the last event with the file
from the new event.

One problem with this is that I like to use --resume-playback for other
kinds of media, so I have it on by default. That works great for, say, a
movie, but doesn't work so well with this scheme, because you can
trivially forget to pass --no-resume-playback on the command line and
end up 2 hours in, watching spoilers as the race results scroll down the
screen :-)

This patch adds a new option, --resume-playback-check-mtime, which
validates that the file's mtime hasn't changed since the watch_later
configuration was saved. It does this by setting the watch_later
configuration to have the same mtime as the file after it is saved.

Switching back and forth between checking mtime and not checking mtime
works fine, as we only choose whether to compare based on it, but we
update the watch_later configuration mtime regardless of its value.
2019-11-20 15:11:33 +01:00
wm4 1649ba15ab manpage: extend documentation of key names
These things weren't written down anywhere yet.
2019-11-19 23:13:12 +01:00
wm4 b08c8f50b5 lua: report key name for "complex" key bindings
This might make certain use cases less of a mess.
2019-11-19 23:11:05 +01:00
wm4 13815bf251 manpage: deprecate input section commands
These were a bad idea and are obscure. Scripting key mapping support
still uses them, but this is not relevant to scripting authors, because
the mpv provided helper code (defaults.lua) takes care of this. In
addition, the OSC uses a legacy form of this.

Hopefully, this input section stuff can be removed, and replaced by a
simpler mechanism.
2019-11-19 23:09:59 +01:00
Aman Gupta 03fbb57bd9 audio: add ao_audiotrack for android 2019-11-19 12:10:26 -08:00
Aman Gupta 1a006d6f06 misc: add jni helpers 2019-11-19 12:10:26 -08:00
Aman Gupta f93faf26d8 audio: fix minor whitespace issue in out/internal.h 2019-11-19 12:10:26 -08:00
Avi Halachmi (:avih) eb033bc29f js: don't pre-filter log level argument in mp.enable_messages()
Match lua's 8e5642ff
2019-11-19 18:13:39 +02:00
wm4 521535cebe DOCS/contribute.md: some clarifications
Even if nobody ever reads this file.
2019-11-18 18:14:07 +01:00
Michael Forney 78963d1e66 video/out/bitmap_packer: Avoid empty initializer list 2019-11-18 16:50:21 +01:00
Michael Forney 235fabcfae video/out/vo_tct: Use octal escape sequence instead of non-standard \e 2019-11-18 16:50:21 +01:00
Michael Forney bea582f383 video/out/gpu: Remove stray top-level ';' 2019-11-18 16:50:21 +01:00
wm4 8c2d73f112 player: remove mechanisms for better logging with repl.lua
As preparation for making repl.lua part of the core (maybe), add some
mechanisms which are supposed to improve its behavior.

Add a silent mode. Calling mpv_request_log_messages() with the log level
name prefixed with "silent:" will disable logging from the API user's
perspective. But it will keep the log buffer, and record new messages,
without returning them to the user. If logging is enabled again by
requesting the same log level without "silent:" prefix, the buffered log
messages are returned to the user at once. This is not documented,
because it's far too messy and special as that I'd want anyone to rely
on this behavior, but it will be perfectly fine for an internal script.

Another thing is that we record early startup messages. The goal is to
make the repl.lua script show option and config parsing file errors.
This works only with the special "terminal-default" log level.

In addition, reduce the "terminal-default" capacity to only 100 log
messages. If this is going to be enabled by default, it shouldn't use
too much resources.
2019-11-18 00:44:54 +01:00
wm4 8e5642ff68 lua: don't pre-filter log level argument in mp.enable_messages()
This will just make it  not work if mpv_request_log_messages() gets
extended to accept more names. Pass the argument without checking.

To keep the behavior the same (for whatever reasons, probably not
important), still raise an error if the libmpv API function returns an
error that the argument was bad.

(The check_loglevel() function is still used when the script _emits_ log
messages, which is different, and for which there is no API anyway.)
2019-11-18 00:44:54 +01:00
Philip Langdale a714ab0601 vo_gpu: hwdec_cuda: Reduce message level of errors while probing
We should only be printing errors that occur when not probing, to
avoid creating the impression that something is wrong - and errors
during probing isn't a problem.
2019-11-17 09:44:32 -08:00
wm4 78cf974375 options: deprecate --video-sync=display-adrop
A stupid thing that will probably be in the way.
2019-11-17 02:11:45 +01:00
wm4 d92395d205 player: remove some unnecessary coverart special cases
These should not be needed, since video is in EOF mode in this case
anyway.

Not too sure about the video.c case to be honest, well, here goes
nothing.
2019-11-17 02:11:45 +01:00
wm4 4e74320320 video: make track switching work for external images
Until now, this didn't work, since the external image had pts 0; so
enabling video at a later time did nothing, because the image was
discarded. Since hrseek now ends on the last frame (instead of nothing),
reusing the hrseek mechanism solves this, and we don't even need to
treat the cursed coverart case separately.
2019-11-17 02:11:45 +01:00
wm4 42c5867c4e player: remove commented declaration
It was commented almost 2 years ago in a "rewrite everything" commit.
2019-11-17 02:11:45 +01:00
wm4 23414d1d71 audio: log A/V initial sync status 2019-11-17 02:11:45 +01:00
wm4 c7487cebd1 demux_mf: fix backward seeking behavior
If SEEK_FORWARD is set, a demuxer should skip to the next frame if the
timestamp does not fall on the start of a frame. If that flag is not
set, it should always seek to the first frame before the target
timestamp (or the first frame in the file).
2019-11-17 02:11:45 +01:00
wm4 f942071524 video: set EOF status as soon as possible
See what the added code comment says. Normally when this is needed, it's
the cover art case. But this flag is not set when using an external
image. This gives weird seek behavior, because the frame will be
"normally" displayed for its determined duration, and during normal
video playback, the video pts will be used - which is always 0 here.

This should happen only if audio is active. Otherwise, we're more or
less in image viewer mode, where the image should be displayed for a
configured duration.
2019-11-17 02:11:45 +01:00
wm4 6bcda94cbc video: if hr-seek goes past last frame, seek to last frame
This gives much better behavior in general, and is what we want if video
somehow ends earlier than audio.

A common special is using an audio file with an external image file.
This commit makes things like switching aspect ratio work (provided the
demuxer for the image behaves correctly, which currently isn't the case
with demux_mf.c). Since the image file had timestamp 0, it was usually
skipped by hr-seek, and changed properties weren't applied to it at the
start of the filter chain.
2019-11-17 02:11:45 +01:00
wm4 ba6ba32825 f_decoder_wrapper: put coverart through image output logic
This wasn't done, probably regression from one of the last dozen of
times this special code path was touched. This meant coverart images
ignored the user-set aspect ratio completely, and some other things.
2019-11-17 02:11:45 +01:00
Philip Langdale ba370e9599 vo_gpu: context_glx: Add X11 native resource
Surprisingly, we've managed to get this far without context_glx ever
adding the X11 display as a native resource. But with the recent change
to attempt to enable vdpau when using EGL, the hwdec now requires the
display to be added. So let's add it.
2019-11-16 15:35:32 -08:00
Dudemanguy 0d8a6c6984 wayland: use eglGetPlatformDisplay()
See aacc194. The same logic all applies to Wayland. In fact, we already
require EGL 1.5 for wayland anyway, so it's better to do it right.
2019-11-16 14:23:07 -06:00
wm4 aacc1942fb x11: require EGL 1.5 and use eglGetPlatformDisplay()
eglGetPlatform() is a broken API, since it takes a windowing specific
argument, yet is supposed to work for multiple APIs at the same time. On
Linux, it can take both a X11 "Display" and a "wl_display". Obviously
there is no way to specify what kind of display the argument is (it's
just a void*).

Mesa has _eglNativePlatformDetectNativeDisplay, which does funny stuff
to try to guess the display type, including trying to call mincore() to
determine whether the pointer can be accessed at all. I guess this
recently accidentally broke (as a bug), but on the other hand, maybe
it's time to do this properly.

The fix is using eglGetPlaformDisplay(). This requires EGL 1.5, plus
Mesa needs to support the associated platform extension
(EGL_KHR_platform_x11).

Since I see no reasonable way to do this in a compatible way, just
require that EGL 1.5 is available. The problem is that EGL 1.4 seems to
require you to create a display to query EGL version and extension, and
you have a chicken-and-egg problem. It's very stupid. Maybe you could
jump through some more hoops to get something compatible, but fuck that.
Users on "too old" Mesa will fall back to GLX (which we keep around for
a regrettable company known by the name of Nvidia).

I think Wayland and GBM should do the same. They're sufficiently
bleeding-edge that you can expect them to have EGL 1.5. On the other
hand, the cursed RPI code will have to stay with a eglGetDisplay().

Speculative fix for #7154.

(Rant about EGL follows. Actually I deleted it.)
2019-11-16 20:55:03 +01:00
wm4 73c3dc0a7b vo_gpu: sync duplicated condition on peak computation
pass_color_map() (in video_shaders.c) and pass_colormanage() (video.c)
both duplicate the condition on whether to do peak computation. Peak
computation requires a compute shader, so if the duplicated conditions
don't match, video_shaders.c will generate a compute shader, but video.c
will try to run it as fragment shader. This leads to a "blue screen".

This can be reproduced by playing a HDTV video with --target-peak=99.

It's not clear how to fix this. Should pass_tone_map() be only invoked
if mp_trc_is_hdr() == true (what pass_colormanage() uses to decide
whether to enable peak computation), or should pass_colormanage() just
tell pass_color_map() to skip peak computation? Decide for the latter,
as it's more robust.

Even if not correct, at least it gets rid of the blue shit.

Fixes: #7149
2019-11-16 19:02:36 +01:00
wm4 b2006eeb74 client API: remove sync. property notification code again
It's too easy to introduce unintended circular lock dependencies. Just
now we found that the (old) cocoa vo_gpu backend is also affected by
this, because it waits on the Cocoa main thread, which in turn uses
libmpv API for OSX... stuff.

Also fix a missing initial property update after observe.

This leaves me unhappy, because it just leads to a stupid thread ping
pong. Will probably rewrite this later.
2019-11-16 18:33:28 +01:00
wm4 b0d95f6f3c manpage: add section about using mpv from programs and scripts
Give an overview over the various methods. I feel like I've written text
like this over and over again (compatibility.rst and
interface-changes.rst for example duplicate the list of mpv API
abstractions), but such is life in hell.

Use this in particular to strongly suggest not to parse terminal output.
This suggestion got lost or de-emphasized at some point (maybe when
removing MPlayer and "slave mode" references). Some of this text is
still there, but it can be considered "fine print" at best, that nobody
will see. Now we have it in a more prominent place. This is especially
important since MPlayer-style use of mpv still seems to be prevalent,
see for example #7153.
2019-11-16 15:38:05 +01:00
wm4 f57f13ceb0 options: deprecate --input-file
I have no idea why this still exists, since we have --input-ipc-server.
I think there was something about Windows, but the latter option is
implemented even on Windows.
2019-11-16 15:28:18 +01:00
wm4 6bbf44d842 video: take first frame into account in audio-sync mode
It appears commit 4ad68d9452 broke handling the first video
frame duration through roundabout ways (I think because the duration of
the first frame was now available at all in the normal case). The first
frame was cut short, which showed up especially with looping, or if the
file had a low FPS.

This questionable change seems to fix it without breaking any other
known cases => push and call it a day.

The display-sync mode did not have this problem.

Fixes: #7150
2019-11-16 13:47:23 +01:00
wm4 b6413f82b2 demux_lavf: fight ffmpeg API some more and get the timeout set
It sometimes happens that HLS streams freeze because the HTTP server is
not responding for a fragment (or something similar, the exact
circumstances are unknown). The --timeout option didn't affect this,
because it's never set on HLS recursive connections (these download the
fragments, while the main connection likely nothing and just wastes a
TCP socket).

Apply an elaborate hack on top of an existing elaborate hack to somehow
get these options set. Of course this could still break easily, but hey,
it's ffmpeg, it can't not try to fuck you over. I'm so fucking sick of
ffmpeg's API bullshit, especially wrt. HLS.

Of course the change is sort of pointless. For HLS, GET requests should
just aggressively retried (because they're not "streamed", they're just
actual files on a CDN), while normal HTTP connections should probably
not be made this fragile (they could be streamed, i.e. they are backed
by some sort of real time encoder, and block if there is no data yet).
The 1 minute default timeout is too high to save playback if this
happens with HLS.

Vaguely related to #5793.
2019-11-16 13:15:45 +01:00
wm4 8d4e012bfa demux_playlist: fix previous commit
This just froze, due to obvious stupidity (I forgot to deal with all
semantic changes done to the the former stream_skip()).

Fixes: ac7f67b3f2
2019-11-15 12:10:01 +01:00
wm4 9efdb0368e player: enable "pause caching" code for local playback too
There isn't really a need to disable this for local playback. I think
originally I did this because I was afraid the code could mess up or be
annoying on local mode, but that's not really a good argument. I'd
rather test this code in local mode too. In this case, it shouldn't
really happen that it runs out of cache in the first place.
2019-11-14 13:51:47 +01:00
wm4 5a99015acf stream_lavf: set --network-timeout to 60 seconds by default
Until now, we've made FFmpeg use the default network timeout - which is
apparently infinite. I don't know if this was changed at some point,
although it seems likely, as I was sure there was a more useful default.

For most use cases, a smaller timeout is more useful (for example
recording something in the background), so force a timeout of 1 minute.

See: #5793
2019-11-14 13:46:03 +01:00
wm4 ac7f67b3f2 demux_mkv, stream: attempt to improve behavior in unseekable streams
stream_skip() semantics were kind of bad, especially after the recent
change to the stream code. Forward stream_skip() calls could still
trigger a seek and fail, even if it was supposed to actually skip data.
(Maybe the idea that stream_skip() should try to seek is worthless in
the first place.)

Rename it to stream_seek_skip() (takes absolute position now because I
think that's better), and make it always skip if the stream is marked as
forward.

While we're at it, make EOF detection more robust. I guess s->eof
shouldn't exist at all, since it's valid only "sometimes". It should be
removed... but not today. A 1-byte stream_read_peek() call is good to
get the s->eof flag set to a correct value.
2019-11-14 12:59:14 +01:00
dudemanguy dcc3c2eb38 wayland: use hidpi-window-scale option 2019-11-12 01:00:08 +00:00
Philip Sequeira b5894e760d github: ask for build/config.log 2019-11-10 20:59:17 -08:00
Philip Sequeira 85aa9635e0 build: fix compilation conditions for vaapi interop inits
This makes the condition for including each init match the condition for
compiling the file that defines it.

It's possible to e.g. HAVE_GL and HAVE_VAAPI without HAVE_VAAPI_EGL,
which resulted in "undefined reference to `vaapi_gl_init'" with the old
code.
2019-11-10 20:59:17 -08:00
wm4 07fd511e14 options: remove M_SETOPT_RUNTIME
Used to contain flags for "save" setting of options at runtime. Now
there is nothing special needed anymore and it's 0. So drop it
completely, and remove anything that distinguishes between runtime and
initialization time.
2019-11-10 23:53:57 +01:00
wm4 4cae192377 options: remove M_OPT_FIXED
Options marked with this flag were changed to strictly read-only after
initialization (mpv_initialize() in the client API, after option parsing
and config file loading with the CLI player).

This used to be necessary, because there was a single option struct that
could be accessed by multiple threads. For example, --config-dir sets
MPOpts.force_configdir, which was read whenever anything accessed the
mpv config dir (which could be on different threads, e.g. font
initialization tries to lookup fonts.conf from an arbitrary thread).

This isn't needed anymore, because threads now access these in a thread
safe way. In the case of --config-dir, the path is actually just copied
on init.

This M_OPT_FIXED mechanism is thus not strictly needed anymore. It still
prevents writing to some options that cannot take effect at runtime, but
even that can be dropped. In general, all mpv options can be changed any
time at runtime, even if they never take effect, and there's no need to
make an exception for a very low number of options. So just get rid of
it.
2019-11-10 23:49:23 +01:00
wm4 20c9538e32 audio: more alignment nonsense
It's hard to see what FFmpeg does or what its API requires. It looks
like the alignment in our own allocation code might be slightly too
lenient, but who knows. Even if this is not needed, upping the alignment
only wastes memory and doesn't do anything bad.

(Note that the only reason why we have our own code is because FFmpeg
doesn't even provide it as API. API users are forced to recreate this,
even if they have no need for custom allocation!)
2019-11-10 15:30:29 +01:00
wm4 4667b3a182 audio: work around ffmpeg being a piece of shit
The "amultiply" filter crashes in AVX mode on unaligned access if an
audio pointer is unaligned (on 32 or 64 bytes I assume).

A requirement that audio data needs to be aligned isn't documented
anywhere. In our case, the data is still sample- and channel-aligned,
which is completely sane. Sure, you can imagine optimizations which make
some algorithms even faster by requiring higher alignment. But, and this
is a big but, you shouldn't crash api users because you just invented a
new undocumented requirement. And even more importantly, your
user-crashing optimization won't matter because it's just a trivial
algorithm working on audio. You don't need to pretend to be an
optimization devil, and nobody will give you a prize for this. But no,
lets random make API users crash (and then probably blame them for it!)
for something that wouldn't matter at all.

Not to mention that they do "document" some requirements on _video_
data, yet their vf_crop probably can still produce unaligned video
pointers. Oh how hilarious that the same documentation also talks about
libswscale alignment requirements. (This is weird because libswscale is
just one of many, many things which consume video data. Also did you
know that zimg, written in C++ and using intrinsics, i.e. the antithesis
to FFmpeg development, is much faster than libswscale, easier to use,
and produces more correct results, even if you ignore that libswscale
flat out doesn't support some very important features?)

Fucking tired of this bullshit. Can't wait until someone comes up with a
better framework than this... (well let's not write this out).

Fix this by copying instead of adjusting the start pointer when skipping
samples. This makes general operations slower just to fix interoperating
with a single filter. Thank you for your "optimization", FFmpeg. Go die
in a fire.

Didn't check whether this is correct. It probably is? If the frame needs
to be copied (due to COW), and memory allocation fails, it just silently
(or audibly lol) doesn't skip samples, because a never-fail function can
suddenly fail. Well, who cares.

Fixes: #7141
2019-11-10 15:13:25 +01:00
wm4 35de8ea0a8 vo_gpu: yuv alpha is always full range
Probably. It's not like these pixel formats are formally specified -
FFmpeg added them because _some_ file format or decoder supports it, and
while that format/codec may define it precisely, the pixel format is
sort of disconnected and just a FFmpeg thing.

In any case, the yuva sample I had at hand uses the full range the
component data type can provide. The old code used the same "shifted"
range as for Y/U/V components, which must have been wrong.

This will not work correctly for packed YUVA formats, but fortunately
they matter even less.
2019-11-09 23:56:44 +01:00
wm4 05f018b81a github: suggest using as github attachment for log files
It's not that we _want_ the log to be on an external site. We just want
the log, somehow. Probably not pasted inline into the issue text.

Also reword the "we are assholes who really want logs" part of the text.
It's a subtle balance between trying to be nice and being a complete
asshole, but no matter what you do, it will always sound like the
latter, so be direct.
2019-11-09 23:56:44 +01:00
wm4 f762303feb manpage: expand MPV_LEAK_REPORT environment variable description 2019-11-09 23:56:44 +01:00
Timothy DeHerrera cb2d7c1534 README.md: fix dead FAQ link due to syntax error 2019-11-09 13:18:15 +01:00
wm4 94d853d3a3 test: add tests for zimg RGB repacking
This tests the RGB repacker code in zimg, which deserves to be tested
because it's tricky and there will be more formats.

scale_test.c contains some code that can be used to test any scaler. Or
at least that would be great; currently it can only test repacking of
some byte-aligned-component RGB formats. It should be called
repack_test.c, but I'm too lazy to change the filename now.

The idea is that libswscale is used to cross-check the conversions
performed by the zimg wrapper. This is why it's "OK" that scale_test.c
does libswscale calls.

scale_sws.c is the equivalent to scale_zimg.c, and is of course
worthless (because it tests libswscale by comparing the results with
libswscale), but still might help with finding bugs in scale_test.c.

This borrows a sorted list of image formats from test/img_format.c, for
the same reason that file sorts them.

There's a slight possibility that this can be used to test vo_gpu.c too
some times in the future.
2019-11-09 01:55:13 +01:00
wm4 27d88e4a9b test: fix --unittest matching
Hurrr.
2019-11-08 21:22:49 +01:00
wm4 cd8fd4b788 vo_gpu: context_x11egl: check eglGetConfigAttrib() for errors
Not sure why it assumes that it always succeeds (although generally it
won't fail).
2019-11-08 21:22:49 +01:00
wm4 bcfabf40a4 img_format: remove some unneeded alpha flag handling
Don't know what this was for, but the result doesn't change.
2019-11-08 21:22:49 +01:00
wm4 1edb3d061b test: add dumping of img_format metadata
This is fragile enough that it warrants getting "monitored".

This takes the commented test program code from img_format.c, makes it
output to a text file, and then compares it to a "ref" file stored in
git.

Originally, I wanted to do the comparison etc. in a shell or Python
script. But why not do it in C. So mpv calls /usr/bin/diff as a
sub-process now.

This test will start producing different output if FFmpeg adds new pixel
formats or pixel format flags, or if mpv adds new IMGFMT (either aliases
to FFmpeg formats or own formats). That is unavoidable, and requires
manual inspection of the results, and then updating the ref file.

The changes in the non-test code are to guarantee that the format ID
conversion functions only translate between valid IDs.
2019-11-08 21:22:49 +01:00
wm4 a6c8b4efa5 test: merge test_helpers.c and index.c
No need to keep them separate. Originally I thought index.c was only
going to contain the list of tests, but that didn't happen.
2019-11-08 20:34:07 +01:00
wm4 98b38b04c9 player: do not require dummy file arguments to use --unittest
Move the test execution above the point where it checks for an empty
playlist and exits if that's the case.
2019-11-08 14:29:58 +01:00
wm4 3e401bf652 test: make build fail if NDEBUG is defined
Defining NDEBUG via CFLAGS is the canonical way to disable assertions in
C. mpv respects this (and ta.c actually disables some debugging
machinery if it's defined).

But for tests, this is not useful at all. So if --enable-tests is passed
to configure, the user must not define NDEBUG, even if the rest of the
player does not care.

(We could just #undef NDEBUG, but let's not. Tests calling into the rest
of the player might depend on asserts there, or so.)
2019-11-08 14:23:56 +01:00
wm4 3ed9c1c970 test: just always provide a context for all entrypoints 2019-11-08 14:21:40 +01:00
wm4 53b7a10f54 wscript: add --enable-ta-leak-report option
Kind of more convenient because I'm lazy.
2019-11-08 00:43:46 +01:00
wm4 640b8532aa wscript: remove outdated --enable-libaf
This stopped doing anything since how many years?

The only actual effect was that af_rubberband was made GPL only. Now it
is available in LGPL builds too.
2019-11-08 00:40:11 +01:00
wm4 fb56896319 test: make tests part of the mpv binary
Until now, each .c file in test/ was built as separate, self-contained
binary. Each binary could be run to execute the tests it contained.

Change this and make them part of the normal mpv binary. Now the tests
have to be invoked via the --unittest option. Do this for two reasons:

- Tests now run within a "properly" initialized mpv instance, so all
  services are available.
- Possibly simplifying the situation for future build systems.

The first point is the main motivation. The mpv code is entangled with
mp_log and the option system. It feels like a bad idea to duplicate some
of the initialization of this just so you can call code using them.

I'm also getting rid of cmocka. There wouldn't be any problem to keep it
(it's a perfectly sane set of helpers), but NIH calls. I would have had
to aggregate all tests into a CMUnitTest list, and I don't see how I'd
get different types of entry points easily. Probably easily solvable,
but since we made only pretty basic use of this library, NIH-ing this is
actually easier (I needed a list of tests with custom metadata anyway,
so all what was left was reimplement the assert_* helpers).

Unit tests now don't output anything, and if they fail, they'll simply
crash and leave a message that typically requires inspecting the test
code to figure out what went wrong (and probably editing the test code
to get more information). I even merged the various test functions into
single ones. Sucks, but here you go.

chmap_sel.c is merged into chmap.c, because I didn't see the point of
this being separate. json.c drops the print_message() to go along with
the new silent-by-default idea, also there's a memory leak fix unrelated
to the rest of this commit.

The new code is enabled with --enable-tests (--enable-test goes away).
Due to waf's option parser, --enable-test still works, because it's a
unique prefix to --enable-tests.
2019-11-08 00:26:37 +01:00
wm4 17dde8eeb6 msg: try to document purpose of log levels better
(But I bet nobody ever reads this anyway.)
2019-11-07 22:53:13 +01:00
wm4 1c8d2246bf vo_gpu: vdpau actually works under EGL
The use of glXGetCurrentDisplay() restricted this to the GLX backend.
But actually it works under EGL as well. Removing the GLX-specific call
and using the general mpv-internal method to get the X "Display" makes
it work in mpv.

I didn't know this. Nvidia didn't list this as extension in the EGL
context when I still used their GPUs.

Note that this might in theory break use of vdpau in some libmpv clients
using the render API. But only if MPV_RENDER_PARAM_X11_DISPLAY is not
used, and they relied on mpv using glXGetCurrentDisplay(). EGL does not
provide such an API, and hwdec_vaapi.c also uses what hwdec_vdpau.c uses
now. Considering that vaapi is preferable these days, it's not bad at
all if these clients get "broken". They can be easily fixed by passing
the display to mpv correctly.
2019-11-07 22:53:13 +01:00
wm4 17a89e5778 manpage: vdpauglx backend was removed
A while ago. It was 100% useless.
2019-11-07 22:53:13 +01:00
wm4 1ab5d829ce builtin.conf: set minimal --stream-buffer-size
Some stream inputs may have higher latency with higher buffer sizes, for
example network filesystems via normal OS filesystem interface (these
have to wait until the full buffer is read, which means higher latency).
Probably doesn't matter in practice, but why take chances.
2019-11-07 22:53:13 +01:00
wm4 573673e6aa DOCS/contribute.md: add #include order to coding style
Another thing nobody will read, or consciously follow.
2019-11-07 22:53:13 +01:00
wm4 afbddbdf8f DOCS/contribute.md, zimg: remove 2 instances of an extraneous "s" 2019-11-07 22:53:13 +01:00
wm4 19becc8ea9 stats, demux: log byte level stream seeks 2019-11-07 22:53:13 +01:00
wm4 6487abde79 stream: remove unused read_chunk field
It was set, but its value was never used. The stream cache used to use
it, but it was removed. It controlled how much data it tried to read
from the underlying stream at once.

The user can now control the buffer size with --stream-buffer-size,
which achieves a similar effect, because the stream will in the common
case read half of the buffer size at once. In fact, the new default size
is 128KB, i.e. 64KB read size, which is as much as stream_file and
stream_cb requested by default. stream_memory requested more, but it
doesn't matter anyway. Only stream_smb set a larger size with 128KB.
2019-11-07 22:53:13 +01:00
wm4 e5a9b792ec stream: replace STREAM_CTRL_GET_SIZE with a proper entrypoint
This is overlay convoluted as a stream control, and important enough to
warrant "first class" functionality.
2019-11-07 22:53:13 +01:00
wm4 ca75fedaf4 stream_dvdnav: ok, this makes no sense at all
The dvdnav API reads in 2K blocks (dvdnav_get_next_block()). The mpv
wrapper (fill_buffer() in this file) expects that the read size done by
the mpv core is at least 2K for this reason. If not, it returns an
error.

This used to be OK, because there was a thing called section alignment
in the core code. This was removed because the core shouldn't suffer
from optical disc idiosyncrasies. Which means that ever since, it has
been working only by coincidence, or maybe not at all.

Fixing this would require keeping a buffer in the priv struct, and
returning it piece by piece if the core makes smaller reads. I have no
intention of writing such code, so add an error message asking for a
patch. If anyone actually cares about DVD, maybe it'll get fixed.
2019-11-07 22:53:13 +01:00
wm4 6fc0e7e0a0 stream_bluray: remove size getter
This isn't really needed, since it doesn't support byte seeking (only
for avoiding that demux_disc fucks up even more if the nested demux_lavf
tries to seek in the TS).
2019-11-07 22:53:13 +01:00
wm4 d3479018db stream: change buffer argument types from char* to void*
This is slightly better, although not much, and ultimately doesn't
matter.

The public API in stream_cb.h also uses char*, but can't change that.
2019-11-07 22:53:13 +01:00
wm4 f850d82e65 stream: avoid a duplicate condition
stream_read_peek() duplicated what stream_read_more() checks for anyway
(whether the forward buffer is large enough). This can be skipped by
making the stream_read_more() return value more consistent.
2019-11-07 22:53:13 +01:00
wm4 53f17a71f4 stream: fix typos in a comments 2019-11-07 22:53:13 +01:00
wm4 12d1761064 stream: remove eof getter
demux_mkv was the only thing using this, and everything else accessed it
directly. No need to keep the indirection wrapper around.

(Funny how this getter was in the initial commit of MPlayer.)
2019-11-07 22:53:10 +01:00
wm4 8a0929973d vo_gpu: unconditionally clear framebuffer on start of frame
For some reason, the first frame displayed on X11 with amdgpu and OpenGL
will be garbled. This is especially visible if the player starts,
displays a frame, but then still takes a while to properly start
playback.

With --interpolation, the behavior somehow changes (usually gets worse).
I'm not sure what exactly is going on, and the code in video.c is way
too abstruse. Maybe there is some slight possibility that a frame with
uncleared contents gets displayed, which somehow also corrupts another
frame that is displayed immediately after that.

If clear is unconditionally run, this somehow doesn't happen, and you
see a video frame. By any logic this shouldn't happen: a video frame
should always overwrite the background. So I can't exclude that this
isn't some sort of driver bug, or at least very obscure interaction.

Clearing should be practically free anyway, so always do it.

Fixes: #7105
2019-11-06 22:42:44 +01:00
wm4 e8aae688c3 stream: bump default buffer size from 2K to 64K
(Only half of the buffer is actually used in a useful way, see manpage
or commit which added the option.)

Might have some advantages with broken network filesystem drivers.

See: #6802
2019-11-06 21:57:31 +01:00
wm4 b4466cf0d4 stream: remove inline buffer optimization
Was probably worthless, and I can't measure a difference anymore (I used
to be able and it still seemed worth doing so back then).

When the default buffer size is enlarged in the next commit, the inline
buffer probably won't even be useful in theory, because the data will
rarely be on the same page as the other stream fields. It surely makes
the inline buffer seem like a ridiculous micro-optimization. Farewell...
2019-11-06 21:54:41 +01:00
wm4 f37f4de849 stream: turn into a ring buffer, make size configurable
In some corner cases (see #6802), it can be beneficial to use a larger
stream buffer size. Use this as argument to rewrite everything for no
reason.

Turn stream.c itself into a ring buffer, with configurable size. The
latter would have been easily achievable with minimal changes, and the
ring buffer is the hard part. There is no reason to have a ring buffer
at all, except possibly if ffmpeg don't fix their awful mp4 demuxer, and
some subtle issues with demux_mkv.c wanting to seek back by small
offsets (the latter was handled with small stream_peek() calls, which
are unneeded now).

In addition, this turns small forward seeks into reads (where data is
simply skipped). Before this commit, only stream_skip() did this (which
also mean that stream_skip() simply calls stream_seek() now).

Replace all stream_peek() calls with something else (usually
stream_read_peek()). The function was a problem, because it returned a
pointer to the internal buffer, which is now a ring buffer with
wrapping. The new function just copies the data into a buffer, and in
some cases requires callers to dynamically allocate memory. (The most
common case, demux_lavf.c, required a separate buffer allocation anyway
due to FFmpeg "idiosyncrasies".) This is the bulk of the demuxer_*
changes.

I'm not happy with this. There still isn't a good reason why there
should be a ring buffer, that is complex, and most of the time just
wastes half of the available memory. Maybe another rewrite soon.

It also contains bugs; you're an alpha tester now.
2019-11-06 21:36:02 +01:00
wm4 abb089431d common: add a helper to round up to next power of 2
This is something relatively frequently needed, and there must be half a
dozen ad-hoc implementations in mpv. The next commit uses this, the
suspected duplicate implementations are hiding.
2019-11-06 21:35:49 +01:00
wm4 48fc642e0c demux: unconditionally reposition stream to start before opening
The old code made it depend on ->seekable. If it isn't seekable, and
something discarded the data, then it'll just show an error message,
which will at least be somewhat informative. If no data was discarded,
the seek call is always a no-op.

There's a weird "timeline" condition in the old code; this doesn't
matter anymore, because timeline stuff does not pass streams down to
nested demuxers anymore.
2019-11-06 21:35:32 +01:00
wm4 517489814d manpage: update input protocols
tv:// and pvr:// are gone, DVD almost. The former didn't really have any
uses left, except webcams. Provide a replacement example for that.

We don't need a separate section for DVD. If you use DVD, you're on your
own. There's still enough documentation left to puzzle things together
even if you don't read the source code.
2019-11-04 16:24:57 +01:00
wm4 872df1e06f manpage: opengl-cb -> libmpv
This was renamed ages ago. Fix the outdated usage. Except where
opengl-cb was correct.
2019-11-04 16:17:07 +01:00
wm4 f043d73405 manpage: fix global config file path in --hwdec description 2019-11-04 00:48:03 +01:00
wm4 2ff14f92be build: fix strict ABI option
Fixes: #7118
2019-11-04 00:25:12 +01:00
wm4 a4f92cef1a manpage: shovel around --hwdec description (again)
Not like anyone reads it. Although putting all this text before listing
the allowed option values sort of has the intention to discourage users
from using the option at all. Advertise Ctrl+h, which is a decent way of
enabling hardware decoding temporarily.
2019-11-04 00:01:05 +01:00
wm4 bcb18b8847 DOCS/interface-changes.rst: improve entry about sws changes
This was pretty vague. Add some context, and explicitly mention how
these options now affect screenshots.
2019-11-03 23:32:59 +01:00
wm4 98352362ea img_format: remove some unused format flags
They were used at some point, but then fell into disuse. In general,
these old flags are all a bit fuzzy, so it's a good idea to remove them
as much as possible.

The comment about MP_IMGFLAG_PAL isn't true anymore. The old meaning was
deprecated at some point, and the flag was removed from "pseudo
paletted" formats. I think mpv at one point changed its own flag from
AV_PIX_FMT_FLAG_PSEUDOPAL to AV_PIX_FMT_FLAG_PAL, when the former was
deprecated, and it became unnecessary to allocate a palette for
non-paletted formats. (The one who deprecated in FFmpeg was me, if you
wonder.)

MP_IMGFLAG_PLANAR was used in command.c, use a relatively similar flag
as replacement.
2019-11-03 23:18:35 +01:00
wm4 cfd6595386 vo_x11: accept zimg formats
This is slightly helpful for testing, and otherwise useless and without
consequence.

I'm not using the correct output format and using IMGFMT_RGB0 as
placeholder. This doesn't matter currently, as both sws and zimg support
this as output (and support any input for it). I'm doing this because
it's surprisingly tricky to get the correct output format at this point,
without digging deeper into x11 shit or refactoring parts of the VO. I
don't care enough about this.
2019-11-03 22:52:12 +01:00
wm4 a19571679f sws_utils: remove some unnecessary sws bug work around
Seems like this was needed in 2012. The comment indicates the bug was
fixed in ffmpeg git, so it's long gone.
2019-11-03 22:48:49 +01:00
wm4 67e17f1104 vd_lavc: don't keep packets for fallbacks if errors are tolerated
The user can raise the number of tolerated hardware decoding errors. On
the other hand, we have a static limit on packets that are "saved" for
fallback handling (and that's a good idea to avoid unbounded memory
usage). In this case, it could happen that the start of a file was fine
after a fallback, but after that buffered amount of data, it would
suddenly skip.

It's more useful to skip buffering entirely if the number of tolerated
decoding errors exceeds the fixed buffer.

(And also, I'm sure nobody gives a shit about this feature.)
2019-11-02 23:00:49 +01:00
wm4 0e1cfe0c42 vd_lavc: fix prepare_decoding() failure modes
prepare_decoding() returned a bool that was supposed to tell whether
decoding could work, or if something was fucked. After recent changes to
the decoder loop, this did not work anymore, and caused an endless loop.
Redo it, so it makes more sense. avctx being NULL (software fallback
initialization failed) now signals EOF. hwdec_failed needs to be handled
on send_packet() only, where it probably never happens anyway.

(Who was the idiot who made libavcodec have two entrypoints for
decoding? Oh right, it was me. PEBKAC.)
2019-11-02 22:44:39 +01:00
wm4 7bf31c51f2 vd_lavc: mention hw decoding if decoding fails in hwdec mode
Just so the user knows. Provides some context.
2019-11-02 22:38:08 +01:00
wm4 1bb726dedc vd_lavc: simplify fallback handling for full stream hw decoder
Shovel the code around to make the data flow slightly simpler (?). At
least there's only one send_packet function now. The old code had the
problem that send_packet() could be called even if there were queued
packets; due to sending the queued packets in the receive_frame
function, this should not happen anymore (the code checking for this
case in send_packet should normally never be called).

Untested with actual full stream hw decoders (none available here); I
created a test case by making hwaccel decoding fail.
2019-11-02 22:37:14 +01:00
wm4 dab588a4a2 vd_lavc: signal packet consumed in drop-all case
This is just a very special code path. This probably got stuck, now that
the previous commit returned the EAGAIN properly. Untested.
2019-11-02 21:38:19 +01:00
wm4 203fc6fe44 vd_lavc: change incorrect bool return type to int
Forgotten in commit 5d5fdb7. This failed to return the error code
properly. In particular, if the decoder rejected the packet, this was
not properly detected. Normally, this mattered only in specific cases.

Fixes: #7115
2019-11-02 21:35:48 +01:00
wm4 3ae9f671d4 README.md: reduce focus on MPlayer, small improvements
MPlayer isn't all too well-known anymore. It does not make sense to
"advertise" with it (and it actually never did).

The GPU comment needed clarification. I think originally, it was just to
signal that you'll have a bad time with Intel. Make that broader.
2019-11-02 19:15:59 +01:00
wm4 6eb0dc5447 zimg: support subsampled chroma with non-aligned image sizes 2019-11-02 18:49:17 +01:00
wm4 d26c1c6814 zinmg: stop using GBRP for RGB
Instead, use a YUV planar format. It doesn't matter, since we use the
format only internally and for "management" purposes. We're only
interested in the physical layout, not what colorspace FFmpeg "forcibly"
associates with it.

Also get rid of using the old and slightly sketchy mp_imgfmt_find()
function. Yep, the IMGFMT_RGB30 now "constructs" the planar format,
instead of using a pixfmt constant. Slightly inconvenient, tricky, and
fragile, but I like it, so bugger off.

This whole thing gets rid of some of the strange plane permutations that
were needed earlier.
2019-11-02 18:11:02 +01:00
wm4 20c1bd8a5e zimg: correct RGB30 order (probably)
According to the definition of the GL format, and the definition in
img_format.h, and the actual output by vo_gpu, the order of components
was probably wrong. It's exceedingly likely that the vo_drm format (for
which this was originally written) has the same layout, so this was
probably a bug from when the zimg wrapper code was refactored.
2019-11-02 17:52:13 +01:00
wm4 e58e650a97 video: mess with the filte chain to enable zimg IMGFMT_RGB30 output
This was too hardcoded to libswscale. In particular, IMGFMT_RGB30 output
is only possible with the zimg wrapper, so the context needs to be taken
into account (since this depends on the --sws-allow-zimg option
dynamically). This is still slightly risky, because zimg currently will
still fall back to swscale in some cases, such as when it refuses to
initialize the particular color conversion that is requested.
f_autoconvert.c could actually handle this better, but I'm tool fucking
lazy right now, and nobody cares anyway, so go away, OK?
2019-11-02 17:50:32 +01:00
wm4 3e660f6164 vo_gpu: opengl: add support for IMGFMT_RGB30
This integrates it as "special" format, with no alpha component, as the
equivalent IMGFMT_RGB30 isn't meant to contain any.

Nothing can produce this format in the video chain yet, so the next
commits are needed to make this actually work.
2019-11-02 17:46:46 +01:00
Dan Elkouby dfc060f099 ass_mp: reset packer when allocation fails
Sometimes the atlas can get so large that it exceeds the maximum allowed
size for an mp_image. Since the atlas will never shrink naturally, this
breaks subtitles entirely until mpv is restarted. Reset the packer so
that subtitles can rendered properly once the atlas fits again.

This is a partial workaround for #6286.
2019-11-02 14:42:36 +01:00
wm4 985a1cde5a manpage: update --framedrop option
The statement about the display FPS is outdated by several years.
"audio"-sync mode does not use the display FPS anymore, and that it's
X11 only also isn't true anymore.

These modes have separate implementations for audio and display video
sync. modes, so the explanations are separate.

Why the hell are users playing around with this anyway? The explanations
are probably too special to make sense for anyone who doesn't know the
code (and who knows the code doesn't need them anyway), but whatever.
2019-11-02 14:29:24 +01:00
wm4 00838fe0c3 zimg: make --zimg-fast=yes default
This is mostly just because of the odd RGB default gamma issue, which
shouldn't have any real impact. This also sets allow_approximate_gamma,
which I hope is fine for normal use cases.
2019-11-02 02:22:16 +01:00
wm4 c9d685f5d6 zimg: pass through Y plane when repacking nv12
Normally, the Y plane can just be passed directly to zimg, and only the
chroma plane needs to be (de)interleaved. It still needs a copy if the Y
pointer is not aligned, though. (Whether this is actually a problem
depends on the CPU and probably zimg's compiler.)

This requires deciding per plane whether the plane should go through the
repack buffer or not. This logic is active in non-nv12 cases, because
not doing so would require extra code (maybe 2 lines or so).
repack_align is now always called, even if it's planar->planar with all
input aligned, but it won't actually do anything in that case. The
assumption is that zimg won't change behavior if you pass a callback
that does nothing versus passing NULL as callback.
2019-11-02 02:18:24 +01:00
wm4 3b56f82965 zimg: add semi-planar repacker
This is for formats like nv12 (including p010, nv24, etc.). Might be
important for hardware decoding. Previously, this would have forced a
libswscale fallback.

The genericism makes this only slightly more complicated. The main
complication is due to the fact that mixing planar and packed stuff is
insane (thanks, Nvidia).

P010 output will actually happily set any of the 6 bit "padding" LSB,
that are normally supposed to be 0 (for unpadded data there is P016).
Scaling happens with 16 bit precision. Not going to bother adding an
extra packer which zeros them out, or with shifting them in
packing/unpacking. Lets just hope nobody notices.
2019-11-02 01:10:22 +01:00
wm4 c3cee4b9ec img_format: add function to find image format by layout
This is similar to mp_imgfmt_find(), but probably a bit saner. Used by
the next commit. The previous commit is required to map this
unambiguously between all formats.
2019-11-02 01:02:54 +01:00
wm4 bdd1e1e7ec img_format: add mp_regular_imgfmt.forced_csp field
As the code comment says, this is needed to disambiguate FFmpeg formats.
This struct only describes the "physical" layout of a format, while
FFmpeg also attaches part of the colorspace information to the format.
2019-11-02 01:00:32 +01:00
wm4 337ccc50dc img_format: add more explanations to component_pad field
Weird shit. I thought this was a clever way to elegantly handle two
cases at once, but maybe it's just confusing.
2019-11-02 00:55:55 +01:00
wm4 4b3666329e zimg: fix out of bounds memory accesses due to broken zmask
We've set all planes to the same zmask. But for subsampled chroma, the
zmask obviously needs to be smaller. This could lead to out of bounds
memory read and write accesses.

Move the align repacker to a single function, since this is now more
convenient.
2019-11-02 00:48:04 +01:00
wm4 871900f562 github: we want a -v -v log now
--log-file uses debug log level by default. On command line, -v -v will
use debug log level.
2019-11-01 01:56:08 +01:00
wm4 2ce4568018 f_decoder_wrapper: reduce uninit message log level
For vd/ad.
2019-11-01 01:55:06 +01:00
wm4 6cd0978f8a client API: reduce log level of client exiting
See previous commit message.
2019-11-01 01:54:39 +01:00
wm4 5189ea4696 demux: reduce log level for cache index resizing
Now that I probably removed all bugs in this (?), this is uninteresting.
2019-11-01 01:54:12 +01:00
wm4 fdce778605 lua: change config file logging
Make the existing "not found" messages debug only, and add a new verbose
message if a config file was opened. The idea is that logging should
make it apparent whether or not config files are loaded, and it's more
common to use scripts without config files, leading to fewer log
messages in verbose mode.
2019-11-01 01:52:05 +01:00
wm4 02cb44ac8b x11: reduce log level for relatively uninteresting things
Normally nobody cares about the WM detection stuff etc., so log this
only at debug log levels.
2019-11-01 01:40:22 +01:00
wm4 67aa7b0439 demux_mkv: reduce log level of mkvinfo part to debug
demux_mkv has lots of logging that shows information about the file. It
sort of reminds of mkvinfo output. While this is sometimes interesting,
it's too much for verbose mode, and should be in debug log level.
2019-11-01 01:37:09 +01:00
wm4 f7073a5ec9 m_config: log applying profiles 2019-11-01 01:29:44 +01:00
wm4 89ae370d41 m_config: raise log level of setting options to verbose
In 2017, we lowered this to debug level. But I think setting options is
important enough that it should be logged even in verbose, at least
compared to all the other dumb noise.

This might be reduced again if verbose logging becomes much cleaner.
2019-11-01 01:29:30 +01:00
wm4 04b4155582 zimg: add more packers/unpackers
This probably covers all packed formats which have byte-aligned
component, no alpha, and no subsampling. Everything else needs more
imgfmt metadata, or something even more complicated. Alpha is primarily
not supported, because zimg requires a second scaler instance for it,
and handling packing/unpacking with it is an unacceptable mess.
2019-10-31 22:43:58 +01:00
wm4 821320252e m_option: remove an unused function
I think the last real use of this went away in 2014 or so.
2019-10-31 17:42:41 +01:00
wm4 706e708d2f options: make --show-profile without parameters list all profiles 2019-10-31 17:32:57 +01:00
wm4 e96ab5becb manpage: fix another typo 2019-10-31 17:27:17 +01:00
wm4 9e0b0be8ee manpage: update --zimg-scaler default
Forgotten in previous commit.
2019-10-31 17:01:31 +01:00
wm4 a7230dfed0 sws_utils, zimg: destroy vo_x11 and vo_drm performance
Raise swscale and zimg default parameters. This restores screenshot
quality settings (maybe) unset in the commit before. Also expose some
more libswscale and zimg options.

Since these options are also used for VOs like x11 and drm, this will
make x11/drm/etc. much slower. For compensation, provide a profile that
sets the old option values: sw-fast. I'm also enabling zimg here, just
as an experiment.

The core problem is that we have a single set of command line options
which control the settings used for most swscale/zimg uses. This was
done in the previous commit. It cannot differentiate between the VOs,
which need to be realtime and may accept/require lower quality options,
and things like screenshots or vo_image, which can be slower, but should
not sacrifice quality by default.

Should this have two sets of options or something similar to do the
right thing depending on the code which calls libswscale? Maybe. Or
should I just ignore the problem, make it someone else's problem (users
who want to use software conversion VOs), provide a sub-optimal
solution, and call it a day? Definitely, sounds good, pushing to master,
goodbye.
2019-10-31 16:51:12 +01:00
wm4 2c43d2b75a screenshot, vo_image: use global swscale/zimg parameters
Lots of dumb crap to do... something. Instead of adding yet another dumb
helper, just use the main" sws_utils API in both callers. (Which,
unfortunately, has been duplicated for glorious webp screenshots,
despite the fact that webp is crap.)

Good part: can enable zimg for screenshots (as far as needed).
Bad part: uses "default" swscale parameters instead of HQ now.
2019-10-31 15:44:09 +01:00
wm4 835586513d sws_utils: shuffle around some shit
Purpose uncertain. I guess it's slightly better, maybe.

The move of the sws/zimg options from VO opts (vo_opt_list) to the
top-level option list is tricky. VO opts have some helper code in vo.c,
that sends VOCTRL_SET_PANSCAN to the VO on every VO opts change. That's
because updating certain VO options used to be this way (and not just
the panscan option). This isn't needed anymore for sws/zimg options, so
explicitly move them away.
2019-10-31 15:26:03 +01:00
wm4 c10ba5eb8e Use mp_log2() instead of av_log2() 2019-10-31 13:17:18 +01:00
wm4 7510ed6f68 common: add mp_log2()
To be used in the next commit.

According to compiler explorer, __builtin_clz is very widely available,
and it barely makes sense to provide a fallback. clang also eats this
(and identifies at least as GCC 4). Actually, there's doubt that a fast
log2 implementation is needed at all (I guess UTF-8 parsing needs it,
but something UTF-8-specific would probably make it faster than using
log2). So the fallback is just something naive.
2019-10-31 13:16:58 +01:00
wm4 6d92e55502 Replace uses of FFMIN/MAX with MPMIN/MAX
And remove libavutil includes where possible.
2019-10-31 11:24:20 +01:00
wm4 6fdfa7c991 stream_memory: remove trivial ffmpeg dependency 2019-10-31 11:06:44 +01:00
wm4 a5461b29c4 manpage: document stats page 3 2019-10-31 11:06:22 +01:00
wm4 1c984f992f player: simplify --stream-dump code
Not sure why it was so complicated. It avoided allocation data on the
stack and copying it twice, but who cares.
2019-10-31 11:05:55 +01:00
wm4 a267452b00 stream: move stream_read_line to demux_playlist.c
demux_playlist.c is the only remaining user of this. Not sure if it
should stay this way, but for now I'll say yes.
2019-10-31 11:05:48 +01:00
wm4 c6b08d222f stream: stop accessing buffer internals in stream_read_line()
Getting this out of the way in preparation for reworking stream
internals.
2019-10-31 11:05:45 +01:00
Jan Ekström be4996e312 interface-changes: fixup the location of d3d11-output-csp
0.30.0 is already cut, so +1 it is.
2019-10-30 20:02:08 +02:00
Jan Ekström 17ad806993 vo_gpu/opengl: fully initialize FBO when passing it to rendering
Until now, we only properly initialized two values, leaving the
rest be garbage.

Fixes #7104
2019-10-30 15:54:41 +01:00
Jan Ekström fc29620ec8 vo_gpu/d3d11: add support for configuring swap chain color space
By default utilizes the color space of the desktop on which the
swap chain is located. If a specific value is defined, it will be
instead be utilized.

Enables configuration of the PQ color space (BT.2020 primaries,
PQ transfer function) for HDR.

Additionally, signals the swap chain color space to the renderer,
so that the render looks correct without having to specify
target-trc or target-prim manually.

Due to all of the APIs being Win10+ only, will only work starting
with Windows 10.
2019-10-30 02:41:25 +02:00
Jan Ekström 93dd77b38e vo_gpu/d3d11: add helpers for getting names for DXGI formats & CSPs
Additionally, define the few enum values that are currently missing
in mingw-w64 headers.
2019-10-30 02:41:25 +02:00
Jan Ekström 4e712e627c vo_gpu: add and utilize color space information from ra_fbo
This lets us set primaries, transfer function and the target peak
based on what the presenting layer would want us to have.

Now that this mechanism is available, warn if the user has
overridden values such as primaries or transfer function.
2019-10-30 02:41:25 +02:00
Jan Janssen b27836011e osc: calculate osc_geo position after aspect correction
Fixes #7098
2019-10-29 17:09:26 +01:00
Cameron Cawley afe3a5a010 vo_caca: Implement VOCTRL_UPDATE_WINDOW_TITLE 2019-10-29 17:07:41 +01:00
Jan Janssen 00c9a6c237 osc: Unify bottom and topbar code
Among the pointless duplication the right timecode label was given some extra space that wasn't needed.

Fixes: #6904
2019-10-28 17:16:02 +01:00
Cameron Cawley 69f7251f32 manpage: Update information about default mouse bindings 2019-10-28 17:14:49 +01:00
Cameron Cawley c2ab4d22b4 vo_sdl: Acknowledge when the mouse enters or leaves the window 2019-10-28 17:14:49 +01:00
Cameron Cawley 619b466cef input: Add default bindings for MBTN_BACK and MBTN_FORWARD 2019-10-28 17:14:49 +01:00
Cameron Cawley f4c04f5a3c vo_sdl: Improve mouse button input
SDL_BUTTON_X1 and SDL_BUTTON_X2 are now correctly mapped to MP_MBTN_BACK and MP_MBTN_FORWARD.
2019-10-28 17:14:49 +01:00
Cameron Cawley d51e637150 vo_sdl: Support mouse wheel input 2019-10-28 17:14:49 +01:00
sfan5 6f9399327e DOCS/release-policy.md: clarify a few details 2019-10-27 14:06:16 +01:00
James Ross-Gowan 8e50d7a746 vo_gpu: log ra_format.storable with the other flags
This seems to have been missed when the storable flag was added, since
all the other flags were logged here. It can be useful to know if an RA
format is storable, so log it as well.
2019-10-27 00:45:27 +11:00
James Ross-Gowan 888f4e63a4 vo_gpu: d3d11: set the ra_format.storable flag
This flag was added in e2976e662d, but it was only set for Vulkan. In
D3D11 it can be set from info in D3D11_FEATURE_FORMAT_SUPPORT2.
2019-10-27 00:45:27 +11:00
wm4 a908101258 vo_gpu: attempt to fix 0bgr format
Using e.g. --vf=format=0bgr showed obviously wrong colors with --vo=gpu.
The reason is that leading padding wasn't handled correctly.

Try to hack fix it. While the code in copy_image() is somewhat
reasonable, I can't tell what the fuck is going on with that HOOKED
shit. For some reason this HOOKED shit doesn't use copy_image() (???),
or uses it incorrectly. It affects debanding. --deband=no works
correctly. If it's enabled, the crap in hook_prelude() is needed.

I bet there are many more bugs with this. For example, the deband shader
will try to deband the alpha channel if the format abgr is used (because
the correct component order is only established later). This can be
tested by inserting a "color.x = 0;" at the end of the deband shader,
and using --vf=format=rgba vs. abgr.

I cannot comprehend why it doesn't just store explicitly which
components a texture contains, and why it doesn't just read the
components always in an uniform way.

There's a big chance this fix works only by coincidence. This shouldn't
have been so hard either. Time for a complete rewrite?
2019-10-26 00:02:55 +02:00
wm4 d3f8d82279 mp_image: copy closed captions when copying attributes
With hwdec copy modes, mp_image_copy_attributes() is used to transfer
metadata other than the image data when copying the image from the
hardware surface. It didn't copy the closed caption data.

Fix this. This makes closed captions in copy mode work.

Fixes: #6376
2019-10-25 22:38:00 +02:00
wm4 40b557db6a mp_image: move buffer ref assigning to a function
Mostly untested, for the next commit.

There's another case of this in this file (ref_buffer()), but it's too
weird, so ignore it.
2019-10-25 22:36:19 +02:00
wm4 c184e290b0 sdl: prevent concurrent use of SDL in different threads
sdl_gamepad.c and vo_sdl.c both have their own event loops and run in
separate threads. They don't know of each other (and shouldn't). Since
SDL only has one global event loop (why didn't they fix this in SDL2?),
these obviously clash. The actual behavior is relatively subtle, which
event being randomly dispatched to either of the threads.

This is very regrettable. Very.

Work this around. "Fortunately" SDL exposes its global state to some
degree. SDL_WasInit() returns whether a "subsystem" was initialized, and
you could say the one who initialized it owns it. Both SDL_INIT_VIDEO
and SDL_INIT_GAMECONTROLLER implicitly enable SDL_INIT_EVENTS, and the
event loop is indeed the resource that cannot be shared.

Unfortunately, this is still racy, since SDL_InitSubSystem is a second
call, and succeeds if the subsystem is already initialized (increases a
refcount I think). But good enough. Blame SDL for everything.

(I think I made this commit message too long. Nobody cares even.)

Fixes: #7085
2019-10-25 22:17:54 +02:00
wm4 e63091b3cc build: make vo_sdl conflict with cocoa
These are inherently incompatible. As far as I'm aware, SDL must be used
from the main thread on OSX.

(Technically, this condition is wrong: the problem happens on OSX in
general, or more precisely, when SDL uses Cocoa. I didn't find the waf
OSX dependency name after 5 second of searching, so I'm just using
cocoa, without which mpv is useless on OSX anyway.)
2019-10-25 22:02:16 +02:00
wm4 9471077efd vo_sdl: put on do not use stamp
It seems some users try to use it (!). This VO was always an experiment,
and intended for low power devices. Whether this experiment succeeded or
not, it's a rather obscure VO. Recently I've seen a regrettable user,
who seemed to use this only because mpv was built without x11 support
(!). Add this warning, like other fallback VOs have it. (The message was
copied from vo_x11.)
2019-10-25 21:58:51 +02:00
wm4 4a82349900 input: disable gamepad code by default
Enabling this by default probably causes a number of issues, such as
breaking vo_sdl, or reacting to various input devices while the window
is not focused. It's also pretty obscure, or at least new. Disable it by
default.
2019-10-25 21:54:35 +02:00
wm4 52536aaa7b f_decoder_wapper: trust frame return over error code
lavc_process() calls the receive/send callbacks, which mirror
libavcodec's send/receive API. The receive API in particular can return
both a status code and a frame. Normally, libavcodec is pretty explicit
that it can't return both a frame and an error. But the receive callback
does more stuff in addition (vd_lavc does hardware decoding fallbacks
etc.). The previous commit shows an instance where this happened, and
where it leaked a frame in this case.

For robustness, check whether the frame is set first, i.e. trust it over
the status code. Before this, it checked for an EOF status first.

Hopefully is of no consequence otherwise. I made this change after
testing everything (can someone implement a test suite which tests this
exhaustively).
2019-10-25 21:50:10 +02:00
wm4 edc6075fa3 vd_lavc: fix draining with hwdec copy modes
Commit 5d5fdb77e9 changed details of the decoding control flow, and
called it a "high-risk" change. It turns out that this broke with with
hwdec copy mode, where there is some sort of delay queue (supposedly
increases efficiency, but more likely worthless cargo-cult).

It simply used the wrong (basically inverted) condition for the draining
case.

This was the only case that did not work properly. Other tests,
including video/audio decoding errors, software decoding fallbacks,
etc., seemed to work well. Might still not be exhaustive, as there are
so many corner cases.

Also change two error code returns. This don't/shouldn't really matter,
though the second error code led it to return both a frame and
AVERROR_EOF, which is unexpected, and makes lavc_process() leak a frame.
But also see next commit.

Fixes: 5d5fdb77e9
2019-10-25 21:44:49 +02:00
James Ross-Gowan 7384b05433 vo_gpu: d3d11: prevent wraparound in queued frames calc
If expected_sync_pc is greater than submit_count, the unsigned
subtraction will wraparound, which breaks playback. This bug was found
while experimenting with bit-blt model present, but it might be possible
to trigger it with the flip model as well, if there was a dropped frame.
2019-10-26 01:14:01 +11:00
sfan5 ca0177481b Update VERSION 2019-10-25 15:39:16 +02:00
sfan5 51ec2e86e8 Merge branch 'release/0.30' 2019-10-25 15:39:02 +02:00
wm4 8b0ff53b69 sdl_gamepad: fix typo in function name
As pointed out by LaserEyess on IRC.
2019-10-25 15:33:23 +02:00
wm4 49cde32be0 sdl_gamepad: fix function signature
This is semantically different in C.
2019-10-25 15:26:34 +02:00
wm4 50f263990a vo_drm: allow use of zimg 2019-10-25 15:25:49 +02:00
wm4 5e2779b2da client API: copy instead of move old value on async path
In theory, it's better to keep the old value, because that's more
consistent with the logic of using change timestamps. With the current
code, the old value will probably never be used (instead it will fetch a
new value on every change), so this shouldn't make a difference in
practice.
2019-10-25 15:14:05 +02:00
wm4 e67386e50b manpage: fix --script docs
This doesn't take a ',' separated list. --script is just an alias for
--scripts--append. --scripts accepts a list, but uses the
mplayer-inherited platform-dependent path separator.

Fixes: #5996
2019-10-25 13:41:34 +02:00
wm4 d66eb93e5d client API: add async path; fix deadlock for vo_libmpv users
In commit 065c307e8e, I broke everything. It seemed like a nice idea,
but it explicitly broke an assumption vo_libmpv were explicitly allowed
to make: that observing properties does not lock the core. The commit
did just that and locked the core for property updates. This made for
example mpv's own OSX backend freeze (it uses vo_libmpv for convenience
to make up for Apple's incredibly broken OpenGL shit).

I don't want to revert that commit just because vo_libmpv's design is
horrible. So instead add an optional asynchronous path, that is only
used if vo_libmpv is in use (best idea ever?).

Interestingly, this isn't so hard. It adds about 90 lines of code, which
are only run on OSX and libmpv users, so I don't have to care about the
crashes and weird behavior this might cause. It even worked on the first
try except for a quickly fixed memory leak. The code path can be tested
anywhere by just turning the uses_vo_libmpv condition into always true.

The atomic is out of laziness. Saves some thinking how to get around the
locking order.
2019-10-25 01:57:51 +02:00
wm4 767c35c883 command: remove some unused property metadata
Also add an OSD entry for the video aspect.
2019-10-25 00:50:38 +02:00
wm4 223876d92b options: set correct range for --video-aspect-override
It appears this option didn't have min/max enabled for quite a while
(broken while it was still called --aspect).
2019-10-25 00:47:45 +02:00
wm4 7ac622bc5f json: write NaN/Infinity float values as strings
JSON doesn't support these for some god-awful reason. (JSON would have
been so much better if it weren't based on JavaScript, the plague of
this world.)

We don't really care whether these specific values "round trip", so we
might as well write them in a standard-compliant way.

Untested. I was too lazy to even run this, but it probably works.

See #6691.
2019-10-25 00:30:04 +02:00
wm4 77f309c94f vo_gpu, options: don't return NaN through API
Internally, vo_gpu uses NaN for some options to indicate a default value
that is different depending on the context (e.g. different scalers).
There are 2 problems with this:

1. you couldn't reset the options to their defaults
2. NaN is a damn mess and shouldn't be part of the API

The option parser already rejected NaN explicitly, which is why 1.
didn't work. Regarding 2., JSON might be a good example, and actually
caused a bug report.

Fix this by mapping NaN to the special value "default". I think I'd
prefer other mechanisms (maybe just having every scaler expose separate
options?), but for now this will do. See you in a future commit, which
painfully deprecates this and replaces it with something else.

I refrained from using "no" (my favorite magic value for "unset" etc.)
because then I'd have e.g. make --no-scale-param1 work, which in
addition to a lot of effort looks dumb and nobody will use it.

Here's also an apology for the shitty added test script.

Fixes: #6691
2019-10-25 00:25:05 +02:00
wm4 b0827b4dc4 client API: avoid lost wakeups
The commit linked below added temporary unlocking to update_prop(),
which is indirectly called by mpv_wait_event(). If an unlock happens,
and no property change event is returned, we must re-poll the event
queue. Rechecking the state on unlocks is basically a standard
requirement for code using condition variables.

Untested beyond a simple test.

Fixes: 065c307e8e
2019-10-24 19:12:36 +02:00
wm4 5d5fdb77e9 ad_lavc, vd_lavc: return full error codes to shared decoder loop
ad_lavc and vd_lavc use the lavc_process() helper to translate the
FFmpeg push/pull API to the internal filter API (which completely
mismatch, even though I'm responsible for both, just fucking kill me).

This interface was "slightly" too tight. It returned only a bool
indicating "progress", which was not enough to handle some cases (see
following commit).

While we're at it, move all state into a struct. This is only a single
bool, but we get the chance to add more if needed.

This fixes mpv falling asleep if decoding returns an error during
draining. If decoding fails when we already sent EOF, the state machine
stopped making progress. This left mpv just sitting around and doing
nothing.

A test case can be created with: echo $RANDOM >> image.png

This makes libavformat read a proper packet plus a packet of garbage.
libavcodec will decode a frame, and then return an error code. The
lavc_process() wrapper could not deal with this, because there was no
way to differentiate between "retry" and "send new packet". Normally, it
would send a new packet, so decoding would make progress anyway. If
there was "progress", we couldn't just retry, because it'd retry
forever.

This is made worse by the fact that it tries to decode at least two
frames before starting display, meaning it will "sit around and do
nothing" before the picture is displayed.

Change it so that on error return, "receiving" a frame is retried. This
will make it return the EOF, so everything works properly.

This is a high-risk change, because all these funny bullshit exceptions
for hardware decoding are in the way, and I didn't retest them. For
example, if hardware decoding is enabled, it keeps a list of packets,
that are fed into the decoder again if hardware decoding fails, and a
software fallback is performed. Another case of horrifying accidental
complexity.

Fixes: #6618
2019-10-24 18:50:28 +02:00
wm4 065c307e8e client API: simplify (?) property change notification generation
Property change notification works by having the mpv core wake up all
clients observing a property when the property potentially changes. The
clients then read the property's value, and determine if there was an
actual change. (The latter part depends what the property returned for
the previous change notification, so it depends on the client, and
cannot be generated by the core itself.)

Until now, reading the property value was done in a pseudo-async way by
queuing a callback back to the core, running it there, and then waking
up the client thread again. I cannot comprehend why this was done in
such a complicated, fragile way. Maybe it's a leftover from times when
client.c had to do this (in short, because properties could access
vo_opengl, which has thread-local state).

One past idea was to make the implementation of true async properties
easier (for which you would need such a state machine anyway). But they
don't exist yet, and I doubt the current mess would be really helpful
when actually implementing them.

Simplify this, and run the update in the client's thread directly. In
addition to the fundamental change, many roundabout things can be
removed as a consequence.

Unfortunately, I noticed that lock order issues force you to release
ctx->lock before doing so, which makes things more complex due to
possible concurrent mpv_unobserve_property() calls. Solve this by
removing properties lazily, which means you may have to do multiple
mpv_wait_event() calls before the property entry is actually destroyed.
This should not matter in practice, and does not affect the semantics.
It could also cause "leaks" by observing/unobserving properties in a
loop, without ever calling mpv_wait_event(). Just don't do this, duh.

(I considered making this dependent on whether the previous
mpv_wait_event() call returned the property being removed, but a
separate code path seemed too complicated. I also considered copying the
name and property data when returning a MPV_EVENT_PROPERTY_CHANGE, but
actually this doesn't solve the problem of update_prop() being
interrupted by mpv_unobserve_property(); there are ways around it, but I
just said no.)

This was made using the cowboy coding software engineering methodology.
If you find any bugs, keep them yourself.
2019-10-24 17:51:36 +02:00
272 changed files with 14843 additions and 7613 deletions

No files matched your search

-26
View File
@@ -1,26 +0,0 @@
### mpv version and platform
If you're not using git master or the latest release, update.
Releases are listed here: https://github.com/mpv-player/mpv/releases
### Reproduction steps
### Expected behavior
### Actual behavior
### Log file
Make a log file made with -v or --log-file=output.txt, paste it to
https://0x0.st/ or a similar site, and replace this text with a link to it.
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, and your bug report will be closed
or ignored.
### Sample files
Sample files needed to reproduce this issue can be uploaded to https://0x0.st/
or similar sites. (Only needed if the issue cannot be reproduced without it.)
Do not use garbage like "cloud storage", especially not Google Drive.
+16
View File
@@ -0,0 +1,16 @@
---
name: 'README: DO NOT IGNORE OR DELETE THE ISSUE TEMPLATE'
about: 'Chose and fill out one of the following templates!'
title: ''
labels: priority:ignored-issue-template
assignees: ''
---
We ask you to not ignore the issue template. Fill it out as good and correct as
possible. Issues that don't adhere to our request will be closed for ignoring
the issue template. This is because analyzing a bug without a log file is harder
than necessary. Low quality bug reports are noise.
Please go back and chose the proper issue template. Opening issues with this
template will be closed immediately.
@@ -0,0 +1,46 @@
---
name: 'Report a Linux Issue'
about: 'Create a report for a runtime related Linux Issue'
title: ''
labels: 'os:linux'
assignees: ''
---
### Important Information
Provide following Information:
- mpv version
- Linux Distribution and Version
- Source of the mpv binary
- If known which version of mpv introduced the problem
- Window Manager and version
- GPU driver and version
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Releases are listed here: https://github.com/mpv-player/mpv/releases
### Reproduction steps
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differes from your own.
### Expected behavior
### Actual behavior
### Log file
Make a log file made with -v -v or --log-file=output.txt, paste it to
https://0x0.st/ or attach it to the github issue, and replace this text with a
link to it.
The issue will be closed for ignoring the issue template.
### Sample files
Sample files needed to reproduce this issue can be uploaded to https://0x0.st/
or similar sites. (Only needed if the issue cannot be reproduced without it.)
Do not use garbage like "cloud storage", especially not Google Drive.
@@ -0,0 +1,46 @@
---
name: 'Report a macOS Issue'
about: 'Create a report for a runtime related macOS Issue'
title: ''
labels: 'os:mac'
assignees: ''
---
### Important Information
Provide following Information:
- mpv version
- macOS Version
- Source of the mpv binary or bundle
- If known which version of mpv introduced the problem
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Releases are listed here: https://github.com/mpv-player/mpv/releases
### Reproduction steps
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differes from your own.
### Expected behavior
### Actual behavior
### Log file
Make a log file made with -v -v or --log-file=output.txt, paste it to
https://0x0.st/ or attach it to the github issue, and replace this text with a
link to it.
In the case of a crash please provide the macOS Crash Report (Backtrace).
The issue will be closed for ignoring the issue template.
### Sample files
Sample files needed to reproduce this issue can be uploaded to https://0x0.st/
or similar sites. (Only needed if the issue cannot be reproduced without it.)
Do not use garbage like "cloud storage", especially not Google Drive.
@@ -0,0 +1,44 @@
---
name: 'Report a Windows Issue'
about: 'Create a report for a runtime related Windows Issue'
title: ''
labels: 'os:win'
assignees: ''
---
### Important Information
Provide following Information:
- mpv version
- Windows Version
- Source of the mpv binary
- If known which version of mpv introduced the problem
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Releases are listed here: https://github.com/mpv-player/mpv/releases
### Reproduction steps
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differes from your own.
### Expected behavior
### Actual behavior
### Log file
Make a log file made with -v -v or --log-file=output.txt, paste it to
https://0x0.st/ or attach it to the github issue, and replace this text with a
link to it.
The issue will be closed for ignoring the issue template.
### Sample files
Sample files needed to reproduce this issue can be uploaded to https://0x0.st/
or similar sites. (Only needed if the issue cannot be reproduced without it.)
Do not use garbage like "cloud storage", especially not Google Drive.
+40
View File
@@ -0,0 +1,40 @@
---
name: 'Report a different Issue'
about: 'Create a report for a runtime related Issue'
title: ''
labels: ''
assignees: ''
---
### Important Information
Provide following Information:
- mpv version
- Platform and Version
- Source of the mpv binary
If you're not using git master or the latest release, update.
Releases are listed here: https://github.com/mpv-player/mpv/releases
### Reproduction steps
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differes from your own.
### Expected behavior
### Actual behavior
### Log file
Make a log file made with -v -v or --log-file=output.txt, paste it to
https://0x0.st/ or attach it to the github issue, and replace this text with a
link to it.
### Sample files
Sample files needed to reproduce this issue can be uploaded to https://0x0.st/
or similar sites. (Only needed if the issue cannot be reproduced without it.)
Do not use garbage like "cloud storage", especially not Google Drive.
@@ -0,0 +1,30 @@
---
name: 'Report a build Problem'
about: 'Create a report for a build related Issue'
title: ''
labels: 'core:waf'
assignees: ''
---
### mpv version and platform versions
If you're not using git master or the latest release, update.
Releases are listed here: https://github.com/mpv-player/mpv/releases
### Reproduction steps
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differes from your own.
### Expected behavior
### Actual behavior
### Log file
Upload build/config.log or ./waf configure output to https://0x0.st/ or attach
it to the github issue, and replace this text with a link to it.
The issue will be closed for ignoring the issue template.
@@ -0,0 +1,15 @@
---
name: 'Request a new Feature'
about: 'Create a request for a new feature'
title: ''
labels: 'meta:feature-request'
assignees: ''
---
Before requesting a new feature make sure it hasn't been requested yet.
https://github.com/mpv-player/mpv/labels/meta%3Afeature-request
### Expected behavior of the wanted feature
### Alternative behavior of the wanted feature
+18
View File
@@ -0,0 +1,18 @@
---
name: 'Ask a Question'
about: 'Ask a question about mpv'
title: ''
labels: 'meta:question'
assignees: ''
---
Don't ask questions about issues, errors or problems you have and instead open
a proper issue with the right template from the previous selection.
This template is meant for questions about the workings of mpv, to clarify about
unspecified behaviour of options or command, or anything else that is not well
described and needs clarification.
Before asking a question make sure it hasn't been asked or answered yet.
https://github.com/mpv-player/mpv/labels/meta%3Aquestion
+9
View File
@@ -0,0 +1,9 @@
blank_issues_enabled: false
contact_links:
- name: mpv irc channel
url: https://mpv.io/community/
about: Feel free to ask question here irc://irc.freenode.net/mpv
- name: mpv irc developer channel
url: https://mpv.io/community/
about: Ask question related to the development of mpv here
irc://irc.freenode.net/mpv-devel
+55 -21
View File
@@ -1,16 +1,29 @@
language: c
macbase:
- &macOld
os: osx
compiler: clang
env:
- HOMEBREW_NO_AUTO_UPDATE=1
- HOMEBREW_NO_INSTALL_CLEANUP=1
- &macNew
<<: *macOld
addons:
homebrew:
packages: ['autoconf', 'automake', 'ffmpeg', 'freetype', 'fribidi',
'libass', 'libtool', 'little-cms2', 'luajit', 'nasm',
'pkg-config', 'python']
update: true
matrix:
include:
- os: osx
osx_image: xcode11
compiler: clang
- os: osx
- <<: *macNew
osx_image: xcode11.3
- <<: *macNew
osx_image: xcode10.1
compiler: clang
- os: osx
- <<: *macOld
osx_image: xcode9.2
compiler: clang
- os: linux
compiler: gcc
env: CONTAINER=registry.cirno.systems/kiwi/containers/mpv-ci:stable-deps CI_SCRIPT=ci/build-tumbleweed.sh
@@ -21,6 +34,10 @@ matrix:
env: CONTAINER=registry.cirno.systems/kiwi/containers/mpv-ci-mingw64:i686 CI_SCRIPT=ci/build-mingw64.sh TARGET=i686-w64-mingw32
- os: linux
env: CONTAINER=registry.cirno.systems/kiwi/containers/mpv-ci-mingw64:x86_64 CI_SCRIPT=ci/build-mingw64.sh TARGET=x86_64-w64-mingw32
allow_failures:
- os: osx
osx_image: xcode9.2
fast_finish: true
dist: bionic
services:
@@ -46,7 +63,36 @@ before_install:
- if [ "$TRAVIS_COMPILER" = "clang" ]; then export CXX="clang++"; fi
- if [ "$TRAVIS_COMPILER" = "gcc" ]; then export CXX="g++"; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then docker pull $CONTAINER; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then "$TRAVIS_BUILD_DIR/ci/get_ffmpeg.sh"; fi
- |
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
if [[ "$TRAVIS_OSX_IMAGE" == "xcode9.2" ]]; then
brew update
pushd "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core"
git checkout 55e02323812604add9a69bab8730319b9255a697
popd
brew install autoconf
brew install automake
brew install pkg-config
brew install libtool
brew install python
brew install freetype
brew install fribidi
brew install little-cms2
brew install luajit
brew install libass
brew install ffmpeg
else
brew link --overwrite python
fi
fi
before_cache:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew cleanup -s ; fi
cache:
directories:
- $HOME/Library/Caches/Homebrew
script:
- ./bootstrap.py
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then docker run --env CC --env TARGET -v $TRAVIS_BUILD_DIR:/build $CONTAINER /bin/sh -c "cd /build && $CI_SCRIPT"; fi
@@ -57,6 +103,7 @@ after_script: TOOLS/travis-rebuild-website
notifications:
email: false
irc:
if: fork = false
channels:
- "irc.freenode.org#mpv-devel"
on_success: change
@@ -71,16 +118,3 @@ addons:
build_command_prepend: "./bootstrap.py && ./waf configure"
build_command: "./waf build"
branch_pattern: coverity_scan
homebrew:
packages:
- autoconf
- automake
- freetype
- fribidi
- libass
- libtool
- little-cms2
- luajit
- nasm
- pkg-config
update: true
+3
View File
@@ -32,6 +32,9 @@ API changes
::
--- mpv 0.31.0 ---
1.107 - Deprecate MPV_EVENT_TICK
--- mpv 0.30.0 ---
1.106 - Add cancel_fn to mpv_stream_cb_info
1.105 - Fix deadlock problems with MPV_RENDER_PARAM_ADVANCED_CONTROL and if
+6 -2
View File
@@ -168,8 +168,12 @@ Or, compile and install both libmpv and mpv:
Linking libmpv with MSVC programs
---------------------------------
You can build C++ programs in Visual Studio and link them with libmpv. To do
this, you need a Visual Studio which supports ``stdint.h`` (recent ones do),
mpv/libmpv cannot be built with Visual Studio (Microsoft is too incompetent to
support C99/C11 properly and/or hates open source and Linux too much to
seriously do it). But you can build C++ programs in Visual Studio and link them
with a libmpv built with MinGW.
To do this, you need a Visual Studio which supports ``stdint.h`` (recent ones do),
and you need to create a import library for the mpv DLL:
```bash
+26 -11
View File
@@ -41,7 +41,7 @@ Copyright of contributions
behalf of your employer, and the employer owns the copyright, you must mention
this. If the license of the code is not LGPLv2.1+, you must mention this.
- These license statements are legally binding.
- Don't use fake names (something that looks like an actual names, and may be
- Don't use fake names (something that looks like an actual name, and may be
someone else's name, but is not your legal name). Using a pseudonyms is
allowed if it can be used to identify or contact you, even if whatever
account you used to submit the patch dies.
@@ -55,10 +55,10 @@ Write good commit messages
- Write informative commit messages. Use present tense to describe the
situation with the patch applied, and past tense for the situation before
the change.
- The subject line (the first line in a commit message) should contain a
- The subject line (the first line in a commit message) must contain a
prefix identifying the sub system, followed by a short description what
impact this commit has. This subject line and the commit message body
shouldn't be longer than 72 characters per line, because it messes up the
must not be longer than 72 characters per line, because it messes up the
output of many git tools otherwise.
For example, you fixed a crash in af_volume.c:
@@ -68,7 +68,11 @@ Write good commit messages
Having a prefix gives context, and is especially useful when trying to find
a specific change by looking at the history, or when running ``git blame``.
- The body of the commit message (everything else after the subject line) should
- The first word after the ``:`` is lower case.
- Don't end the subject line with a ``.``.
- Put an empty line between the subject line and the commit message.
If this is missing, it will break display in common git tools.
- The body of the commit message (everything else after the subject line) must
be as informative as possible and contain everything that isn't obvious. Don't
hesitate to dump as much information as you can - it doesn't cost you
anything. Put some effort into it. If someone finds a bug months or years
@@ -77,13 +81,10 @@ Write good commit messages
information to test the original bug. The old bug might be reintroduced while
fixing the new bug.
The commit message should be wrapped on 72 characters per line, because git
The commit message must be wrapped on 72 characters per line, because git
tools usually do not break text automatically. On the other hand, you do not
need to break text that would be unnatural to break (like data for test cases,
or long URLs).
Important: put an empty line between the subject line and the commit message.
If this is missing, it will break display in common git tools.
- Another summary of good conventions: https://chris.beams.io/posts/git-commit/
Split changes into multiple commits
@@ -95,6 +96,9 @@ Split changes into multiple commits
additional cosmetic changes in the same file you're working on. But don't do
something like reformatting a whole file, and hiding an actual functional
change in the same commit.
- Splitting changes does _not_ mean that you should make them as fine-grained
as possible. Commits should form logical steps in development. The way you
split changes is important for code review and analyzing bugs.
Touching user-visible parts may require updating the mpv docs
-------------------------------------------------------------
@@ -120,7 +124,7 @@ mpv uses C99 with K&R formatting, with some exceptions.
- Use the K&R indent style.
- Use 4 spaces of indentation, never use tabs (except in Makefiles).
- Add a single space between keywords and binary operators. There are some other
cases where spaces should be added. Example:
cases where spaces must be added. Example:
```C
if ((a * b) > c) {
@@ -153,7 +157,7 @@ mpv uses C99 with K&R formatting, with some exceptions.
do_something();
}
```
- If the if has an else branch, both branches should use braces, even if they're
- If the if has an else branch, both branches must use braces, even if they're
technically redundant.
Example:
@@ -185,6 +189,17 @@ mpv uses C99 with K&R formatting, with some exceptions.
- Remove any trailing whitespace.
- Do not make stray whitespaces changes.
Header #include statement order
-------------------------------
The order of ``#include`` statements in the source code is not very consistent.
New code must follow the following conventions:
- Put standard includes (``#include <stdlib.h>`` etc.) on the top,
- then after a blank line, add library includes (``#include <zlib.h>`` etc.)
- then after a blank line, add internal includes (``#include "player/core.h"``)
- sort them alphabetically within these sections
General coding
--------------
@@ -193,7 +208,7 @@ General coding
- Don't use non-standard language (such as GNU C-only features). In some cases
they may be warranted, if they are optional (such as attributes enabling
printf-like format string checks). "#pragma once" is allowed as an exception.
But in general, standard C99 should be used.
But in general, standard C99 must be used.
- The same applies to libc functions. We have to be Windows-compatible too. Use
functions guaranteed by C99 or POSIX only, unless your use is guarded by a
configure check. There is some restricted use of C11 (ask on IRC for details).
-3
View File
@@ -254,6 +254,3 @@ header, the syntax is exactly the same. It's far more convenient to use ``;``
instead of line breaks, but that is orthogonal.
Example: ``edl://f1.mkv,length=5,start=10;f2.mkv,30,20;f3.mkv``
As a quirks, mpv will accept arbitrary paths in EDLs originating from
``edl://``, while ``.edl`` does not. This makes no sense.
+6 -2
View File
@@ -30,9 +30,13 @@ section::
[myencprofile]
vf-add = scale=480:-2
ovc = libx264
ovcopts-add = preset=medium,tune=fastdecode
ovcopts-add = preset=medium
ovcopts-add = tune=fastdecode
ovcopts-add = crf=23
ovcopts-add = maxrate=1500k,bufsize=1000k,rc_init_occupancy=900k,refs=2
ovcopts-add = maxrate=1500k
ovcopts-add = bufsize=1000k
ovcopts-add = rc_init_occupancy=900k
ovcopts-add = refs=2
ovcopts-add = profile=baseline
oac = aac
oacopts-add = b=96k
+66
View File
@@ -24,6 +24,72 @@ Interface changes
::
--- mpv 0.32.0 ---
- change behavior when using legacy option syntax with options that start
with two dashes (``--`` instead of a ``-``). Now, using the recommended
syntax is required for options starting with ``--``, which means an option
value must be strictly passed after a ``=``, instead of as separate
argument. For example, ``--log-file f.txt`` was previously accepted and
behaved like ``--log-file=f.txt``, but now causes an error. Use of legacy
syntax that is still supported now prints a deprecation warning.
--- mpv 0.31.0 ---
- add `--resume-playback-check-mtime` to check consistent mtime when
restoring playback state.
- add `--d3d11-output-csp` to enable explicit selection of a D3D11
swap chain color space.
- the --sws- options and similar now affect vo_image and screenshot
conversion (does not matter as much for vo_gpu, which does most of this
with shaders)
- add a builtin "sw-fast" profile, which restores performance settings
for software video conversion. These were switched to higher quality since
mpv 0.30.0 (related to the previous changelog entry). This affects video
outputs like vo_x11 and vo_drm, and screenshots, but not much else.
- deprecate --input-file (there are no plans to remove this short-term,
but it will probably eventually go away)
- deprecate --video-sync=display-adrop (might be removed if it's in the way;
undeprecated or readded if it's not too much of a problem)
- deprecate all input section commands (these will be changed/removed, as
soon as mpv internals do not require them anymore)
- remove deprecated --playlist-pos alias (use --playlist-start)
- deprecate --display-fps, introduce --override-display-fps. The display-fps
property now is unavailable if no VO exists (or the VO did not return a
display FPS), instead of returning the option value in this case. The
property will keep existing, but writing to it is deprecated.
- the vf/af properties now do not reject the set value anymore, even if
filter chain initialization fails. Instead, the vf/af options are always
set to the user's value, even if it does not reflect the "runtime" vf/af
chain.
- the vid/aid/sid/secondary-sid properties (and their aliases: "audio",
"video", "sub") will now allow setting any track ID; before this change,
only IDs of actually existing tracks could be set (the restriction was
active the MPV_EVENT_FILE_LOADED/"file-loaded" event was sent). Setting
an ID for which no track exists is equivalent to disabling it. Note that
setting the properties to non-existing tracks may report it as selected
track for a small time window, until it's forced back to "no". The exact
details how this is handled may change in the future.
- remove old Apple Remote support, including --input-appleremote
- add MediaPlayer support and remove the old Media Key event tap on macOS.
this possibly also re-adds the Apple Remote support
- the "edition" property now strictly returns the value of the option,
instead of the runtime value. The new "current-edition" property needs to
be queried to read the runtime-chosen edition. This is a breaking change
for any users which expected "edition" to return the runtime-chosen
edition at default settings (--edition=auto).
- the "window-scale" property now strictly returns the value of the option,
instead of the actual size of the window. The new "current-window-scale"
property needs to be queried to read the value as indicated by the current
window size. This is a breaking change.
- explicitly deprecate passing more than 1 item to "-add" suffix in key/value
options (for example --script-opts-add). This was actually always
deprecated, like with other list options, but the option parser did not
print a warning in this particular case.
- deprecate -del for list options (use -remove instead, which is by content
instead of by integer index)
- if `--fs` is used but `--fs-screen` is not set, mpv will now use `--screen`
instead.
- change the default of --hwdec to "no" on RPI. The default used to be "mmal"
specifically if 'Raspberry Pi support' was enabled at configure time
(equivalent to --enable-rpi). Use --hwdec=mmal to get the old behavior.
--- mpv 0.30.0 ---
- add `--d3d11-output-format` to enable explicit selection of a D3D11
swap chain format.
+107
View File
@@ -0,0 +1,107 @@
CONSOLE
=======
The console is a REPL for mpv input commands. It is displayed on the video
window. It also shows log messages. It can be disabled entirely using the
``--load-osd-console=no`` option.
Keybindings
-----------
\`
Show the console.
ESC
Hide the console.
ENTER
Run the typed command.
Shift+ENTER
Type a literal newline character.
Ctrl+LEFT and Ctrl+RIGHT
Move cursor to previous/next word.
UP and DOWN
Navigate command history.
PGUP
Go to the first command in the history.
PGDN
Stop navigating command history.
INSERT
Toggle insert mode.
Shift+INSERT
Paste text (uses the primary selection on X11.)
TAB
Complete the command or property name at the cursor.
Ctrl+C
Clear current line.
Ctrl+K.
Delete text from the cursor to the end of the line.
Ctrl+L
Clear all log messages from the console.
Ctrl+U
Delete text from the cursor to the beginning of the line.
Ctrl+V
Paste text (uses the clipboard on X11.)
Ctrl+W
Delete text from the cursor to the beginning of the current word.
Commands
--------
``script-message-to console type <text>``
Show the console and pre-fill it with the provided text.
Known issues
------------
- Pasting text is slow on Windows
- Non-ASCII keyboard input has restrictions
- The cursor keys move between Unicode code-points, not grapheme clusters
Configuration
-------------
This script can be customized through a config file ``script-opts/console.conf``
placed in mpv's user directory and through the ``--script-opts`` command-line
option. The configuration syntax is described in `ON SCREEN CONTROLLER`_.
Key bindings can be changed in a standard way, see for example stats.lua
documentation.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``scale``
Default: 1
All drawing is scaled by this value, including the text borders and the
cursor.
If the VO backend in use has HiDPI scale reporting implemented, the option
value is scaled with the reported HiDPI scale.
``font``
Default: unset (picks a hardcoded font depending on detected platform)
Set the font used for the REPL and the console. This probably doesn't
have to be a monospaced font.
``font_size``
Default: 16
Set the font size used for the REPL and the console. This will be
multiplied by "scale."
+16 -12
View File
@@ -15,11 +15,11 @@ You can encode files from one format/codec to another using this facility.
Specifies the output format options for libavformat.
See ``--ofopts=help`` for a full list of supported options.
Options are managed in lists. There are a few commands to manage the
options list.
This is a key/value list option. See `List Options`_ for details.
``--ofopts-add=<options1[,options2,...]>``
Appends the options given as arguments to the options list.
``--ofopts-add=<option>``
Appends the option given as an argument to the options list. (Passing
multiple options is currently still possible, but deprecated.)
``--ofopts=""``
Completely empties the options list.
@@ -41,11 +41,11 @@ You can encode files from one format/codec to another using this facility.
"``--oac=libmp3lame --oacopts=b=128000``"
selects 128 kbps MP3 encoding.
Options are managed in lists. There are a few commands to manage the
options list.
This is a key/value list option. See `List Options`_ for details.
``--oacopts-add=<options1[,options2,...]>``
Appends the options given as arguments to the options list.
``--oacopts-add=<option>``
Appends the option given as an argument to the options list. (Passing
multiple options is currently still possible, but deprecated.)
``--oacopts=""``
Completely empties the options list.
@@ -74,11 +74,11 @@ You can encode files from one format/codec to another using this facility.
``"--ovc=libx264 --ovcopts=crf=23"``
selects VBR quality factor 23 for H.264 encoding.
Options are managed in lists. There are a few commands to manage the
options list.
This is a key/value list option. See `List Options`_ for details.
``--ovcopts-add=<options1[,options2,...]>``
Appends the options given as arguments to the options list.
``--ovcopts-add=<option>``
Appends the option given as an argument to the options list. (Passing
multiple options is currently still possible, but deprecated.)
``--ovcopts=""``
Completely empties the options list.
@@ -103,6 +103,8 @@ You can encode files from one format/codec to another using this facility.
FLAC allow almost arbitrary keys, while support in MP4 and MP3 is more
limited.
This is a key/value list option. See `List Options`_ for details.
.. admonition:: Example
"``--oset-metadata=title="Output title",comment="Another tag"``"
@@ -112,6 +114,8 @@ You can encode files from one format/codec to another using this facility.
Specifies metadata to exclude from the output file when copying from the
input file.
This is a string list option. See `List Options`_ for details.
.. admonition:: Example
"``--oremove-metadata=comment,genre``"
+340 -42
View File
@@ -41,6 +41,8 @@ commands they're bound to on the OSD, instead of executing the commands::
(Only closing the window will make **mpv** exit, pressing normal keys will
merely display the binding, even if mapped to quit.)
Also see `Key names`_.
input.conf syntax
-----------------
@@ -78,6 +80,80 @@ that matches, and the multi-key command will never be called. Intermediate keys
can be remapped to ``ignore`` in order to avoid this issue. The maximum number
of (non-modifier) keys for combinations is currently 4.
Key names
---------
All mouse and keyboard input is to converted to mpv-specific key names. Key
names are either special symbolic identifiers representing a physical key, or a
text key names, which are unicode code points encoded as UTF-8. These are what
keyboard input would normally produce, for example ``a`` for the A key. As a
consequence, mpv uses input translated by the current OS keyboard layout, rather
than physical scan codes.
Currently there is the hardcoded assumption that every text key can be
represented as a single unicode code point (in NFKC form).
All key names can be combined with the modifiers ``Shift``, ``Ctrl``, ``Alt``,
``Meta``. They must be prefixed to the actual key name, where each modifier
is followed by a ``+`` (for example ``ctrl+q``).
Symbolic key names and modifier names are case-insensitive. Unicode key names
are case-sensitive because input bindings typically respect the shift key.
Another type of key names are hexadecimal key names, that serve as fallback
for special keys that are neither unicode, nor have a special mpv defined name.
They will break as soon as mpv adds proper names for them, but can enable you
to use a key at all if that does not happen.
All symbolic names are listed by ``--input-keylist``. ``--input-test`` is a
special mode that prints all input on the OSD.
Comments on some symbolic names:
``KP*``
Keypad names. Behavior varies by backend (whether they implement this, and
on how they treat numlock), but typically, mpv tries to map keys on the
keypad to separate names, even if they produce the same text as normal keys.
``MOUSE_BTN*``, ``MBTN*``
Various mouse buttons.
Depending on backend, the mouse wheel might also be represented as a button.
In addition, ``MOUSE_BTN3`` to ``MOUSE_BTN6`` are deprecated aliases for
``WHEEL_UP``, ``WHEEL_DOWN``, ``WHEEL_LEFT``, ``WHEEL_RIGHT``.
``MBTN*`` are aliases for ``MOUSE_BTN*``.
``WHEEL_*``
Mouse wheels (typically).
``AXIS_*``
Deprecated aliases for ``WHEEL_*``.
``*_DBL``
Mouse button double clicks.
``MOUSE_MOVE``, ``MOUSE_ENTER``, ``MOUSE_LEAVE``
Emitted by mouse move events. Enter/leave happens when the mouse enters or
leave the mpv window (or the current mouse region, using the deprecated
mouse region input section mechanism).
``CLOSE_WIN``
Pseudo key emitted when closing the mpv window using the OS window manager
(for example, by clicking the close button in the window title bar).
``GAMEPAD_*``
Keys emitted by the SDL gamepad backend.
``UNMAPPED``
Pseudo-key that matches any unmapped key. (You should probably avoid this
if possible, because it might change behavior or get removed in the future.)
``ANY_UNICODE``
Pseudo-key that matches any key that produces text. (You should probably
avoid this if possible, because it might change behavior or get removed in
the future.)
Flat command syntax
-------------------
@@ -350,6 +426,12 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
Shuffle the playlist. This is similar to what is done on start if the
``--shuffle`` option is used.
``playlist-unshuffle``
Attempt to revert the previous ``playlist-shuffle`` command. This works
only once (multiple successive ``playlist-unshuffle`` commands do nothing).
May not work correctly if new recursive playlists have been opened since
a ``playlist-shuffle`` command.
``run <command> [<arg1> [<arg2> [...]]]``
Run the given command. Unlike in MPlayer/mplayer2 and earlier versions of
mpv (0.2.x and older), this doesn't call the shell. Instead, the command
@@ -649,6 +731,10 @@ Input Commands that are Possibly Subject to Change
``vf <operation> <value>``
Change video filter chain.
The semantics are exactly the same as with option parsing (see
`VIDEO FILTERS`_). As such the text below is a redundant and incomplete
summary.
The first argument decides what happens:
<set>
@@ -672,7 +758,7 @@ Input Commands that are Possibly Subject to Change
cases, the second parameter is a comma separated list of filter names
or integer indexes. ``0`` would denote the first filter. Negative
indexes start from the last filter, and ``-1`` denotes the last
filter.
filter. Deprecated.
<clr>
Remove all filters. Note that like the other sub-commands, this does
@@ -728,6 +814,8 @@ Input Commands that are Possibly Subject to Change
list yourself when adding a second key binding for cycling backwards.
``enable-section <name> [<flags>]``
This command is deprecated, except for mpv-internal uses.
Enable all key bindings in the named input section.
The enabled input sections form a stack. Bindings in sections on the top of
@@ -750,9 +838,13 @@ Input Commands that are Possibly Subject to Change
Same.
``disable-section <name>``
This command is deprecated, except for mpv-internal uses.
Disable the named input section. Undoes ``enable-section``.
``define-section <name> <contents> [<flags>]``
This command is deprecated, except for mpv-internal uses.
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
@@ -851,6 +943,86 @@ Input Commands that are Possibly Subject to Change
Remove an overlay added with ``overlay-add`` and the same ID. Does nothing
if no overlay with this ID exists.
``osd-overlay``
Add/update/remove an OSD overlay.
(Although this sounds similar to ``overlay-add``, ``osd-overlay`` is for
text overlays, while ``overlay-add`` is for bitmaps. Maybe ``overlay-add``
will be merged into ``osd-overlay`` to remove this oddity.)
You can use this to add text overlays in ASS format. ASS has advanced
positioning and rendering tags, which can be used to render almost any kind
of vector graphics.
This command accepts the following parameters:
``id``
Arbitrary integer that identifies the overlay. Multiple overlays can be
added by calling this command with different ``id`` parameters. Calling
this command with the same ``id`` replaces the previously set overlay.
There is a separate namespace for each libmpv client (i.e. IPC
connection, script), so IDs can be made up and assigned by the API user
without conflicting with other API users.
If the libmpv client is destroyed, all overlays associated with it are
also deleted. In particular, connecting via ``--input-ipc-server``,
adding an overlay, and disconnecting will remove the overlay immediately
again.
``format``
String that gives the type of the overlay. Accepts the following values:
``ass-events``
The ``data`` parameter is a string. The string is split on the
newline character. Every line is turned into the ``Text`` part of
a ``Dialogue`` ASS event. Timing is unused (but behavior of timing
dependent ASS tags may change in future mpv versions).
Note that it's better to put multiple lines into ``data``, instead
of adding multiple OSD overlays.
This provides 2 ASS ``Styles``. ``OSD`` contains the text style as
defined by the current ``--osd-...`` options. ``Default`` is
similar, and contains style that ``OSD`` would have if all options
were set to the default.
In addition, the ``res_x`` and ``res_y`` options specify the value
of the ASS ``PlayResX`` and ``PlayResY`` header fields. If ``res_y``
is set to 0, ``PlayResY`` is initialized to an arbitrary default
value (but note that the default for this command is 720, not 0).
If ``res_x`` is set to 0, ``PlayResX`` is set based on ``res_y``
such that a virtual ASS pixel has a square pixel aspect ratio.
``none``
Special value that causes the overlay to be removed. Most parameters
other than ``id`` and ``format`` are mostly ignored.
``data``
String defining the overlay contents according to the ``format``
parameter.
``res_x``, ``res_y``
Used if ``format`` is set to ``ass-events`` (see description there).
Optional, defaults to 0/720.
``z``
The Z order of the overlay. Optional, defaults to 0.
Note that Z order between different overlays of different formats is
static, and cannot be changed (currently, this means that bitmap
overlays added by ``overlay-add`` are always on top of the ASS overlays
added by ``osd-overlay``). In addition, the builtin OSD components are
always below any of the custom OSD. (This includes subtitles of any kind
as well as text rendered by ``show-text``.)
It's possible that future mpv versions will randomly change how Z order
between different OSD formats and builtin OSD is handled.
Note: always use named arguments (``mpv_command_node()``). Scripts should
use the ``mp.create_osd_overlay()`` helper instead of invoking this command
directly.
``script-message [<arg1> [<arg2> [...]]]``
Send a message to all clients, and pass it the following list of arguments.
What this message means, how many arguments it takes, and what the arguments
@@ -886,8 +1058,13 @@ Input Commands that are Possibly Subject to Change
2. The name of the binding (as established above).
3. The key state as string (see below).
4. The key name (since mpv 0.15.0).
5. The text the key would produce, or empty string if not applicable.
The key state consists of 2 letters:
The 5th argument is only set if no modifiers are present (using the shift
key with a letter is normally not emitted as having a modifier, and results
in upper case text instead, but some backends may mess up).
The key state consists of 2 characters:
1. One of ``d`` (key was pressed down), ``u`` (was released), ``r`` (key
is still down, and was repeated; only if key repeat is enabled for this
@@ -895,6 +1072,9 @@ Input Commands that are Possibly Subject to Change
2. Whether the event originates from the mouse, either ``m`` (mouse button)
or ``-`` (something else).
Future versions can add more arguments and more key state characters to
support more input peculiarities.
``ab-loop``
Cycle through A-B loop states. The first command will set the ``A`` point
(the ``ab-loop-a`` property); the second the ``B`` point, and the third
@@ -1435,6 +1615,18 @@ Property list
Current MKV edition number. Setting this property to a different value will
restart playback. The number of the first edition is 0.
Before mpv 0.31.0, this showed the actual edition selected at runtime, if
you didn't set the option or property manually. With mpv 0.31.0 and later,
this strictly returns the user-set option or property value, and the
``current-edition`` property was added to return the runtime selected
edition (this matters with ``--edition=auto``, the default).
``current-edition``
Currently selected edition. This property is unavailable if no file is
loaded, or the file has no editions. (Matroska files make a difference
between having no editions and a single edition, which will be reflected by
the property, although in practice it does not matter.)
``chapters``
Number of chapters.
@@ -1924,8 +2116,19 @@ Property list
(or to be exact, the size the video filters output). ``2`` will set the
double size, ``0.5`` halves the size.
``window-minimized``
Return whether the video window is minimized or not.
See ``current-window-scale`` for the value derived from the actual window
size.
Since mpv 0.31.0, this always returns the previously set value (or the
default value), instead of the value implied by the actual window size.
Before mpv 0.31.0, this returned what ``current-window-scale`` returns now,
after the window was created.
``current-window-scale``
The ``window-scale`` value calculated from the current window size. This
has the same value as ``window-scale`` if the window size was not changed
since setting the option, and the window size was not restricted in other
ways. The property is unavailable if no video is active.
``display-names``
Names of the displays that the mpv window covers. On X11, these
@@ -1936,13 +2139,18 @@ Property list
Display Product Names as used in the System Information and only one display
name is returned since a window can only be on one screen.
``display-fps`` (RW)
``display-fps``
The refresh rate of the current display. Currently, this is the lowest FPS
of any display covered by the video, as retrieved by the underlying system
APIs (e.g. xrandr on X11). It is not the measured FPS. It's not necessarily
available on all platforms. Note that any of the listed facts may change
any time without a warning.
Writing to this property is deprecated. It has the same effect as writing to
``override-display-fps``. Since mpv 0.31.0, this property is unavailable
if no display FPS was reported (e.g. if no video is active), while in older
versions, it returned the ``--display-fps`` option value.
``estimated-display-fps``
Only available if display-sync mode (as selected by ``--video-sync``) is
active. Returns the actual rate at which display refreshes seem to occur,
@@ -1951,6 +2159,12 @@ Property list
``vsync-jitter``
Estimated deviation factor of the vsync duration.
``display-hidpi-scale``
The HiDPI scale factor as reported by the windowing backend. If no VO is
active, or if the VO does not report a value, this property is unavailable.
It may be saner to report an absolute DPI, however, this is the way HiDPI
support is implemented on most OS APIs. See also ``--hidpi-window-scale``.
``video-aspect`` (RW)
Deprecated. This is tied to ``--video-aspect-override``, but always
reports the current video aspect if video is active.
@@ -1963,9 +2177,40 @@ Property list
``overlay-add`` command. It gives you the actual OSD size, which can be
different from the window size in some cases.
Alias to ``osd-dimensions/w`` and ``osd-dimensions/h``.
``osd-par``
Last known OSD display pixel aspect (can be 0).
Alias to ``osd-dimensions/osd-par``.
``osd-dimensions``
Last known OSD dimensions.
Has the following sub-properties (which can be read as ``MPV_FORMAT_NODE``
or Lua table with ``mp.get_property_native``):
``w``
Size of the VO window in OSD render units (usually pixels, but may be
scaled pixels with VOs like ``xv``).
``h``
Size of the VO window in OSD render units,
``par``
Pixel aspect ratio of the OSD (usually 1).
``aspect``
Display aspect ratio of the VO window. (Computing from the properties
above.)
``mt``, ``mb``, ``ml``, ``mr``
OSD to video margins (top, bottom, left, right). This describes the
area into which the video is rendered.
Any of these properties may be unavailable or set to dummy values if the
VO window is not created or visible.
``sub-text``
Return the current subtitle text regardless of sub visibility.
Formatting is stripped. If the subtitle is not text-based
@@ -2050,7 +2295,11 @@ Property list
String describing the media type. One of ``audio``, ``video``, ``sub``.
``track-list/N/src-id``
Track ID as used in the source file. Not always available.
Track ID as used in the source file. Not always available. (It is
missing if the format has no native ID, if the track is a pseudo-track
that does not exist in this way in the actual file, or if the format
is handled by libavformat, and the format was not whitelisted as having
track IDs.)
``track-list/N/title``
Track title as it is stored in the file. Not always available.
@@ -2407,6 +2656,28 @@ Property list
``current-ao``
Current audio output driver (name as used with ``--ao``).
``shared-script-properties`` (RW)
This is a key/value map of arbitrary strings shared between scripts for
general use. The player itself does not use any data in it (although some
builtin scripts may). The property is not preserved across player restarts.
This is very primitive, inefficient, and annoying to use. It's a makeshift
solution which could go away any time (for example, when a better solution
becomes available). This is also why this property has an annoying name. You
should avoid using it, unless you absolutely have to.
Lua scripting has helpers starting with ``utils.shared_script_property_``.
They are undocumented because you should not use this property. If you still
think you must, you should use the helpers instead of the property directly.
You are supposed to use the ``change-list`` command to modify the contents.
Reading, modifying, and writing the property manually could data loss if two
scripts update different keys at the same time due to lack of
synchronization. The Lua helpers take care of this.
(There is no way to ensure synchronization if two scripts try to update the
same key at the same time.)
``working-directory``
Return the working directory of the mpv process. Can be useful for JSON IPC
users, because the command line player usually works with relative paths.
@@ -2540,6 +2811,56 @@ Property list
is not a map, as order matters and duplicate entries are possible. Recursive
profiles are not expanded, and show up as special ``profile`` options.
``command-list``
Return the list of input commands. This returns an array of maps, where
each map node represents a command. This map currently only has a single
entry: ``name`` for the name of the command. (This property is supposed to
be a replacement for ``--input-cmdlist``. The option dumps some more
information, but it's a valid feature request to extend this property if
needed.)
``input-bindings``
Return list of current input key bindings. This returns an array of maps,
where each map node represents a binding for a single key/command. This map
has the following entries:
``key``
The key name. This is normalized and may look slightly different from
how it was specified in the source (e.g. in input.conf).
``cmd``
The command mapped to the key. (Currently, this is exactly the same
string as specified in the source, other than stripping whitespace and
comments. It's possible that it will be normalized in the future.)
``is_weak``
If set to true, any existing and active user bindings will take priority.
``owner``
If this entry exists, the name of the script (or similar) which added
this binding.
``section``
Name of the section this binding is part of. This is a rarely used
mechanism. This entry may be removed or change meaning in the future.
``priority``
A number. Bindings with a higher value are preferred over bindings
with a lower value. If the value is negative, this binding is inactive
and will not be triggered by input. Note that mpv does not use this
value internally, and matching of bindings may work slightly differently
in some cases. In addition, this value is dynamic and can change around
at runtime.
``comment``
If available, the comment following the command on the same line. (For
example, the input.conf entry ``f cycle bla # toggle bla`` would
result in an entry with ``comment = "toggle bla", cmd = "cycle bla"``.)
This property is read-only, and change notification is not supported.
Currently, there is no mechanism to change key bindings at runtime, other
than scripts adding or removing their own bindings.
Inconsistencies between options and properties
----------------------------------------------
@@ -2547,55 +2868,32 @@ 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.)
While playback is active, these result the actually active tracks. For
example, if you set ``aid=5``, and the currently played file contains no
audio track with ID 5, the ``aid`` property will return ``no``.
Option changes at runtime are affected by this as well.
Before mpv 0.31.0, you could set existing tracks at runtime only.
``display-fps``
If a VO is created, this will return either the actual display FPS, or
an invalid value, instead of the option value.
This inconsistent behavior is deprecated. Post-deprecation, the reported
value and the option value are cleanly separated (``override-display-fps``
for 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.
reinitialize, the option will be set, but the runtime filter chain does not
change. On the other hand, the next video to be played will fail, because
the initial filter chain cannot be created.
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).
This behavior changed in mpv 0.31.0. Before this, the new value was rejected
*iff* video (for ``vf``) or audio (for ``af``) was active. If playback was
not active, the behavior was the same as the current behavior.
``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.
``playlist-pos``, ``chapter``
These properties behave different from the deprecated options with the same
names.
``profile``, ``include``
These are write-only, and will perform actions as they are written to,
exactly as if they were used on the mpv CLI commandline. Their only use is
+24 -8
View File
@@ -153,6 +153,10 @@ success, ``fn`` is called always a-sync, ``error`` is empty string on success.
``mp.unregister_script_message(name)``
``mp.create_osd_overlay(format)``
``mp.get_osd_size()`` (returned object has properties: width, height, aspect)
``mp.msg.log(level, ...)``
``mp.msg.fatal(...)``
@@ -187,7 +191,8 @@ success, ``fn`` is called always a-sync, ``error`` is empty string on success.
``mp.add_hook(type, priority, fn)``
``mp.options.read_options(obj [, identifier])`` (types: string/boolean/number)
``mp.options.read_options(obj [, identifier [, on_update]])`` (types:
string/boolean/number)
Additional utilities
--------------------
@@ -240,6 +245,9 @@ Note: ``read_file`` and ``write_file`` throw on errors, allow text content only.
anything from the filesystem), and returns it as a function. Very similar
to a ``Function`` constructor, but shows at stack traces as ``fname``.
``mp.module_paths``
Global modules search paths array for the ``require`` function (see below).
Timers (global)
---------------
@@ -278,9 +286,11 @@ CommonJS modules and ``require(id)``
------------------------------------
CommonJS Modules are a standard system where scripts can export common functions
for use by other scripts. A module is a script which adds properties (functions,
etc) to its invisible ``exports`` object, which another script can access by
loading it with ``require(module-id)`` - which returns that ``exports`` object.
for use by other scripts. Specifically, a module is a script which adds
properties (functions, etc) to its pre-existing ``exports`` object, which
another script can access with ``require(module-id)``. This runs the module and
returns its ``exports`` object. Further calls to ``require`` for the same module
will return its cached ``exports`` object without running the module again.
Modules and ``require`` are supported, standard compliant, and generally similar
to node.js. However, most node.js modules won't run due to missing modules such
@@ -293,10 +303,16 @@ will load the file ``./foo.js`` and return its ``exports`` object.
An id is relative (to the script which ``require``'d it) if it starts with
``./`` or ``../``. Otherwise, it's considered a "top-level id" (CommonJS term).
Top level id is evaluated as absolute filesystem path if possible (e.g. ``/x/y``
or ``~/x``). Otherwise, it's searched at ``scripts/modules.js/`` in mpv config
dirs - in normal config search order. E.g. ``require("x")`` is searched as file
``x.js`` at those dirs, and id ``foo/x`` is searched as file ``foo/x.js``.
Top level id is evaluated as absolute filesystem path if possible, e.g. ``/x/y``
or ``~/x``. Otherwise, it's considered a global module id and searched at
``scripts/modules.js/`` in mpv config dirs - in normal config search order. E.g.
``require("x")`` is searched as file ``x.js`` at those dirs, and id ``foo/x`` is
searched as file ``x.js`` inside dir ``foo`` at those dirs.
Search paths for global module id's are at the array ``mp.module_paths``, which
is searched in order. Initially it contains one item: ``~~/scripts/modules.js``
such that it behaves as described above. Modifying it will affect future
``require`` calls with global module id's which are not already loaded/cached.
No ``global`` variable, but a module's ``this`` at its top lexical scope is the
global object - also in strict mode. If you have a module which needs ``global``
+75 -8
View File
@@ -240,7 +240,9 @@ The ``mp`` module is preloaded, although it can be loaded manually with
an example). The name should be unique across other bindings in the same
script - if not, the previous binding with the same name will be
overwritten. You can omit the name, in which case a random name is generated
internally.
internally. (Omitting works as follows: either pass ``nil`` for ``name``,
or pass the ``fn`` argument in place of the name. The latter is not
recommended and is handled for compatibility only.)
The last argument is used for optional flags. This is a table, which can
have the following entries:
@@ -251,11 +253,24 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``complex``
If set to ``true``, then ``fn`` is called on both key up and down
events (as well as key repeat, if enabled), with the first
argument being a table. This table has an ``event`` entry, which
is set to one of the strings ``down``, ``repeat``, ``up`` or
``press`` (the latter if key up/down can't be tracked). It further
has an ``is_mouse`` entry, which tells whether the event was caused
by a mouse button.
argument being a table. This table has the following entries (and
may contain undocumented ones):
``event``
Set to one of the strings ``down``, ``repeat``, ``up`` or
``press`` (the latter if key up/down can't be tracked).
``is_mouse``
Boolean Whether the event was caused by a mouse button.
``key_name``
The name of they key that triggered this, or ``nil`` if invoked
artificially. If the key name is unknown, it's an empty string.
``key_text``
Text if triggered by a text key, otherwise ``nil``. See
description of ``script-binding`` command for details (this
field is equivalent to the 5th argument).
Internally, key bindings are dispatched via the ``script-message-to`` or
``script-binding`` input commands and ``mp.register_script_message``.
@@ -343,6 +358,10 @@ The ``mp`` module is preloaded, although it can be loaded manually with
of times in a row, only the last change triggers the change function. (The
exact behavior depends on timing and other things.)
If a property is unavailable, or on error, the value argument to ``fn`` is
``nil``. (The ``observe_property()`` call always succeeds, even if a
property does not exist.)
In some cases the function is not called even if the property changes.
This depends on the property, and it's a valid feature request to ask for
better update handling of a specific property.
@@ -517,6 +536,41 @@ are useful only in special situations.
Undo a previous registration with ``mp.register_script_message``. Does
nothing if the ``name`` wasn't registered.
``mp.create_osd_overlay(format)``
Create an OSD overlay. This is a very thin wrapper around the ``osd-overlay``
command. The function returns a table, which mostly contains fields that
will be passed to ``osd-overlay``. The ``format`` parameter is used to
initialize the ``format`` field. The ``data`` field contains the text to
be used as overlay. For details, see the ``osd-overlay`` command.
In addition, it provides the following methods:
``update()``
Commit the OSD overlay to the screen, or in other words, run the
``osd-overlay`` command with the current fields of the overlay table.
``remove()``
Remove the overlay from the screen. A ``update()`` call will add it
again.
Example:
::
ov = mp.create_osd_overlay("ass-events")
ov.data = "{\\an5}{\\b1}hello world!"
ov:update()
The advantage of using this wrapper (as opposed to running ``osd-overlay``
directly) is that the ``id`` field is allocated automatically.
``mp.get_osd_size()``
Returns a tuple of ``osd_width, osd_height, osd_par``. The first two give
the size of the OSD in pixels (for video ouputs like ``--vo=xv``, this may
be "scaled" pixels). The third is the display pixel aspect ratio.
May return invalid/nonsense values if OSD is not initialized yet.
mp.msg functions
----------------
@@ -547,14 +601,27 @@ command-line. All you have to do is to supply a table with default options to
the read_options function. The function will overwrite the default values
with values found in the config-file and the command-line (in that order).
``options.read_options(table [, identifier])``
``options.read_options(table [, identifier [, on_update]])``
A ``table`` with key-value pairs. The type of the default values is
important for converting the values read from the config file or
command-line back. Do not use ``nil`` as a default value!
The ``identifier`` is used to identify the config-file and the command-line
options. These needs to unique to avoid collisions with other scripts.
Defaults to ``mp.get_script_name()``.
Defaults to ``mp.get_script_name()`` if the parameter is ``nil`` or missing.
The ``on_update`` parameter enables run-time updates of all matching option
values via the ``script-opts`` option/property. If any of the matching
options changes, the values in the ``table`` (which was originally passed to
the function) are changed, and ``on_update(list)`` is called. ``list`` is
a table where each updated option has a ``list[option_name] = true`` entry.
There is no initial ``on_update()`` call. This never re-reads the config file.
``script-opts`` is always applied on the original config file, ignoring
previous ``script-opts`` values (for example, if an option is removed from
``script-opts`` at runtime, the option will have the value in the config
file). ``table`` entries are only written for option values whose values
effectively change (this is important if the script changes ``table``
entries independently).
Example implementation::
+182 -83
View File
@@ -223,6 +223,12 @@ i and I
file such as codec, framerate, number of dropped frames and so on. See
`STATS`_ for more information.
del
Cycles visibility between never / auto (mouse-move) / always
\`
Show the console. (ESC closes it again. See `CONSOLE`_.)
(The following keys are valid only when using a video output that supports the
corresponding adjustment.)
@@ -268,10 +274,19 @@ in the mpv git repository.
Mouse Control
-------------
button 3 and button 4
Seek backward/forward 1 minute.
Left double click
Toggle fullscreen on/off.
button 5 and button 6
Right click
Toggle pause on/off.
Forward/Back button
Skip to next/previous entry in playlist.
Wheel up/down
Seek forward/backward 10 seconds.
Wheel left/right
Decrease/increase volume.
@@ -299,7 +314,7 @@ Legacy option syntax
--------------------
The ``--option=value`` syntax is not strictly enforced, and the alternative
legacy syntax ``-option value`` and ``--option value`` will also work. This is
legacy syntax ``-option value`` and ``-option=value`` will also work. This is
mostly for compatibility with MPlayer. Using these should be avoided. Their
semantics can change any time in the future.
@@ -309,9 +324,15 @@ because ``--fs`` is a flag option that requires no parameter. If an option
changes and its parameter becomes optional, then a command line using the
alternative syntax will break.
Currently, the parser makes no difference whether an option starts with ``--``
or a single ``-``. This might also change in the future, and ``--option value``
might always interpret ``value`` as filename in order to reduce ambiguities.
Until mpv 0.31.0, there was no difference whether an option started with ``--``
or a single ``-``. Newer mpv releases strictly expect that you pass the option
value after a ``=``. For example, before ``mpv --log-file f.txt`` would write
a log to ``f.txt``, but now this command line fails, as ``--log-file`` expects
an option value, and ``f.txt`` is simply considered a normal file to be played
(as in ``mpv f.txt``).
The future plan is that ``-option value`` will not work anymore, and options
with a single ``-`` behave the same as ``--`` options.
Escaping spaces and other special characters
--------------------------------------------
@@ -463,62 +484,98 @@ List Options
------------
Some options which store lists of option values can have action suffixes. For
example, you can set a ``,``-separated list of filters with ``--vf``, but the
option also allows you to append filters with ``--vf-append``.
example, the ``--display-tags`` option takes a ``,``-separated list of tags, but
the option also allows you to append a single tag with ``--display-tags-append``,
and the tag name can for example contain a literal ``,`` without the need for
escaping.
Options for filenames do not use ``,`` as separator, but ``:`` (Unix) or ``;``
(Windows).
String list and path list options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
String lists are separated by ``,``. The strings are not parsed or interpreted
by the option system itself. However, most
Path or file list options use ``:`` (Unix) or ``;`` (Windows) as separator,
instead of ``,``.
They support the following operations:
============= ===============================================
Suffix Meaning
============= ===============================================
-add Append 1 or more items (may become alias for -append)
-append Append single item (avoids need for escaping)
-clr Clear the option
-del Delete an existing item by integer index
-pre Prepend 1 or more items
-set Set a list of items
-toggle Append an item, or remove if if it already exists
-set Set a list of items (using the list separator, interprets escapes)
-append Append single item (does not interpret escapes)
-add Append 1 or more items (same syntax as -set)
-pre Prepend 1 or more items (same syntax as -set)
-clr Clear the option (remove all items)
-remove Delete item if present (does not interpret escapes)
-del Delete 1 or more items by integer index (deprecated)
-toggle Append an item, or remove if if it already exists (no escapes)
============= ===============================================
Although some operations allow specifying multiple ``,``-separated items, using
this is strongly discouraged and deprecated, except for ``-set``.
``-append`` is meant as a simple way to append a single item without having
to escape the argument (you may still need to escape on the shell level).
Without suffix, the action taken is normally ``-set``.
Key/value list options
~~~~~~~~~~~~~~~~~~~~~~
A key/value list is a list of key/value string pairs. In programming languages,
this type of data structure is often called a map or a dictionary. The order
normally does not matter, although in some cases the order might matter.
They support the following operations:
============= ===============================================
Suffix Meaning
============= ===============================================
-set Set a list of items (using ``,`` as separator)
-append Append a single item (escapes for the key, no escapes for the value)
-add Append 1 or more items (same syntax as -set)
-remove Delete item by key if present (does not interpret escapes)
============= ===============================================
Keys are unique within the list. If an already present key is set, the existing
key is removed before the new value is appended.
Filter options
~~~~~~~~~~~~~~
This is a very complex option type for the ``--af`` and ``--vf`` options only.
They often require complicated escaping. See `VIDEO FILTERS`_ for details. They
support the following operations:
============= ===============================================
Suffix Meaning
============= ===============================================
-set Set a list of filters (using ``,`` as separator)
-append Append single filter
-add Append 1 or more filters (same syntax as -set)
-pre Prepend 1 or more filters (same syntax as -set)
-clr Clear the option (remove all filters)
-remove Delete filter if present
-del Delete 1 or more filters by integer index or filter label (deprecated)
-toggle Append a filter, or remove if if it already exists
-help Pseudo operation that prints a help text to the terminal
============= ===============================================
General
~~~~~~~
Without suffix, the operation used is normally ``-set``.
Although some operations allow specifying multiple items, using this is strongly
discouraged and deprecated, except for ``-set``. There is a chance that
operations like ``-add`` and ``-pre`` will work like ``-append`` and accept a
single, unescaped item only (so the ``,`` separator will not be interpreted and
is passed on as part of the value).
Some options (like ``--sub-file``, ``--audio-file``, ``--glsl-shader``) are
aliases for the proper option with ``-append`` action. For example,
``--sub-file`` is an alias for ``--sub-files-append``.
Some options only support a subset of the above.
Options of this type can be changed at runtime using the ``change-list``
command, which takes the suffix as separate operation parameter.
Playing DVDs
------------
DVDs can be played with the ``dvd://[title]`` syntax. The optional
title specifier is a number which selects between separate video
streams on the DVD. If no title is given (``dvd://``) then the longest
title is selected automatically by the library. This is usually what
you want. mpv does not support DVD menus.
DVDs which have been copied on to a hard drive or other mounted
filesystem (by e.g. the ``dvdbackup`` tool) are accommodated by
specifying the path to the local copy: ``--dvd-device=PATH``.
Alternatively, running ``mpv PATH`` should auto-detect a DVD directory
tree and play the longest title.
.. note:: DVD subtitles
DVDs use image-based subtitles. Image subtitles are implemented as
a bitmap video stream which can be superimposed over the main
movie. mpv's subtitle styling and positioning options and keyboard
shortcuts generally do not work with image-based subtitles.
Exceptions include options like ``--stretch-dvd-subs`` and
``--stretch-image-subs-to-screen``.
command, which takes the suffix (without the ``-``) as separate operation
parameter.
CONFIGURATION FILES
===================
@@ -641,12 +698,8 @@ Some profiles are loaded automatically. The following example demonstrates this:
::
[protocol.dvd]
profile-desc="profile for dvd:// streams"
alang=en
[extension.flv]
profile-desc="profile for .flv files"
[extension.mkv]
profile-desc="profile for .mkv files"
vf=flip
The profile name follows the schema ``type.name``, where type can be
@@ -656,6 +709,51 @@ and ``extension`` for the extension of the path of the currently played file
This feature is very limited, and there are no other auto profiles.
Using mpv from other programs or scripts
========================================
There are three choices for using mpv from other programs or scripts:
1. Calling it as UNIX process. If you do this, *do not parse terminal output*.
The terminal output is intended for humans, and may change any time. In
addition, terminal behavior itself may change any time. Compatibility
cannot be guaranteed.
Your code should work even if you pass ``--no-terminal``. Do not attempt
to simulate user input by sending terminal control codes to mpv's stdin.
If you need interactive control, using ``--input-ipc-server`` is
recommended. This gives you access to the `JSON IPC`_ over unix domain
sockets (or named pipes on Windows).
Depending on what you do, passing ``--no-config`` or ``--config-dir`` may
be a good idea to avoid conflicts with the normal mpv user configuration
intended for CLI playback.
Using ``--input-ipc-server`` is also suitable for purposes like remote
control (however, the IPC protocol itself is not "secure" and not
intended to be so).
2. Using libmpv. This is generally recommended when mpv is used as playback
backend for a completely different application. The provided C API is
very close to CLI mechanisms and the scripting API.
Note that even though libmpv has different defaults, it can be configured
to work exactly like the CLI player (except command line parsing is
unavailable).
See `EMBEDDING INTO OTHER PROGRAMS (LIBMPV)`_.
3. As a user script (`LUA SCRIPTING`_, `JAVASCRIPT`_, `C PLUGINS`_). This is
recommended when the goal is to "enhance" the CLI player. Scripts get
access to the entire client API of mpv.
This is the standard way to create third-party extensions for the player.
All these access the client API, which is the sum of the various mechanisms
provided by the player core, as documented here: `OPTIONS`_,
`List of Input Commands`_, `Properties`_, `List of events`_ (also see C API),
`Hooks`_.
TAKING SCREENSHOTS
==================
@@ -783,10 +881,10 @@ PROTOCOLS
``ytdl://...``
By default, the youtube-dl hook script (enabled by default for mpv CLI)
only looks at http URLs. Prefixing an URL with ``ytdl://`` forces it to
be always processed by the script. This can also be used to invoke special
youtube-dl functionality like playing a video by ID or invoking search.
By default, the youtube-dl hook script only looks at http(s) URLs. Prefixing
an URL with ``ytdl://`` forces it to be always processed by the script. This
can also be used to invoke special youtube-dl functionality like playing a
video by ID or invoking search.
Keep in mind that you can't pass youtube-dl command line options by this,
and you have to use ``--ytdl-raw-options`` instead.
@@ -811,29 +909,15 @@ PROTOCOLS
``bluray://`` is an alias.
``dvd://[title|[starttitle]-endtitle][/device]`` ``--dvd-device=PATH``
``dvd://[title][/device]`` ``--dvd-device=PATH``
Play a DVD. DVD menus are not supported. If no title is given, the longest
title is auto-selected.
title is auto-selected. Without ``--dvd-device``, it will probably try
to open an actual optical drive, if available and implemented for the OS.
``dvdnav://`` is an old alias for ``dvd://`` and does exactly the same
thing.
``dvdread://...:``
Play a DVD using the old libdvdread code. This is what MPlayer and
older mpv versions used for ``dvd://``. Use is discouraged. It's
provided only for compatibility and for transition, and to work
around outstanding dvdnav bugs (see "DVD library choices" above).
``tv://[channel][/input_id]`` ``--tv-...``
Analogue TV via V4L. Also useful for webcams. (Linux only.)
``pvr://`` ``--pvr-...``
PVR. (Linux only.)
``dvb://[cardnumber@]channel`` ``--dvbin-...``
Digital TV via DVB. (Linux only.)
@@ -857,9 +941,17 @@ PROTOCOLS
demuxer name, and ``options`` is the (pseudo-)filename passed to the
demuxer.
For example, ``mpv av://lavfi:mandelbrot`` makes use of the libavfilter
wrapper included in libavdevice, and will use the ``mandelbrot`` source
filter to generate input data.
.. admonition:: Example
::
mpv av://v4l2:/dev/video0 --profile=low-latency --untimed
This plays video from the first v4l input with nearly the lowest latency
possible. It's a good replacement for the removed ``tv://`` input.
Using ``--untimed`` is a hack to output a captured frame immediately,
instead of respecting the input framerate. (There may be better ways to
handle this in the future.)
``avdevice://`` is an alias.
@@ -972,6 +1064,8 @@ works like in older mpv releases. The profiles are currently defined as follows:
.. include:: stats.rst
.. include:: console.rst
.. include:: lua.rst
.. include:: javascript.rst
@@ -1009,7 +1103,11 @@ behavior of mpv.
of ``--v`` options passed to the command line.
``MPV_LEAK_REPORT``
If set to ``1``, enable internal talloc leak reporting.
If set to ``1``, enable internal talloc leak reporting. If set to another
value, disable leak reporting. If unset, use the default, which normally is
``0``. If mpv was built with ``--enable-ta-leak-report``, the default is
``1``. If leak reporting was disabled at compile time (``NDEBUG`` in
custom ``CFLAGS``), this environment variable is ignored.
``LADSPA_PATH``
Specifies the search path for LADSPA plugins. If it is unset, fully
@@ -1144,9 +1242,10 @@ For Windows-specifics, see `FILES ON WINDOWS`_ section.
``~/.config/mpv/scripts/``
All files in this directory are loaded as if they were passed to the
``--script`` option. They are loaded in alphabetical order, and sub-directories
and files with no ``.lua`` extension are ignored. The ``--load-scripts=no``
option disables loading these files.
``--script`` option. They are loaded in alphabetical order. Directory entries
other than files are ignored. Files with unknown extension lead to an
initialization error. Files with ``.disable`` extension are ignored. The
``--load-scripts=no`` option disables loading these files.
``~/.config/mpv/watch_later/``
Contains temporary config files needed for resuming playback of files with
+368 -107
View File
@@ -10,6 +10,8 @@ Track Selection
language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter
language codes, while OGM uses a free-form identifier. See also ``--aid``.
This is a string list option. See `List Options`_ for details.
.. admonition:: Examples
- ``mpv dvd://1 --alang=hu,en`` chooses the Hungarian language track
@@ -23,6 +25,8 @@ Track Selection
language codes, Matroska uses ISO 639-2 three letter language codes while
OGM uses a free-form identifier. See also ``--sid``.
This is a string list option. See `List Options`_ for details.
.. admonition:: Examples
- ``mpv dvd://1 --slang=hu,en`` chooses the Hungarian subtitle track on
@@ -33,6 +37,8 @@ Track Selection
``--vlang=<...>``
Equivalent to ``--alang`` and ``--slang``, for video tracks.
This is a string list option. See `List Options`_ for details.
``--aid=<ID|auto|no>``
Select audio track. ``auto`` selects the default, ``no`` disables audio.
See also ``--alang``. mpv normally prints available audio tracks on the
@@ -700,11 +706,15 @@ Program Behavior
Load a Lua script. The second option allows you to load multiple scripts by
separating them with the path separator (``:`` on Unix, ``;`` on Windows).
``--scripts`` is a path list option. See `List Options`_ for details.
``--script-opts=key1=value1,key2=value2,...``
Set options for scripts. A script can query an option by key. If an
option is used and what semantics the option value has depends entirely on
the loaded scripts. Values not claimed by any scripts are ignored.
This is a key/value list option. See `List Options`_ for details.
``--merge-files``
Pretend that all files passed to mpv are concatenated into a single, big
file. This uses timeline/EDL support internally.
@@ -714,6 +724,13 @@ Program Behavior
subdirectory (usually ``~/.config/mpv/watch_later/``).
See ``quit-watch-later`` input command.
``--resume-playback-check-mtime``
Only restore the playback position from the ``watch_later`` configuration
subdirectory (usually ``~/.config/mpv/watch_later/``) if the file's
modification time is the same as at the time of saving. This may prevent
skipping forward in files with the same name which have different content.
(Default: ``no``)
``--profile=<profile1,profile2,...>``
Use the given profile(s), ``--profile=help`` displays a list of the
defined profiles.
@@ -737,6 +754,8 @@ Program Behavior
The special name ``all`` resets as many options as possible.
This is a string list option. See `List Options`_ for details.
.. admonition:: Examples
- ``--reset-on-next-file=pause``
@@ -761,7 +780,8 @@ Program Behavior
(Default: disabled)
``--show-profile=<profile>``
Show the description and content of a profile.
Show the description and content of a profile. Lists all profiles if no
parameter is provided.
``--use-filedir-conf``
Look for a file-specific configuration file in the same directory as the
@@ -827,6 +847,8 @@ Program Behavior
information to mpv. Take note that SOCKS proxies aren't supported and
https URLs also bypass the proxy. This is a limitation in FFmpeg.
This is a key/value list option. See `List Options`_ for details.
.. admonition:: Example
- ``--ytdl-raw-options=username=user,password=pass``
@@ -839,6 +861,12 @@ Program Behavior
binding (default: yes). By default, the ``i`` key is used (``I`` to make
the overlay permanent).
``--load-osd-console=<yes|no>``
Enable the builtin script that shows a console on a key binding and lets
you enter commands (default: yes). By default,. The ``´`` key is used to
show the console, and ``ESC`` to hide it again. (This is based on a user
script called ``repl.lua``.)
``--player-operation-mode=<cplayer|pseudo-gui>``
For enabling "pseudo GUI mode", which means that the defaults for some
options are changed. This option should not normally be used directly, but
@@ -881,25 +909,41 @@ Video
The argument selects the drop methods, and can be one of the following:
<no>
Disable any framedropping.
Disable any frame dropping. Not recommended, for testing only.
<vo>
Drop late frames on video output (default). This still decodes and
filters all frames, but doesn't render them on the VO. It tries to query
the display FPS (X11 only, not correct on multi-monitor systems), or
assumes infinite display FPS if that fails. Drops are indicated in
the terminal status line as ``Dropped:`` field. If the decoder is too slow,
in theory all frames would have to be dropped (because all frames are
too late) - to avoid this, frame dropping stops if the effective
framerate is below 10 FPS.
filters all frames, but doesn't render them on the VO. Drops are
indicated in the terminal status line as ``Dropped:`` field.
In audio sync. mode, this drops frames that are outdated at the time of
display. If the decoder is too slow, in theory all frames would have to
be dropped (because all frames are too late) - to avoid this, frame
dropping stops if the effective framerate is below 10 FPS.
In display-sync. modes (see ``--video-sync``), this affects only how
A/V drops or repeats frames. If this mode is disabled, A/V desync will
in theory not affect video scheduling anymore (much like the
``display-resample-desync`` mode). However, even if disabled, frames
will still be skipped (i.e. dropped) according to the ratio between
video and display frequencies.
This is the recommended mode, and the default.
<decoder>
Old, decoder-based framedrop mode. (This is the same as ``--framedrop=yes``
in mpv 0.5.x and before.) This tells the decoder to skip frames (unless
they are needed to decode future frames). May help with slow systems,
but can produce unwatchable choppy output, or even freeze the display
completely. Not recommended.
completely.
This uses a heuristic which may not make sense, and in general cannot
achieve good results, because the decoder's frame dropping cannot be
controlled in a predictable manner. Not recommended.
Even if you want to use this, prefer ``decoder+vo`` for better results.
The ``--vd-lavc-framedrop`` option controls what frames to drop.
<decoder+vo>
Enable both modes. Not recommended.
Enable both modes. Not recommended. Better than just ``decoder`` mode.
.. note::
@@ -925,8 +969,7 @@ Video
frame, so if this is not done, there is some likeliness that the VO has
to drop some frames if rendering the first frame takes longer than needed.
``--display-fps=<fps>``
``--override-display-fps=<fps>``
Set the display FPS used with the ``--video-sync=display-*`` modes. By
default, a detected value is used. Keep in mind that setting an incorrect
value (even if slightly incorrect) can ruin video playback. On multi-monitor
@@ -936,24 +979,68 @@ Video
Set this option only if you have reason to believe the automatically
determined value is wrong.
``--display-fps=<fps>``
Deprecated alias for ``--override-display-fps``.
``--hwdec=<api>``
Specify the hardware video decoding API that should be used if possible.
Whether hardware decoding is actually done depends on the video codec. If
hardware decoding is not possible, mpv will fall back on software decoding.
Hardware decoding is not enabled by default, because it is typically an
additional source of errors. It is worth using only if your CPU is too
slow to decode a specific video.
.. note::
Use the ``Ctrl+h`` shortcut to toggle hardware decoding at runtime. It
toggles this option between ``auto`` and ``no``.
Always enabling HW decoding by putting it into the config file is
discouraged. If you use the Ubuntu package, delete ``/etc/mpv/mpv.conf``,
as the package tries to enable HW decoding by default by setting
``hwdec=vaapi`` (which is less than ideal, and may even cause
sub-optimal wrappers to be used). Or at least change it to
``hwdec=auto-safe``.
Use one of the auto modes if you want to enable hardware decoding.
Explicitly selecting the mode is mostly meant for testing and debugging.
It's a bad idea to put explicit selection into the config file if you
want thing to just keep working after updates and so on.
.. note::
Even if enabled, hardware decoding is still only white-listed for some
codecs. See ``--hwdec-codecs`` to enable hardware decoding in more cases.
.. admonition:: Which method to choose?
- If you only want to enable hardware decoding at runtime, don't set the
parameter, or put ``hwdec=no`` into your ``mpv.conf`` (relevant on
distros which force-enable it by default, such as on Ubuntu). Use the
``Ctrl+h`` default binding to enable it at runtime.
- If you're not sure, but want hardware decoding always enabled by
default, put ``hwdec=auto-safe`` into your ``mpv.conf``, and
acknowledge that this use case is not "really" supported and may cause
problems.
- If you want to test available hardware decoding methods, pass
``--hwdec=auto --hwdec-codecs=all`` and look at the terminal output.
- If you're a developer, or want to perform elaborate tests, you may
need any of the other possible option values.
``<api>`` can be one of the following:
:no: always use software decoding (default)
:auto: enable best hw decoder (see below)
:auto: forcibly enable any hw decoder found (see below)
:yes: exactly the same as ``auto``
:auto-safe: enable any whitelisted hw decoder (see below)
:auto-copy: enable best hw decoder with copy-back (see below)
:vdpau: requires ``--vo=gpu`` with ``--gpu-context=x11``,
or ``--vo=vdpau`` (Linux only)
:vdpau: requires ``--vo=gpu`` with X11, or ``--vo=vdpau`` (Linux only)
:vdpau-copy: copies video back into system RAM (Linux with some GPUs only)
:vaapi: requires ``--vo=gpu`` or ``--vo=vaapi`` (Linux only)
:vaapi-copy: copies video back into system RAM (Linux with some GPUs only)
:videotoolbox: requires ``--vo=gpu`` (OS X 10.8 and up),
or ``--vo=opengl-cb`` (iOS 9.0 and up)
or ``--vo=libmpv`` (iOS 9.0 and up)
:videotoolbox-copy: copies video back into system RAM (OS X 10.8 or iOS 9.0 and up)
:dxva2: requires ``--vo=gpu`` with ``--gpu-context=d3d11``,
``--gpu-context=angle`` or ``--gpu-context=dxinterop``
@@ -966,10 +1053,10 @@ Video
:mediacodec-copy: copies video back to system RAM (Android only)
:mmal: requires ``--vo=gpu`` (Raspberry Pi only - default if available)
:mmal-copy: copies video back to system RAM (Raspberry Pi only)
:cuda: requires ``--vo=gpu`` (Any platform CUDA is available)
:cuda-copy: copies video back to system RAM (Any platform CUDA is available)
:nvdec: requires ``--vo=gpu`` (Any platform CUDA is available)
:nvdec-copy: copies video back to system RAM (Any platform CUDA is available)
:cuda: requires ``--vo=gpu`` (Any platform CUDA is available)
:cuda-copy: copies video back to system RAM (Any platform CUDA is available)
:crystalhd: copies video back to system RAM (Any platform supported by hardware)
:rkmpp: requires ``--vo=gpu`` (some RockChip devices only)
@@ -980,49 +1067,53 @@ Video
work, it will always fall back to software decoding, instead of trying the
next method (might matter on some Linux systems).
``auto-safe`` is similar to ``auto``, but allows only whitelisted methods
that are considered "safe". This is supposed to be a reasonable way to
enable hardware decdoding by default in a config file (even though you
shouldn't do that anyway; prefer runtime enabling with ``Ctrl+h``). Unlike
``auto``, this will not try to enable unknown or known-to-be-bad methods. In
addition, this may disable hardware decoding in other situations when it's
known to cause problems, but currently this mechanism is quite primitive.
(As an example for something that still causes problems: certain
combinations of HEVC and Intel chips on Windows tend to cause mpv to crash,
most likely due to driver bugs.)
``auto-copy-safe`` selects the union of methods selected with ``auto-safe``
and ``auto-copy``.
``auto-copy`` selects only modes that copy the video data back to system
memory after decoding. This selects modes like ``vaapi-copy`` (and so on).
If none of these work, hardware decoding is disabled. This mode is always
guaranteed to incur no additional loss compared to software decoding, and
will allow CPU processing with video filters.
If none of these work, hardware decoding is disabled. This mode is usually
guaranteed to incur no additional quality loss compared to software
decoding (assuming modern codecs and an error free video stream), and will
allow CPU processing with video filters. This mode works with all video
filters and VOs.
The ``vaapi`` mode, if used with ``--vo=gpu``, requires Mesa 11 and most
likely works with Intel GPUs only. It also requires the opengl EGL backend.
The ``cuda`` and ``cuda-copy`` modes provides deinterlacing in the decoder
which is useful as there is no other deinterlacing mechanism in the gpu
output path. To use this deinterlacing you must pass the option:
``vd-lavc-o=deint=[weave|bob|adaptive]``.
Pass ``weave`` (or leave the option unset) to not attempt any
deinterlacing. ``cuda`` should always be preferred unless the ``gpu``
vo is not being used or filters are required.
``nvdec`` is a newer implementation of CUVID/CUDA decoding, which uses the
FFmpeg decoders for file parsing. Experimental, is known not to correctly
check whether decoding is supported by the hardware at all. Deinterlacing
is not supported. Since this uses FFmpeg's codec parsers, it is expected
that this generally causes fewer issues than ``cuda``.
Most video filters will not work with hardware decoding as they are
primarily implemented on the CPU. Some exceptions are ``vdpaupp``,
``vdpaurb`` and ``vavpp``. See `VIDEO FILTERS`_ for more details.
The ``...-copy`` modes (e.g. ``dxva2-copy``) allow you to use hardware
decoding with any VO, backend or filter. Because these copy the decoded
video back to system RAM, they're likely less efficient than the direct
modes (like e.g. ``dxva2``), and probably not more efficient than software
decoding except for some codecs (e.g. HEVC).
.. note::
When using this switch, hardware decoding is still only done for some
codecs. See ``--hwdec-codecs`` to enable hardware decoding for more
codecs.
Because these copy the decoded video back to system RAM, they're often less
efficient than the direct modes, and may not help too much over software
decoding.
.. note::
Most non-copy methods only work with the OpenGL GPU backend. Currently,
only the ``nvdec`` and ``cuda`` methods work with Vulkan.
only the ``vaapi``, ``nvdec`` and ``cuda`` methods work with Vulkan.
The ``vaapi`` mode, if used with ``--vo=gpu``, requires Mesa 11, and most
likely works with Intel and AMD GPUs only. It also requires the opengl EGL
backend.
``nvdec`` and ``nvdec-copy`` are the newest, and recommended method to do
hardware decoding on Nvidia GPUs.
``cuda`` and ``cuda-copy`` are an older implementation of hardware decoding
on Nvidia GPUs that uses Nvidia's bitstream parsers rather than FFmpeg's.
This can lead to feature deficiencies, such as incorrect playback of HDR
content, and ``nvdec``/``nvdec-copy`` should always be preferred unless you
specifically need Nvidia's deinterlacing algorithms. To use this
deinterlacing you must pass the option:
``vd-lavc-o=deint=[weave|bob|adaptive]``.
Pass ``weave`` (or leave the option unset) to not attempt any
deinterlacing.
.. admonition:: Quality reduction with hardware decoding
@@ -1040,10 +1131,10 @@ Video
cases, hardware decoding can also reduce the bit depth of the decoded
image, which can introduce banding or precision loss for 10-bit files.
``vdpau`` is usually safe, except for 10 bit video. If deinterlacing
enabled (or the ``vdpaupp`` video filter is active in general), it
forces RGB conversion. The latter currently does not treat certain
colorspaces like BT.2020 correctly.
``vdpau`` always does RGB conversion in hardware, which does not
support newer colorspaces like BT.2020 correctly. However, ``vdpau``
doesn't support 10 bit or HDR encodings, so these limitations are
unlikely to be relevant.
``vaapi`` and ``d3d11va`` are safe. Enabling deinterlacing (or simply
their respective post-processing filters) will possibly at least reduce
@@ -1059,10 +1150,11 @@ Video
``rpi`` always uses the hardware overlay renderer, even with
``--vo=gpu``.
``cuda`` should be safe, but it has been reported to corrupt the
timestamps causing glitched, flashing frames on some files. It can also
sometimes cause massive framedrops for unknown reasons. Caution is
advised.
``cuda`` should usually be safe, but depending on how a file/stream
has been mixed, it has been reported to corrupt the timestamps causing
glitched, flashing frames. It can also sometimes cause massive
framedrops for unknown reasons. Caution is advised, and ``nvdec``
should always be preferred.
``crystalhd`` is not safe. It always converts to 4:2:2 YUV, which
may be lossy, depending on how chroma sub-sampling is done during
@@ -1088,13 +1180,13 @@ Video
This option is for troubleshooting hwdec interop issues. Since it's a
debugging option, its semantics may change at any time.
This is useful for the ``gpu`` and ``opengl-cb`` VOs for selecting which
This is useful for the ``gpu`` and ``libmpv`` VOs for selecting which
hwdec interop context to use exactly. Effectively it also can be used
to block loading of certain backends.
If set to ``auto`` (default), the behavior depends on the VO: for ``gpu``,
it does nothing, and the interop context is loaded on demand (when the
decoder probes for ``--hwdec`` support). For ``opengl-cb``, which has
decoder probes for ``--hwdec`` support). For ``libmpv``, which has
has no on-demand loading, this is equivalent to ``all``.
The empty string is equivalent to ``auto``.
@@ -1140,17 +1232,18 @@ Video
``--cuda-decode-device=<auto|0..>``
Choose the GPU device used for decoding when using the ``cuda`` or
``nvdec`` hwdecs with the OpenGL GPU backend.
``nvdec`` hwdecs with the OpenGL GPU backend, and with the ``cuda-copy``
or ``nvdec-copy`` hwdecs in all cases.
By default, the device that is being used to provide ``gpu`` output will
also be used for decoding (and in the vast majority of cases, only one
GPU will be present).
For the OpenGL GPU backend, the default device used for decoding is the one
being used to provide ``gpu`` output (and in the vast majority of cases,
only one GPU will be present).
Note that when using the ``cuda-copy`` or ``nvdec-copy`` hwdec, a
different option must be passed: ``--vd-lavc-o=gpu=<0..>``.
For the ``copy`` hwdecs, the default device will be the first device
enumerated by the CUDA libraries - however that is done.
Note that this option is not available with the Vulkan GPU backend. With
Vulkan, decoding must always happen on the display device.
For the Vulkan GPU backend, decoding must always happen on the display
device, and this option has no effect.
``--vaapi-device=<device file>``
Choose the DRM device for ``vaapi-copy``. This should be the path to a
@@ -1371,6 +1464,11 @@ Video
(default: 3). If this is a number, then fallback will be triggered if
N frames fail to decode in a row. 1 is equivalent to ``yes``.
Setting this to a higher number might break the playback start fallback: if
a fallback happens, parts of the file will be skipped, approximately by to
the number of packets that could not be decoded. Values below an unspecified
count will not have this problem, because mpv retains the packets.
``--vd-lavc-dr=<yes|no>``
Enable direct rendering (default: yes). If this is set to ``yes``, the
video will be decoded directly to GPU video memory (or staging buffers).
@@ -1403,6 +1501,8 @@ Video
mechanism, like ``bug``, ``gray``, ``idct``, ``ec``, ``vismv``,
``skip_top`` (was ``st``), ``skip_bottom`` (was ``sb``), ``debug``.
This is a key/value list option. See `List Options`_ for details.
.. admonition:: Example
``--vd-lavc-o=debug=pict``
@@ -1662,6 +1762,8 @@ Audio
unneeded and pass all unknown options through the AVOption system is
welcome. A full list of AVOptions can be found in the FFmpeg manual.
This is a key/value list option. See `List Options`_ for details.
``--ad-spdif-dtshd=<yes|no>``, ``--dtshd``, ``--no-dtshd``
If DTS is passed through, use DTS-HD.
@@ -1749,7 +1851,7 @@ Audio
``--audio-files=<files>``
Play audio from an external file while viewing a video.
This is a list option. See `List Options`_ for details.
This is a path list option. See `List Options`_ for details.
``--audio-file=<file>``
CLI/config file only alias for ``--audio-files-append``. Each use of this
@@ -1830,6 +1932,8 @@ Audio
``--audio-file-paths=<path1:path2:...>``
Equivalent to ``--sub-file-paths`` option, but for auto-loaded audio files.
This is a path list option. See `List Options`_ for details.
``--audio-client-name=<name>``
The application name the player reports to the audio API. Can be useful
if you want to force a different audio profile (e.g. with PulseAudio),
@@ -1903,7 +2007,7 @@ Subtitles
and ``--secondary-sid`` to select the second index. (The index is printed
on the terminal output after the ``--sid=`` in the list of streams.)
``--sub-files`` is a list option (see `List Options`_ for details), and
``--sub-files`` is a path list option (see `List Options`_ for details), and
can take multiple file names separated by ``:`` (Unix) or ``;`` (Windows),
while ``--sub-file`` takes a single filename, but can be used multiple
times to add multiple files. Technically, ``--sub-file`` is a CLI/config
@@ -1995,6 +2099,8 @@ Subtitles
``--sub-ass-force-style=<[Style.]Param=Value[,...]>``
Override some style or script info parameters.
This is a string list option. See `List Options`_ for details.
.. admonition:: Examples
- ``--sub-ass-force-style=FontName=Arial,Default.Bold=1``
@@ -2275,7 +2381,7 @@ Subtitles
- ``/path/to/video/subtitles/``
- the ``sub`` configuration subdirectory (usually ``~/.config/mpv/sub/``)
This is a list option. See `List Options`_ for details.
This is a path list option. See `List Options`_ for details.
``--sub-visibility``, ``--no-sub-visibility``
Can be used to disable display of subtitles, but still select and decode
@@ -2510,8 +2616,8 @@ Window
``--fs-screen=<all|current|0-32>``
In multi-monitor configurations (i.e. a single desktop that spans across
multiple displays), this option tells mpv which screen to go fullscreen to.
If ``default`` is provided mpv will fallback on using the behavior
depending on what the user provided with the ``screen`` option.
If ``current`` is used mpv will fallback on what the user provided with
the ``screen`` option.
.. admonition:: Note (X11)
@@ -2763,6 +2869,23 @@ Window
For example, ``--window-scale=0.5`` would show the window at half the
video size.
``--window-minimized=<yes|no>``
Whether the video window is minimized or not. Setting this will minimize,
or unminimze, the video window if the current VO supports it. Note that
some VOs may support minimization while not supporting unminimization
(eg: Wayland).
Whether this option and ``--window-maximized`` work on program start or
at runtime, and whether they're (at runtime) updated to reflect the actual
window state, heavily depends on the VO and the windowing system. Some VOs
simply do not implement them or parts of them, while other VOs may be
restricted by the windowing systems (especially Wayland).
``--window-maximized=<yes|no>``
Whether the video window is maximized or not. Setting this will maximize,
or unmaximize, the video window if the current VO supports it. See
``--window-minimized`` for further remarks.
``--cursor-autohide=<number|no|always>``
Make mouse cursor automatically hide after given number of milliseconds.
``no`` will disable cursor autohide. ``always`` means the cursor will stay
@@ -2815,7 +2938,7 @@ Window
- ``--monitoraspect=16:9`` or ``--monitoraspect=1.7777``
``--hidpi-window-scale``, ``--no-hidpi-window-scale``
(OS X and X11 only)
(OS X, X11, and Wayland only)
Scale the window size according to the backing scale factor (default: yes).
On regular HiDPI resolutions the window opens with double the size but appears
as having the same size as on none-HiDPI resolutions. This is the default OS X
@@ -3061,6 +3184,8 @@ Demuxer
be found in the FFmpeg manual. Note that some options may conflict
with mpv options.
This is a key/value list option. See `List Options`_ for details.
.. admonition:: Example
``--demuxer-lavf-o=fflags=+ignidx``
@@ -3092,6 +3217,18 @@ Demuxer
the first song in the stream. Well, you won't get anything useful either
way if the seek is outside of mpv's cache.
``--demuxer-lavf-propagate-opts=<yes|no>``
Propagate FFmpeg-level options to recursively opened connections (default:
yes). This is needed because FFmpeg will apply these settings to nested
AVIO contexts automatically. On the other hand, this could break in certain
situations - it's the FFmpeg API, you just can't win.
This affects in particular the ``--timeout`` option and anything passed
with ``--demuxer-lavf-o``.
If this option is deemed unnecessary at some point in the future, it will
be removed without notice.
``--demuxer-mkv-subtitle-preroll=<yes|index|no>``, ``--mkv-subtitle-preroll``
Try harder to show embedded soft subtitles when seeking somewhere. Normally,
it can happen that the subtitle at the seek target is not shown due to how
@@ -3321,6 +3458,18 @@ Demuxer
after the initial caching. This option is useless if the file cannot be
cached completely.
``--rar-list-all-volumes=<yes|no>``
When opening multi-volume rar files, open all volumes to create a full list
of contained files (default: no). If disabled, only the archive entries
whose headers are located within the first volume are listed (and thus
played when opening a .rar file with mpv). Doing so speeds up opening, and
the typical idiotic use-case of playing uncompressed multi-volume rar files
that contain a single media file is made faster.
Opening is still slow, because for unknown, idiotic, and unnecessary reasons
libarchive opens all volumes anyway when playing the main file, even though
mpv iterated no archive entries yet.
Input
-----
@@ -3368,6 +3517,8 @@ Input
like any other binding). See `INPUT.CONF`_.
``--input-file=<filename>``
Deprecated. Use ``--input-ipc-server``.
Read commands from the given file. Mostly useful with a FIFO. Since
mpv 0.7.0 also understands JSON commands (see `JSON IPC`_), but you can't
get replies or events. Use ``--input-ipc-server`` for something
@@ -3403,12 +3554,8 @@ Input
See `JSON IPC`_ for details.
``--input-appleremote=<yes|no>``
(OS X only)
Enable/disable Apple Remote support. Enabled by default (except for libmpv).
``--input-gamepad=<yes|no>``
Enable/disable SDL2 Gamepad support. Enabled by default (except for libmpv).
Enable/disable SDL2 Gamepad support. Disabled by default.
``--input-cursor``, ``--no-input-cursor``
Permit mpv to receive pointer events reported by the video output
@@ -3833,6 +3980,21 @@ Software Scaler
``--sws-cvs=<v>``
Software scaler chroma vertical shifting. See ``--sws-scaler``.
``--sws-bitexact=<yes|no>``
Unknown functionality (default: no). Consult libswscale source code. The
primary purpose of this, as far as libswscale API goes), is to produce
exactly the same output for the same input on all platforms (output has the
same "bits" everywhere, thus "bitexact"). Typically disables optimizations.
``--sws-fast=<yes|no>``
Allow optimizations that help with performance, but reduce quality (default:
no).
VOs like ``drm`` and ``x11`` will benefit a lot from using ``--sws-fast``.
You may need to set other options, like ``--sws-scaler``. The builtin
``sws-fast`` profile sets this option and some others to gain performance
for reduced quality.
``--sws-allow-zimg=<yes|no>``
Allow using zimg (if the component using the internal swscale wrapper
explicitly allows so). In this case, zimg *may* be used, if the internal
@@ -3846,10 +4008,30 @@ Software Scaler
correctly, a verbose priority log message will indicate whether zimg is
being used.
Currently, barely anything uses this.
Most things which need software conversion can make use of this.
``--zimg--scaler=<point|bilinear|bicubic|spline16|lanczos>``
Zimg luma scaler to use (default: bilinear).
``--zimg-scaler=<point|bilinear|bicubic|spline16|spline36|lanczos>``
Zimg luma scaler to use (default: lanczos).
``--zimg-scaler-param-a=<default|float>``, ``--zimg-scaler-param-b=<default|float>``
Set scaler parameters. By default, these are set to the special string
``default``, which maps to a scaler-specific default value. Ignored if the
scaler is not tunable.
``lanczos``
``--zimg-scaler-param-a`` is the number of taps.
``bicubic``
a and b are the bicubic b and c parameters.
``--zimg-scaler-chroma=...``
Same as ``--zimg-scaler``, for for chroma interpolation (default: bilinear).
``--zimg-scaler-chroma-param-a``, ``--zimg-scaler-chroma-param-b``
Same as ``--zimg-scaler-param-a`` / ``--zimg-scaler-param-b``, for chroma.
``--zimg-dither=<no|ordered|random|error-diffusion>``
Dithering (default: random).
``--zimg-fast=<yes|no>``
Allow optimizations that help with performance, but reduce quality (default:
@@ -3904,6 +4086,8 @@ It also sets the defaults for the ``lavrresample`` audio filter.
Set AVOptions on the SwrContext or AVAudioResampleContext. These should
be documented by FFmpeg or Libav.
This is a key/value list option. See `List Options`_ for details.
Terminal
--------
@@ -4125,6 +4309,32 @@ Cache
Currently, this is used for ``--cache-on-disk`` only.
``--stream-buffer-size=<bytesize>``
Size of the low level stream byte buffer (default: 128KB). This is used as
buffer between demuxer and low level I/O (e.g. sockets). Generally, this
can be very small, and the main purpose is similar to the internal buffer
FILE in the C standard library will have.
Half of the buffer is always used for guaranteed seek back, which is
important for unseekable input.
There are known cases where this can help performance to set a large buffer:
1. mp4 files. libavformat may trigger many small seeks in both
directions, depending on how the file was muxed.
2. Certain network filesystems, which do not have a cache, and where
small reads can be inefficient.
In other cases, setting this to a large value can reduce performance.
Usually, read accesses are at half the buffer size, but it may happen that
accesses are done alternating with smaller and larger sizes (this is due to
the internal ring buffer wrap-around).
See ``--list-options`` for defaults and value range. ``<bytesize>`` options
accept suffixes such as ``KiB`` and ``MiB``.
Network
-------
@@ -4141,6 +4351,8 @@ Network
``--http-header-fields=<field1,field2>``
Set custom HTTP fields when accessing HTTP stream.
This is a string list option. See `List Options`_ for details.
.. admonition:: Example
::
@@ -4184,9 +4396,10 @@ Network
Specify a referrer path or URL for HTTP requests.
``--network-timeout=<seconds>``
Specify the network timeout in seconds. This affects at least HTTP. The
special value 0 (default) uses the FFmpeg/Libav defaults. If a protocol
is used which does not support timeouts, this option is silently ignored.
Specify the network timeout in seconds (default: 60 seconds). This affects
at least HTTP. The special value 0 uses the FFmpeg/Libav defaults. If a
protocol is used which does not support timeouts, this option is silently
ignored.
.. warning::
@@ -4195,8 +4408,10 @@ Network
option accept different units (seconds instead of microseconds, causing
mpv to pass it huge values), it will also overflow FFmpeg internal
calculations. The worst is that merely setting the option will put RTSP
into listening mode, which breaks any client uses. Do not use this
option with RTSP URLs.
into listening mode, which breaks any client uses. At time of this
writing, the fix was not made effective yet. For this reason, this
option is ignored (or should be ignored) on RTSP URLs. You can still
set the timeout option directly with ``--demuxer-lavf-o``.
``--rtsp-transport=<lavf|udp|tcp|http>``
Select RTSP transport method (default: tcp). This selects the underlying
@@ -4329,7 +4544,7 @@ GPU renderer options
-----------------------
The following video options are currently all specific to ``--vo=gpu`` and
``--vo=opengl-cb`` only, which are the only VOs that implement them.
``--vo=libmpv`` only, which are the only VOs that implement them.
``--scale=<filter>``
The filter function to use when upscaling video.
@@ -4656,7 +4871,7 @@ The following video options are currently all specific to ``--vo=gpu`` and
require driver-specific hacks if using multiple monitors, to ensure mpv
syncs to the right one. Compositing window managers can also lead to bad
results, as can missing or incorrect display FPS information (see
``--display-fps``).
``--override-display-fps``).
``--vulkan-swap-mode=<mode>``
Controls the presentation mode of the vulkan swapchain. This is similar
@@ -4694,8 +4909,8 @@ The following video options are currently all specific to ``--vo=gpu`` and
GPUs. It's worth noting that if async compute is enabled, and the device
supports more compute queues than graphics queues (bound by the restrictions
set by ``--vulkan-queue-count``), mpv will internally try and prefer the
use of compute shaders over fragment shaders wherever possible. Not enabled
by default, since it seems to cause issues with some drivers.
use of compute shaders over fragment shaders wherever possible. Enabled by
default, although Nvidia users may want to disable it.
``--d3d11-warp=<yes|no|auto>``
Use WARP (Windows Advanced Rasterization Platform) with the D3D11 GPU
@@ -4746,6 +4961,19 @@ The following video options are currently all specific to ``--vo=gpu`` and
from Windows 10. Thus on older systems it will only automatically
utilize the rgba8 output format.
``--d3d11-output-csp=<auto|srgb|linear|pq|bt.2020>``
Select a specific D3D11 output color space to utilize for D3D11 rendering.
"auto" is the default, which will select the color space of the desktop
on which the swap chain is located.
Values other than "srgb" and "pq" have had issues in testing, so they
are mostly available for manual testing.
.. note::
Swap chain color space configuration is only available from an API
available from Windows 10. Thus on older systems it will not work.
``--d3d11va-zero-copy=<yes|no>``
By default, when using hardware decoding with ``--gpu-api=d3d11``, the
video image will be copied (GPU-to-GPU) from the decoder surface to a
@@ -4758,7 +4986,7 @@ The following video options are currently all specific to ``--vo=gpu`` and
Currently only relevant for ``--gpu-api=d3d11``.
``--wayland-frame-wait-offset=<-100..3000>``
``--wayland-frame-wait-offset=<-500..3000>``
Control the amount of offset (in microseconds) to add to wayland's frame wait
(default 1000). The wayland context assumes that if frame callback or presentation
feedback isn't received within a certain amount of time then the video is being
@@ -4789,11 +5017,15 @@ The following video options are currently all specific to ``--vo=gpu`` and
This option is deprecated, since there is only one reasonable value.
It may be removed in the future.
``--glsl-shaders=<file-list>``
``--glsl-shader=<file>``, ``--glsl-shaders=<file-list>``
Custom GLSL hooks. These are a flexible way to add custom fragment shaders,
which can be injected at almost arbitrary points in the rendering pipeline,
and access all previous intermediate textures. Each use of the option will
add another file to the internal list of shaders (see `List Options`_).
and access all previous intermediate textures.
Each use of the ``--glsl-shader`` option will add another file to the
internal list of shaders, while ``--glsl-shaders`` takes a list of files,
and overwrites the internal list with it. The latter is a path list option
(see `List Options`_ for details).
.. admonition:: Warning
@@ -5274,7 +5506,7 @@ The following video options are currently all specific to ``--vo=gpu`` and
auto
auto-select (default)
cocoa
Cocoa/OS X (deprecated, use --vo=opengl-cb instead)
Cocoa/OS X (deprecated, use --vo=libmpv instead)
win
Win32/WGL
winvk
@@ -5303,11 +5535,6 @@ The following video options are currently all specific to ``--vo=gpu`` and
X11/EGL
android
Android/EGL. Requires ``--wid`` be set to an ``android.view.Surface``.
vdpauglx
Use vdpau presentation with GLX as backing. Experimental use only.
Using this will have no advantage (other than additional bugs or
performance problems), and is for doing experiments only. Will not
be used automatically.
``--gpu-api=<type>``
Controls which type of graphics APIs will be accepted:
@@ -5784,6 +6011,8 @@ Miscellaneous
The default includes a common list of tags, call mpv with ``--list-options``
to see it.
This is a string list option. See `List Options`_ for details.
``--mc=<seconds/frame>``
Maximum A-V sync correction per frame (in seconds)
@@ -5940,6 +6169,8 @@ Miscellaneous
other options such as e.g. user agent are not available with all protocols,
and printing errors for unknown options would end up being too noisy.)
This is a key/value list option. See `List Options`_ for details.
``--vo-mmcss-profile=<name>``
(Windows only.)
Set the MMCSS profile for the video renderer thread (default: ``Playback``).
@@ -5970,7 +6201,7 @@ Miscellaneous
it slightly less intrusive. (In mpv 0.28.0 and before, this was not quite
strictly enforced.)
This is a list option. See `List Options`_ for details.
This is a path list option. See `List Options`_ for details.
``--external-file=<file>``
CLI/config file only alias for ``--external-files-append``. Each use of this
@@ -6080,3 +6311,33 @@ Miscellaneous
See the FFmpeg libavfilter documentation for details on the available
filters.
``--metadata-codepage=<codepage>``
Codepage for various input metadata (default: ``utf-8``). This affects how
file tags, chapter titles, etc. are interpreted. You can for example set
this to ``auto`` to enable autodetection of the codepage. (This is not the
default because non-UTF-8 codepages are an obscure fringe use-case.)
See ``--sub-codepage`` option on how codepages are specified and further
details regarding autodetection and codepage conversion. (The underlying
code is the same.)
Conversion is not applied to metadata that is updated at runtime.
Debugging
---------
``--unittest=<name>``
Run an internal unit test. There are multiple, and the name specifies which.
The special value ``all-simple`` runs all tests which do not need further
setup (other arguments and such). Some tests may need additional arguments
to do anything useful.
On success, the player binary exits with exit status 0, otherwise it returns
with an undefined non-0 exit status (it may crash or abort itself on test
failures).
This is only enabled if built with ``--enable-tests``, and should normally
be enabled and used by developers only.
+34 -2
View File
@@ -330,8 +330,10 @@ Configurable Options
user has set them. (It will not overwrite them if all of them are set to
default values.)
Currently, this is supported for the ``bottombar`` layout only. The other
layouts do not change if this option is set.
Currently, this is supported for the ``bottombar`` and ``topbar`` layout
only. The other layouts do not change if this option is set. Separately,
if window controls are present (see below), they will be affected
regardless of which osc layout is in use.
The border is static and appears even if the OSC is configured to appear
only on mouse interaction. If the OSC is invisible, the border is simply
@@ -341,6 +343,36 @@ Configurable Options
``--sub-use-margins`` option is set to ``yes``, the default). This may be
fixed later.
This does not work correctly with video outputs like ``--vo=xv``, which
render OSD into the unscaled video.
``windowcontrols``
Default: auto (Show window controls if there is no window border)
Whether to show window management controls over the video, and if so,
which side of the window to place them. This may be desirable when the
window has no decorations, either because they have been explicitly
disabled (``border=no``) or because the current platform doesn't support
them (eg: gnome-shell with wayland).
The set of window controls is fixed, offering ``minimize``, ``maximize``,
and ``quit``. Not all platforms implement ``minimize`` and ``maximize``,
but ``quit`` will always work.
``windowcontrols_alignment``
Default: right
If window controls are shown, indicates which side should they be aligned
to.
Supports ``left`` and ``right`` which will place the controls on those
respective sides.
``greenandgrumpy``
Default: no
Set to ``yes`` to reduce festivity (i.e. disable santa hat in December.)
Script Commands
~~~~~~~~~~~~~~~
+3
View File
@@ -23,6 +23,7 @@ stats:
==== ==================
1 Show usual stats
2 Show frame timings
3 Input cache stats
==== ==================
Font
@@ -53,6 +54,8 @@ Configurable Options
Default: 1
``key_page_2``
Default: 2
``key_page_3``
Default: 3
Key bindings for page switching while stats are displayed.
+56 -5
View File
@@ -85,6 +85,9 @@ libavfilter bridge.
Video filters are managed in lists. There are a few commands to manage the
filter list.
``--vf-append=filter``
Appends the filter given as arguments to the filter list.
``--vf-add=filter``
Appends the filter given as arguments to the filter list. (Passing multiple
filters is currently still possible, but deprecated.)
@@ -93,12 +96,24 @@ filter list.
Prepends the filters given as arguments to the filter list. (Passing
multiple filters is currently still possible, but deprecated.)
``--vf-remove=filter``
Deletes the filter from the list. The filter can be either given the way it
was added (filter name and its full argument list), or by label (prefixed
with ``@``). Matching of filters works as follows: if either of the compared
filters has a label set, only the labels are compared. If none of the
filters have a label, the filter name, arguments, and argument order are
compared. (Passing multiple filters is currently still possible, but
deprecated.)
``-vf-toggle=filter``
Add the given filter to the list if it was not present yet, or remove it
from the list if it was present. Matching of filters works as described in
``--vf-remove``.
``--vf-del=filter``
Deletes the filter. The filter can even given the way it was added (filter
name and its full argument list), by label (prefixed with ``@``), or as
index number. Index numbers start at 0, negative numbers address the end of
the list (-1 is the last). (Passing multiple filters is currently still
possible, but deprecated.)
Sort of like ``--vf-remove``, but also accepts an index number. Index
numbers start at 0, negative numbers address the end of the list (-1 is the
last). Deprecated.
``--vf-clr``
Completely empties the filter list.
@@ -710,3 +725,39 @@ Available mpv-only filters are:
Print computed fingerprints the the terminal (default: no). This is
mostly for testing and such. Scripts should use ``vf-metadata`` to
read information from this filter instead.
``gpu=...``
Convert video to RGB using the OpenGL renderer normally used with
``--vo=gpu``. This requires that the EGL implementation supports off-screen
rendering on the default display. (This is the case with Mesa.)
Sub-options:
``w=<pixels>``, ``h=<pixels>``
Size of the output in pixels (default: 0). If not positive, this will
use the size of the first filtered input frame.
.. warning::
This is highly experimental. Performance is bad, and it will not work
everywhere in the first place. Some features are not supported.
.. warning::
This does not do OSD rendering. If you see OSD, then it has been
rendered by the VO backend. (Subtitles are rendered by the ``gpu``
filter, if possible.)
.. warning::
If you use this with encoding mode, keep in mind that encoding mode will
convert the RGB filter's output back to yuv420p in software, using the
configured software scaler. Using ``zimg`` might improve this, but in
any case it might go against your goals when using this filter.
.. warning::
Do not use this with ``--vo=gpu``. It will apply filtering twice, since
most ``--vo=gpu`` options are unconditionally applied to the ``gpu``
filter. There is no mechanism in mpv to prevent this.
+12
View File
@@ -71,6 +71,9 @@ Available video output drivers are:
Shared memory video output driver without hardware acceleration that works
whenever X11 is present.
Since mpv 0.30.0, you may need to use ``--profile=sw-fast`` to get decent
performance.
.. note:: This is a fallback only, and should not be normally used.
``vdpau`` (X11 only)
@@ -383,6 +386,9 @@ Available video output drivers are:
Depends on support of true color by modern terminals to display the images
at full color range. On Windows it requires an ansi terminal such as mintty.
Since mpv 0.30.0, you may need to use ``--profile=sw-fast`` to get decent
performance.
``--vo-tct-algo=<algo>``
Select how to write the pixels to the terminal.
@@ -482,6 +488,9 @@ Available video output drivers are:
environment (e.g. no X). Does not support hardware acceleration (if you
need this, check the ``drm`` backend for ``gpu`` VO).
Since mpv 0.30.0, you may need to use ``--profile=sw-fast`` to get decent
performance.
The following global options are supported by this video output:
``--drm-connector=[<gpu_number>.]<name>``
@@ -583,4 +592,7 @@ Available video output drivers are:
Shared memory video output driver without hardware acceleration that works
whenever Wayland is present.
Since mpv 0.30.0, you may need to use ``--profile=sw-fast`` to get decent
performance.
.. note:: This is a fallback only, and should not be normally used.
+1 -2
View File
@@ -144,7 +144,6 @@ Mac OS X
* Native OpenGL backend.
* Cocoa event loop is independent from MPlayer's event loop, so user
actions like accessing menus and live resizing do not block the playback.
* Apple Remote support.
* Media Keys support.
* VDA support using libavcodec hwaccel API instead of FFmpeg's decoder with up
to 2-2.5x reduction in CPU usage.
@@ -248,7 +247,7 @@ Command Line Switches
``-msglevel`` ``--msg-level`` (changed semantics)
``-msgmodule`` ``--msg-module``
``-name`` ``--x11-name``
``-noar`` ``--no-input-appleremote``
``-noar`` ``(removed; replaced by MediaPlayer framework)``
``-noautosub`` ``--no-sub-auto``
``-noconsolecontrols`` ``--no-input-terminal``
``-nosound`` ``--no-audio``
+7 -3
View File
@@ -20,24 +20,28 @@ Release procedure
While on master:
- Update the `RELEASE_NOTES` file.
- Update the `RELEASE_NOTES` file, replacing the previous release notes.
- Update the `VERSION` file.
- Update `DOCS/client-api-changes.rst` and `DOCS/interface-changes.rst`
(in particular, update the last version numbers if necessary)
- Commit changes.
- Create signed commit with changes.
- Create signed tag v0.X.Y.
- Add -UNKNOWN suffix to version in `VERSION` file.
- Commit changes, push branch and tag to GitHub.
- Commit changes, push release branch (`release/0.X`) and tag to GitHub.
- Create a new GitHub release using the content of `RELEASE_NOTES` related to
the new version.
If necessary (to e.g. exclude commits already on master), the release can
be done on a branch with different commit history. The release branch **must**
then be merged to master so `git describe` will pick up the tag.
Release notes template
----------------------
+421 -7
View File
@@ -15,7 +15,7 @@ player/*.c:
* parse command line, add files from the command line to playlist
(m_config_parse_mp_command_line())
* check help options etc. (call handle_help_options()), possibly exit
* call play_files() function that works down the playlist:
* call mp_play_files() function that works down the playlist:
* run idle loop (idle_loop()), until there are files in the
playlist or an exit command was given (only if --idle it set)
* actually load and play a file in play_current_file():
@@ -30,7 +30,7 @@ player/*.c:
* determine next entry on the playlist to play
* loop, or exit if no next file or quit is requested
(see enum stop_play_reason)
* call exit_player_with_rc()
* call mp_destroy()
* run_playloop():
* calls fill_audio_out_buffers()
This checks whether new audio needs to be decoded, and pushes it
@@ -44,9 +44,9 @@ player/*.c:
Things worth saying about the playback core:
- most state is in MPContext (core.h), which is not available to the
subsystems
subsystems (and should not be made available)
- the currently played tracks are in mpctx->current_tracks, and decoder
state in track.d_video/d_audio/d_sub
state in track.dec/d_sub
- the other subsystems rarely call back into the frontend, and the frontend
polls them instead (probably a good thing)
- one exceptions are wakeup callbacks, which notify a "higher" component
@@ -68,6 +68,7 @@ ta.h & ta.c:
as in it doesn't require valgrind.) You can enable it by setting the
MPV_LEAK_REPORT environment variable to "1":
export MPV_LEAK_REPORT=1
Or permanently by building with --enable-ta-leak-report.
This will list all unfree'd allocations on exit.
Documentation can be found here:
@@ -103,13 +104,45 @@ options/options.h, options/options.c
options.c. Most default values for options and MPOpts are in
mp_default_opts at the end of options.c.
MPOpts is unfortunately quite monolithic, and virtually accessed by
everything.But some components (like video outputs and video filters) have
their own sub-option tables separate from MPOpts.
MPOpts is unfortunately quite monolithic, but is being incrementally broken
up into sub-structs. Many components have their own sub-option structs
separate from MPOpts. New options should be bound to the component that uses
them. Add a new option table/struct if needed.
The global MPOpts still contains the sub-structs as fields, which serves to
link them to the option parser. For example, an entry like this may be
typical:
OPT_SUBSTRUCT("", demux_opts, demux_conf, 0),
This directs the option access code to include all options in demux_conf
into the global option list, with no prefix (""), and as part of the
MPOpts.demux_opts field. The MPOpts.demux_opts field is actually not
accessed anywhere, and instead demux.c does this:
struct m_config_cache *opts_cache =
m_config_cache_alloc(demuxer, global, &demux_conf);
struct demux_opts *opts = opts_cache->opts;
... to get a copy of its options.
See m_config.h (below) how to access options.
The actual option parser is spread over m_option.c, m_config.c, and
parse_commandline.c, and uses the option table in options.c.
options/m_config.h & m_config.c:
Code for querying and managing options. This (unfortunately) contains both
declarations for the "legacy-ish" global m_config struct, and ways to access
options in a threads-safe way anywhere, like m_config_cache_alloc().
m_config_cache_alloc() lets anyone read, observe, and write options in any
thread. The only state it needs is struct mpv_global, which is an opaque
type that can be passed "down" the component hierarchy. For safety reasons,
you should not pass down any pointers to option structs (like MPOpts), but
instead pass down mpv_global, and use m_config_cache_alloc() (or similar)
to get a synchronized copy of the options.
input/input.c:
This translates keyboard input coming from VOs and other sources (such
as remote control devices like Apple IR or client API commands) to the
@@ -241,3 +274,384 @@ sub/:
etc/:
The file input.conf is actually integrated into the mpv binary by the
build system. It contains the default keybindings.
Best practices and Concepts within mpv
======================================
General contribution etc.
-------------------------
See: DOCS/contribute.md
Error checking
--------------
If an error is relevant, it should be handled. If it's interesting, log the
error. However, mpv often keeps errors silent and reports failures somewhat
coarsely by propagating them upwards the caller chain. This is OK, as long as
the errors are not very interesting, or would require a developer to debug it
anyway (in which case using a debugger would be more convenient, and the
developer would need to add temporary debug printfs to get extremely detailed
information which would not be appropriate during normal operation).
Basically, keep a balance on error reporting. But always check them, unless you
have a good argument not to.
Memory allocation errors (OOM) are a special class of errors. Normally such
allocation failures are not handled "properly". Instead, abort() is called.
(New code should use MP_HANDLE_OOM() for this.) This is done out of laziness and
for convenience, and due to the fact that MPlayer/mplayer2 never handled it
correctly. (MPlayer varied between handling it correctly, trying to do so but
failing, and just not caring, while mplayer2 started using abort() for it.)
This is justifiable in a number of ways. Error handling paths are notoriously
untested and buggy, so merely having them won't make your program more reliable.
Having these error handling paths also complicates non-error code, due to the
need to roll back state at any point after a memory allocation.
Take any larger body of code, that is supposed to handle OOM, and test whether
the error paths actually work, for example by overriding malloc with a version
that randomly fails. You will find bugs quickly, and often they will be very
annoying to fix (if you can even reproduce them).
In addition, a clear indication that something went wrong may be missing. On
error your program may exhibit "degraded" behavior by design. Consider a video
encoder dropping frames somewhere in the middle of a video due to temporary
allocation failures, instead of just exiting with an errors. In other cases, it
may open conceptual security holes. Failing fast may be better.
mpv uses GPU APIs, which may be break on allocation errors (because driver
authors will have the same issues as described here), or don't even have a real
concept for dealing with OOM (OpenGL).
libmpv is often used by GUIs, which I predict always break if OOM happens.
Last but not least, OSes like Linux use "overcommit", which basically means that
your program may crash any time OOM happens, even if it doesn't use malloc() at
all!
But still, don't just assume malloc() always succeeds. Use MP_HANDLE_OOM(). The
ta* APIs do this for you. The reason for this is that dereferencing a NULL
pointer can have security relevant consequences if large offsets are involved.
Also, a clear error message is better than a random segfault.
Some big memory allocations are checked anyway. For example, all code must
assume that allocating video frames or packets can fail. (The above example
of dropping video frames during encoding is entirely possible in mpv.)
Undefined behavior
------------------
Undefined behavior (UB) is a concept in the C language. C is famous for being a
language that makes it almost impossible to write working code, because
undefined behavior is so easily triggered, compilers will happily abuse it to
generate "faster" code, debugging tools will shout at you, and sometimes it
even means your code doesn't work.
There is a lot of literature on this topic. Read it.
(In C's defense, UB exists in other languages too, but since they're not used
for low level infrastructure, and/or these languages are at times not rigorously
defined, simply nobody cares. However, the C standard committee is still guilty
for not addressing this. I'll admit that I can't even tell from the standard's
gibberish whether some specific behavior is UB or not. It's written like tax
law.)
In mpv, we generally try to avoid undefined behavior. For one, we want portable
and reliable operation. But more importantly, we want clean output from
debugging tools, in order to find real bugs more quickly and effectively.
Avoid the "works in practice" argument. Once debugging tools come into play, or
simply when "in practice" stops being true, this will all get back to you in a
bad way.
Global state, library safety
----------------------------
Mutable global state is when code uses global variables that are not read-only.
This must be avoided in mpv. Always use context structs that the caller of
your code needs to allocate, and whose pointers are passed to your functions.
Library safety means that your code (or library) can be used by a library
without causing conflicts with other library users in the same process. To any
piece of code, a "safe" library's API can simply be used, without having to
worry about other API users that may be around somewhere.
Libraries are often not library safe, because they they use global mutable state
or other "global" resources. Typical examples include use of signals, simple
global variables (like hsearch() in libc), or internal caches not protected by
locks.
A surprisingly high number of libraries are not library safe because they need
global initialization. Typically they provide an API function, which
"initializes" the library, and which must be called before calling any other
API functions. Often, you are to provide global configuration parameters, which
can change the behavior of the library. If two libraries A and B use library C,
but A and B initialize C with different parameters, something "bad" may happen.
In addition, these global initialization functions are often not thread-safe. So
if A and B try to initialize C at the same time (from different threads and
without knowing about each other), it may cause undefined behavior. (libcurl is
a good example of both of these issues. FFmpeg and some TLS libraries used to be
affected, but improved.)
This is so bad because library A and B from the previous example most likely
have no way to cooperate, because they're from different authors and have no
business knowing each others. They'd need a library D, which wraps library C
in a safe way. Unfortunately, typically something worse happens: libraries get
"infected" by the unsafeness of its sub-libraries, and export a global init API
just to initialize the sub-libraries. In the previous example, libraries A and B
would export global init APIs just to init library C, even though the rest of
A/B are clean and library safe. (Again, libcurl is an example of this, if you
subtract other historic anti-features.)
The main problem with library safety is that its lack propagates to all
libraries using the library.
We require libmpv to be library safe. This is not really possible, because some
libraries are not library safe (FFmpeg, Xlib, partially ALSA). However, for
ideological reasons, there is no global init API, and best effort is made to try
to avoid problems.
libmpv has some features that are not library safe, but which are disabled by
default (such as terminal usage aka stdout, or JSON IPC blocking SIGPIPE for
internal convenience).
A notable, very disgustingly library unsafe behavior of libmpv is calling
abort() on some memory allocation failure. See error checking section.
Logging
-------
All logging and terminal output in mpv goes through the functions and macros
provided in common/msg.h. This is in part for library safety, and in part to
make sure users can silence all output, or to redirect the output elsewhere,
like a log file or the internal console.lua script.
Locking
-------
See generally available literature. In mpv, we use pthread for this.
Always keep locking clean. Don't skip locking just because it will work "in
practice". (See undefined behavior section.) If your use case is simple, you may
use C11 atomics (osdep/atomic.h for partial C99 support), but most likely you
will only hurt yourself and others.
Always make clear which fields in a struct are protected by which lock. If a
field is immutable, or simply not thread-safe (e.g. state for a single worker
thread), document it as well.
Internal mpv APIs are assumed to be not thread-safe by default. If they have
special guarantees (such as being usable by more than one thread at a time),
these should be explicitly documented.
All internal mpv APIs must be free of global state. Even if a component is not
thread-safe, multiple threads can use _different_ instances of it without any
locking.
On a side note, recursive locks may seem convenient at first, but introduce
additional problems with condition variables and locking hierarchies. They
should be avoided.
Locking hierarchy
-----------------
A simple way to avoid deadlocks with classic locking is to define a locking
hierarchy or lock order. If all threads acquire locks in the same order, no
deadlocks will happen.
For example, a "leaf" lock is a lock that is below all other locks in the
hierarchy. You can acquire it any time, as long as you don't acquire other
locks while holding it.
Unfortunately, C has no way to declare or check the lock order, so you should at
least document it.
In addition, try to avoid exposing locks to the outside. Making the declaration
of a lock private to a specific .c file (and _not_ exporting accessors or
lock/unlock functions that manipulate the lock) is a good idea. Your component's
API may acquire internal locks, but should release them when returning. Keeping
the entire locking in a single file makes it easy to check it.
Avoiding callback hell
----------------------
mpv code is separated in components, like the "frontend" (i.e. MPContext mpctx),
VOs, AOs, demuxers, and more. The frontend usually calls "down" the usage
hierarchy: mpctx almost on top, then things like vo/ao, and utility code on the
very bottom.
"Callback hell" is when when components call both up and down the hierarchy,
which for example leads to accidentally recursion, reentrancy problems, or
locking nightmares. This is avoided by (mostly) calling only down the hierarchy.
Basically the call graph forms a DAG. The other direction is handled by event
queues, wakeup callbacks, and similar mechanisms.
Typically, a component provides an API, and does not know anything about its
user. The API user (component higher in the hierarchy) polls the state of the
lower component when needed.
This also enforces some level of modularization, and with some luck the locking
hierarchy. (Basically, locks of lower components automatically become leaf
locks.) Another positive effect is simpler memory management.
(Also see e.g.: http://250bpm.com/blog:24)
Wakeup callbacks
----------------
This is a common concept in mpv. Even the public API uses it. It's used when an
API has internal threads (or otherwise triggers asynchronous events), but the
component call hierarchy needs to be kept. The wakeup callback is the only
exception to the call hierarchy, and always calls up.
For example, vo spawns a thread that the API user (the mpv frontend) does not
need to know about. vo simply provides a single-threaded API (or that looks like
one). This API needs a way to notify the API user of new events. But the vo
event producer is on the vo thread - it can't simply invoke a callback back into
the API user, because then the API user has to deal with locking, despite not
using threads. In addition, this will probably cause problems like mentioned in
the "callback hell" section, especially lock order issues.
The solution is the wakeup callback. It merely unblocks the API user from
waiting, and the API user then uses the normal vo API to examine whether or
which state changed. As a concept, it documents what a wakeup callback is
allowed to do and what not, to avoid the aforementioned problems.
Generally, you are not allowed to call any API from the wakeup callback. You
just do whatever is needed to unblock your thread. For example, if it's waiting
on a mutex/condition variable, acquire the mutex, set a change flag, signal
the condition variable, unlock, return. (This mutex must not be held when
calling the API. It must be a leaf lock.)
Restricting the wakeup callback like this sidesteps any reentrancy issues and
other complexities. The API implementation can simply hold internal (and
non-recursive) locks while invoking the wakeup callback.
The API user still needs to deal with locking (probably), but there's only the
need to implement a single "receiver", that can handle the entire API of the
used component. (Or multiple APIs - MPContext for example has only 1 wakeup
callback that handles all AOs, VOs, input, demuxers, and more. It simple re-runs
the playloop.)
You could get something more advanced by turning this into a message queue. The
API would append a message to the queue, and the API user can read it. But then
you still need a way to "wakeup" the API user (unless you force the API user
to block on your API, which will make things inconvenient for the API user). You
also need to worry about what happens if the message queue overruns (you either
lose messages or have unbounded memory usage). In the mpv public API, the
distinction between message queue and wakeup callback is sort of blurry, because
it does provide a message queue, but an additional wakeup callback, so API
users are not required to call mpv_wait_event() with a high timeout.
mpv itself prefers using wakeup callbacks over a generic event queue, because
most times an event queue is not needed (or complicates things), and it is
better to do it manually.
(You could still abstract the API user side of wakeup callback handling, and
avoid reimplementing it all the time. Although mp_dispatch_queue already
provides mechanisms for this.)
Condition variables
-------------------
They're used whenever a thread needs to wait for something, without nonsense
like sleep calls or busy waiting. mpv uses the standard pthread API for this.
There's a lot of literature on it. Read it.
For initial understanding, it may be helpful to know that condition variables
are not variables that signal a condition. pthread_cond_t does not have any
state per-se. Maybe pthread_cond_t would better be named pthread_interrupt_t,
because its sole purpose is to interrupt a thread waiting via pthread_cond_wait()
(or similar). The "something" in "waiting for something" can be called
predicate (to avoid confusing it with "condition"). Consult literature for the
proper terms.
The very short version is...
Shared declarations:
pthread_mutex_t lock;
pthread_cond_t cond_var;
struct something state_var; // protected by lock, changes signaled by cond_var
Waiter thread:
pthread_mutex_lock(&lock);
// Wait for a change in state_var. We want to wait until predicate_fulfilled()
// returns true.
// Must be a loop for 2 reasons:
// 1. cond_var may be associated with other conditions too
// 2. pthread_cond_wait() can have sporadic wakeups
while (!predicate_fulfilled(&state_var)) {
// This unlocks, waits for cond_var to be signaled, and then locks again.
// The _whole_ point of cond_var is that unlocking and waiting for the
// signal happens atomically.
pthread_cond_wait(&cond_var, &lock);
}
// Here you may react to the state change. The state cannot change
// asynchronously as long as you still hold the lock (and didn't release
// and reacquire it).
// ...
pthread_mutex_unlock(&lock);
Signaler thread:
pthread_mutex_lock(&lock);
// Something changed. Update the shared variable with the new state.
update_state(&state_var);
// Notify that something changed. This will wake up the waiter thread if
// it's blocked in pthread_cond_wait(). If not, nothing happens.
pthread_cond_broadcast(&cond_var);
// Fun fact: good implementations wake up the waiter only when the lock is
// released, to reduce kernel scheduling overhead.
pthread_mutex_unlock(&lock);
Some basic rules:
1. Always access your state under proper locking
2. Always check your predicate before every call to pthread_cond_wait()
(And don't call pthread_cond_wait() if the predicate is fulfilled.)
3. Always call pthread_cond_wait() in a loop
(And only if your predicate failed without releasing the lock..)
4. Always call pthread_cond_broadcast()/_signal() inside of its associated
lock
mpv sometimes violates rule 3, and leaves "retrying" (i.e. looping) to the
caller.
Common pitfalls:
- Thinking that pthread_cond_t is some kind of semaphore, or holds any
application state or the user predicate (it _only_ wakes up threads
that are at the same time blocking on pthread_cond_wait() and friends,
nothing else)
- Changing the predicate, but not updating all pthread_cond_broadcast()/
_signal() calls correctly
- Forgetting that pthread_cond_wait() unlocks the lock (other threads can
and must acquire the lock)
- Holding multiple nested locks while trying to wait (=> deadlock, violates
the lock order anyway)
- Waiting for a predicate correctly, but unlocking/relocking before acting
on it (unlocking allows arbitrary state changes)
- Confusing which lock/condition var. is used to manage a bit of state
Generally available literature probably has better examples and explanations.
Using condition variables the proper way is generally preferred over using more
messy variants of them. (Just saying because on win32, "SetEvent" exists, and
it's inferior to condition variables. Try to avoid the win32 primitives, even if
you're dealing with Windows-only code.)
Threads
-------
Threading should be conservatively used. Normally, mpv code pretends to be
single-threaded, and provides thread-unsafe APIs. Threads are used coarsely,
and if you can avoid messing with threads, you should. For example, VOs and AOs
do not need to deal with threads normally, even though they run on separate
threads. The glue code "isolates" them from any threading issues.
+22 -11
View File
@@ -20,15 +20,17 @@
* [Wiki](https://github.com/mpv-player/mpv/wiki)
* [FAQ](https://github.com/mpv-player/mpv/wiki/FAQ)
* [FAQ][FAQ]
* [Manual](http://mpv.io/manual/master/)
## Overview
**mpv** is a media player based on MPlayer and mplayer2. It supports a wide
variety of video file formats, audio and video codecs, and subtitle types.
**mpv** is a free (as in freedom) media player for the command line. It supports
a wide variety of media file formats, audio and video codecs, and subtitle types.
There is a [FAQ][FAQ].
Releases can be found on the [release list][releases].
@@ -38,11 +40,14 @@ Releases can be found on the [release list][releases].
- A somewhat capable CPU. Hardware decoding might help if the CPU is too slow to
decode video in realtime, but must be explicitly enabled with the `--hwdec`
option.
- A not too crappy GPU. mpv is not intended to be used with bad GPUs. There are
many caveats with drivers or system compositors causing tearing, stutter,
etc. On Windows, you might want to make sure the graphics drivers are
current. In some cases, ancient fallback video output methods can help
(such as `--vo=xv` on Linux), but this use is not recommended or supported.
- A not too crappy GPU. mpv's focus is not on power-efficient playback on
embedded or integrated GPUs (for example, hardware decoding is not even
enabled by default). Low power GPUs may cause issues like tearing, stutter,
etc. The main video output uses shaders for video rendering and scaling,
rather than GPU fixed function hardware. On Windows, you might want to make
sure the graphics drivers are current. In some cases, ancient fallback video
output methods can help (such as `--vo=xv` on Linux), but this use is not
recommended or supported.
## Downloads
@@ -113,7 +118,7 @@ Essential dependencies (incomplete list):
- uchardet (optional, for subtitle charset detection)
- nvdec and vaapi libraries for hardware decoding on Linux (optional)
Libass dependencies:
Libass dependencies (when building libass):
- gcc or clang, yasm on x86 and x86_64
- fribidi, freetype, fontconfig development headers (for libass)
@@ -121,14 +126,14 @@ Libass dependencies:
particularly for correct rendering of non-English text on OSX, and
Arabic/Indic scripts on any platform)
FFmpeg dependencies:
FFmpeg dependencies (when building FFmpeg):
- gcc or clang, yasm on x86 and x86_64
- OpenSSL or GnuTLS (have to be explicitly enabled when compiling FFmpeg)
- libx264/libmp3lame/libfdk-aac if you want to use encoding (have to be
explicitly enabled when compiling FFmpeg)
- For native DASH playback, FFmpeg needs to be built with --enable-libxml2
(although there are security implications, and DAHS support has lots of bugs).
(although there are security implications, and DASH support has lots of bugs).
- AV1 decoding support requires dav1d.
- For good nvidia support on Linux, make sure nv-codec-headers is installed
and can be found by configure.
@@ -185,6 +190,11 @@ for ideas on what you could contribute with.
GPLv2 "or later" by default, LGPLv2.1 "or later" with `--enable-lgpl`.
See [details.](https://github.com/mpv-player/mpv/blob/master/Copyright)
## History
This software is based on the MPlayer project. Before mpv existed as a project,
the code base was briefly developed under the mplayer2 project. For details,
see the [FAQ][FAQ].
## Contact
@@ -195,6 +205,7 @@ Most activity happens on the IRC channel and the github issue tracker.
- **User IRC Channel**: `#mpv` on `irc.freenode.net`
- **Developer IRC Channel**: `#mpv-devel` on `irc.freenode.net`
[FAQ]: https://github.com/mpv-player/mpv/wiki/FAQ
[releases]: https://github.com/mpv-player/mpv/releases
[mpv-build]: https://github.com/mpv-player/mpv-build
[issue-tracker]: https://github.com/mpv-player/mpv/issues
+23 -88
View File
@@ -1,9 +1,7 @@
Release 0.30.0
Release 0.32.0
==============
This release requires FFmpeg 4.0 or newer.
This release has replaced the internal Vulkan rendering abstraction
with libplacebo's more up-to-date implementation.
Features
@@ -12,54 +10,25 @@ Features
Added
~~~~~
- vo_gpu: vulkan: hwdec_cuda: Add support for Vulkan interop
- command: support for async commands
- input: support for named arguments
- cocoa-cb: add support for mac 10.14 Dark mode and run time switching
- vo_gpu: switch to Vulkan API implementation based on libplacebo
- context_drm_egl: Add support for presentation feedback
- vo_gpu: implement error diffusion for dithering
- vo/gpu: hwdec_vdpau: Support direct mode for 4:4:4 content
- vo_gpu: hwdec_vaapi: Add Vulkan interop
- video, TOOLS: add vf_fingerprint and a skip-logo script
- vo_gpu: d3d11: add support for presentation feedback
- vo_drm: 30bpp support
- cocoa-cb: add support for 10bit opengl rendering
- video: add pure gamma TRC curves for 2.0, 2.4 and 2.6
- vo_drm: Implement N-buffering and presentation feedback
- Reintroduce vo_wayland as vo_wlshm
- video: add zimg wrapper
- wayland: add presentation time
- input: add gamepad support through SDL2
- stream_libarchive: enable RAR5 support
- bash completion: add initial implementation
- cocoa-cb: add support for forcing the dedicated GPU for rendering
- cocoa-cb: add pinch to resize window gesture
- w32_common: support minimizing/maximizing using osc window controls
Changed
~~~~~~~
- cocoa-cb: use libmpv's advanced rendering control and timing
- vo_gpu: improve tone mapping desaturation
- vo_gpu: redesign peak detection algorithm
- vo_gpu: allow boosting dark scenes when tone mapping
- osc: improve look of seekranges
- vo_gpu: x11: remove special vdpau probing, use EGL by default
- demux: sort filenames naturally when playing a directory / archive
- stream_dvb: rewrite channel switching, remove old stream control
- filters: extend vf_format so that it can convert color parameters
- wayland: print warning on GNOME due to serious issues with their compositor
- player: write watch-later config even for unseekable streams
Removed
~~~~~~~
- demux, stream: rip out the classic stream cache
- vo_gpu: removed internal Vulkan implementation
- Remove libdvdread support in favor of libdvdnav
- demux, stream: remove much of the optical disc support
- Remove classic Linux analog TV support, and DVB runtime controls
- demux, stream: remove old rar support in favor of libarchive
- vo_gpu: remove mali-fbdev
- vo_gpu: remove vdpau/GLX backend
- vf_vapourynth: remove Lua backend
- vo_gpu: remove hwdec_d3d11eglrgb
- vo_gpu: hwdec_vdpau: remove direct_mode
- vo_gpu: hwdec_vaegl: remove support for old-style interop
Options and Commands
@@ -68,67 +37,33 @@ Options and Commands
Added
~~~~~
- command: add a subprocess command
- vo_gpu: added --tone-mapping-max-boost, --hdr-peak-decay-rate, --hdr-scene-threshold-low/high
- player: add --demuxer-cache-wait option
- Implement backwards playback
- demux: add a on-disk cache
- demux, command: add another stream recording mechanism, `dump-cache` command
- ao_pulse: add --pulse-allow-suspended
- command: add video-add/video-remove/video-reload commands
- demux_cue: added --demuxer-cue-codepage to select CUE sheet charset
- input: add keybind command
- command: add sub-start & sub-end properties
- video/d3d11: added --d3d11-adapter to select a rendering adapter by name
- vo_gpu/d3d11: added --d3d11-output-format for configuring swap chain format
- command: add a playlist-unshuffle command
- command: add osd-dimensions property
- input: new PLAYONLY and PAUSEONLY keycodes
Changed
~~~~~~~
- vo_gpu: split --linear-scaling into --linear-upscaling and --linear-downscaling
- vo_gpu: split --tone-mapping-desaturate into strength and exponent
- drm: rename --drm-osd-plane-id to --drm-draw-plane, --drm-video-plane-id to --drm-drmprime-video-plane, --drm-osd-size to --drm-draw-surface-size
Deprecated
~~~~~~~~~~
- options: deprecate --video-aspect, replaced by --video-aspect-override
- options: deprecate --record-file, --spirv-compiler
Removed
~~~~~~~
- options: remove deprecated --chapter option
- demux: remove "program" property
- stream: remove "disc-titles", "disc-title", "disc-title-list", and "angle" properties
- cocoa-cb: remove --macos-title-bar-style, replaced by --macos-title-bar-material and --macos-title-bar-appearance
- spirv: remove support for --spirv-compiler=nvidia (shaderc is the only remaining option)
- options: change option parsing when using a single dash
This adds a warning for `-o file.mkv` and disallows the use of
`--o file.mkv` (use `--o=file.mkv` instead).
Fixes and Minor Enhancements
----------------------------
- context_drm_egl: implement n-buffering
- cocoa-cb: add support for custom colored title bar
- vo_gpu: x11egl: support Mesa OML sync extension
- demux, demux_edl: add extension for tracks sourced from separate streams
- context_drm_egl: Use eglGetPlatformDisplayEXT if available
- vo_gpu: vulkan: add Android context
- wayland: use xdg-decoration if available
- vo_gpu: glx: use GLX_OML_sync_control for better vsync reporting
- demux: runtime option changing for cache and stream recording
- x11: fix ICC profiling for multiple monitors
- zsh completion: move generation to runtime and improve
- lua: fix mp.file_info for large files
- vo_gpu: fix crash if dither texture fails to allocate
- wayland: unscrew up cursors, fix various issues
- osc: usability improvements for osc window controls
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.29.1..v0.30.0`
A complete changelog can be seen by running `git log v0.31.0..v0.32.0`
in the git repository or by visiting either
https://github.com/mpv-player/mpv/compare/v0.29.1...v0.30.0 or
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.29.1..v0.30.0
https://github.com/mpv-player/mpv/compare/v0.31.0...v0.32.0 or
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.31.0..v0.32.0
+8 -22
View File
@@ -61,29 +61,19 @@ def libraries(objfile, result = dict()):
return result
def leafs(libs_dict, processed = []):
result = []
processed = set(processed)
for objfile, libs in libs_dict.items():
if libs <= processed:
result.append(objfile)
return result
def lib_path(binary):
return os.path.join(os.path.dirname(binary), 'lib')
def lib_name(lib):
return os.path.join("@executable_path", "lib", os.path.basename(lib))
def process_libraries(libs_dict, binary, processed = []):
ls = leafs(libs_dict, processed)
diff = set(ls) - set(processed)
if diff == set([binary]):
return
def process_libraries(libs_dict, binary):
libs_set = set(libs_dict)
# Remove binary from libs_set to prevent a duplicate of the binary being
# added to the libs directory.
libs_set.remove(binary)
for src in diff:
for src in libs_set:
name = lib_name(src)
dst = os.path.join(lib_path(binary), os.path.basename(src))
@@ -94,12 +84,10 @@ def process_libraries(libs_dict, binary, processed = []):
if src in libs_dict[binary]:
install_name_tool_change(src, name, binary)
for p in processed:
for p in libs_set:
if p in libs_dict[src]:
install_name_tool_change(p, lib_name(p), dst)
return ls
def process_swift_libraries(binary):
command = ['xcrun', '--find', 'swift-stdlib-tool']
swiftStdlibTool = subprocess.check_output(command, universal_newlines=True).strip()
@@ -130,9 +118,7 @@ def main():
libs = libraries(binary)
print(">> copying and processing all linked libraries")
libs_processed = process_libraries(libs, binary)
while libs_processed is not None:
libs_processed = process_libraries(libs, binary, libs_processed)
process_libraries(libs, binary)
print(">> removing rpath definitions towards dev tools")
remove_dev_tools_rapths(binary)
+1 -1
View File
@@ -22,7 +22,7 @@ OS2Version: 3
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 0
CreationTime: 1408646554
ModificationTime: 1492879730
ModificationTime: 1576096543
PfmFamily: 81
TTFWeight: 400
TTFWidth: 5
+15
View File
@@ -0,0 +1,15 @@
StartChar: uniE112
Encoding: 57618 57618 30
Width: 768
VWidth: 1176
Flags: HW
LayerCount: 2
Fore
SplineSet
512 40 m 1
0 40 l 1
0 168 l 1
512 168 l 1
512 40 l 1
EndSplineSet
EndChar
+20
View File
@@ -0,0 +1,20 @@
StartChar: uniE113
Encoding: 57619 57619 31
Width: 622
VWidth: 1178
Flags: HW
LayerCount: 2
Fore
SplineSet
768 42 m 5
0 42 l 5
0 746 l 5
768 746 l 5
768 42 l 5
704 106 m 5
704 618 l 5
64 618 l 5
64 106 l 5
704 106 l 5
EndSplineSet
EndChar
+31
View File
@@ -0,0 +1,31 @@
StartChar: uniE114
Encoding: 57620 57620 32
Width: 896
VWidth: 1178
Flags: HW
LayerCount: 2
Fore
SplineSet
768 298 m 1
576 298 l 1
576 42 l 1
0 42 l 1
0 490 l 1
192 490 l 1
192 746 l 1
768 746 l 1
768 298 l 1
704 362 m 1
704 618 l 1
256 618 l 1
256 490 l 1
576 490 l 1
576 362 l 1
704 362 l 1
512 106 m 1
512 362 l 1
64 362 l 1
64 106 l 1
512 106 l 1
EndSplineSet
EndChar
+27
View File
@@ -0,0 +1,27 @@
StartChar: uniE115
Encoding: 57621 57621 33
Width: 844
VWidth: 1112
Flags: HW
LayerCount: 2
Fore
SplineSet
671 40 m 1
575 40 l 1
335 277 l 1
98 40 l 1
-1 40 l 1
-1 136 l 1
236 376 l 1
-1 613 l 1
-1 712 l 1
98 712 l 1
335 475 l 1
575 712 l 1
671 712 l 1
671 613 l 1
434 376 l 1
671 139 l 1
671 40 l 1
EndSplineSet
EndChar
+1 -1
View File
@@ -1 +1 @@
0.30.0
0.32.0
+13 -3
View File
@@ -410,10 +410,16 @@ void mp_aframe_skip_samples(struct mp_aframe *f, int samples)
{
assert(samples >= 0 && samples <= mp_aframe_get_size(f));
if (av_frame_make_writable(f->av_frame) < 0)
return; // go complain to ffmpeg
int num_planes = mp_aframe_get_planes(f);
size_t sstride = mp_aframe_get_sstride(f);
for (int n = 0; n < num_planes; n++)
f->av_frame->extended_data[n] += samples * sstride;
for (int n = 0; n < num_planes; n++) {
memmove(f->av_frame->extended_data[n],
f->av_frame->extended_data[n] + samples * sstride,
(f->av_frame->nb_samples - samples) * sstride);
}
f->av_frame->nb_samples -= samples;
@@ -592,7 +598,11 @@ int mp_aframe_pool_allocate(struct mp_aframe_pool *pool, struct mp_aframe *frame
{
int planes = mp_aframe_get_planes(frame);
size_t sstride = mp_aframe_get_sstride(frame);
int plane_size = MP_ALIGN_UP(sstride * MPMAX(samples, 1), 32);
// FFmpeg hardcodes similar hidden possibly-requirements in a number of
// places: av_frame_get_buffer(), libavcodec's get_buffer(), mem.c,
// probably more.
int align_samples = MP_ALIGN_UP(MPMAX(samples, 1), 32);
int plane_size = MP_ALIGN_UP(sstride * align_samples, 64);
int size = plane_size * planes;
if (size <= 0 || mp_aframe_is_allocated(frame))
+11 -15
View File
@@ -48,7 +48,7 @@ struct priv {
bool preroll_done;
double next_pts;
AVRational codec_timebase;
bool eof_returned;
struct lavc_state state;
struct mp_decoder public;
};
@@ -81,7 +81,7 @@ static bool init(struct mp_filter *da, struct mp_codec_params *codec,
const char *decoder)
{
struct priv *ctx = da->priv;
struct MPOpts *mpopts = mp_get_config_group(ctx, da->global, GLOBAL_CONFIG);
struct MPOpts *mpopts = mp_get_config_group(ctx, da->global, &mp_opt_root);
struct ad_lavc_params *opts =
mp_get_config_group(ctx, da->global, &ad_lavc_conf);
AVCodecContext *lavc_context;
@@ -159,10 +159,10 @@ static void reset(struct mp_filter *da)
ctx->trim_samples = 0;
ctx->preroll_done = false;
ctx->next_pts = MP_NOPTS_VALUE;
ctx->eof_returned = false;
ctx->state = (struct lavc_state){0};
}
static bool send_packet(struct mp_filter *da, struct demux_packet *mpkt)
static int send_packet(struct mp_filter *da, struct demux_packet *mpkt)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
@@ -177,16 +177,12 @@ static bool send_packet(struct mp_filter *da, struct demux_packet *mpkt)
mp_set_av_packet(&pkt, mpkt, &priv->codec_timebase);
int ret = avcodec_send_packet(avctx, mpkt ? &pkt : NULL);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return false;
if (ret < 0)
MP_ERR(da, "Error decoding audio.\n");
return true;
return ret;
}
static bool receive_frame(struct mp_filter *da, struct mp_frame *out)
static int receive_frame(struct mp_filter *da, struct mp_frame *out)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
@@ -198,7 +194,7 @@ static bool receive_frame(struct mp_filter *da, struct mp_frame *out)
// over in case we get new packets at some point in the future.
// (Dont' reset the filter itself, we want to keep other state.)
avcodec_flush_buffers(priv->avctx);
return false;
return ret;
} else if (ret < 0 && ret != AVERROR(EAGAIN)) {
MP_ERR(da, "Error decoding audio.\n");
}
@@ -209,14 +205,14 @@ static bool receive_frame(struct mp_filter *da, struct mp_frame *out)
#endif
if (!priv->avframe->buf[0])
return true;
return ret;
double out_pts = mp_pts_from_av(priv->avframe->pts, &priv->codec_timebase);
struct mp_aframe *mpframe = mp_aframe_from_avframe(priv->avframe);
if (!mpframe) {
MP_ERR(da, "Converting libavcodec frame to mpv frame failed.\n");
return true;
return ret;
}
if (priv->force_channel_map.num)
@@ -264,14 +260,14 @@ static bool receive_frame(struct mp_filter *da, struct mp_frame *out)
av_frame_unref(priv->avframe);
return true;
return ret;
}
static void process(struct mp_filter *ad)
{
struct priv *priv = ad->priv;
lavc_process(ad, &priv->eof_returned, send_packet, receive_frame);
lavc_process(ad, &priv->state, send_packet, receive_frame);
}
static const struct mp_filter_info ad_lavc_filter = {
+7 -3
View File
@@ -36,6 +36,7 @@
#include "common/global.h"
extern const struct ao_driver audio_out_oss;
extern const struct ao_driver audio_out_audiotrack;
extern const struct ao_driver audio_out_audiounit;
extern const struct ao_driver audio_out_coreaudio;
extern const struct ao_driver audio_out_coreaudio_exclusive;
@@ -54,6 +55,9 @@ extern const struct ao_driver audio_out_sdl;
static const struct ao_driver * const audio_out_drivers[] = {
// native:
#if HAVE_ANDROID
&audio_out_audiotrack,
#endif
#if HAVE_AUDIOUNIT
&audio_out_audiounit,
#endif
@@ -132,11 +136,11 @@ static const struct m_obj_list ao_obj_list = {
#define OPT_BASE_STRUCT struct ao_opts
const struct m_sub_options ao_conf = {
.opts = (const struct m_option[]) {
OPT_SETTINGSLIST("ao", audio_driver_list, 0, &ao_obj_list, ),
OPT_SETTINGSLIST("ao", audio_driver_list, UPDATE_AUDIO, &ao_obj_list, ),
OPT_STRING("audio-device", audio_device, UPDATE_AUDIO),
OPT_STRING("audio-client-name", audio_client_name, UPDATE_AUDIO),
OPT_DOUBLE("audio-buffer", audio_buffer, M_OPT_MIN | M_OPT_MAX,
.min = 0, .max = 10),
OPT_DOUBLE("audio-buffer", audio_buffer,
UPDATE_AUDIO | M_OPT_MIN | M_OPT_MAX, .min = 0, .max = 10),
{0}
},
.size = sizeof(OPT_BASE_STRUCT),
+717
View File
@@ -0,0 +1,717 @@
/*
* Android AudioTrack audio output driver.
* Copyright (C) 2018 Aman Gupta <aman@tmm1.net>
* Copyright (C) 2012-2015 VLC authors and VideoLAN, VideoLabs
* Authors: Thomas Guillem <thomas@gllm.fr>
* Ming Hu <tewilove@gmail.com>
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ao.h"
#include "internal.h"
#include "common/msg.h"
#include "audio/format.h"
#include "options/m_option.h"
#include "osdep/threads.h"
#include "osdep/timer.h"
#include "misc/jni.h"
struct priv {
jobject audiotrack;
jint samplerate;
jint channel_config;
jint format;
jint size;
jobject timestamp;
int64_t timestamp_fetched;
bool timestamp_set;
int timestamp_stable;
uint32_t written_frames; /* requires uint32_t rollover semantics */
uint32_t playhead_pos;
uint32_t playhead_offset;
bool reset_pending;
void *chunk;
int chunksize;
jbyteArray bytearray;
jshortArray shortarray;
jfloatArray floatarray;
jobject bbuf;
int cfg_pcm_float;
int cfg_session_id;
bool needs_timestamp_offset;
int64_t timestamp_offset;
bool thread_terminate;
bool thread_created;
pthread_t thread;
pthread_mutex_t lock;
pthread_cond_t wakeup;
};
struct JNIByteBuffer {
jclass clazz;
jmethodID clear;
struct MPJniField mapping[];
} ByteBuffer = {.mapping = {
#define OFFSET(member) offsetof(struct JNIByteBuffer, member)
{"java/nio/ByteBuffer", NULL, NULL, MP_JNI_CLASS, OFFSET(clazz), 1},
{"java/nio/ByteBuffer", "clear", "()Ljava/nio/Buffer;", MP_JNI_METHOD, OFFSET(clear), 1},
{0},
#undef OFFSET
}};
struct JNIAudioTrack {
jclass clazz;
jmethodID ctor;
jmethodID release;
jmethodID getState;
jmethodID getPlayState;
jmethodID play;
jmethodID stop;
jmethodID flush;
jmethodID pause;
jmethodID write;
jmethodID writeFloat;
jmethodID writeV23;
jmethodID writeShortV23;
jmethodID writeBufferV21;
jmethodID getPlaybackHeadPosition;
jmethodID getTimestamp;
jmethodID getLatency;
jmethodID getMinBufferSize;
jmethodID getNativeOutputSampleRate;
jint STATE_INITIALIZED;
jint PLAYSTATE_STOPPED;
jint PLAYSTATE_PAUSED;
jint PLAYSTATE_PLAYING;
jint MODE_STREAM;
jint ERROR;
jint ERROR_BAD_VALUE;
jint ERROR_INVALID_OPERATION;
jint WRITE_BLOCKING;
jint WRITE_NON_BLOCKING;
struct MPJniField mapping[];
} AudioTrack = {.mapping = {
#define OFFSET(member) offsetof(struct JNIAudioTrack, member)
{"android/media/AudioTrack", NULL, NULL, MP_JNI_CLASS, OFFSET(clazz), 1},
{"android/media/AudioTrack", "<init>", "(IIIIIII)V", MP_JNI_METHOD, OFFSET(ctor), 1},
{"android/media/AudioTrack", "release", "()V", MP_JNI_METHOD, OFFSET(release), 1},
{"android/media/AudioTrack", "getState", "()I", MP_JNI_METHOD, OFFSET(getState), 1},
{"android/media/AudioTrack", "getPlayState", "()I", MP_JNI_METHOD, OFFSET(getPlayState), 1},
{"android/media/AudioTrack", "play", "()V", MP_JNI_METHOD, OFFSET(play), 1},
{"android/media/AudioTrack", "stop", "()V", MP_JNI_METHOD, OFFSET(stop), 1},
{"android/media/AudioTrack", "flush", "()V", MP_JNI_METHOD, OFFSET(flush), 1},
{"android/media/AudioTrack", "pause", "()V", MP_JNI_METHOD, OFFSET(pause), 1},
{"android/media/AudioTrack", "write", "([BII)I", MP_JNI_METHOD, OFFSET(write), 1},
{"android/media/AudioTrack", "write", "([FIII)I", MP_JNI_METHOD, OFFSET(writeFloat), 1},
{"android/media/AudioTrack", "write", "([BIII)I", MP_JNI_METHOD, OFFSET(writeV23), 0},
{"android/media/AudioTrack", "write", "([SIII)I", MP_JNI_METHOD, OFFSET(writeShortV23), 0},
{"android/media/AudioTrack", "write", "(Ljava/nio/ByteBuffer;II)I", MP_JNI_METHOD, OFFSET(writeBufferV21), 1},
{"android/media/AudioTrack", "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", MP_JNI_METHOD, OFFSET(getTimestamp), 1},
{"android/media/AudioTrack", "getPlaybackHeadPosition", "()I", MP_JNI_METHOD, OFFSET(getPlaybackHeadPosition), 1},
{"android/media/AudioTrack", "getLatency", "()I", MP_JNI_METHOD, OFFSET(getLatency), 1},
{"android/media/AudioTrack", "getMinBufferSize", "(III)I", MP_JNI_STATIC_METHOD, OFFSET(getMinBufferSize), 1},
{"android/media/AudioTrack", "getNativeOutputSampleRate", "(I)I", MP_JNI_STATIC_METHOD, OFFSET(getNativeOutputSampleRate), 1},
{"android/media/AudioTrack", "WRITE_BLOCKING", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(WRITE_BLOCKING), 0},
{"android/media/AudioTrack", "WRITE_NON_BLOCKING", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(WRITE_NON_BLOCKING), 0},
{"android/media/AudioTrack", "STATE_INITIALIZED", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(STATE_INITIALIZED), 1},
{"android/media/AudioTrack", "PLAYSTATE_STOPPED", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(PLAYSTATE_STOPPED), 1},
{"android/media/AudioTrack", "PLAYSTATE_PAUSED", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(PLAYSTATE_PAUSED), 1},
{"android/media/AudioTrack", "PLAYSTATE_PLAYING", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(PLAYSTATE_PLAYING), 1},
{"android/media/AudioTrack", "MODE_STREAM", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(MODE_STREAM), 1},
{"android/media/AudioTrack", "ERROR", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ERROR), 1},
{"android/media/AudioTrack", "ERROR_BAD_VALUE", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ERROR_BAD_VALUE), 1},
{"android/media/AudioTrack", "ERROR_INVALID_OPERATION", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ERROR_INVALID_OPERATION), 1},
{0}
#undef OFFSET
}};
struct JNIAudioFormat {
jclass clazz;
jint ENCODING_PCM_8BIT;
jint ENCODING_PCM_16BIT;
jint ENCODING_PCM_FLOAT;
jint ENCODING_IEC61937;
jint ENCODING_AC3;
jint CHANNEL_OUT_MONO;
jint CHANNEL_OUT_STEREO;
jint CHANNEL_OUT_FRONT_LEFT;
jint CHANNEL_OUT_FRONT_RIGHT;
jint CHANNEL_OUT_BACK_LEFT;
jint CHANNEL_OUT_BACK_RIGHT;
jint CHANNEL_OUT_FRONT_CENTER;
jint CHANNEL_OUT_LOW_FREQUENCY;
jint CHANNEL_OUT_BACK_CENTER;
jint CHANNEL_OUT_5POINT1;
jint CHANNEL_OUT_SIDE_LEFT;
jint CHANNEL_OUT_SIDE_RIGHT;
struct MPJniField mapping[];
} AudioFormat = {.mapping = {
#define OFFSET(member) offsetof(struct JNIAudioFormat, member)
{"android/media/AudioFormat", NULL, NULL, MP_JNI_CLASS, OFFSET(clazz), 1},
{"android/media/AudioFormat", "ENCODING_PCM_8BIT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ENCODING_PCM_8BIT), 1},
{"android/media/AudioFormat", "ENCODING_PCM_16BIT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ENCODING_PCM_16BIT), 1},
{"android/media/AudioFormat", "ENCODING_PCM_FLOAT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ENCODING_PCM_FLOAT), 1},
{"android/media/AudioFormat", "ENCODING_AC3", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ENCODING_AC3), 0},
{"android/media/AudioFormat", "ENCODING_IEC61937", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ENCODING_IEC61937), 0},
{"android/media/AudioFormat", "CHANNEL_OUT_MONO", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_MONO), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_STEREO", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_STEREO), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_5POINT1", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_5POINT1), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_FRONT_LEFT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_FRONT_LEFT), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_FRONT_RIGHT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_FRONT_RIGHT), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_FRONT_CENTER", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_FRONT_CENTER), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_LOW_FREQUENCY", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_LOW_FREQUENCY), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_BACK_LEFT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_BACK_LEFT), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_BACK_RIGHT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_BACK_RIGHT), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_BACK_CENTER", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_BACK_CENTER), 1},
{"android/media/AudioFormat", "CHANNEL_OUT_SIDE_LEFT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_SIDE_LEFT), 0},
{"android/media/AudioFormat", "CHANNEL_OUT_SIDE_RIGHT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(CHANNEL_OUT_SIDE_RIGHT), 0},
{0}
#undef OFFSET
}};
struct JNIAudioManager {
jclass clazz;
jint ERROR_DEAD_OBJECT;
jint STREAM_MUSIC;
struct MPJniField mapping[];
} AudioManager = {.mapping = {
#define OFFSET(member) offsetof(struct JNIAudioManager, member)
{"android/media/AudioManager", NULL, NULL, MP_JNI_CLASS, OFFSET(clazz), 1},
{"android/media/AudioManager", "STREAM_MUSIC", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(STREAM_MUSIC), 1},
{"android/media/AudioManager", "ERROR_DEAD_OBJECT", "I", MP_JNI_STATIC_FIELD_AS_INT, OFFSET(ERROR_DEAD_OBJECT), 0},
{0}
#undef OFFSET
}};
struct JNIAudioTimestamp {
jclass clazz;
jmethodID ctor;
jfieldID framePosition;
jfieldID nanoTime;
struct MPJniField mapping[];
} AudioTimestamp = {.mapping = {
#define OFFSET(member) offsetof(struct JNIAudioTimestamp, member)
{"android/media/AudioTimestamp", NULL, NULL, MP_JNI_CLASS, OFFSET(clazz), 1},
{"android/media/AudioTimestamp", "<init>", "()V", MP_JNI_METHOD, OFFSET(ctor), 1},
{"android/media/AudioTimestamp", "framePosition", "J", MP_JNI_FIELD, OFFSET(framePosition), 1},
{"android/media/AudioTimestamp", "nanoTime", "J", MP_JNI_FIELD, OFFSET(nanoTime), 1},
{0}
#undef OFFSET
}};
static int AudioTrack_New(struct ao *ao)
{
struct priv *p = ao->priv;
JNIEnv *env = MP_JNI_GET_ENV(ao);
jobject audiotrack = MP_JNI_NEW(
AudioTrack.clazz,
AudioTrack.ctor,
AudioManager.STREAM_MUSIC,
p->samplerate,
p->channel_config,
p->format,
p->size,
AudioTrack.MODE_STREAM,
p->cfg_session_id
);
if (!audiotrack || MP_JNI_EXCEPTION_LOG(ao) < 0) {
MP_FATAL(ao, "AudioTrack Init failed\n");
return -1;
}
if (MP_JNI_CALL_INT(audiotrack, AudioTrack.getState) != AudioTrack.STATE_INITIALIZED) {
MP_JNI_CALL_VOID(audiotrack, AudioTrack.release);
MP_JNI_EXCEPTION_LOG(ao);
(*env)->DeleteLocalRef(env, audiotrack);
MP_ERR(ao, "AudioTrack.getState failed\n");
return -1;
}
p->audiotrack = (*env)->NewGlobalRef(env, audiotrack);
(*env)->DeleteLocalRef(env, audiotrack);
if (!p->audiotrack)
return -1;
return 0;
}
static int AudioTrack_Recreate(struct ao *ao)
{
struct priv *p = ao->priv;
JNIEnv *env = MP_JNI_GET_ENV(ao);
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.release);
MP_JNI_EXCEPTION_LOG(ao);
(*env)->DeleteGlobalRef(env, p->audiotrack);
p->audiotrack = NULL;
return AudioTrack_New(ao);
}
static uint32_t AudioTrack_getPlaybackHeadPosition(struct ao *ao)
{
struct priv *p = ao->priv;
if (!p->audiotrack)
return 0;
JNIEnv *env = MP_JNI_GET_ENV(ao);
uint32_t pos = 0;
int64_t now = mp_raw_time_us();
int state = MP_JNI_CALL_INT(p->audiotrack, AudioTrack.getPlayState);
int stable_count = 20;
int64_t wait = p->timestamp_stable < stable_count ? 50000 : 3000000;
if (state == AudioTrack.PLAYSTATE_PLAYING && p->format != AudioFormat.ENCODING_IEC61937 &&
(p->timestamp_fetched == 0 || now - p->timestamp_fetched >= wait)) {
if (!p->timestamp_fetched)
p->timestamp_stable = 0;
int64_t utime1 = MP_JNI_GET_LONG(p->timestamp, AudioTimestamp.nanoTime) / 1000;
if (MP_JNI_CALL_BOOL(p->audiotrack, AudioTrack.getTimestamp, p->timestamp)) {
p->timestamp_set = true;
p->timestamp_fetched = now;
if (p->timestamp_stable < stable_count) {
uint32_t fpos = 0xFFFFFFFFL & MP_JNI_GET_LONG(p->timestamp, AudioTimestamp.framePosition);
int64_t utime2 = MP_JNI_GET_LONG(p->timestamp, AudioTimestamp.nanoTime) / 1000;
//MP_VERBOSE(ao, "getTimestamp: fpos= %u / time= %"PRId64" / now= %"PRId64" / stable= %d\n", fpos, utime2, now, p->timestamp_stable);
if (utime1 != utime2 && utime2 != 0 && fpos != 0) {
p->timestamp_stable++;
}
}
}
}
/* AudioTrack's framePosition and playbackHeadPosition return a signed integer,
* but documentation states it should be interpreted as a 32-bit unsigned integer.
*/
if (p->timestamp_set) {
pos = 0xFFFFFFFFL & MP_JNI_GET_LONG(p->timestamp, AudioTimestamp.framePosition);
uint32_t fpos = pos;
int64_t utime = MP_JNI_GET_LONG(p->timestamp, AudioTimestamp.nanoTime) / 1000;
if (utime == 0)
fpos = pos = 0;
if (p->needs_timestamp_offset) {
if (utime != 0 && !p->timestamp_offset)
p->timestamp_offset = now - utime;
utime += p->timestamp_offset;
}
if (fpos != 0 && utime != 0 && state == AudioTrack.PLAYSTATE_PLAYING) {
double diff = (double)(now - utime) / 1e6;
pos += diff * ao->samplerate;
}
//MP_VERBOSE(ao, "position = %u via getTimestamp (state = %d / fpos= %u / time= %"PRId64")\n", pos, state, fpos, utime);
} else {
pos = 0xFFFFFFFFL & MP_JNI_CALL_INT(p->audiotrack, AudioTrack.getPlaybackHeadPosition);
//MP_VERBOSE(ao, "playbackHeadPosition = %u (reset_pending=%d)\n", pos, p->reset_pending);
}
if (p->format == AudioFormat.ENCODING_IEC61937) {
if (p->reset_pending) {
// after a flush(), playbackHeadPosition will not reset to 0 right away.
// sometimes, it will never reset at all.
// save the initial offset after the reset, to subtract it going forward.
if (p->playhead_offset == 0)
p->playhead_offset = pos;
p->reset_pending = false;
MP_VERBOSE(ao, "IEC/playbackHead offset = %d\n", pos);
}
// usually shortly after a flush(), playbackHeadPosition will reset to 0.
// clear out the position and offset to avoid regular "rollover" below
if (pos == 0 && p->playhead_offset != 0) {
MP_VERBOSE(ao, "IEC/playbackHeadPosition %d -> %d (flush)\n", p->playhead_pos, pos);
p->playhead_offset = 0;
p->playhead_pos = 0;
}
// sometimes on a new AudioTrack instance, playbackHeadPosition will reset
// to 0 shortly after playback starts for no reason.
if (pos == 0 && p->playhead_pos != 0) {
MP_VERBOSE(ao, "IEC/playbackHeadPosition %d -> %d (reset)\n", p->playhead_pos, pos);
p->playhead_offset = 0;
p->playhead_pos = 0;
p->written_frames = 0;
}
}
p->playhead_pos = pos;
return p->playhead_pos - p->playhead_offset;
}
static double AudioTrack_getLatency(struct ao *ao)
{
JNIEnv *env = MP_JNI_GET_ENV(ao);
struct priv *p = ao->priv;
if (!p->audiotrack)
return 0;
uint32_t playhead = AudioTrack_getPlaybackHeadPosition(ao);
uint32_t diff = p->written_frames - playhead;
double delay = diff / (double)(ao->samplerate);
if (!p->timestamp_set &&
p->format != AudioFormat.ENCODING_IEC61937)
delay += (double)MP_JNI_CALL_INT(p->audiotrack, AudioTrack.getLatency)/1000.0;
if (delay > 1.0) {
//MP_WARN(ao, "getLatency: written=%u playhead=%u diff=%u delay=%f\n", p->written_frames, playhead, diff, delay);
p->timestamp_fetched = 0;
return 0;
}
return MPCLAMP(delay, 0.0, 1.0);
}
static int AudioTrack_write(struct ao *ao, int len)
{
struct priv *p = ao->priv;
if (!p->audiotrack)
return -1;
JNIEnv *env = MP_JNI_GET_ENV(ao);
void *buf = p->chunk;
jint ret;
if (p->format == AudioFormat.ENCODING_IEC61937) {
(*env)->SetShortArrayRegion(env, p->shortarray, 0, len / 2, buf);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
ret = MP_JNI_CALL_INT(p->audiotrack, AudioTrack.writeShortV23, p->shortarray, 0, len / 2, AudioTrack.WRITE_BLOCKING);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
if (ret > 0) ret *= 2;
} else if (p->format == AudioFormat.ENCODING_PCM_FLOAT) {
(*env)->SetFloatArrayRegion(env, p->floatarray, 0, len / sizeof(float), buf);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
ret = MP_JNI_CALL_INT(p->audiotrack, AudioTrack.writeFloat, p->floatarray, 0, len / sizeof(float), AudioTrack.WRITE_BLOCKING);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
if (ret > 0) ret *= sizeof(float);
} else if (AudioTrack.writeBufferV21) {
jobject bbuf = MP_JNI_CALL_OBJECT(p->bbuf, ByteBuffer.clear);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
(*env)->DeleteLocalRef(env, bbuf);
ret = MP_JNI_CALL_INT(p->audiotrack, AudioTrack.writeBufferV21, p->bbuf, len, AudioTrack.WRITE_BLOCKING);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
} else {
(*env)->SetByteArrayRegion(env, p->bytearray, 0, len, buf);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
ret = MP_JNI_CALL_INT(p->audiotrack, AudioTrack.write, p->bytearray, 0, len);
if (MP_JNI_EXCEPTION_LOG(ao) < 0) return -1;
}
return ret;
}
static void uninit_jni(struct ao *ao)
{
JNIEnv *env = MP_JNI_GET_ENV(ao);
mp_jni_reset_jfields(env, &AudioTrack, AudioTrack.mapping, 1, ao->log);
mp_jni_reset_jfields(env, &AudioTimestamp, AudioTimestamp.mapping, 1, ao->log);
mp_jni_reset_jfields(env, &AudioManager, AudioManager.mapping, 1, ao->log);
mp_jni_reset_jfields(env, &AudioFormat, AudioFormat.mapping, 1, ao->log);
mp_jni_reset_jfields(env, &ByteBuffer, ByteBuffer.mapping, 1, ao->log);
}
static int init_jni(struct ao *ao)
{
JNIEnv *env = MP_JNI_GET_ENV(ao);
if (mp_jni_init_jfields(env, &AudioTrack, AudioTrack.mapping, 1, ao->log) < 0 ||
mp_jni_init_jfields(env, &ByteBuffer, ByteBuffer.mapping, 1, ao->log) < 0 ||
mp_jni_init_jfields(env, &AudioTimestamp, AudioTimestamp.mapping, 1, ao->log) < 0 ||
mp_jni_init_jfields(env, &AudioManager, AudioManager.mapping, 1, ao->log) < 0 ||
mp_jni_init_jfields(env, &AudioFormat, AudioFormat.mapping, 1, ao->log) < 0) {
uninit_jni(ao);
return -1;
}
return 0;
}
static void *playthread(void *arg)
{
struct ao *ao = arg;
struct priv *p = ao->priv;
JNIEnv *env = MP_JNI_GET_ENV(ao);
mpthread_set_name("audiotrack");
pthread_mutex_lock(&p->lock);
while (!p->thread_terminate) {
int state = AudioTrack.PLAYSTATE_PAUSED;
if (p->audiotrack) {
state = MP_JNI_CALL_INT(p->audiotrack, AudioTrack.getPlayState);
}
if (state == AudioTrack.PLAYSTATE_PLAYING) {
int read_samples = p->chunksize / ao->sstride;
int64_t ts = mp_time_us();
ts += (read_samples / (double)(ao->samplerate)) * 1e6;
ts += AudioTrack_getLatency(ao) * 1e6;
int samples = ao_read_data(ao, &p->chunk, read_samples, ts);
int write_samples = read_samples;
int ret = AudioTrack_write(ao, write_samples * ao->sstride);
if (ret >= 0) {
p->written_frames += ret / ao->sstride;
} else if (ret == AudioManager.ERROR_DEAD_OBJECT) {
MP_WARN(ao, "AudioTrack.write failed with ERROR_DEAD_OBJECT. Recreating AudioTrack...\n");
if (AudioTrack_Recreate(ao) < 0) {
MP_ERR(ao, "AudioTrack_Recreate failed\n");
}
} else {
MP_ERR(ao, "AudioTrack.write failed with %d\n", ret);
}
} else {
struct timespec wait = mp_rel_time_to_timespec(0.300);
pthread_cond_timedwait(&p->wakeup, &p->lock, &wait);
}
}
pthread_mutex_unlock(&p->lock);
return NULL;
}
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
JNIEnv *env = MP_JNI_GET_ENV(ao);
if (p->audiotrack) {
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.stop);
MP_JNI_EXCEPTION_LOG(ao);
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.flush);
MP_JNI_EXCEPTION_LOG(ao);
}
pthread_mutex_lock(&p->lock);
p->thread_terminate = true;
pthread_cond_signal(&p->wakeup);
pthread_mutex_unlock(&p->lock);
if (p->thread_created)
pthread_join(p->thread, NULL);
if (p->audiotrack) {
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.release);
MP_JNI_EXCEPTION_LOG(ao);
(*env)->DeleteGlobalRef(env, p->audiotrack);
p->audiotrack = NULL;
}
if (p->bytearray) {
(*env)->DeleteGlobalRef(env, p->bytearray);
p->bytearray = NULL;
}
if (p->shortarray) {
(*env)->DeleteGlobalRef(env, p->shortarray);
p->shortarray = NULL;
}
if (p->floatarray) {
(*env)->DeleteGlobalRef(env, p->floatarray);
p->floatarray = NULL;
}
if (p->bbuf) {
(*env)->DeleteGlobalRef(env, p->bbuf);
p->bbuf = NULL;
}
if (p->timestamp) {
(*env)->DeleteGlobalRef(env, p->timestamp);
p->timestamp = NULL;
}
if (p->chunk) {
free(p->chunk);
p->chunk = NULL;
}
pthread_cond_destroy(&p->wakeup);
pthread_mutex_destroy(&p->lock);
uninit_jni(ao);
}
static int init(struct ao *ao)
{
struct priv *p = ao->priv;
JNIEnv *env = MP_JNI_GET_ENV(ao);
if (!env)
return -1;
pthread_mutex_init(&p->lock, NULL);
pthread_cond_init(&p->wakeup, NULL);
if (init_jni(ao) < 0)
return -1;
if (af_fmt_is_spdif(ao->format)) {
p->format = AudioFormat.ENCODING_IEC61937;
} else if (ao->format == AF_FORMAT_U8) {
p->format = AudioFormat.ENCODING_PCM_8BIT;
} else if (p->cfg_pcm_float && (ao->format == AF_FORMAT_FLOAT || ao->format == AF_FORMAT_FLOATP)) {
ao->format = AF_FORMAT_FLOAT;
p->format = AudioFormat.ENCODING_PCM_FLOAT;
} else {
ao->format = AF_FORMAT_S16;
p->format = AudioFormat.ENCODING_PCM_16BIT;
}
if (AudioTrack.getNativeOutputSampleRate) {
jint samplerate = MP_JNI_CALL_STATIC_INT(
AudioTrack.clazz,
AudioTrack.getNativeOutputSampleRate,
AudioManager.STREAM_MUSIC
);
if (MP_JNI_EXCEPTION_LOG(ao) == 0) {
ao->samplerate = samplerate;
MP_VERBOSE(ao, "AudioTrack.nativeOutputSampleRate = %d\n", samplerate);
}
}
p->samplerate = ao->samplerate;
if (p->format == AudioFormat.ENCODING_IEC61937) {
p->channel_config = AudioFormat.CHANNEL_OUT_STEREO;
} else if (ao->channels.num == 1) {
p->channel_config = AudioFormat.CHANNEL_OUT_MONO;
} else if (ao->channels.num == 6) {
p->channel_config = AudioFormat.CHANNEL_OUT_5POINT1;
ao->channels = (struct mp_chmap)MP_CHMAP6(FL, FR, FC, LFE, BL, BR);
} else {
p->channel_config = AudioFormat.CHANNEL_OUT_STEREO;
ao->channels = (struct mp_chmap)MP_CHMAP_INIT_STEREO;
}
jint buffer_size = MP_JNI_CALL_STATIC_INT(
AudioTrack.clazz,
AudioTrack.getMinBufferSize,
p->samplerate,
p->channel_config,
p->format
);
if (buffer_size <= 0 || MP_JNI_EXCEPTION_LOG(ao) < 0) {
MP_FATAL(ao, "AudioTrack.getMinBufferSize returned an invalid size: %d", buffer_size);
return -1;
}
p->chunksize = buffer_size;
p->chunk = malloc(buffer_size);
int min = 0.200 * p->samplerate * af_fmt_to_bytes(ao->format);
int max = min * 3 / 2;
p->size = MPCLAMP(buffer_size * 2, min, max);
MP_VERBOSE(ao, "Setting bufferSize = %d (driver=%d, min=%d, max=%d)\n", p->size, buffer_size, min, max);
ao->device_buffer = p->size / af_fmt_to_bytes(ao->format);
jobject timestamp = MP_JNI_NEW(AudioTimestamp.clazz, AudioTimestamp.ctor);
if (!timestamp || MP_JNI_EXCEPTION_LOG(ao) < 0) {
MP_FATAL(ao, "AudioTimestamp could not be created\n");
return -1;
}
p->timestamp = (*env)->NewGlobalRef(env, timestamp);
(*env)->DeleteLocalRef(env, timestamp);
if (p->format == AudioFormat.ENCODING_IEC61937) {
jshortArray shortarray = (*env)->NewShortArray(env, p->chunksize / 2);
p->shortarray = (*env)->NewGlobalRef(env, shortarray);
(*env)->DeleteLocalRef(env, shortarray);
} else if (p->format == AudioFormat.ENCODING_PCM_FLOAT) {
jfloatArray floatarray = (*env)->NewFloatArray(env, p->chunksize / sizeof(float));
p->floatarray = (*env)->NewGlobalRef(env, floatarray);
(*env)->DeleteLocalRef(env, floatarray);
} else if (AudioTrack.writeBufferV21) {
jobject bbuf = (*env)->NewDirectByteBuffer(env, p->chunk, p->chunksize);
p->bbuf = (*env)->NewGlobalRef(env, bbuf);
(*env)->DeleteLocalRef(env, bbuf);
} else {
jbyteArray bytearray = (*env)->NewByteArray(env, p->chunksize);
p->bytearray = (*env)->NewGlobalRef(env, bytearray);
(*env)->DeleteLocalRef(env, bytearray);
}
/* create AudioTrack object */
if (AudioTrack_New(ao) != 0) {
MP_FATAL(ao, "Failed to create AudioTrack\n");
goto error;
}
if (pthread_create(&p->thread, NULL, playthread, ao)) {
MP_ERR(ao, "pthread creation failed\n");
goto error;
}
p->thread_created = true;
return 1;
error:
uninit(ao);
return -1;
}
static void stop(struct ao *ao)
{
struct priv *p = ao->priv;
if (!p->audiotrack) {
MP_ERR(ao, "AudioTrack does not exist to stop!\n");
return;
}
JNIEnv *env = MP_JNI_GET_ENV(ao);
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.pause);
MP_JNI_EXCEPTION_LOG(ao);
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.flush);
MP_JNI_EXCEPTION_LOG(ao);
p->playhead_offset = 0;
p->reset_pending = true;
p->written_frames = 0;
p->timestamp_fetched = 0;
p->timestamp_set = false;
p->timestamp_offset = 0;
}
static void start(struct ao *ao)
{
struct priv *p = ao->priv;
if (!p->audiotrack) {
MP_ERR(ao, "AudioTrack does not exist to start!\n");
return;
}
JNIEnv *env = MP_JNI_GET_ENV(ao);
MP_JNI_CALL_VOID(p->audiotrack, AudioTrack.play);
MP_JNI_EXCEPTION_LOG(ao);
pthread_cond_signal(&p->wakeup);
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_audiotrack = {
.description = "Android AudioTrack audio output",
.name = "audiotrack",
.init = init,
.uninit = uninit,
.reset = stop,
.resume = start,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_FLAG("pcm-float", cfg_pcm_float, 0),
OPT_INT("session-id", cfg_session_id, 0),
{0}
},
.options_prefix = "audiotrack",
};
+2 -2
View File
@@ -146,7 +146,7 @@ static int init(struct ao *ao)
// enough frames for at least 0.25 seconds
ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize);
// but at least one!
ac->framecount = FFMAX(ac->framecount, 1);
ac->framecount = MPMAX(ac->framecount, 1);
ac->savepts = AV_NOPTS_VALUE;
ac->lastpts = AV_NOPTS_VALUE;
@@ -324,7 +324,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
talloc_free(tempdata);
int taken = FFMIN(bufpos, orig_samples);
int taken = MPMIN(bufpos, orig_samples);
ectx->samples_since_last_pts += taken;
pthread_mutex_unlock(&ectx->lock);
+1 -1
View File
@@ -148,7 +148,7 @@ struct ao_driver {
void (*uninit)(struct ao *ao);
// push based: see ao_reset()
// pull based: stop the audio callback
void (*reset)(struct ao*ao);
void (*reset)(struct ao *ao);
// push based: see ao_pause()
void (*pause)(struct ao *ao);
// push based: see ao_resume()
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This script simply downloads waf to the current directory
+1 -1
View File
@@ -19,7 +19,7 @@ PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" pytho
--variant="${MPV_VARIANT}" \
--prefix="${MPV_INSTALL_PREFIX}" \
--enable-{gl,iconv,lcms2,libass,libass-osd,libmpv-shared,lua,jpeg,plain-gl,zlib} \
--enable-{apple-remote,cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl}
--enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl}
python3 ./waf build --variant="${MPV_VARIANT}" -j4
-38
View File
@@ -1,38 +0,0 @@
#!/usr/bin/env bash
set -e
FFMPEG_SRC_DIR="${HOME}/deps/src/ffmpeg"
FFMPEG_BUILD_DIR="${FFMPEG_SRC_DIR}/${TRAVIS_OS_NAME}"
FFMPEG_SYSROOT="${HOME}/deps/sysroot"
FFMPEG_HASH="18928e2bb4568cbe5e9061c3e6b63559392af3d2"
# Get the sauce if not around
if [[ ! -d "${FFMPEG_SRC_DIR}" ]] ; then
git clone "https://git.videolan.org/git/ffmpeg.git" "${FFMPEG_SRC_DIR}"
fi
# pop into FFmpeg's source dir and clean up & check out our wanted revision
pushd "${FFMPEG_SRC_DIR}"
git reset --hard HEAD && git clean -dfx
git checkout "${FFMPEG_HASH}"
popd
# If a build dir of the same type is around, clean it up
if [[ -d "${FFMPEG_BUILD_DIR}" ]] ; then
rm -rf "${FFMPEG_BUILD_DIR}"
fi
# Create and move into the build dir, configure and build!
mkdir -p "${FFMPEG_BUILD_DIR}" && pushd "${FFMPEG_BUILD_DIR}"
PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" ../configure \
--disable-{autodetect,stripping} \
--cc="${CC}" \
--cxx="${CXX}" \
--prefix="${FFMPEG_SYSROOT}" \
--enable-{zlib,securetransport,videotoolbox}
make -j4 && make install && popd
exit 0
+40 -8
View File
@@ -96,10 +96,10 @@ char *mp_format_time(double time, bool fractions)
// Set rc to the union of rc and rc2
void mp_rect_union(struct mp_rect *rc, const struct mp_rect *rc2)
{
rc->x0 = FFMIN(rc->x0, rc2->x0);
rc->y0 = FFMIN(rc->y0, rc2->y0);
rc->x1 = FFMAX(rc->x1, rc2->x1);
rc->y1 = FFMAX(rc->y1, rc2->y1);
rc->x0 = MPMIN(rc->x0, rc2->x0);
rc->y0 = MPMIN(rc->y0, rc2->y0);
rc->x1 = MPMAX(rc->x1, rc2->x1);
rc->y1 = MPMAX(rc->y1, rc2->y1);
}
// Returns whether or not a point is contained by rc
@@ -112,10 +112,10 @@ bool mp_rect_contains(struct mp_rect *rc, int x, int y)
// Return false if the result is empty.
bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2)
{
rc->x0 = FFMAX(rc->x0, rc2->x0);
rc->y0 = FFMAX(rc->y0, rc2->y0);
rc->x1 = FFMIN(rc->x1, rc2->x1);
rc->y1 = FFMIN(rc->y1, rc2->y1);
rc->x0 = MPMAX(rc->x0, rc2->x0);
rc->y0 = MPMAX(rc->y0, rc2->y0);
rc->x1 = MPMIN(rc->x1, rc2->x1);
rc->y1 = MPMIN(rc->y1, rc2->y1);
return rc->x1 > rc->x0 && rc->y1 > rc->y0;
}
@@ -318,3 +318,35 @@ char **mp_dup_str_array(void *tctx, char **s)
MP_TARRAY_APPEND(tctx, r, num_r, NULL);
return r;
}
// Return rounded down integer log 2 of v, i.e. position of highest set bit.
// mp_log2(0) == 0
// mp_log2(1) == 0
// mp_log2(31) == 4
// mp_log2(32) == 5
unsigned int mp_log2(uint32_t v)
{
#if defined(__GNUC__) && __GNUC__ >= 4
return v ? 31 - __builtin_clz(v) : 0;
#else
for (int x = 31; x >= 0; x--) {
if (v & (((uint32_t)1) << x))
return x;
}
return 0;
#endif
}
// If a power of 2, return it, otherwise return the next highest one, or 0.
// mp_round_next_power_of_2(65) == 128
// mp_round_next_power_of_2(64) == 64
// mp_round_next_power_of_2(0) == 1
// mp_round_next_power_of_2(UINT32_MAX) == 0
uint32_t mp_round_next_power_of_2(uint32_t v)
{
for (int n = 0; n < 30; n++) {
if ((1 << n) >= v)
return 1 << n;
}
return 0;
}
+3
View File
@@ -88,6 +88,9 @@ bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2);
bool mp_rect_contains(struct mp_rect *rc, int x, int y);
bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2);
unsigned int mp_log2(uint32_t v);
uint32_t mp_round_next_power_of_2(uint32_t v);
int mp_snprintf_cat(char *str, size_t size, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
+19 -17
View File
@@ -77,25 +77,25 @@ struct mux_stream {
#define OPT_BASE_STRUCT struct encode_opts
const struct m_sub_options encode_config = {
.opts = (const m_option_t[]) {
OPT_STRING("o", file, M_OPT_FIXED | CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE),
OPT_STRING("of", format, M_OPT_FIXED),
OPT_KEYVALUELIST("ofopts", fopts, M_OPT_FIXED | M_OPT_HAVE_HELP),
OPT_STRING("ovc", vcodec, M_OPT_FIXED),
OPT_KEYVALUELIST("ovcopts", vopts, M_OPT_FIXED | M_OPT_HAVE_HELP),
OPT_STRING("oac", acodec, M_OPT_FIXED),
OPT_KEYVALUELIST("oacopts", aopts, M_OPT_FIXED | M_OPT_HAVE_HELP),
OPT_FLOATRANGE("ovoffset", voffset, M_OPT_FIXED, -1000000.0, 1000000.0,
OPT_STRING("o", file, CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE),
OPT_STRING("of", format, 0),
OPT_KEYVALUELIST("ofopts", fopts, M_OPT_HAVE_HELP),
OPT_STRING("ovc", vcodec, 0),
OPT_KEYVALUELIST("ovcopts", vopts, M_OPT_HAVE_HELP),
OPT_STRING("oac", acodec, 0),
OPT_KEYVALUELIST("oacopts", aopts, M_OPT_HAVE_HELP),
OPT_FLOATRANGE("ovoffset", voffset, 0, -1000000.0, 1000000.0,
.deprecation_message = "--audio-delay (once unbroken)"),
OPT_FLOATRANGE("oaoffset", aoffset, M_OPT_FIXED, -1000000.0, 1000000.0,
OPT_FLOATRANGE("oaoffset", aoffset, 0, -1000000.0, 1000000.0,
.deprecation_message = "--audio-delay (once unbroken)"),
OPT_FLAG("orawts", rawts, M_OPT_FIXED),
OPT_FLAG("ovfirst", video_first, M_OPT_FIXED,
OPT_FLAG("orawts", rawts, 0),
OPT_FLAG("ovfirst", video_first, 0,
.deprecation_message = "no replacement"),
OPT_FLAG("oafirst", audio_first, M_OPT_FIXED,
OPT_FLAG("oafirst", audio_first, 0,
.deprecation_message = "no replacement"),
OPT_FLAG("ocopy-metadata", copy_metadata, M_OPT_FIXED),
OPT_KEYVALUELIST("oset-metadata", set_metadata, M_OPT_FIXED),
OPT_STRINGLIST("oremove-metadata", remove_metadata, M_OPT_FIXED),
OPT_FLAG("ocopy-metadata", copy_metadata, 0),
OPT_KEYVALUELIST("oset-metadata", set_metadata, 0),
OPT_STRINGLIST("oremove-metadata", remove_metadata, 0),
OPT_REMOVED("ocopyts", "ocopyts is now the default"),
OPT_REMOVED("oneverdrop", "no replacement"),
@@ -720,7 +720,7 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx,
double now = mp_time_sec();
float minutes, megabytes, fps, x;
float f = FFMAX(0.0001, relative_position);
float f = MPMAX(0.0001, relative_position);
pthread_mutex_lock(&ctx->lock);
@@ -830,7 +830,9 @@ static void encoder_2pass_prepare(struct encoder_context *p)
if (p->encoder->flags & AV_CODEC_FLAG_PASS2) {
MP_INFO(p, "Reading 2-pass log: %s\n", filename);
struct stream *s = stream_open(filename, p->global);
struct stream *s = stream_create(filename,
STREAM_ORIGIN_DIRECT | STREAM_READ,
NULL, p->global);
if (s) {
struct bstr content = stream_read_complete(s, p, 1000000000);
if (content.start) {
+119 -40
View File
@@ -30,7 +30,6 @@
#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"
@@ -43,6 +42,8 @@
#include "msg.h"
#include "msg_control.h"
#define TERM_BUF 100
struct mp_log_root {
struct mpv_global *global;
// --- protected by mp_msg_lock
@@ -58,6 +59,7 @@ struct mp_log_root {
bool force_stderr;
struct mp_log_buffer **buffers;
int num_buffers;
struct mp_log_buffer *early_buffer;
FILE *log_file;
FILE *stats_file;
char *log_path;
@@ -83,8 +85,13 @@ struct mp_log {
struct mp_log_buffer {
struct mp_log_root *root;
struct mp_ring *ring;
struct mp_log_buffer_entry **entries; // ringbuffer
int capacity; // total space in entries[]
int entry0; // first (oldest) entry index
int num_entries; // number of valid entries after entry0
uint64_t dropped; // number of skipped entries
int level;
bool silent;
void (*wakeup_cb)(void *ctx);
void *wakeup_cb_ctx;
};
@@ -116,8 +123,11 @@ static void update_loglevel(struct mp_log *log)
log->level = mp_msg_find_level(root->msg_levels[n * 2 + 1]);
}
log->terminal_level = log->level;
for (int n = 0; n < log->root->num_buffers; n++)
log->level = MPMAX(log->level, log->root->buffers[n]->level);
for (int n = 0; n < log->root->num_buffers; n++) {
int buffer_level = log->root->buffers[n]->level;
if (buffer_level != MP_LOG_BUFFER_MSGL_TERM)
log->level = MPMAX(log->level, buffer_level);
}
if (log->root->log_file)
log->level = MPMAX(log->level, MSGL_DEBUG);
if (log->root->stats_file)
@@ -294,6 +304,15 @@ static void write_log_file(struct mp_log *log, int lev, char *text)
fflush(root->log_file);
}
static struct mp_log_buffer_entry *log_buffer_read(struct mp_log_buffer *buffer)
{
assert(buffer->num_entries);
struct mp_log_buffer_entry *res = buffer->entries[buffer->entry0];
buffer->entry0 = (buffer->entry0 + 1) % buffer->capacity;
buffer->num_entries -= 1;
return res;
}
static void write_msg_to_buffers(struct mp_log *log, int lev, char *text)
{
struct mp_log_root *root = log->root;
@@ -303,27 +322,21 @@ static void write_msg_to_buffers(struct mp_log *log, int lev, char *text)
if (buffer_level == MP_LOG_BUFFER_MSGL_TERM)
buffer_level = log->terminal_level;
if (lev <= buffer_level && lev != MSGL_STATUS) {
// Assuming a single writer (serialized by msg lock)
int avail = mp_ring_available(buffer->ring) / sizeof(void *);
if (avail < 1)
continue;
struct mp_log_buffer_entry *entry = talloc_ptrtype(NULL, entry);
if (avail > 1) {
*entry = (struct mp_log_buffer_entry) {
.prefix = talloc_strdup(entry, log->verbose_prefix),
.level = lev,
.text = talloc_strdup(entry, text),
};
} else {
// write overflow message to signal that messages might be lost
*entry = (struct mp_log_buffer_entry) {
.prefix = "overflow",
.level = MSGL_FATAL,
.text = "log message buffer overflow\n",
};
if (buffer->num_entries == buffer->capacity) {
struct mp_log_buffer_entry *skip = log_buffer_read(buffer);
talloc_free(skip);
buffer->dropped += 1;
}
mp_ring_write(buffer->ring, (unsigned char *)&entry, sizeof(entry));
if (buffer->wakeup_cb)
struct mp_log_buffer_entry *entry = talloc_ptrtype(NULL, entry);
*entry = (struct mp_log_buffer_entry) {
.prefix = talloc_strdup(entry, log->verbose_prefix),
.level = lev,
.text = talloc_strdup(entry, text),
};
int pos = (buffer->entry0 + buffer->num_entries) % buffer->capacity;
buffer->entries[pos] = entry;
buffer->num_entries += 1;
if (buffer->wakeup_cb && !buffer->silent)
buffer->wakeup_cb(buffer->wakeup_cb_ctx);
}
}
@@ -548,6 +561,9 @@ bool mp_msg_has_log_file(struct mpv_global *global)
void mp_msg_uninit(struct mpv_global *global)
{
struct mp_log_root *root = global->log->root;
if (root->early_buffer)
mp_msg_log_buffer_destroy(root->early_buffer);
assert(root->num_buffers == 0);
if (root->stats_file)
fclose(root->stats_file);
talloc_free(root->stats_path);
@@ -559,6 +575,32 @@ void mp_msg_uninit(struct mpv_global *global)
global->log = NULL;
}
void mp_msg_set_early_logging(struct mpv_global *global, bool enable)
{
struct mp_log_root *root = global->log->root;
pthread_mutex_lock(&mp_msg_lock);
if (enable != !!root->early_buffer) {
if (enable) {
pthread_mutex_unlock(&mp_msg_lock);
struct mp_log_buffer *buf =
mp_msg_log_buffer_new(global, TERM_BUF, MP_LOG_BUFFER_MSGL_TERM,
NULL, NULL);
pthread_mutex_lock(&mp_msg_lock);
assert(!root->early_buffer); // no concurrent calls to this function
root->early_buffer = buf;
} else {
struct mp_log_buffer *buf = root->early_buffer;
root->early_buffer = NULL;
pthread_mutex_unlock(&mp_msg_lock);
mp_msg_log_buffer_destroy(buf);
return;
}
}
pthread_mutex_unlock(&mp_msg_lock);
}
struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
int size, int level,
void (*wakeup_cb)(void *ctx),
@@ -568,16 +610,34 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
pthread_mutex_lock(&mp_msg_lock);
if (level == MP_LOG_BUFFER_MSGL_TERM) {
size = TERM_BUF;
// The first thing which creates a terminal-level log buffer gets the
// early log buffer, if it exists. This is supposed to enable a script
// to grab log messages from before it was initialized. It's OK that
// this works only for 1 script and only once.
if (root->early_buffer) {
struct mp_log_buffer *buffer = root->early_buffer;
root->early_buffer = NULL;
buffer->wakeup_cb = wakeup_cb;
buffer->wakeup_cb_ctx = wakeup_cb_ctx;
pthread_mutex_unlock(&mp_msg_lock);
return buffer;
}
}
assert(size > 0);
struct mp_log_buffer *buffer = talloc_ptrtype(NULL, buffer);
*buffer = (struct mp_log_buffer) {
.root = root,
.level = level,
.ring = mp_ring_new(buffer, sizeof(void *) * size),
.entries = talloc_array(buffer, struct mp_log_buffer_entry *, size),
.capacity = size,
.wakeup_cb = wakeup_cb,
.wakeup_cb_ctx = wakeup_cb_ctx,
};
if (!buffer->ring)
abort();
MP_TARRAY_APPEND(root, root->buffers, root->num_buffers, buffer);
@@ -587,6 +647,13 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
return buffer;
}
void mp_msg_log_buffer_set_silent(struct mp_log_buffer *buffer, bool silent)
{
pthread_mutex_lock(&mp_msg_lock);
buffer->silent = silent;
pthread_mutex_unlock(&mp_msg_lock);
}
void mp_msg_log_buffer_destroy(struct mp_log_buffer *buffer)
{
if (!buffer)
@@ -606,12 +673,8 @@ void mp_msg_log_buffer_destroy(struct mp_log_buffer *buffer)
found:
while (1) {
struct mp_log_buffer_entry *e = mp_msg_log_buffer_read(buffer);
if (!e)
break;
talloc_free(e);
}
while (buffer->num_entries)
talloc_free(log_buffer_read(buffer));
talloc_free(buffer);
atomic_fetch_add(&root->reload_counter, 1);
@@ -622,13 +685,29 @@ found:
// Thread-safety: one buffer can be read by a single thread only.
struct mp_log_buffer_entry *mp_msg_log_buffer_read(struct mp_log_buffer *buffer)
{
void *ptr = NULL;
int read = mp_ring_read(buffer->ring, (unsigned char *)&ptr, sizeof(ptr));
if (read == 0)
return NULL;
if (read != sizeof(ptr))
abort();
return ptr;
struct mp_log_buffer_entry *res = NULL;
pthread_mutex_lock(&mp_msg_lock);
if (!buffer->silent && buffer->num_entries) {
if (buffer->dropped) {
res = talloc_ptrtype(NULL, res);
*res = (struct mp_log_buffer_entry) {
.prefix = "overflow",
.level = MSGL_FATAL,
.text = talloc_asprintf(res,
"log message buffer overflow: %"PRId64" messages skipped\n",
buffer->dropped),
};
buffer->dropped = 0;
} else {
res = log_buffer_read(buffer);
}
}
pthread_mutex_unlock(&mp_msg_lock);
return res;
}
// Thread-safety: fully thread-safe, but keep in mind that the lifetime of
+9 -8
View File
@@ -32,14 +32,15 @@ extern struct mp_log *const mp_null_log;
// Verbosity levels.
enum {
MSGL_FATAL, // will exit/abort (note: msg.c doesn't exit or abort)
MSGL_ERR, // continues
MSGL_WARN, // only warning
MSGL_INFO, // -quiet
MSGL_STATUS, // exclusively for the playback status line
MSGL_V, // -v
MSGL_DEBUG, // -v -v
MSGL_TRACE, // -v -v -v
MSGL_FATAL, // only errors (difference to MSGL_ERR isn't too clear)
MSGL_ERR, // only errors
MSGL_WARN, // only warnings
MSGL_INFO, // what you normally see on the terminal
MSGL_STATUS, // exclusively for the playback status line (-quiet disables)
MSGL_V, // -v | slightly more information than default
MSGL_DEBUG, // -v -v | full debug information; this and numerically below
// should not produce "per frame" output
MSGL_TRACE, // -v -v -v | anything that might flood the terminal
MSGL_STATS, // dumping fine grained stats (--dump-stats)
MSGL_MAX = MSGL_STATS,
+2
View File
@@ -11,6 +11,7 @@ void mp_msg_update_msglevels(struct mpv_global *global, struct MPOpts *opts);
void mp_msg_force_stderr(struct mpv_global *global, bool force_stderr);
bool mp_msg_has_status_line(struct mpv_global *global);
bool mp_msg_has_log_file(struct mpv_global *global);
void mp_msg_set_early_logging(struct mpv_global *global, bool enable);
void mp_msg_flush_status_line(struct mp_log *log);
@@ -30,6 +31,7 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
void *wakeup_cb_ctx);
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);
void mp_msg_log_buffer_set_silent(struct mp_log_buffer *buffer, bool silent);
int mp_msg_find_level(const char *s);
+150 -121
View File
@@ -32,6 +32,8 @@ struct playlist_entry *playlist_entry_new(const char *filename)
struct playlist_entry *e = talloc_zero(NULL, struct playlist_entry);
char *local_filename = mp_file_url_to_filename(e, bstr0(filename));
e->filename = local_filename ? local_filename : talloc_strdup(e, filename);
e->stream_flags = STREAM_ORIGIN_DIRECT;
e->original_index = -1;
return e;
}
@@ -49,85 +51,68 @@ void playlist_entry_add_params(struct playlist_entry *e,
playlist_entry_add_param(e, params[n].name, params[n].value);
}
// Add entry "add" after entry "after".
// If "after" is NULL, add as first entry.
// Post condition: add->prev == after
void playlist_insert(struct playlist *pl, struct playlist_entry *after,
struct playlist_entry *add)
static void playlist_update_indexes(struct playlist *pl, int start, int end)
{
assert(pl && add->pl == NULL && add->next == NULL && add->prev == NULL);
if (after) {
assert(after->pl == pl);
assert(pl->first && pl->last);
}
add->prev = after;
if (after) {
add->next = after->next;
after->next = add;
} else {
add->next = pl->first;
pl->first = add;
}
if (add->next) {
add->next->prev = add;
} else {
pl->last = add;
}
add->pl = pl;
talloc_steal(pl, add);
start = MPMAX(start, 0);
end = end < 0 ? pl->num_entries : MPMIN(end, pl->num_entries);
for (int n = start; n < end; n++)
pl->entries[n]->pl_index = n;
}
void playlist_add(struct playlist *pl, struct playlist_entry *add)
{
playlist_insert(pl, pl->last, add);
}
static void playlist_unlink(struct playlist *pl, struct playlist_entry *entry)
{
assert(pl && entry->pl == pl);
if (pl->current == entry) {
pl->current = entry->next;
pl->current_was_replaced = true;
}
if (entry->next) {
entry->next->prev = entry->prev;
} else {
pl->last = entry->prev;
}
if (entry->prev) {
entry->prev->next = entry->next;
} else {
pl->first = entry->next;
}
entry->next = entry->prev = NULL;
// xxx: we'd want to reset the talloc parent of entry
entry->pl = NULL;
MP_TARRAY_APPEND(pl, pl->entries, pl->num_entries, add);
add->pl = pl;
add->pl_index = pl->num_entries - 1;
talloc_steal(pl, add);
}
void playlist_entry_unref(struct playlist_entry *e)
{
e->reserved--;
if (e->reserved < 0)
if (e->reserved < 0) {
assert(!e->pl);
talloc_free(e);
}
}
void playlist_remove(struct playlist *pl, struct playlist_entry *entry)
{
playlist_unlink(pl, entry);
assert(pl && entry->pl == pl);
if (pl->current == entry) {
pl->current = playlist_entry_get_rel(entry, 1);
pl->current_was_replaced = true;
}
MP_TARRAY_REMOVE_AT(pl->entries, pl->num_entries, entry->pl_index);
playlist_update_indexes(pl, entry->pl_index, -1);
entry->pl = NULL;
entry->pl_index = -1;
ta_set_parent(entry, NULL);
entry->removed = true;
playlist_entry_unref(entry);
}
void playlist_clear(struct playlist *pl)
{
while (pl->first)
playlist_remove(pl, pl->first);
for (int n = pl->num_entries - 1; n >= 0; n--)
playlist_remove(pl, pl->entries[n]);
assert(!pl->current);
pl->current_was_replaced = false;
}
void playlist_clear_except_current(struct playlist *pl)
{
for (int n = pl->num_entries - 1; n >= 0; n--) {
if (pl->entries[n] != pl->current)
playlist_remove(pl, pl->entries[n]);
}
}
// Moves the entry so that it takes "at"'s place (or move to end, if at==NULL).
void playlist_move(struct playlist *pl, struct playlist_entry *entry,
struct playlist_entry *at)
@@ -135,14 +120,19 @@ void playlist_move(struct playlist *pl, struct playlist_entry *entry,
if (entry == at)
return;
struct playlist_entry *save_current = pl->current;
bool save_replaced = pl->current_was_replaced;
assert(entry && entry->pl == pl);
assert(!at || at->pl == pl);
playlist_unlink(pl, entry);
playlist_insert(pl, at ? at->prev : pl->last, entry);
int index = at ? at->pl_index : pl->num_entries;
MP_TARRAY_INSERT_AT(pl, pl->entries, pl->num_entries, index, entry);
pl->current = save_current;
pl->current_was_replaced = save_replaced;
int old_index = entry->pl_index;
if (old_index >= index)
old_index += 1;
MP_TARRAY_REMOVE_AT(pl->entries, pl->num_entries, old_index);
playlist_update_indexes(pl, MPMIN(index - 1, old_index - 1),
MPMAX(index + 1, old_index + 1));
}
void playlist_add_file(struct playlist *pl, const char *filename)
@@ -150,34 +140,46 @@ void playlist_add_file(struct playlist *pl, const char *filename)
playlist_add(pl, playlist_entry_new(filename));
}
static int playlist_count(struct playlist *pl)
{
int c = 0;
for (struct playlist_entry *e = pl->first; e; e = e->next)
c++;
return c;
}
void playlist_shuffle(struct playlist *pl)
{
struct playlist_entry *save_current = pl->current;
bool save_replaced = pl->current_was_replaced;
int count = playlist_count(pl);
struct playlist_entry **arr = talloc_array(NULL, struct playlist_entry *,
count);
for (int n = 0; n < count; n++) {
arr[n] = pl->first;
playlist_unlink(pl, pl->first);
for (int n = 0; n < pl->num_entries; n++)
pl->entries[n]->original_index = n;
for (int n = 0; n < pl->num_entries - 1; n++) {
int j = (int)((double)(pl->num_entries - n) * rand() / (RAND_MAX + 1.0));
MPSWAP(struct playlist_entry *, pl->entries[n], pl->entries[n + j]);
}
for (int n = 0; n < count - 1; n++) {
int j = (int)((double)(count - n) * rand() / (RAND_MAX + 1.0));
MPSWAP(struct playlist_entry *, arr[n], arr[n + j]);
}
for (int n = 0; n < count; n++)
playlist_add(pl, arr[n]);
talloc_free(arr);
pl->current = save_current;
pl->current_was_replaced = save_replaced;
playlist_update_indexes(pl, 0, -1);
}
#define CMP_INT(a, b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1))
static int cmp_unshuffle(const void *a, const void *b)
{
struct playlist_entry *ea = *(struct playlist_entry **)a;
struct playlist_entry *eb = *(struct playlist_entry **)b;
if (ea->original_index >= 0 && ea->original_index != eb->original_index)
return CMP_INT(ea->original_index, eb->original_index);
return CMP_INT(ea->pl_index, eb->pl_index);
}
void playlist_unshuffle(struct playlist *pl)
{
if (pl->num_entries)
qsort(pl->entries, pl->num_entries, sizeof(pl->entries[0]), cmp_unshuffle);
playlist_update_indexes(pl, 0, -1);
}
// (Explicitly ignores current_was_replaced.)
struct playlist_entry *playlist_get_first(struct playlist *pl)
{
return pl->num_entries ? pl->entries[0] : NULL;
}
// (Explicitly ignores current_was_replaced.)
struct playlist_entry *playlist_get_last(struct playlist *pl)
{
return pl->num_entries ? pl->entries[pl->num_entries - 1] : NULL;
}
struct playlist_entry *playlist_get_next(struct playlist *pl, int direction)
@@ -187,15 +189,27 @@ struct playlist_entry *playlist_get_next(struct playlist *pl, int direction)
return NULL;
assert(pl->current->pl == pl);
if (direction < 0)
return pl->current->prev;
return pl->current_was_replaced ? pl->current : pl->current->next;
return playlist_entry_get_rel(pl->current, -1);
return pl->current_was_replaced ? pl->current :
playlist_entry_get_rel(pl->current, 1);
}
// (Explicitly ignores current_was_replaced.)
struct playlist_entry *playlist_entry_get_rel(struct playlist_entry *e,
int direction)
{
assert(direction == -1 || direction == +1);
if (!e->pl)
return NULL;
return playlist_entry_from_index(e->pl, e->pl_index + direction);
}
void playlist_add_base_path(struct playlist *pl, bstr base_path)
{
if (base_path.len == 0 || bstrcmp0(base_path, ".") == 0)
return;
for (struct playlist_entry *e = pl->first; e; e = e->next) {
for (int n = 0; n < pl->num_entries; n++) {
struct playlist_entry *e = pl->entries[n];
if (!mp_is_url(bstr0(e->filename))) {
char *new_file = mp_path_join_bstr(e, base_path, bstr0(e->filename));
talloc_free(e->filename);
@@ -207,72 +221,84 @@ void playlist_add_base_path(struct playlist *pl, bstr base_path)
// Add redirected_from as new redirect entry to each item in pl.
void playlist_add_redirect(struct playlist *pl, const char *redirected_from)
{
for (struct playlist_entry *e = pl->first; e; e = e->next) {
for (int n = 0; n < pl->num_entries; n++) {
struct playlist_entry *e = pl->entries[n];
if (e->num_redirects >= 10) // arbitrary limit for sanity
break;
continue;
char *s = talloc_strdup(e, redirected_from);
if (s)
MP_TARRAY_APPEND(e, e->redirects, e->num_redirects, s);
}
}
void playlist_set_stream_flags(struct playlist *pl, int flags)
{
for (int n = 0; n < pl->num_entries; n++)
pl->entries[n]->stream_flags = flags;
}
static void playlist_transfer_entries_to(struct playlist *pl, int dst_index,
struct playlist *source_pl)
{
assert(pl != source_pl);
int count = source_pl->num_entries;
MP_TARRAY_INSERT_N_AT(pl, pl->entries, pl->num_entries, dst_index, count);
for (int n = 0; n < count; n++) {
struct playlist_entry *e = source_pl->entries[n];
e->pl = pl;
e->pl_index = dst_index + n;
pl->entries[e->pl_index] = e;
talloc_steal(pl, e);
}
playlist_update_indexes(pl, dst_index + count, -1);
source_pl->num_entries = 0;
}
// Move all entries from source_pl to pl, appending them after the current entry
// of pl. source_pl will be empty, and all entries have changed ownership to pl.
void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl)
{
struct playlist_entry *add_after = pl->current;
if (pl->current && pl->current_was_replaced)
add_after = pl->current->next;
if (!add_after)
add_after = pl->last;
while (source_pl->first) {
struct playlist_entry *e = source_pl->first;
playlist_unlink(source_pl, e);
playlist_insert(pl, add_after, e);
add_after = e;
int add_at = pl->num_entries;
if (pl->current) {
add_at = pl->current->pl_index + 1;
if (pl->current_was_replaced)
add_at += 1;
}
assert(add_at >= 0);
assert(add_at <= pl->num_entries);
playlist_transfer_entries_to(pl, add_at, source_pl);
}
void playlist_append_entries(struct playlist *pl, struct playlist *source_pl)
{
while (source_pl->first) {
struct playlist_entry *e = source_pl->first;
playlist_unlink(source_pl, e);
playlist_add(pl, e);
}
playlist_transfer_entries_to(pl, pl->num_entries, source_pl);
}
// Return number of entries between list start and e.
// Return -1 if e is not on the list, or if e is NULL.
int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e)
{
struct playlist_entry *cur = pl->first;
int pos = 0;
if (!e)
return -1;
while (cur && cur != e) {
cur = cur->next;
pos++;
}
return cur == e ? pos : -1;
assert(e->pl == pl);
return e->pl_index;
}
int playlist_entry_count(struct playlist *pl)
{
return playlist_entry_to_index(pl, pl->last) + 1;
return pl->num_entries;
}
// Return entry for which playlist_entry_to_index() would return index.
// Return NULL if not found.
struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index)
{
struct playlist_entry *e = pl->first;
for (int n = 0; ; n++) {
if (!e || n == index)
return e;
e = e->next;
}
return index >= 0 && index < pl->num_entries ? pl->entries[index] : NULL;
}
struct playlist *playlist_parse_file(const char *file, struct mp_cancel *cancel,
@@ -281,7 +307,10 @@ struct playlist *playlist_parse_file(const char *file, struct mp_cancel *cancel,
struct mp_log *log = mp_log_new(NULL, global->log, "!playlist_parser");
mp_verbose(log, "Parsing playlist file %s...\n", file);
struct demuxer_params p = {.force_format = "playlist"};
struct demuxer_params p = {
.force_format = "playlist",
.stream_flags = STREAM_ORIGIN_DIRECT,
};
struct demuxer *d = demux_open_url(file, &p, cancel, global);
if (!d) {
talloc_free(log);
@@ -305,7 +334,7 @@ struct playlist *playlist_parse_file(const char *file, struct mp_cancel *cancel,
mp_err(log, "Error while parsing playlist\n");
}
if (ret && !ret->first)
if (ret && !ret->num_entries)
mp_warn(log, "Warning: empty playlist\n");
talloc_free(log);
+15 -10
View File
@@ -26,8 +26,9 @@ struct playlist_param {
};
struct playlist_entry {
struct playlist_entry *prev, *next;
// Invariant: (pl && pl->entries[pl_index] == this) || (!pl && pl_index < 0)
struct playlist *pl;
int pl_index;
char *filename;
@@ -41,6 +42,9 @@ struct playlist_entry {
char **redirects;
int num_redirects;
// Used for unshuffling: the pl_index before it was shuffled. -1 => unknown.
int original_index;
// Set to true if playback didn't seem to work, or if the file could be
// played only for a very short time. This is used to make playlist
// navigation just work in case the user has unplayable files in the
@@ -53,24 +57,20 @@ struct playlist_entry {
// Additional refcount. Normally (reserved==0), the entry is owned by the
// playlist, and this can be used to keep the entry alive.
int reserved;
// Any flags from STREAM_ORIGIN_FLAGS. 0 if unknown.
// Used to reject loading of unsafe entries from external playlists.
// Can have any of the following bit flags set:
// STREAM_SAFE_ONLY: only allow streams marked with is_safe
// STREAM_NETWORK_ONLY: only allow streams marked with is_network
// The value 0 allows everything.
int stream_flags;
};
struct playlist {
struct playlist_entry *first, *last;
struct playlist_entry **entries;
int num_entries;
// This provides some sort of stable iterator. If this entry is removed from
// the playlist, current is set to the next element (or NULL), and
// current_was_replaced is set to true.
struct playlist_entry *current;
bool current_was_replaced;
bool disable_safety;
};
void playlist_entry_add_param(struct playlist_entry *e, bstr name, bstr value);
@@ -80,20 +80,25 @@ void playlist_entry_add_params(struct playlist_entry *e,
struct playlist_entry *playlist_entry_new(const char *filename);
void playlist_insert(struct playlist *pl, struct playlist_entry *after,
struct playlist_entry *add);
void playlist_add(struct playlist *pl, struct playlist_entry *add);
void playlist_remove(struct playlist *pl, struct playlist_entry *entry);
void playlist_clear(struct playlist *pl);
void playlist_clear_except_current(struct playlist *pl);
void playlist_move(struct playlist *pl, struct playlist_entry *entry,
struct playlist_entry *at);
void playlist_add_file(struct playlist *pl, const char *filename);
void playlist_shuffle(struct playlist *pl);
void playlist_unshuffle(struct playlist *pl);
struct playlist_entry *playlist_get_first(struct playlist *pl);
struct playlist_entry *playlist_get_last(struct playlist *pl);
struct playlist_entry *playlist_get_next(struct playlist *pl, int direction);
struct playlist_entry *playlist_entry_get_rel(struct playlist_entry *e,
int direction);
void playlist_add_base_path(struct playlist *pl, bstr base_path);
void playlist_add_redirect(struct playlist *pl, const char *redirected_from);
void playlist_set_stream_flags(struct playlist *pl, int flags);
void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl);
void playlist_append_entries(struct playlist *pl, struct playlist *source_pl);
+131 -18
View File
@@ -38,6 +38,7 @@
#include "common/msg.h"
#include "common/global.h"
#include "common/recorder.h"
#include "misc/charset_conv.h"
#include "misc/thread_tools.h"
#include "osdep/atomic.h"
#include "osdep/timer.h"
@@ -97,12 +98,15 @@ struct demux_opts {
int audio_back_preroll;
int back_batch[STREAM_TYPE_COUNT];
double back_seek_size;
char *meta_cp;
};
#define OPT_BASE_STRUCT struct demux_opts
#define MAX_BYTES MPMIN(INT64_MAX, SIZE_MAX / 2)
static bool get_demux_sub_opts(int index, const struct m_sub_options **sub);
const struct m_sub_options demux_conf = {
.opts = (const struct m_option[]){
OPT_CHOICE("cache", enable_cache, 0,
@@ -128,6 +132,7 @@ const struct m_sub_options demux_conf = {
OPT_INTRANGE("audio-backward-batch", back_batch[STREAM_AUDIO], 0, 0, 1024),
OPT_DOUBLE("demuxer-backward-playback-step", back_seek_size, M_OPT_MIN,
.min = 0),
OPT_STRING("metadata-codepage", meta_cp, 0),
{0}
},
.size = sizeof(struct demux_opts),
@@ -146,7 +151,9 @@ const struct m_sub_options demux_conf = {
[STREAM_VIDEO] = 1,
[STREAM_AUDIO] = 10,
},
.meta_cp = "utf-8",
},
.get_sub_options = get_demux_sub_opts,
};
struct demux_internal {
@@ -181,6 +188,8 @@ struct demux_internal {
struct sh_stream **streams;
int num_streams;
char *meta_charset;
// If non-NULL, a stream which is used for global (timed) metadata. It will
// be an arbitrary stream, which hopefully will happen to work.
struct sh_stream *metadata_stream;
@@ -273,6 +282,7 @@ struct demux_internal {
int64_t slave_unbuffered_read_bytes; // value repoted from demuxer impl.
int64_t hack_unbuffered_read_bytes; // for demux_get_bytes_read_hack()
int64_t cache_unbuffered_read_bytes; // for demux_reader_state.bytes_per_second
int64_t byte_level_seeks; // for demux_reader_state.byte_level_seeks
};
struct timed_metadata {
@@ -330,6 +340,7 @@ struct demux_queue {
bool correct_dts; // packet DTS is strictly monotonically increasing
bool correct_pos; // packet pos is strictly monotonically increasing
int64_t last_pos; // for determining correct_pos
int64_t last_pos_fixup; // for filling in unset dp->pos values
double last_dts; // for determining correct_dts
double last_ts; // timestamp of the last packet added to queue
@@ -442,6 +453,7 @@ static struct demux_packet *find_seek_target(struct demux_queue *queue,
double pts, int flags);
static void prune_old_packets(struct demux_internal *in);
static void dumper_close(struct demux_internal *in);
static void demux_convert_tags_charset(struct demuxer *demuxer);
static uint64_t get_foward_buffered_bytes(struct demux_stream *ds)
{
@@ -733,6 +745,7 @@ static void clear_queue(struct demux_queue *queue)
queue->correct_dts = queue->correct_pos = true;
queue->last_pos = -1;
queue->last_ts = queue->last_dts = MP_NOPTS_VALUE;
queue->last_pos_fixup = -1;
queue->is_eof = false;
queue->is_bof = false;
@@ -979,13 +992,6 @@ static void demux_add_sh_stream_locked(struct demux_internal *in,
if (sh->ff_index < 0)
sh->ff_index = sh->index;
if (sh->demuxer_id < 0) {
sh->demuxer_id = 0;
for (int n = 0; n < in->num_streams; n++) {
if (in->streams[n]->type == sh->type)
sh->demuxer_id += 1;
}
}
MP_TARRAY_APPEND(in, in->streams, in->num_streams, sh);
assert(in->streams[sh->index] == sh);
@@ -1605,8 +1611,8 @@ static void add_index_entry(struct demux_queue *queue, struct demux_packet *dp,
// Needs to honor power-of-2 requirement.
size_t new_size = MPMAX(128, queue->index_size * 2);
assert(!(new_size & (new_size - 1)));
MP_VERBOSE(in, "stream %d: resize index to %zu\n", queue->ds->index,
new_size);
MP_DBG(in, "stream %d: resize index to %zu\n", queue->ds->index,
new_size);
// Note: we could tolerate allocation failure, and just discard the
// entire index (and prevent the index from being recreated).
MP_RESIZE_ARRAY(NULL, queue->index, new_size);
@@ -1760,6 +1766,8 @@ static void attempt_range_joining(struct demux_internal *in)
q1->keyframe_latest = q2->keyframe_latest;
q1->is_eof = q2->is_eof;
q1->last_pos_fixup = -1;
q2->head = q2->tail = NULL;
q2->keyframe_first = NULL;
q2->keyframe_latest = NULL;
@@ -1995,6 +2003,15 @@ static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp)
struct demux_queue *queue = ds->queue;
bool drop = !ds->selected || in->seeking || ds->sh->attached_picture;
if (!drop) {
// If libavformat splits packets, some packets will have pos unset, so
// make up one based on the first packet => makes refresh seeks work.
if (dp->pos < 0 && !dp->keyframe && queue->last_pos_fixup >= 0)
dp->pos = queue->last_pos_fixup + 1;
queue->last_pos_fixup = dp->pos;
}
if (!drop && ds->refreshing) {
// Resume reading once the old position was reached (i.e. we start
// returning packets where we left off before the refresh).
@@ -2377,6 +2394,9 @@ static void execute_seek(struct demux_internal *in)
!(flags & (SEEK_FORWARD | SEEK_FACTOR)) &&
pts <= in->d_thread->start_time;
for (int n = 0; n < in->num_streams; n++)
in->streams[n]->ds->queue->last_pos_fixup = -1;
if (in->recorder)
mp_recorder_mark_discontinuity(in->recorder);
@@ -2443,8 +2463,8 @@ static void update_opts(struct demux_internal *in)
mp_recorder_destroy(in->recorder);
in->recorder = NULL;
}
in->record_filename = talloc_strdup(in, opts->record_file);
talloc_free(in->record_filename);
in->record_filename = talloc_strdup(in, opts->record_file);
// Note: actual recording only starts once packets are read. It may be
// important to delay creating in->recorder to that point, because the
// demuxer might detect more streams until finding the first packet.
@@ -2900,6 +2920,7 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src)
dst->duration = src->duration;
dst->is_network = src->is_network;
dst->is_streaming = src->is_streaming;
dst->stream_origin = src->stream_origin;
dst->priv = src->priv;
dst->metadata = mp_tags_dup(dst, src->metadata);
}
@@ -3102,7 +3123,6 @@ static void demux_init_cuesheet(struct demuxer *demuxer)
// Calling this after opening was completed is not allowed. Also, if opening
// failed, this must not be called (or trying another demuxer would fail).
// Useful so that e.g. subtitles don't keep the file or socket open.
// Replaces it with a dummy stream for dumb reasons.
// If there's ever the situation where we can't allow the demuxer to close
// the stream, this function could ignore the request.
void demux_close_stream(struct demuxer *demuxer)
@@ -3115,9 +3135,8 @@ void demux_close_stream(struct demuxer *demuxer)
MP_VERBOSE(demuxer, "demuxer read all data; closing stream\n");
free_stream(demuxer->stream);
demuxer->stream = stream_memory_open(demuxer->global, NULL, 0); // dummy
demuxer->stream->cancel = demuxer->cancel;
in->d_user->stream = demuxer->stream;
demuxer->stream = NULL;
in->d_user->stream = NULL;
}
static void demux_init_ccs(struct demuxer *demuxer, struct demux_opts *opts)
@@ -3151,6 +3170,7 @@ struct parent_stream_info {
bool seekable;
bool is_network;
bool is_streaming;
int stream_origin;
struct mp_cancel *cancel;
char *filename;
};
@@ -3182,6 +3202,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
.filename = talloc_strdup(demuxer, sinfo->filename),
.is_network = sinfo->is_network,
.is_streaming = sinfo->is_streaming,
.stream_origin = sinfo->stream_origin,
.access_references = opts->access_references,
.events = DEMUX_EVENT_ALL,
.duration = -1,
@@ -3214,6 +3235,9 @@ static struct demuxer *open_given_type(struct mpv_global *global,
mp_dbg(log, "Trying demuxer: %s (force-level: %s)\n",
desc->name, d_level(check));
if (stream)
stream_seek(stream, 0);
in->d_thread->params = params; // temporary during open()
int ret = demuxer->desc->open(in->d_thread, check);
if (ret >= 0) {
@@ -3232,6 +3256,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
}
demux_init_cuesheet(in->d_thread);
demux_init_ccs(demuxer, opts);
demux_convert_tags_charset(in->d_thread);
demux_copy(in->d_user, in->d_thread);
in->duration = in->d_thread->duration;
demuxer_sort_chapters(demuxer);
@@ -3312,6 +3337,7 @@ static struct demuxer *demux_open(struct stream *stream,
.seekable = stream->seekable,
.is_network = stream->is_network,
.is_streaming = stream->streaming,
.stream_origin = stream->stream_origin,
.cancel = cancel,
.filename = talloc_strdup(NULL, stream->url),
};
@@ -3323,8 +3349,6 @@ static struct demuxer *demux_open(struct stream *stream,
for (int n = 0; demuxer_list[n]; n++) {
const struct demuxer_desc *desc = demuxer_list[n];
if (!check_desc || desc == check_desc) {
if (stream->seekable && (!params || !params->timeline))
stream_seek(stream, 0);
demuxer = open_given_type(global, log, desc, stream, &sinfo,
params, level);
if (demuxer) {
@@ -3369,9 +3393,8 @@ struct demuxer *demux_open_url(const char *url,
struct mp_cancel *cancel,
struct mpv_global *global)
{
struct demuxer_params dummy = {0};
if (!params)
params = &dummy;
return NULL;
struct mp_cancel *priv_cancel = mp_cancel_new(NULL);
if (cancel)
mp_cancel_set_parent(priv_cancel, cancel);
@@ -3760,6 +3783,8 @@ static bool queue_seek(struct demux_internal *in, double seek_pts, int flags,
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
enum stream_type t, int id)
{
if (id < 0)
return NULL;
int num = demux_get_num_stream(d);
for (int n = 0; n < num; n++) {
struct sh_stream *s = demux_get_stream(d, n);
@@ -3977,14 +4002,19 @@ static void update_bytes_read(struct demux_internal *in)
int64_t new = in->slave_unbuffered_read_bytes;
in->slave_unbuffered_read_bytes = 0;
int64_t new_seeks = 0;
struct stream *stream = demuxer->stream;
if (stream) {
new += stream->total_unbuffered_read_bytes;
stream->total_unbuffered_read_bytes = 0;
new_seeks += stream->total_stream_seeks;
stream->total_stream_seeks = 0;
}
in->cache_unbuffered_read_bytes += new;
in->hack_unbuffered_read_bytes += new;
in->byte_level_seeks += new_seeks;
}
// must be called not locked
@@ -4345,6 +4375,7 @@ void demux_get_reader_state(struct demuxer *demuxer, struct demux_reader_state *
.low_level_seeks = in->low_level_seeks,
.ts_last = in->demux_ts,
.bytes_per_second = in->bytes_per_second,
.byte_level_seeks = in->byte_level_seeks,
.file_cache_bytes = in->cache ? demux_cache_get_size(in->cache) : -1,
};
bool any_packets = false;
@@ -4396,3 +4427,85 @@ struct demux_chapter *demux_copy_chapter_data(struct demux_chapter *c, int num)
}
return new;
}
static void visit_tags(void *ctx, void (*visit)(void *ctx, void *ta, char **s),
struct mp_tags *tags)
{
for (int n = 0; n < (tags ? tags->num_keys : 0); n++)
visit(ctx, tags, &tags->values[n]);
}
static void visit_meta(struct demuxer *demuxer, void *ctx,
void (*visit)(void *ctx, void *ta, char **s))
{
struct demux_internal *in = demuxer->in;
for (int n = 0; n < in->num_streams; n++) {
struct sh_stream *sh = in->streams[n];
visit(ctx, sh, &sh->title);
visit_tags(ctx, visit, sh->tags);
}
for (int n = 0; n < demuxer->num_chapters; n++)
visit_tags(ctx, visit, demuxer->chapters[n].metadata);
visit_tags(ctx, visit, demuxer->metadata);
}
static void visit_detect(void *ctx, void *ta, char **s)
{
char **all = ctx;
if (*s)
*all = talloc_asprintf_append_buffer(*all, "%s\n", *s);
}
static void visit_convert(void *ctx, void *ta, char **s)
{
struct demuxer *demuxer = ctx;
struct demux_internal *in = demuxer->in;
if (!*s)
return;
bstr data = bstr0(*s);
bstr conv = mp_iconv_to_utf8(in->log, data, in->meta_charset,
MP_ICONV_VERBOSE);
if (conv.start && conv.start != data.start) {
char *ns = conv.start; // 0-termination is guaranteed
// (The old string might not be an alloc, but if it is, it's a talloc
// child, and will not leak, even if it stays allocated uselessly.)
*s = ns;
talloc_steal(ta, *s);
}
}
static void demux_convert_tags_charset(struct demuxer *demuxer)
{
struct demux_internal *in = demuxer->in;
char *cp = in->opts->meta_cp;
if (!cp || mp_charset_is_utf8(cp))
return;
char *data = talloc_strdup(NULL, "");
visit_meta(demuxer, &data, visit_detect);
in->meta_charset = (char *)mp_charset_guess(in, in->log, bstr0(data), cp, 0);
if (in->meta_charset && !mp_charset_is_utf8(in->meta_charset)) {
MP_INFO(demuxer, "Using tag charset: %s\n", in->meta_charset);
visit_meta(demuxer, demuxer, visit_convert);
}
talloc_free(data);
}
static bool get_demux_sub_opts(int index, const struct m_sub_options **sub)
{
if (!demuxer_list[index])
return false;
*sub = demuxer_list[index]->options;
return true;
}
+5
View File
@@ -47,6 +47,7 @@ struct demux_reader_state {
int64_t file_cache_bytes;
double seeking; // current low level seek target, or NOPTS
int low_level_seeks; // number of started low level seeks
uint64_t byte_level_seeks; // number of byte stream level seeks
double ts_last; // approx. timestamp of demuxer position
uint64_t bytes_per_second; // low level statistics
// Positions that can be seeked to without incurring the latency of a low
@@ -97,6 +98,9 @@ typedef struct demuxer_desc {
const char *name; // Demuxer name, used with -demuxer switch
const char *desc; // Displayed to user
// If non-NULL, these are added to the global option list.
const struct m_sub_options *options;
// Return 0 on success, otherwise -1
int (*open)(struct demuxer *demuxer, enum demux_check check);
// The following functions are all optional
@@ -196,6 +200,7 @@ typedef struct demuxer {
bool fully_read;
bool is_network; // opened directly from a network stream
bool is_streaming; // implies a "slow" input, such as network or FUSE
int stream_origin; // any STREAM_ORIGIN_* (set from source stream)
bool access_references; // allow opening other files/URLs
// Bitmask of DEMUX_EVENT_*
+9 -4
View File
@@ -78,7 +78,11 @@ static bool try_open(struct timeline *tl, char *filename)
|| bstrcasecmp(bstr0(tl->demuxer->filename), bfilename) == 0)
return false;
struct demuxer *d = demux_open_url(filename, NULL, tl->cancel, tl->global);
struct demuxer_params p = {
.stream_flags = tl->stream_origin,
};
struct demuxer *d = demux_open_url(filename, &p, tl->cancel, tl->global);
// Since .bin files are raw PCM data with no headers, we have to explicitly
// open them. Also, try to avoid to open files that are most likely not .bin
// files, as that would only play noise. Checking the file extension is
@@ -87,7 +91,7 @@ static bool try_open(struct timeline *tl, char *filename)
// CD sector size (2352 bytes)
if (!d && bstr_case_endswith(bfilename, bstr0(".bin"))) {
MP_WARN(tl, "CUE: Opening as BIN file!\n");
struct demuxer_params p = {.force_format = "rawaudio"};
p.force_format = "rawaudio";
d = demux_open_url(filename, &p, tl->cancel, tl->global);
}
if (d) {
@@ -265,8 +269,9 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check)
struct stream *s = demuxer->stream;
if (check >= DEMUX_CHECK_UNSAFE) {
bstr d = stream_peek(s, PROBE_SIZE);
if (d.len < 1 || !mp_probe_cue(d))
char probe[PROBE_SIZE];
int len = stream_read_peek(s, probe, sizeof(probe));
if (len < 1 || !mp_probe_cue((bstr){probe, len}))
return -1;
}
struct priv *p = talloc_zero(demuxer, struct priv);
+2 -1
View File
@@ -296,6 +296,7 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
struct demuxer_params params = {
.force_format = "+lavf",
.external_stream = demuxer->stream,
.stream_flags = demuxer->stream_origin,
};
struct stream *cur = demuxer->stream;
@@ -321,7 +322,7 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
// Initialize the playback time. We need to read _some_ data to get the
// correct stream-layer time (at least with libdvdnav).
stream_peek(demuxer->stream, 1);
stream_read_peek(demuxer->stream, &(char){0}, 1);
reset_pts(demuxer);
p->slave = demux_open_url("-", &params, demuxer->cancel, demuxer->global);
+15 -13
View File
@@ -61,7 +61,6 @@ struct tl_root {
struct priv {
bstr data;
bool allow_any;
};
// Parse a time (absolute file time or duration). Currently equivalent to a
@@ -198,11 +197,12 @@ static struct demuxer *open_source(struct timeline *root,
{
for (int n = 0; n < tl->num_parts; n++) {
struct demuxer *d = tl->parts[n].source;
if (d && strcmp(d->stream->url, filename) == 0)
if (d && d->filename && strcmp(d->filename, filename) == 0)
return d;
}
struct demuxer_params params = {
.init_fragment = tl->init_fragment,
.stream_flags = root->stream_origin,
};
struct demuxer *d = demux_open_url(filename, &params, root->cancel,
root->global);
@@ -268,7 +268,8 @@ static struct timeline_par *build_timeline(struct timeline *root,
if (parts->init_fragment_url && parts->init_fragment_url[0]) {
MP_VERBOSE(root, "Opening init fragment...\n");
stream_t *s = stream_create(parts->init_fragment_url, STREAM_READ,
stream_t *s = stream_create(parts->init_fragment_url,
STREAM_READ | root->stream_origin,
root->cancel, root->global);
if (s) {
root->is_network |= s->is_network;
@@ -282,6 +283,7 @@ static struct timeline_par *build_timeline(struct timeline *root,
}
struct demuxer_params params = {
.init_fragment = tl->init_fragment,
.stream_flags = root->stream_origin,
};
tl->track_layout = demux_open_url("memory://", &params, root->cancel,
root->global);
@@ -366,6 +368,8 @@ static struct timeline_par *build_timeline(struct timeline *root,
if (source && !tl->track_layout && part->is_layout)
tl->track_layout = source;
tl->num_parts++;
}
if (!tl->track_layout) {
@@ -385,7 +389,7 @@ static struct timeline_par *build_timeline(struct timeline *root,
if (!root->meta)
root->meta = tl->track_layout;
tl->num_parts = parts->num_parts;
assert(tl->num_parts == parts->num_parts);
return tl;
error:
@@ -393,15 +397,14 @@ error:
return NULL;
}
// For security, don't allow relative or absolute paths, only plain filenames.
// Also, make these filenames relative to the edl source file.
static void fix_filenames(struct tl_parts *parts, char *source_path)
{
if (bstr_equals0(mp_split_proto(bstr0(source_path), NULL), "edl"))
return;
struct bstr dirname = mp_dirname(source_path);
for (int n = 0; n < parts->num_parts; n++) {
struct tl_part *part = &parts->parts[n];
char *filename = mp_basename(part->filename); // plain filename only
part->filename = mp_path_join_bstr(parts, dirname, bstr0(filename));
part->filename = mp_path_join_bstr(parts, dirname, bstr0(part->filename));
}
}
@@ -421,8 +424,7 @@ static void build_mpv_edl_timeline(struct timeline *tl)
for (int n = 0; n < root->num_pars; n++) {
struct tl_parts *parts = root->pars[n];
if (!p->allow_any)
fix_filenames(parts, tl->demuxer->filename);
fix_filenames(parts, tl->demuxer->filename);
struct timeline_par *par = build_timeline(tl, parts);
if (!par)
break;
@@ -454,12 +456,12 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check)
struct stream *s = demuxer->stream;
if (s->info && strcmp(s->info->name, "edl") == 0) {
p->data = bstr0(s->path);
// Source is edl:// and not .edl => allow arbitrary paths
p->allow_any = true;
return 0;
}
if (check >= DEMUX_CHECK_UNSAFE) {
if (!bstr_equals0(stream_peek(s, strlen(HEADER)), HEADER))
char header[sizeof(HEADER) - 1];
int len = stream_read_peek(s, header, sizeof(header));
if (len != strlen(HEADER) || memcmp(header, HEADER, len) != 0)
return -1;
}
p->data = stream_read_complete(s, demuxer, 1000000);
+51 -17
View File
@@ -79,6 +79,7 @@ struct demux_lavf_opts {
char *sub_cp;
int rtsp_transport;
int linearize_ts;
int propagate_opts;
};
const struct m_sub_options demux_lavf_conf = {
@@ -104,6 +105,7 @@ const struct m_sub_options demux_lavf_conf = {
{"http", 3})),
OPT_CHOICE("demuxer-lavf-linearize-timestamps", linearize_ts, 0,
({"no", 0}, {"auto", -1}, {"yes", 1})),
OPT_FLAG("demuxer-lavf-propagate-opts", propagate_opts, 0),
{0}
},
.size = sizeof(struct demux_lavf_opts),
@@ -118,6 +120,7 @@ const struct m_sub_options demux_lavf_conf = {
.sub_cp = "auto",
.rtsp_transport = 2,
.linearize_ts = -1,
.propagate_opts = 1,
},
};
@@ -131,7 +134,7 @@ struct format_hack {
bool max_probe : 1; // use probescore only if max. probe size reached
bool ignore : 1; // blacklisted
bool no_stream : 1; // do not wrap struct stream as AVIOContext
bool use_stream_ids : 1; // export the native stream IDs
bool use_stream_ids : 1; // has a meaningful native stream IDs (export it)
bool fully_read : 1; // set demuxer.fully_read flag
bool detect_charset : 1; // format is a small text file, possibly not UTF8
bool image_format : 1; // expected to contain exactly 1 frame
@@ -163,9 +166,12 @@ static const struct format_hack format_hacks[] = {
{"sdp", .clear_filepos = true, .is_network = true, .no_seek = true},
{"mpeg", .use_stream_ids = true},
{"mpegts", .use_stream_ids = true},
{"mp4", .skipinfo = true, .fix_editlists = true, .no_pcm_seek = true},
{"matroska", .skipinfo = true, .no_pcm_seek = true},
{"mxf", .use_stream_ids = true},
{"avi", .use_stream_ids = true},
{"asf", .use_stream_ids = true},
{"mp4", .skipinfo = true, .fix_editlists = true, .no_pcm_seek = true,
.use_stream_ids = true},
{"matroska", .skipinfo = true, .no_pcm_seek = true, .use_stream_ids = true},
{"v4l2", .no_seek = true},
@@ -175,7 +181,7 @@ static const struct format_hack format_hacks[] = {
// Some Ogg shoutcast streams are essentially concatenated OGG files. They
// reset timestamps, which causes all sorts of problems.
{"ogg", .linearize_audio_ts = true},
{"ogg", .linearize_audio_ts = true, .use_stream_ids = true},
TEXTSUB("aqtitle"), TEXTSUB("jacosub"), TEXTSUB("microdvd"),
TEXTSUB("mpl2"), TEXTSUB("mpsub"), TEXTSUB("pjs"), TEXTSUB("realtext"),
@@ -232,6 +238,8 @@ typedef struct lavf_priv {
int linearize_ts;
bool any_ts_fixed;
AVDictionary *av_opts;
// Proxying nested streams.
struct nested_stream *nested;
int num_nested;
@@ -282,6 +290,8 @@ static int mp_read(void *opaque, uint8_t *buf, int size)
struct demuxer *demuxer = opaque;
lavf_priv_t *priv = demuxer->priv;
struct stream *stream = priv->stream;
if (!stream)
return 0;
int ret = stream_read_partial(stream, buf, size);
@@ -295,6 +305,8 @@ static int64_t mp_seek(void *opaque, int64_t pos, int whence)
struct demuxer *demuxer = opaque;
lavf_priv_t *priv = demuxer->priv;
struct stream *stream = priv->stream;
if (!stream)
return -1;
MP_TRACE(demuxer, "mp_seek(%p, %"PRId64", %s)\n", stream, pos,
whence == SEEK_END ? "end" :
@@ -337,7 +349,7 @@ static int64_t mp_read_seek(void *opaque, int stream_idx, int64_t ts, int flags)
.flags = flags,
};
if (stream_control(stream, STREAM_CTRL_AVSEEK, &cmd) == STREAM_OK) {
if (stream && stream_control(stream, STREAM_CTRL_AVSEEK, &cmd) == STREAM_OK) {
stream_drop_buffers(stream);
return 0;
}
@@ -357,7 +369,7 @@ static void convert_charset(struct demuxer *demuxer)
{
lavf_priv_t *priv = demuxer->priv;
char *cp = priv->opts->sub_cp;
if (!cp || mp_charset_is_utf8(cp))
if (!cp || !cp[0] || mp_charset_is_utf8(cp))
return;
bstr data = stream_read_complete(priv->stream, NULL, 128 * 1024 * 1024);
if (!data.start) {
@@ -458,11 +470,10 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
} else {
int nsize = av_clip(avpd.buf_size * 2, INITIAL_PROBE_SIZE,
PROBE_BUF_SIZE);
bstr buf = stream_peek(s, nsize);
if (buf.len <= avpd.buf_size)
nsize = stream_read_peek(s, avpd.buf, nsize);
if (nsize <= avpd.buf_size)
final_probe = true;
memcpy(avpd.buf, buf.start, buf.len);
avpd.buf_size = buf.len;
avpd.buf_size = nsize;
priv->avif = av_probe_input_format2(&avpd, avpd.buf_size > 0, &score);
}
@@ -852,8 +863,27 @@ static int nested_io_open(struct AVFormatContext *s, AVIOContext **pb,
struct demuxer *demuxer = s->opaque;
lavf_priv_t *priv = demuxer->priv;
if (priv->opts->propagate_opts) {
// Copy av_opts to options, but only entries that are not present in
// options. (Hope this will break less by not overwriting important
// settings.)
AVDictionaryEntry *cur = NULL;
while ((cur = av_dict_get(priv->av_opts, "", cur, AV_DICT_IGNORE_SUFFIX)))
{
if (!*options || !av_dict_get(*options, cur->key, NULL, 0)) {
MP_TRACE(demuxer, "Nested option: '%s'='%s'\n",
cur->key, cur->value);
av_dict_set(options, cur->key, cur->value, 0);
} else {
MP_TRACE(demuxer, "Skipping nested option: '%s'\n", cur->key);
}
}
}
int r = priv->default_io_open(s, pb, url, flags, options);
if (r >= 0) {
if (options)
mp_avdict_print_unset(demuxer->log, MSGL_TRACE, *options);
struct nested_stream nest = {
.id = *pb,
};
@@ -926,7 +956,8 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
AVDictionary *dopts = NULL;
if ((priv->avif_flags & AVFMT_NOFILE) || priv->format_hack.no_stream) {
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log);
mp_setup_av_network_options(&dopts, priv->avif->name,
demuxer->global, demuxer->log);
// This might be incorrect.
demuxer->seekable = true;
} else {
@@ -972,16 +1003,19 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if (demuxer->access_references) {
priv->default_io_open = avfc->io_open;
priv->default_io_close = avfc->io_close;
#if !HAVE_FFMPEG_STRICT_ABI
avfc->io_open = nested_io_open;
avfc->io_close = nested_io_close;
#endif
} else {
avfc->io_open = block_io_open;
}
mp_set_avdict(&dopts, lavfdopts->avopts);
if (av_dict_copy(&priv->av_opts, dopts, 0) < 0) {
av_dict_free(&dopts);
return -1;
}
if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) {
MP_ERR(demuxer, "avformat_open_input() failed\n");
av_dict_free(&dopts);
@@ -1076,7 +1110,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if (priv->own_stream)
free_stream(priv->stream);
priv->own_stream = false;
priv->stream = demuxer->stream;
priv->stream = NULL;
}
return 0;
@@ -1096,7 +1130,7 @@ static bool demux_lavf_read_packet(struct demuxer *demux,
return true;
if (r == AVERROR_EOF)
return false;
MP_WARN(demux, "error reading packet.\n");
MP_WARN(demux, "error reading packet: %s.\n", av_err2str(r));
return false;
}
@@ -1197,7 +1231,7 @@ static void demux_seek_lavf(demuxer_t *demuxer, double seek_pts, int flags)
if (flags & SEEK_FACTOR) {
struct stream *s = priv->stream;
int64_t end = stream_get_size(s);
int64_t end = s ? stream_get_size(s) : -1;
if (end > 0 && demuxer->ts_resets_possible &&
!(priv->avif_flags & AVFMT_NO_BYTE_SEEK))
{
+30 -9
View File
@@ -20,12 +20,17 @@
#include "common/common.h"
#include "common/playlist.h"
#include "options/m_config.h"
#include "stream/stream.h"
#include "misc/natural_sort.h"
#include "demux.h"
#include "stream/stream_libarchive.h"
struct demux_libarchive_opts {
int rar_list_all_volumes;
};
static int cmp_filename(const void *a, const void *b)
{
return mp_natural_sort_cmp(*(char **)a, *(char **)b);
@@ -43,28 +48,33 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
probe_size *= 100;
}
bstr probe = stream_peek(demuxer->stream, probe_size);
if (probe.len == 0)
void *probe = ta_alloc_size(NULL, probe_size);
if (!probe)
return -1;
int probe_got = stream_read_peek(demuxer->stream, probe, probe_size);
struct stream *probe_stream =
stream_memory_open(demuxer->global, probe.start, probe.len);
struct mp_archive *mpa = mp_archive_new(mp_null_log, probe_stream, flags);
stream_memory_open(demuxer->global, probe, probe_got);
struct mp_archive *mpa = mp_archive_new(mp_null_log, probe_stream, flags, 0);
bool ok = !!mpa;
free_stream(probe_stream);
mp_archive_free(mpa);
ta_free(probe);
if (!ok)
return -1;
mpa = mp_archive_new(demuxer->log, demuxer->stream, flags);
struct demux_libarchive_opts *opts =
mp_get_config_group(demuxer, demuxer->global, demuxer->desc->options);
if (!opts->rar_list_all_volumes)
flags |= MP_ARCHIVE_FLAG_NO_RAR_VOLUMES;
mpa = mp_archive_new(demuxer->log, demuxer->stream, flags, 0);
if (!mpa)
return -1;
struct playlist *pl = talloc_zero(demuxer, struct playlist);
demuxer->playlist = pl;
// make it load archive://
pl->disable_safety = true;
char *prefix = mp_url_escape(mpa, demuxer->stream->url, "~|");
char **files = NULL;
@@ -72,7 +82,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
while (mp_archive_next_entry(mpa)) {
// stream_libarchive.c does the real work
char *f = talloc_asprintf(mpa, "archive://%s|%s", prefix,
char *f = talloc_asprintf(mpa, "archive://%s|/%s", prefix,
mpa->entry_filename);
MP_TARRAY_APPEND(mpa, files, num_files, f);
}
@@ -83,6 +93,8 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
for (int n = 0; n < num_files; n++)
playlist_add_file(pl, files[n]);
playlist_set_stream_flags(pl, demuxer->stream_origin);
demuxer->filetype = "archive";
demuxer->fully_read = true;
@@ -92,8 +104,17 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
return 0;
}
#define OPT_BASE_STRUCT struct demux_libarchive_opts
const struct demuxer_desc demuxer_desc_libarchive = {
.name = "libarchive",
.desc = "libarchive wrapper",
.open = open_file,
.options = &(const struct m_sub_options){
.opts = (const struct m_option[]) {
OPT_FLAG("rar-list-all-volumes", rar_list_all_volumes, 0),
{0}
},
.size = sizeof(OPT_BASE_STRUCT),
},
};
+40 -23
View File
@@ -15,6 +15,7 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
@@ -55,8 +56,9 @@ static void mf_add(mf_t *mf, const char *fname)
MP_TARRAY_APPEND(mf, mf->names, mf->nr_of_files, entry);
}
static mf_t *open_mf_pattern(void *talloc_ctx, struct mp_log *log, char *filename)
static mf_t *open_mf_pattern(void *talloc_ctx, struct demuxer *d, char *filename)
{
struct mp_log *log = d->log;
int error_count = 0;
int count = 0;
@@ -64,21 +66,33 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct mp_log *log, char *filenam
mf->log = log;
if (filename[0] == '@') {
FILE *lst_f = fopen(filename + 1, "r");
if (lst_f) {
char *fname = talloc_size(mf, 512);
while (fgets(fname, 512, lst_f)) {
/* remove spaces from end of fname */
char *t = fname + strlen(fname) - 1;
while (t > fname && mp_isspace(*t))
*(t--) = 0;
if (!mp_path_exists(fname)) {
mp_verbose(log, "file not found: '%s'\n", fname);
} else {
mf_add(mf, fname);
struct stream *s = stream_create(filename + 1,
d->stream_origin | STREAM_READ, d->cancel, d->global);
if (s) {
while (1) {
char buf[512];
int len = stream_read_peek(s, buf, sizeof(buf));
if (!len)
break;
bstr data = (bstr){buf, len};
int pos = bstrchr(data, '\n');
data = bstr_splice(data, 0, pos < 0 ? data.len : pos + 1);
bstr fname = bstr_strip(data);
if (fname.len) {
if (bstrchr(fname, '\0') >= 0) {
mp_err(log, "invalid filename\n");
break;
}
char *entry = bstrto0(mf, fname);
if (!mp_path_exists(entry)) {
mp_verbose(log, "file not found: '%s'\n", entry);
} else {
MP_TARRAY_APPEND(mf, mf->names, mf->nr_of_files, entry);
}
}
stream_seek_skip(s, stream_tell(s) + data.len);
}
fclose(lst_f);
free_stream(s);
mp_info(log, "number of files: %d\n", mf->nr_of_files);
goto exit_mf;
@@ -163,14 +177,15 @@ static mf_t *open_mf_single(void *talloc_ctx, struct mp_log *log, char *filename
static void demux_seek_mf(demuxer_t *demuxer, double seek_pts, int flags)
{
mf_t *mf = demuxer->priv;
int newpos = seek_pts * mf->sh->codec->fps;
double newpos = seek_pts * mf->sh->codec->fps;
if (flags & SEEK_FACTOR)
newpos = seek_pts * (mf->nr_of_files - 1);
if (newpos < 0)
newpos = 0;
if (newpos >= mf->nr_of_files)
newpos = mf->nr_of_files;
mf->curr_frame = newpos;
if (flags & SEEK_FORWARD) {
newpos = ceil(newpos);
} else {
newpos = MPMIN(floor(newpos), mf->nr_of_files - 1);
}
mf->curr_frame = MPCLAMP((int)newpos, 0, mf->nr_of_files);
}
static bool demux_mf_read_packet(struct demuxer *demuxer,
@@ -186,8 +201,10 @@ static bool demux_mf_read_packet(struct demuxer *demuxer,
struct stream *stream = entry_stream;
if (!stream) {
char *filename = mf->names[mf->curr_frame];
if (filename)
stream = stream_open(filename, demuxer->global);
if (filename) {
stream = stream_create(filename, demuxer->stream_origin | STREAM_READ,
demuxer->cancel, demuxer->global);
}
}
if (stream) {
@@ -295,7 +312,7 @@ static int demux_open_mf(demuxer_t *demuxer, enum demux_check check)
if (strncmp(demuxer->stream->url, "mf://", 5) == 0 &&
demuxer->stream->info && strcmp(demuxer->stream->info->name, "mf") == 0)
{
mf = open_mf_pattern(demuxer, demuxer->log, demuxer->stream->url + 5);
mf = open_mf_pattern(demuxer, demuxer, demuxer->stream->url + 5);
} else {
mf = open_mf_single(demuxer, demuxer->log, demuxer->stream->url);
int bog = 0;
+64 -74
View File
@@ -404,7 +404,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
stream_t *s = demuxer->stream;
int res = 0;
MP_VERBOSE(demuxer, "|+ segment information...\n");
MP_DBG(demuxer, "|+ segment information...\n");
mkv_d->tc_scale = 1000000;
mkv_d->duration = 0;
@@ -414,12 +414,12 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
if (ebml_read_element(s, &parse_ctx, &info, &ebml_info_desc) < 0)
return -1;
if (info.muxing_app)
MP_VERBOSE(demuxer, "| + muxing app: %s\n", info.muxing_app);
MP_DBG(demuxer, "| + muxing app: %s\n", info.muxing_app);
if (info.writing_app)
MP_VERBOSE(demuxer, "| + writing app: %s\n", info.writing_app);
MP_DBG(demuxer, "| + writing app: %s\n", info.writing_app);
if (info.n_timecode_scale) {
mkv_d->tc_scale = info.timecode_scale;
MP_VERBOSE(demuxer, "| + timecode scale: %"PRId64"\n", mkv_d->tc_scale);
MP_DBG(demuxer, "| + timecode scale: %"PRId64"\n", mkv_d->tc_scale);
if (mkv_d->tc_scale < 1 || mkv_d->tc_scale > INT_MAX) {
res = -1;
goto out;
@@ -427,7 +427,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
}
if (info.n_duration) {
mkv_d->duration = info.duration * mkv_d->tc_scale / 1e9;
MP_VERBOSE(demuxer, "| + duration: %.3fs\n",
MP_DBG(demuxer, "| + duration: %.3fs\n",
mkv_d->duration);
demuxer->duration = mkv_d->duration;
}
@@ -441,11 +441,11 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
} else {
memcpy(demuxer->matroska_data.uid.segment, info.segment_uid.start,
len);
MP_VERBOSE(demuxer, "| + segment uid");
MP_DBG(demuxer, "| + segment uid");
for (size_t i = 0; i < len; i++)
MP_VERBOSE(demuxer, " %02x",
MP_DBG(demuxer, " %02x",
demuxer->matroska_data.uid.segment[i]);
MP_VERBOSE(demuxer, "\n");
MP_DBG(demuxer, "\n");
}
}
if (demuxer->params && demuxer->params->matroska_wanted_uids) {
@@ -539,23 +539,23 @@ static void parse_trackaudio(struct demuxer *demuxer, struct mkv_track *track,
{
if (audio->n_sampling_frequency) {
track->a_sfreq = audio->sampling_frequency;
MP_VERBOSE(demuxer, "| + Sampling frequency: %f\n", track->a_sfreq);
MP_DBG(demuxer, "| + Sampling frequency: %f\n", track->a_sfreq);
} else {
track->a_sfreq = 8000;
}
if (audio->n_output_sampling_frequency) {
track->a_osfreq = audio->output_sampling_frequency;
MP_VERBOSE(demuxer, "| + Output sampling frequency: %f\n", track->a_osfreq);
MP_DBG(demuxer, "| + Output sampling frequency: %f\n", track->a_osfreq);
} else {
track->a_osfreq = track->a_sfreq;
}
if (audio->n_bit_depth) {
track->a_bps = audio->bit_depth;
MP_VERBOSE(demuxer, "| + Bit depth: %"PRIu32"\n", track->a_bps);
MP_DBG(demuxer, "| + Bit depth: %"PRIu32"\n", track->a_bps);
}
if (audio->n_channels) {
track->a_channels = audio->channels;
MP_VERBOSE(demuxer, "| + Channels: %"PRIu32"\n", track->a_channels);
MP_DBG(demuxer, "| + Channels: %"PRIu32"\n", track->a_channels);
} else {
track->a_channels = 1;
}
@@ -569,27 +569,27 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track,
// so we can just re-use our avcol_ conversion functions.
if (colour->n_matrix_coefficients) {
track->color.space = avcol_spc_to_mp_csp(colour->matrix_coefficients);
MP_VERBOSE(demuxer, "| + Matrix: %s\n",
MP_DBG(demuxer, "| + Matrix: %s\n",
m_opt_choice_str(mp_csp_names, track->color.space));
}
if (colour->n_primaries) {
track->color.primaries = avcol_pri_to_mp_csp_prim(colour->primaries);
MP_VERBOSE(demuxer, "| + Primaries: %s\n",
MP_DBG(demuxer, "| + Primaries: %s\n",
m_opt_choice_str(mp_csp_prim_names, track->color.primaries));
}
if (colour->n_transfer_characteristics) {
track->color.gamma = avcol_trc_to_mp_csp_trc(colour->transfer_characteristics);
MP_VERBOSE(demuxer, "| + Gamma: %s\n",
MP_DBG(demuxer, "| + Gamma: %s\n",
m_opt_choice_str(mp_csp_trc_names, track->color.gamma));
}
if (colour->n_range) {
track->color.levels = avcol_range_to_mp_csp_levels(colour->range);
MP_VERBOSE(demuxer, "| + Levels: %s\n",
MP_DBG(demuxer, "| + Levels: %s\n",
m_opt_choice_str(mp_csp_levels_names, track->color.levels));
}
if (colour->n_max_cll) {
track->color.sig_peak = colour->max_cll / MP_REF_WHITE;
MP_VERBOSE(demuxer, "| + MaxCLL: %"PRIu64"\n", colour->max_cll);
MP_DBG(demuxer, "| + MaxCLL: %"PRIu64"\n", colour->max_cll);
}
// if MaxCLL is unavailable, try falling back to the mastering metadata
if (!track->color.sig_peak && colour->n_mastering_metadata) {
@@ -597,7 +597,7 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track,
if (mastering->n_luminance_max) {
track->color.sig_peak = mastering->luminance_max / MP_REF_WHITE;
MP_VERBOSE(demuxer, "| + HDR peak: %f\n", track->color.sig_peak);
MP_DBG(demuxer, "| + HDR peak: %f\n", track->color.sig_peak);
}
}
}
@@ -606,39 +606,36 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
struct ebml_video *video)
{
if (video->n_frame_rate) {
MP_VERBOSE(demuxer, "| + Frame rate: %f (ignored)\n", video->frame_rate);
MP_DBG(demuxer, "| + Frame rate: %f (ignored)\n", video->frame_rate);
}
if (video->n_display_width) {
track->v_dwidth = video->display_width;
track->v_dwidth_set = true;
MP_VERBOSE(demuxer, "| + Display width: %"PRIu32"\n",
track->v_dwidth);
MP_DBG(demuxer, "| + Display width: %"PRIu32"\n", track->v_dwidth);
}
if (video->n_display_height) {
track->v_dheight = video->display_height;
track->v_dheight_set = true;
MP_VERBOSE(demuxer, "| + Display height: %"PRIu32"\n",
track->v_dheight);
MP_DBG(demuxer, "| + Display height: %"PRIu32"\n", track->v_dheight);
}
if (video->n_pixel_width) {
track->v_width = video->pixel_width;
MP_VERBOSE(demuxer, "| + Pixel width: %"PRIu32"\n", track->v_width);
MP_DBG(demuxer, "| + Pixel width: %"PRIu32"\n", track->v_width);
}
if (video->n_pixel_height) {
track->v_height = video->pixel_height;
MP_VERBOSE(demuxer, "| + Pixel height: %"PRIu32"\n", track->v_height);
MP_DBG(demuxer, "| + Pixel height: %"PRIu32"\n", track->v_height);
}
if (video->n_colour_space && video->colour_space.len == 4) {
uint8_t *d = (uint8_t *)&video->colour_space.start[0];
track->colorspace = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
MP_VERBOSE(demuxer, "| + Colorspace: %#"PRIx32"\n",
track->colorspace);
MP_DBG(demuxer, "| + Colorspace: %#"PRIx32"\n", track->colorspace);
}
if (video->n_stereo_mode) {
const char *name = MP_STEREO3D_NAME(video->stereo_mode);
if (name) {
track->stereo_mode = video->stereo_mode;
MP_VERBOSE(demuxer, "| + StereoMode: %s\n", name);
MP_DBG(demuxer, "| + StereoMode: %s\n", name);
} else {
MP_WARN(demuxer, "Unknown StereoMode: %"PRIu64"\n",
video->stereo_mode);
@@ -668,7 +665,7 @@ static void parse_trackentry(struct demuxer *demuxer,
track->tnum = entry->track_number;
if (track->tnum) {
MP_VERBOSE(demuxer, "| + Track number: %d\n", track->tnum);
MP_DBG(demuxer, "| + Track number: %d\n", track->tnum);
} else {
MP_ERR(demuxer, "Missing track number!\n");
}
@@ -676,39 +673,39 @@ static void parse_trackentry(struct demuxer *demuxer,
if (entry->name) {
track->name = talloc_strdup(track, entry->name);
MP_VERBOSE(demuxer, "| + Name: %s\n", track->name);
MP_DBG(demuxer, "| + Name: %s\n", track->name);
}
track->type = entry->track_type;
MP_VERBOSE(demuxer, "| + Track type: ");
MP_DBG(demuxer, "| + Track type: ");
switch (track->type) {
case MATROSKA_TRACK_AUDIO:
MP_VERBOSE(demuxer, "Audio\n");
MP_DBG(demuxer, "Audio\n");
break;
case MATROSKA_TRACK_VIDEO:
MP_VERBOSE(demuxer, "Video\n");
MP_DBG(demuxer, "Video\n");
break;
case MATROSKA_TRACK_SUBTITLE:
MP_VERBOSE(demuxer, "Subtitle\n");
MP_DBG(demuxer, "Subtitle\n");
break;
default:
MP_VERBOSE(demuxer, "unknown\n");
MP_DBG(demuxer, "unknown\n");
break;
}
if (entry->n_audio) {
MP_VERBOSE(demuxer, "| + Audio track\n");
MP_DBG(demuxer, "| + Audio track\n");
parse_trackaudio(demuxer, track, &entry->audio);
}
if (entry->n_video) {
MP_VERBOSE(demuxer, "| + Video track\n");
MP_DBG(demuxer, "| + Video track\n");
parse_trackvideo(demuxer, track, &entry->video);
}
if (entry->codec_id) {
track->codec_id = talloc_strdup(track, entry->codec_id);
MP_VERBOSE(demuxer, "| + Codec ID: %s\n", track->codec_id);
MP_DBG(demuxer, "| + Codec ID: %s\n", track->codec_id);
} else {
MP_ERR(demuxer, "Missing codec ID!\n");
track->codec_id = "";
@@ -719,36 +716,36 @@ static void parse_trackentry(struct demuxer *demuxer,
track->private_data = talloc_size(track, len + AV_LZO_INPUT_PADDING);
memcpy(track->private_data, entry->codec_private.start, len);
track->private_size = len;
MP_VERBOSE(demuxer, "| + CodecPrivate, length %u\n", track->private_size);
MP_DBG(demuxer, "| + CodecPrivate, length %u\n", track->private_size);
}
if (entry->language) {
track->language = talloc_strdup(track, entry->language);
MP_VERBOSE(demuxer, "| + Language: %s\n", track->language);
MP_DBG(demuxer, "| + Language: %s\n", track->language);
} else {
track->language = talloc_strdup(track, "eng");
}
if (entry->n_flag_default) {
track->default_track = entry->flag_default;
MP_VERBOSE(demuxer, "| + Default flag: %d\n", track->default_track);
MP_DBG(demuxer, "| + Default flag: %d\n", track->default_track);
} else {
track->default_track = 1;
}
if (entry->n_flag_forced) {
track->forced_track = entry->flag_forced;
MP_VERBOSE(demuxer, "| + Forced flag: %d\n", track->forced_track);
MP_DBG(demuxer, "| + Forced flag: %d\n", track->forced_track);
}
if (entry->n_default_duration) {
track->default_duration = entry->default_duration / 1e9;
if (entry->default_duration == 0) {
MP_VERBOSE(demuxer, "| + Default duration: 0");
MP_DBG(demuxer, "| + Default duration: 0");
} else {
track->v_frate = 1e9 / entry->default_duration;
MP_VERBOSE(demuxer, "| + Default duration: %.3fms ( = %.3f fps)\n",
entry->default_duration / 1000000.0, track->v_frate);
MP_DBG(demuxer, "| + Default duration: %.3fms ( = %.3f fps)\n",
entry->default_duration / 1000000.0, track->v_frate);
}
}
@@ -766,7 +763,7 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
stream_t *s = demuxer->stream;
MP_VERBOSE(demuxer, "|+ segment tracks...\n");
MP_DBG(demuxer, "|+ segment tracks...\n");
struct ebml_tracks tracks = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
@@ -776,7 +773,7 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
mkv_d->tracks = talloc_zero_array(mkv_d, struct mkv_track*,
tracks.n_track_entry);
for (int i = 0; i < tracks.n_track_entry; i++) {
MP_VERBOSE(demuxer, "| + a track...\n");
MP_DBG(demuxer, "| + a track...\n");
parse_trackentry(demuxer, &tracks.track_entry[i]);
}
talloc_free(parse_ctx.talloc_ctx);
@@ -895,7 +892,7 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer)
if (wanted_edition_uid)
wanted_edition = -1;
MP_VERBOSE(demuxer, "Parsing chapters...\n");
MP_DBG(demuxer, "Parsing chapters...\n");
struct ebml_chapters file_chapters = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
if (ebml_read_element(s, &parse_ctx, &file_chapters,
@@ -1001,15 +998,15 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer)
chapter.uid.edition = ca->chapter_segment_edition_uid;
else
chapter.uid.edition = 0;
MP_VERBOSE(demuxer, "Chapter segment uid ");
MP_DBG(demuxer, "Chapter segment uid ");
for (int n = 0; n < len; n++)
MP_VERBOSE(demuxer, "%02x ",
MP_DBG(demuxer, "%02x ",
chapter.uid.segment[n]);
MP_VERBOSE(demuxer, "\n");
MP_DBG(demuxer, "\n");
}
}
MP_VERBOSE(demuxer, "Chapter %u from %02d:%02d:%02d.%03d "
MP_DBG(demuxer, "Chapter %u from %02d:%02d:%02d.%03d "
"to %02d:%02d:%02d.%03d, %s\n", i,
(int) (chapter.start / 60 / 60 / 1000000000),
(int) ((chapter.start / 60 / 1000000000) % 60),
@@ -1116,7 +1113,7 @@ static int demux_mkv_read_attachments(demuxer_t *demuxer)
{
stream_t *s = demuxer->stream;
MP_VERBOSE(demuxer, "Parsing attachments...\n");
MP_DBG(demuxer, "Parsing attachments...\n");
struct ebml_attachments attachments = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
@@ -1135,8 +1132,8 @@ static int demux_mkv_read_attachments(demuxer_t *demuxer)
char *mime = attachment->file_mime_type;
demuxer_add_attachment(demuxer, name, mime, attachment->file_data.start,
attachment->file_data.len);
MP_VERBOSE(demuxer, "Attachment: %s, %s, %zu bytes\n",
name, mime, attachment->file_data.len);
MP_DBG(demuxer, "Attachment: %s, %s, %zu bytes\n",
name, mime, attachment->file_data.len);
}
talloc_free(parse_ctx.talloc_ctx);
@@ -1191,7 +1188,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
struct ebml_seek_head seekhead = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
MP_VERBOSE(demuxer, "Parsing seek head...\n");
MP_DBG(demuxer, "Parsing seek head...\n");
if (ebml_read_element(s, &parse_ctx, &seekhead, &ebml_seek_head_desc) < 0) {
res = -1;
goto out;
@@ -1289,7 +1286,6 @@ static void add_coverart(struct demuxer *demuxer)
if (!codec)
continue;
struct sh_stream *sh = demux_alloc_sh_stream(STREAM_VIDEO);
sh->demuxer_id = -1 - sh->index; // don't clash with mkv IDs
sh->codec->codec = codec;
sh->attached_picture = new_demux_packet_from(att->data, att->data_size);
if (sh->attached_picture) {
@@ -1594,7 +1590,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
// The private_data contains a WAVEFORMATEX struct
if (track->private_size < 18)
goto error;
MP_VERBOSE(demuxer, "track with MS compat audio.\n");
MP_DBG(demuxer, "track with MS compat audio.\n");
unsigned char *h = track->private_data;
sh_a->codec_tag = AV_RL16(h + 0); // wFormatTag
if (track->a_channels == 0)
@@ -1957,18 +1953,18 @@ static int read_mkv_segment_header(demuxer_t *demuxer, int64_t *segment_end)
if (demuxer->params)
num_skip = demuxer->params->matroska_wanted_segment;
while (!s->eof) {
while (stream_read_peek(s, &(char){0}, 1)) {
if (ebml_read_id(s) != MATROSKA_ID_SEGMENT) {
MP_VERBOSE(demuxer, "segment not found\n");
return 0;
}
MP_VERBOSE(demuxer, "+ a segment...\n");
MP_DBG(demuxer, "+ a segment...\n");
uint64_t len = ebml_read_length(s);
*segment_end = (len == EBML_UINT_INVALID) ? 0 : stream_tell(s) + len;
if (num_skip <= 0)
return 1;
num_skip--;
MP_VERBOSE(demuxer, " (skipping)\n");
MP_DBG(demuxer, " (skipping)\n");
if (*segment_end <= 0)
break;
if (*segment_end >= stream_get_size(s))
@@ -2002,16 +1998,12 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
if (demuxer->params)
mkv_d->probably_webm_dash_init = demuxer->params->init_fragment.len > 0;
bstr start = stream_peek(s, 4);
uint32_t start_id = 0;
for (int n = 0; n < start.len; n++)
start_id = (start_id << 8) | start.start[n];
if (start_id != EBML_ID_EBML)
// Make sure you can seek back after read_ebml_header() if no EBML ID.
if (stream_read_peek(s, &(char[4]){0}, 4) != 4)
return -1;
if (!read_ebml_header(demuxer))
return -1;
MP_VERBOSE(demuxer, "Found the head...\n");
MP_DBG(demuxer, "Found the head...\n");
if (!read_mkv_segment_header(demuxer, &end_pos))
return -1;
@@ -2030,7 +2022,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
while (1) {
start_pos = stream_tell(s);
stream_peek(s, 4); // make sure we can always seek back
uint32_t id = ebml_read_id(s);
if (s->eof) {
if (!mkv_d->probably_webm_dash_init)
@@ -2038,7 +2029,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
break;
}
if (id == MATROSKA_ID_CLUSTER) {
MP_VERBOSE(demuxer, "|+ found cluster\n");
MP_DBG(demuxer, "|+ found cluster\n");
mkv_d->cluster_start = start_pos;
break;
}
@@ -2145,7 +2136,7 @@ static int demux_mkv_read_block_lacing(struct block_info *block, int type,
uint8_t t;
do {
t = stream_read_char(s);
if (stream_eof(s) || stream_tell(s) >= endpos)
if (s->eof || stream_tell(s) >= endpos)
goto error;
lace_size[i] += t;
} while (t == 0xFF);
@@ -2588,7 +2579,7 @@ static int read_block(demuxer_t *demuxer, int64_t end, struct block_info *block)
exit:
if (res <= 0)
free_block(block);
stream_seek(s, endpos);
stream_seek_skip(s, endpos);
return res;
}
@@ -2839,7 +2830,6 @@ static int read_next_block_into_queue(demuxer_t *demuxer)
find_next_cluster:
mkv_d->cluster_end = 0;
for (;;) {
stream_peek(s, 4); // guarantee we can undo ebml_read_id() below
mkv_d->cluster_start = stream_tell(s);
uint32_t id = ebml_read_id(s);
if (id == MATROSKA_ID_CLUSTER)
@@ -3076,7 +3066,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double seek_pts, int flags)
if (!(flags & SEEK_FACTOR)) { /* time in secs */
mkv_index_t *index = NULL;
seek_pts = FFMAX(seek_pts, 0);
seek_pts = MPMAX(seek_pts, 0);
int64_t target_timecode = seek_pts * 1e9 + 0.5;
if (create_index_until(demuxer, target_timecode) >= 0) {
+6 -3
View File
@@ -172,6 +172,7 @@ static bool check_file_seg(struct tl_ctx *ctx, char *filename, int segment)
.matroska_wanted_segment = segment,
.matroska_was_valid = &was_valid,
.disable_timeline = true,
.stream_flags = ctx->tl->stream_origin,
};
struct mp_cancel *cancel = ctx->tl->cancel;
if (mp_cancel_test(cancel))
@@ -257,8 +258,10 @@ static void find_ordered_chapter_sources(struct tl_ctx *ctx)
playlist_parse_file(opts->ordered_chapters_files,
ctx->tl->cancel, ctx->global);
talloc_steal(tmp, pl);
for (struct playlist_entry *e = pl ? pl->first : NULL; e; e = e->next)
MP_TARRAY_APPEND(tmp, filenames, num_filenames, e->filename);
for (int n = 0; n < pl->num_entries; n++) {
MP_TARRAY_APPEND(tmp, filenames, num_filenames,
pl->entries[n]->filename);
}
} else if (!ctx->demuxer->stream->is_local_file) {
MP_WARN(ctx, "Playback source is not a "
"normal disk file. Will not search for related files.\n");
@@ -515,7 +518,7 @@ void build_ordered_chapter_timeline(struct timeline *tl)
.global = tl->global,
.tl = tl,
.demuxer = demuxer,
.opts = mp_get_config_group(ctx, tl->global, GLOBAL_CONFIG),
.opts = mp_get_config_group(ctx, tl->global, &mp_opt_root),
};
if (!ctx->opts->ordered_chapters || !demuxer->access_references) {
+79 -4
View File
@@ -20,6 +20,8 @@
#include <strings.h>
#include <dirent.h>
#include <libavutil/common.h>
#include "config.h"
#include "common/common.h"
#include "options/options.h"
@@ -60,9 +62,78 @@ struct pl_parser {
char *format;
};
static uint16_t stream_read_word_endian(stream_t *s, bool big_endian)
{
unsigned int y = stream_read_char(s);
y = (y << 8) | stream_read_char(s);
if (!big_endian)
y = ((y >> 8) & 0xFF) | (y << 8);
return y;
}
// Read characters until the next '\n' (including), or until the buffer in s is
// exhausted.
static int read_characters(stream_t *s, uint8_t *dst, int dstsize, int utf16)
{
if (utf16 == 1 || utf16 == 2) {
uint8_t *cur = dst;
while (1) {
if ((cur - dst) + 8 >= dstsize) // PUT_UTF8 writes max. 8 bytes
return -1; // line too long
uint32_t c;
uint8_t tmp;
GET_UTF16(c, stream_read_word_endian(s, utf16 == 2), return -1;)
if (s->eof)
break; // legitimate EOF; ignore the case of partial reads
PUT_UTF8(c, tmp, *cur++ = tmp;)
if (c == '\n')
break;
}
return cur - dst;
} else {
uint8_t buf[1024];
int buf_len = stream_read_peek(s, buf, sizeof(buf));
uint8_t *end = memchr(buf, '\n', buf_len);
int len = end ? end - buf + 1 : buf_len;
if (len > dstsize)
return -1; // line too long
memcpy(dst, buf, len);
stream_seek_skip(s, stream_tell(s) + len);
return len;
}
}
// On error, or if the line is larger than max-1, return NULL and unset s->eof.
// On EOF, return NULL, and s->eof will be set.
// Otherwise, return the line (including \n or \r\n at the end of the line).
// If the return value is non-NULL, it's always the same as mem.
// utf16: 0: UTF8 or 8 bit legacy, 1: UTF16-LE, 2: UTF16-BE
static char *read_line(stream_t *s, char *mem, int max, int utf16)
{
if (max < 1)
return NULL;
int read = 0;
while (1) {
// Reserve 1 byte of ptr for terminating \0.
int l = read_characters(s, &mem[read], max - read - 1, utf16);
if (l < 0 || memchr(&mem[read], '\0', l)) {
MP_WARN(s, "error reading line\n");
return NULL;
}
read += l;
if (l == 0 || (read > 0 && mem[read - 1] == '\n'))
break;
}
mem[read] = '\0';
if (!stream_read_peek(s, &(char){0}, 1) && read == 0) // legitimate EOF
return NULL;
return mem;
}
static char *pl_get_line0(struct pl_parser *p)
{
char *res = stream_read_line(p->s, p->buffer, sizeof(p->buffer), p->utf16);
char *res = read_line(p->s, p->buffer, sizeof(p->buffer), p->utf16);
if (res) {
int len = strlen(res);
if (len > 0 && res[len - 1] == '\n')
@@ -107,7 +178,9 @@ static int parse_m3u(struct pl_parser *p)
// Last resort: if the file extension is m3u, it might be headerless.
if (p->check_level == DEMUX_CHECK_UNSAFE) {
char *ext = mp_splitext(p->real_stream->url, NULL);
bstr data = stream_peek(p->real_stream, PROBE_SIZE);
char probe[PROBE_SIZE];
int len = stream_read_peek(p->real_stream, probe, sizeof(probe));
bstr data = {probe, len};
if (ext && data.len > 10 && maybe_text(data)) {
const char *exts[] = {"m3u", "m3u8", NULL};
for (int n = 0; exts[n]; n++) {
@@ -366,8 +439,9 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
p->real_stream = demuxer->stream;
p->add_base = true;
bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE);
p->s = stream_memory_open(demuxer->global, probe_buf.start, probe_buf.len);
char probe[PROBE_SIZE];
int probe_len = stream_read_peek(p->real_stream, probe, sizeof(probe));
p->s = stream_memory_open(demuxer->global, probe, probe_len);
p->s->mime_type = demuxer->stream->mime_type;
p->utf16 = stream_skip_bom(p->s);
p->force = force;
@@ -388,6 +462,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
bool ok = fmt->parse(p) >= 0 && !p->error;
if (p->add_base)
playlist_add_base_path(p->pl, mp_dirname(demuxer->filename));
playlist_set_stream_flags(p->pl, demuxer->stream_origin);
demuxer->playlist = talloc_steal(demuxer, p->pl);
demuxer->filetype = p->format ? p->format : fmt->name;
demuxer->fully_read = true;
+4 -5
View File
@@ -137,8 +137,8 @@ static int generic_open(struct demuxer *demuxer)
struct stream *s = demuxer->stream;
struct priv *p = demuxer->priv;
int64_t end = 0;
if (stream_control(s, STREAM_CTRL_GET_SIZE, &end) == STREAM_OK)
int64_t end = stream_get_size(s);
if (end >= 0)
demuxer->duration = (end / p->frame_size) / p->frame_rate;
return 0;
@@ -299,8 +299,7 @@ static void raw_seek(demuxer_t *demuxer, double seek_pts, int flags)
{
struct priv *p = demuxer->priv;
stream_t *s = demuxer->stream;
int64_t end = 0;
stream_control(s, STREAM_CTRL_GET_SIZE, &end);
int64_t end = stream_get_size(s);
int64_t frame_nr = seek_pts * p->frame_rate;
frame_nr = frame_nr - (frame_nr % p->read_frames);
int64_t pos = frame_nr * p->frame_size;
@@ -308,7 +307,7 @@ static void raw_seek(demuxer_t *demuxer, double seek_pts, int flags)
pos = end * seek_pts;
if (pos < 0)
pos = 0;
if (end && pos > end)
if (end > 0 && pos > end)
pos = end;
stream_seek(s, (pos / p->frame_size) * p->frame_size);
}
+2 -1
View File
@@ -133,7 +133,7 @@ static void associate_streams(struct demuxer *demuxer,
// Matching by demuxer ID is supposedly useful and preferable for
// ordered chapters.
if (sh->demuxer_id == vs->sh->demuxer_id)
if (sh->demuxer_id >= 0 && sh->demuxer_id == vs->sh->demuxer_id)
other = vs;
}
@@ -212,6 +212,7 @@ static void reopen_lazy_segments(struct demuxer *demuxer,
struct demuxer_params params = {
.init_fragment = src->tl->init_fragment,
.skip_lavf_probing = true,
.stream_flags = demuxer->stream_origin,
};
src->current->d = demux_open_url(src->current->url, &params,
demuxer->cancel, demuxer->global);
+3 -2
View File
@@ -180,14 +180,14 @@ int ebml_read_skip(struct mp_log *log, int64_t end, stream_t *s)
if (len >= INT64_MAX - pos2 || (end > 0 && pos2 + len > end))
goto invalid;
if (!stream_skip(s, len))
if (!stream_seek_skip(s, pos2 + len))
goto invalid;
return 0;
invalid:
mp_err(log, "Invalid EBML length at position %"PRId64"\n", pos);
stream_seek(s, pos);
stream_seek_skip(s, pos);
return 1;
}
@@ -198,6 +198,7 @@ int ebml_resync_cluster(struct mp_log *log, stream_t *s)
{
int64_t pos = stream_tell(s);
uint32_t last_4_bytes = 0;
stream_read_peek(s, &(char){0}, 1);
if (!s->eof) {
mp_err(log, "Corrupt file detected. "
"Trying to resync starting from position %"PRId64"...\n", pos);
+1
View File
@@ -17,6 +17,7 @@ struct timeline *timeline_load(struct mpv_global *global, struct mp_log *log,
.cancel = demuxer->cancel,
.demuxer = demuxer,
.format = "unknown",
.stream_origin = demuxer->stream_origin,
};
demuxer->desc->load_timeline(tl);
+1
View File
@@ -36,6 +36,7 @@ struct timeline {
struct mp_cancel *cancel;
bool is_network, is_streaming;
int stream_origin;
const char *format;
// main source, and all other sources (this usually only has special meaning
+12 -13
View File
@@ -33,13 +33,6 @@ local -a tag_order
zstyle -a ":completion:*:*:$service:*" tag-order tag_order ||
zstyle ":completion:*:*:$service:*" tag-order '!urls'
# Use PCRE for regular expression matching if possible. This approximately
# halves the execution time of generate_arguments compared to the default POSIX
# regex, which translates to a more responsive first tab press. However, we
# can't rely on PCRE being available, so we keep all our patterns
# POSIX-compatible.
setopt re_match_pcre &>/dev/null
typeset -ga _mpv_completion_arguments _mpv_completion_protocols
function generate_arguments {
@@ -51,7 +44,7 @@ function generate_arguments {
local list_options_line
for list_options_line in "${(@f)$($words[1] --list-options)}"; do
[[ $list_options_line =~ '^\s+--(\S+)\s*(.*)' ]] || continue
[[ $list_options_line =~ $'^[ \t]+--([^ \t]+)[ \t]*(.*)' ]] || continue
local name=$match[1] desc=$match[2]
@@ -79,10 +72,10 @@ function generate_arguments {
_mpv_completion_arguments+="$name"
elif [[ $desc =~ '^alias for --(\S+)' ]]; then
elif [[ $desc =~ $'^alias for (--)?([^ \t]+)' ]]; then
# Save this for later; we might not have parsed the target option yet
option_aliases+="$name $match[1]"
option_aliases+="$name $match[2]"
else
@@ -154,7 +147,7 @@ function generate_protocols {
_mpv_completion_protocols=()
local list_protos_line
for list_protos_line in "${(@f)$($words[1] --list-protocols)}"; do
if [[ $list_protos_line =~ '^\s+(.*)' ]]; then
if [[ $list_protos_line =~ $'^[ \t]+(.*)' ]]; then
_mpv_completion_protocols+="$match[1]"
fi
done
@@ -169,6 +162,12 @@ function generate_if_changed {
zmodload -F zsh/stat b:zstat
current_binary+=T$(zstat +mtime $current_binary)
if [[ $_mpv_completion_binary[$1] != $current_binary ]]; then
# Use PCRE for regular expression matching if possible. This approximately
# halves the execution time of generate_arguments compared to the default
# POSIX regex, which translates to a more responsive first tab press.
# However, we can't rely on PCRE being available, so we keep all our
# patterns POSIX-compatible.
zmodload -s -F zsh/pcre C:pcre-match && setopt re_match_pcre
generate_$1
_mpv_completion_binary[$1]=$current_binary
fi
@@ -193,7 +192,7 @@ case $state in
local pattern name_group=1 desc_group=2
case $option_name in
audio-device|vulkan-device)
pattern='^\s+'\''([^'\'']*)'\''\s+\((.*)\)'
pattern=$'^[ \t]+'\''([^'\'']*)'\'$'[ \t]+''\((.*)\)'
;;
profile)
# The generic pattern would actually work in most cases for --profile,
@@ -202,7 +201,7 @@ case $state in
pattern=$'^\t([^\t]*)\t(.*)'
;;
*)
pattern='^\s+(--'${option_name}'=)?(\S+)\s*[-:]?\s*(.*)'
pattern=$'^[ \t]+(--'${option_name}$'=)?([^ \t]+)[ \t]*[-:]?[ \t]*(.*)'
name_group=2 desc_group=3
;;
esac
+9 -2
View File
@@ -26,9 +26,7 @@ input-terminal=no
osc=no
input-default-bindings=no
input-vo-keyboard=no
input-gamepad=no
# OSX/Cocoa global input hooks
input-appleremote=no
input-media-keys=no
[encoding]
@@ -62,6 +60,15 @@ demuxer-lavf-analyzeduration=0.1 # if it probes, reduce it
video-sync=audio # DS currently requires reading ahead a frame
interpolation=no # requires reference frames (more buffering)
video-latency-hacks=yes # typically 1 or 2 video frame less latency
stream-buffer-size=4k # minimal buffer size; normally not needed
[sw-fast]
# For VOs which use software scalers, also affects screenshots and others.
sws-scaler=bilinear
sws-fast=yes
sws-allow-zimg=yes
zimg-scaler=bilinear
zimg-dither=no
# Compatibility alias (deprecated)
[opengl-hq]
+5 -16
View File
@@ -31,6 +31,8 @@
#MBTN_LEFT ignore # don't do anything
#MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen on/off
#MBTN_RIGHT cycle pause # toggle pause on/off
#MBTN_BACK playlist-prev
#MBTN_FORWARD playlist-next
# Mouse wheels, touchpad or other input devices that have axes
# if the input devices supports precise scrolling it will also scale the
@@ -95,6 +97,7 @@
#P show-progress
#i script-binding stats/display-stats
#I script-binding stats/display-stats-toggle
#` script-binding console/enable
#z add sub-delay -0.1 # subtract 100 ms delay from subs
#Z add sub-delay +0.1 # add
#x add sub-delay +0.1 # same as previous binding (discouraged)
@@ -146,6 +149,8 @@
#PLAY cycle pause
#PAUSE cycle pause
#PLAYPAUSE cycle pause
#PLAYONLY set pause no
#PAUSEONLY set pause yes
#STOP quit
#FORWARD seek 60
#REWIND seek -60
@@ -165,22 +170,6 @@
#F8 show_text ${playlist} # show playlist
#F9 show_text ${track-list} # show list of audio/sub streams
# Apple Remote section
#AR_PLAY cycle pause
#AR_PLAY_HOLD quit
#AR_CENTER cycle pause
#AR_CENTER_HOLD quit
#AR_NEXT seek 10
#AR_NEXT_HOLD seek 120
#AR_PREV seek -10
#AR_PREV_HOLD seek -120
#AR_MENU show-progress
#AR_MENU_HOLD cycle mute
#AR_VUP add volume 2
#AR_VUP_HOLD add chapter 1
#AR_VDOWN add volume -2
#AR_VDOWN_HOLD add chapter -1
#
# Legacy bindings (may or may not be removed in the future)
#
-19
View File
@@ -74,25 +74,6 @@ l cycle tv-channel -1
n cycle tv-norm
#b tv_step_chanlist
##
## Apple Remote section
##
## To use OSD menu with Apple Remote, set key AR_MENU to any OSD menu command,
## or just comment out the 'AR_MENU osd' line and uncomment the line after it.
##
AR_PLAY cycle pause
AR_PLAY_HOLD quit
AR_NEXT seek 30
AR_NEXT_HOLD seek 120
AR_PREV seek -10
AR_PREV_HOLD seek -120
#AR_MENU menu up
#AR_MENU menu cancel
AR_MENU_HOLD cycle mute
AR_VUP add volume 1
AR_VDOWN add volume -1
#? add chapter -1 # skip to previous dvd chapter
#? add chapter +1 # next
+112
View File
@@ -0,0 +1,112 @@
#!/bin/bash
#
# This file is part of mpv.
#
# mpv is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# mpv is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with mpv. If not, see <http://www.gnu.org/licenses/>.
#
_mpv_get_args()
{
local doc=$(mpv --list-options | grep -E "^\\s*$1\\s")
local partial="$2"
local type=$(echo "$doc" | awk '{print $2;}')
if [ "$1" = "--show-profile" ]; then
# This is a special case
type="Profile"
fi
declare -a candidates
case $type in
String)
echo "$doc" | grep -q '\[file\]'
if [ $? -eq 0 ]; then
if [ "$cur" = '=' ]; then
# Without this, _filedir will try and complete files starting with '='
cur=""
fi
_filedir
return 0
else
candidates=($(mpv $1=help | grep -v ':' | awk '{print $1;}'))
candidates+=("help")
fi
;;
Flag)
candidates=("yes" "no" "help")
;;
Choices:)
candidates=($(mpv $1=help | grep -v ':' | awk '{print $1;}'))
candidates+=("help")
;;
Image)
candidates=($(mpv $1=help))
candidates=("${candidates[@]:2}")
candidates+=("help")
;;
Profile)
candidates=($(mpv $1= | grep -v ':' | awk '{print $1;}'))
;;
*)
# There are other categories; some of which we could do something smarter
# about, with enough work.
;;
esac
COMPREPLY=($(compgen -W "${candidates[*]}" -- "${partial}"))
if [ ${#COMPREPLY[@]} -gt 1 ]; then
compopt -o nospace mpv
fi
}
_mpv()
{
compopt +o nospace mpv
# _filedir requires the current candidate be in $cur
local cur=${COMP_WORDS[COMP_CWORD]}
local prev=${COMP_WORDS[((COMP_CWORD - 1))]}
if [ "$cur" = '=' ]; then
# If the current word is '=' then we are looking for an argument for the
# option specified by the previous word.
_mpv_get_args "$prev"
elif [ "$prev" = '=' ]; then
# If the previous word is '=' then we are completing an argument for the
# option specified by the word before the '='.
local prevprev=${COMP_WORDS[((COMP_CWORD - 2))]}
_mpv_get_args "$prevprev" "$cur"
else
case $cur in
-*)
# This regex detects special options where we don't want an '=' appended
local special_regex='Flag.*\[not in config files\]|Print'
local options=($(mpv --list-options | grep -v -E "$special_regex" |awk '{print "\\"$1;}' | grep '\--'))
local specials=($(mpv --list-options | grep -E "$special_regex" |awk '{print "\\"$1;}' | grep '\--'))
COMPREPLY=($(compgen -W "${options[*]}" -S '=' -- "${cur}"))
local normal_count=${#COMPREPLY[@]}
COMPREPLY+=($(compgen -W "${specials[*]}" -- "${cur}"))
if [ $normal_count -gt 0 -o ${#COMPREPLY[@]} -gt 1 ]; then
compopt -o nospace mpv
fi
;;
*)
_filedir
;;
esac
fi
}
complete -F _mpv mpv
+5 -70
View File
@@ -59,17 +59,6 @@ static const struct mp_filter_info convert_filter = {
.name = "convert",
};
// For hw decoding: thing which can convert between underlying surface formats.
// The filter detects the needed target format from struct mp_hwdec_ctx.
struct subfmt_conv {
int hw_imgfmt;
struct mp_filter *(*create)(struct mp_filter *parent);
};
static const struct subfmt_conv subfmt_converters[] = {
{0}
};
void mp_autoconvert_clear(struct mp_autoconvert *c)
{
struct priv *p = c->f->priv;
@@ -121,44 +110,6 @@ void mp_autoconvert_add_all_sw_imgfmts(struct mp_autoconvert *c)
}
}
void mp_autoconvert_add_vo_hwdec_subfmts(struct mp_autoconvert *c,
struct mp_hwdec_devices *devs)
{
struct priv *p = c->f->priv;
assert(devs);
int prev_format = 0;
for (int n = 0; ; n++) {
struct mp_hwdec_ctx *ctx = hwdec_devices_get_n(devs, n);
if (!ctx)
break;
if (!ctx->hw_imgfmt || !ctx->supported_formats)
continue;
// Very hacky: don't let d3d11-egl-rgb overwrite d3d11-egl
if (ctx->hw_imgfmt == prev_format)
continue;
prev_format = ctx->hw_imgfmt;
// Stupidity: VOs export imgfmt only, so subfmt is always 0. Remove it
// to fix it up.
for (int i = 0; i < p->num_imgfmts; i++) {
if (p->imgfmts[i] != ctx->hw_imgfmt)
continue;
int count = p->num_imgfmts;
MP_TARRAY_REMOVE_AT(p->imgfmts, count, i);
count = p->num_imgfmts;
MP_TARRAY_REMOVE_AT(p->subfmts, count, i);
p->num_imgfmts -= 1;
break;
}
for (int i = 0; ctx->supported_formats[i]; i++)
mp_autoconvert_add_imgfmt(c, ctx->hw_imgfmt, ctx->supported_formats[i]);
}
p->vo_convert = true;
}
void mp_autoconvert_add_afmt(struct mp_autoconvert *c, int afmt)
{
struct priv *p = c->f->priv;
@@ -198,13 +149,9 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
if (!p->num_imgfmts)
return true;
bool different_subfmt = false;
for (int n = 0; n < p->num_imgfmts; n++) {
bool samefmt = img->params.imgfmt == p->imgfmts[n];
bool samesubffmt = img->params.hw_subfmt == p->subfmts[n];
if (samefmt && !samesubffmt)
different_subfmt = true;
if (samefmt && (samesubffmt || !p->subfmts[n])) {
if (p->imgparams_set) {
if (!mp_image_params_equal(&p->imgparams, &img->params))
@@ -214,8 +161,6 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
}
}
struct mp_stream_info *info = mp_filter_find_stream_info(f);
struct mp_filter *conv = mp_filter_create(f, &convert_filter);
mp_filter_add_pin(conv, MP_PIN_IN, "in");
mp_filter_add_pin(conv, MP_PIN_OUT, "out");
@@ -230,6 +175,7 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
int *fmts = p->imgfmts;
int num_fmts = p->num_imgfmts;
int hwupload_fmt = 0;
bool imgfmt_is_sw = !IMGFMT_IS_HWACCEL(img->imgfmt);
@@ -256,22 +202,11 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
if (upload) {
mp_info(log, "HW-uploading to %s\n", mp_imgfmt_to_name(fmts[0]));
filters[2] = upload->f;
fmts = upload->upload_fmts;
num_fmts = upload->num_upload_fmts;
hwupload_fmt = mp_hwupload_find_upload_format(upload, img->imgfmt);
fmts = &hwupload_fmt;
num_fmts = hwupload_fmt ? 1 : 0;
hw_to_sw = false;
}
} else if (p->vo_convert && different_subfmt && info && info->hwdec_devs) {
for (int n = 0; subfmt_converters[n].hw_imgfmt; n++) {
if (subfmt_converters[n].hw_imgfmt == img->imgfmt) {
mp_info(log, "Using HW sub-conversion.\n");
filters[2] = subfmt_converters[n].create(conv);
if (filters[2]) {
need_sws = false;
hw_to_sw = false;
break;
}
}
}
}
int src_fmt = img->imgfmt;
@@ -309,7 +244,7 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
goto fail;
}
int out = mp_sws_find_best_out_format(src_fmt, fmts, num_fmts);
int out = mp_sws_find_best_out_format(sws, src_fmt, fmts, num_fmts);
if (!out) {
mp_err(log, "can't find video conversion for %s\n",
mp_imgfmt_to_name(src_fmt));
+1 -1
View File
@@ -35,7 +35,7 @@ void mp_autoconvert_set_target_image_params(struct mp_autoconvert *c,
// Each call adds to the list of allowed formats. Before the first call, all
// formats are allowed (even non-video).
// subfmt can be used to specify underlying surface formats for hardware formats,
// otherwise must be 0.
// otherwise must be 0. (Mismatches lead to conversion errors.)
void mp_autoconvert_add_imgfmt(struct mp_autoconvert *c, int imgfmt, int subfmt);
// Add all sw image formats. The effect is that hardware video image formats are
+23 -15
View File
@@ -22,6 +22,7 @@
#include <assert.h>
#include <libavutil/buffer.h>
#include <libavutil/common.h>
#include <libavutil/rational.h>
#include "config.h"
@@ -161,7 +162,7 @@ static void destroy(struct mp_filter *f)
{
struct priv *p = f->priv;
if (p->decoder) {
MP_VERBOSE(f, "Uninit decoder.\n");
MP_DBG(f, "Uninit decoder.\n");
talloc_free(p->decoder->f);
p->decoder = NULL;
}
@@ -660,11 +661,13 @@ static void read_frame(struct priv *p)
if (p->decoded_coverart.type) {
if (p->coverart_returned == 0) {
mp_pin_in_write(pin, mp_frame_ref(p->decoded_coverart));
frame = mp_frame_ref(p->decoded_coverart);
p->coverart_returned = 1;
goto output_frame;
} else if (p->coverart_returned == 1) {
mp_pin_in_write(pin, MP_EOF_FRAME);
frame = MP_EOF_FRAME;
p->coverart_returned = 2;
goto output_frame;
}
return;
}
@@ -772,7 +775,7 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
struct priv *p = f->priv;
struct mp_decoder_wrapper *w = &p->public;
p->opt_cache = m_config_cache_alloc(p, f->global, GLOBAL_CONFIG);
p->opt_cache = m_config_cache_alloc(p, f->global, &mp_opt_root);
p->log = f->log;
p->f = f;
p->header = src;
@@ -814,22 +817,23 @@ error:
return NULL;
}
void lavc_process(struct mp_filter *f, bool *eof_flag,
bool (*send)(struct mp_filter *f, struct demux_packet *pkt),
bool (*receive)(struct mp_filter *f, struct mp_frame *res))
void lavc_process(struct mp_filter *f, struct lavc_state *state,
int (*send)(struct mp_filter *f, struct demux_packet *pkt),
int (*receive)(struct mp_filter *f, struct mp_frame *res))
{
if (!mp_pin_in_needs_data(f->ppins[1]))
return;
struct mp_frame frame = {0};
if (!receive(f, &frame)) {
if (!*eof_flag)
mp_pin_in_write(f->ppins[1], MP_EOF_FRAME);
*eof_flag = true;
} else if (frame.type) {
*eof_flag = false;
int ret_recv = receive(f, &frame);
if (frame.type) {
state->eof_returned = false;
mp_pin_in_write(f->ppins[1], frame);
} else {
} else if (ret_recv == AVERROR_EOF) {
if (!state->eof_returned)
mp_pin_in_write(f->ppins[1], MP_EOF_FRAME);
state->eof_returned = true;
} else if (ret_recv == AVERROR(EAGAIN)) {
// Need to feed a packet.
frame = mp_pin_out_read(f->ppins[0]);
struct demux_packet *pkt = NULL;
@@ -843,7 +847,8 @@ void lavc_process(struct mp_filter *f, bool *eof_flag,
}
return;
}
if (!send(f, pkt)) {
int ret_send = send(f, pkt);
if (ret_send == AVERROR(EAGAIN)) {
// Should never happen, but can happen with broken decoders.
MP_WARN(f, "could not consume packet\n");
mp_pin_out_unread(f->ppins[0], frame);
@@ -852,5 +857,8 @@ void lavc_process(struct mp_filter *f, bool *eof_flag,
}
talloc_free(pkt);
mp_filter_internal_mark_progress(f);
} else {
// Decoding error, or hwdec fallback recovery. Just try again.
mp_filter_internal_mark_progress(f);
}
}
+8 -5
View File
@@ -109,11 +109,14 @@ extern const struct mp_decoder_fns vd_lavc;
extern const struct mp_decoder_fns ad_lavc;
extern const struct mp_decoder_fns ad_spdif;
// Convenience wrapper for lavc based decoders. eof_flag must be set to false
// on init and resets.
void lavc_process(struct mp_filter *f, bool *eof_flag,
bool (*send)(struct mp_filter *f, struct demux_packet *pkt),
bool (*receive)(struct mp_filter *f, struct mp_frame *res));
// Convenience wrapper for lavc based decoders. Treat lavc_state as private;
// init to all-0 on init and resets.
struct lavc_state {
bool eof_returned;
};
void lavc_process(struct mp_filter *f, struct lavc_state *state,
int (*send)(struct mp_filter *f, struct demux_packet *pkt),
int (*receive)(struct mp_filter *f, struct mp_frame *res));
// ad_spdif.c
struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref);
+130 -59
View File
@@ -19,65 +19,92 @@ struct priv {
int last_upload_fmt;
int last_sw_fmt;
// Hardware wrapper format, e.g. IMGFMT_VAAPI.
int hw_imgfmt;
// List of supported underlying surface formats.
int *fmts;
int num_fmts;
// List of supported upload image formats. May contain duplicate entries
// (which should be ignored).
int *upload_fmts;
int num_upload_fmts;
// For fmts[n], fmt_upload_index[n] gives the index of the first supported
// upload format in upload_fmts[], and fmt_upload_num[n] gives the number
// of formats at this position.
int *fmt_upload_index;
int *fmt_upload_num;
struct mp_hwupload public;
};
static bool update_format_decision(struct priv *p, int input_fmt)
{
struct mp_hwupload *u = &p->public;
struct ffmpeg_and_other_bugs {
int imgfmt; // hw format
const int *const whitelist_formats; // if non-NULL, allow only these
// sw formats
bool force_same_upload_fmt; // force upload fmt == sw fmt
};
// This garbage is so complex and buggy. Hardcoding knowledge makes it work,
// trying to use the dynamic information returned by the API does not. So fuck
// this shit, I'll just whitelist the cases that work, what the fuck.
static const struct ffmpeg_and_other_bugs shitlist[] = {
{
.imgfmt = IMGFMT_VAAPI,
.whitelist_formats = (const int[]){IMGFMT_NV12, IMGFMT_P010, IMGFMT_BGRA,
IMGFMT_ABGR, IMGFMT_RGB0, 0},
.force_same_upload_fmt = true,
},
{0}
};
static bool select_format(struct priv *p, int input_fmt, int *out_sw_fmt,
int *out_upload_fmt)
{
if (!input_fmt)
return false;
if (input_fmt == p->last_input_fmt)
return true;
p->last_input_fmt = 0;
int res = mp_imgfmt_select_best_list(u->upload_fmts, u->num_upload_fmts,
input_fmt);
if (!res)
// First find the closest sw fmt. Some hwdec APIs return crazy lists of
// "supported" formats, which then are not supported or crash (???), so
// the this is a good way to avoid problems.
// (Actually we should just have hardcoded everything instead of relying on
// this fragile bullshit FFmpeg API and the fragile bullshit hwdec drivers.)
int sw_fmt = mp_imgfmt_select_best_list(p->fmts, p->num_fmts, input_fmt);
if (!sw_fmt)
return false;
// Find which sw format we should use.
// NOTE: if there are ever any hw APIs that actually do expensive
// conversions on mismatching format uploads, we should probably first look
// which sw format is preferred?
// Dumb, but find index for p->fmts[index]==sw_fmt.
int index = -1;
for (int n = 0; n < u->num_upload_fmts; n++) {
if (u->upload_fmts[n] == res)
for (int n = 0; n < p->num_fmts; n++) {
if (p->fmts[n] == sw_fmt)
index = n;
}
if (index < 0)
return false;
for (int n = 0; n < u->num_fmts; n++) {
if (index >= u->fmt_upload_index[n] &&
index < u->fmt_upload_index[n] + u->fmt_upload_num[n])
{
p->last_input_fmt = input_fmt;
p->last_upload_fmt = u->upload_fmts[index];
p->last_sw_fmt = u->fmts[n];
MP_INFO(u->f, "upload %s -> %s (%s)\n",
mp_imgfmt_to_name(p->last_input_fmt),
mp_imgfmt_to_name(p->last_upload_fmt),
mp_imgfmt_to_name(p->last_sw_fmt));
return true;
}
}
// Now check the available upload formats. This is the format our sw frame
// has to be in, and which the upload API will take (probably).
return false;
int *upload_fmts = &p->upload_fmts[p->fmt_upload_index[index]];
int num_upload_fmts = p->fmt_upload_num[index];
int up_fmt = mp_imgfmt_select_best_list(upload_fmts, num_upload_fmts,
input_fmt);
if (!up_fmt)
return false;
*out_sw_fmt = sw_fmt;
*out_upload_fmt = up_fmt;
return true;
}
int mp_hwupload_find_upload_format(struct mp_hwupload *u, int imgfmt)
{
struct priv *p = u->f->priv;
if (!update_format_decision(p, imgfmt))
return 0;
return p->last_upload_fmt;
int sw = 0, up = 0;
select_format(p, imgfmt, &sw, &up);
return up;
}
static void process(struct mp_filter *f)
@@ -109,14 +136,27 @@ static void process(struct mp_filter *f)
goto error;
}
if (!update_format_decision(p, src->imgfmt)) {
MP_ERR(f, "no hw upload format found\n");
goto error;
if (src->imgfmt != p->last_input_fmt) {
if (!select_format(p, src->imgfmt, &p->last_sw_fmt, &p->last_upload_fmt))
{
MP_ERR(f, "no hw upload format found\n");
goto error;
}
if (src->imgfmt != p->last_upload_fmt) {
// Should not fail; if it does, mp_hwupload_find_upload_format()
// does not return the src->imgfmt format.
MP_ERR(f, "input format not an upload format\n");
goto error;
}
p->last_input_fmt = src->imgfmt;
MP_INFO(f, "upload %s -> %s[%s]\n",
mp_imgfmt_to_name(p->last_input_fmt),
mp_imgfmt_to_name(p->hw_imgfmt),
mp_imgfmt_to_name(p->last_sw_fmt));
}
if (!mp_update_av_hw_frames_pool(&p->hw_pool, p->av_device_ctx,
p->public.hw_imgfmt, p->last_sw_fmt,
src->w, src->h))
if (!mp_update_av_hw_frames_pool(&p->hw_pool, p->av_device_ctx, p->hw_imgfmt,
p->last_sw_fmt, src->w, src->h))
{
MP_ERR(f, "failed to create frame pool\n");
goto error;
@@ -175,9 +215,9 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
{
struct priv *p = u->f->priv;
u->hw_imgfmt = hw_imgfmt;
u->num_fmts = 0;
u->num_upload_fmts = 0;
p->hw_imgfmt = hw_imgfmt;
p->num_fmts = 0;
p->num_upload_fmts = 0;
struct mp_stream_info *info = mp_filter_find_stream_info(u->f);
if (!info || !info->hwdec_devs) {
@@ -221,6 +261,14 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
// supported formats. This should be relatively cheap as we don't create
// any real frames (although some backends do for probing info).
const struct ffmpeg_and_other_bugs *bugs = NULL;
for (int n = 0; shitlist[n].imgfmt; n++) {
if (shitlist[n].imgfmt == hw_imgfmt) {
bugs = &shitlist[n];
break;
}
}
for (int n = 0; cstr->valid_sw_formats &&
cstr->valid_sw_formats[n] != AV_PIX_FMT_NONE; n++)
{
@@ -228,12 +276,28 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
if (!imgfmt)
continue;
MP_VERBOSE(u->f, "looking at format %s\n", mp_imgfmt_to_name(imgfmt));
MP_VERBOSE(u->f, "looking at format %s/%s\n",
mp_imgfmt_to_name(hw_imgfmt),
mp_imgfmt_to_name(imgfmt));
if (bugs && bugs->whitelist_formats) {
bool found = false;
for (int i = 0; bugs->whitelist_formats[i]; i++) {
if (bugs->whitelist_formats[i] == imgfmt) {
found = true;
break;
}
}
if (!found) {
MP_VERBOSE(u->f, "... skipping blacklisted format\n");
continue;
}
}
// Creates an AVHWFramesContexts with the given parameters.
AVBufferRef *frames = NULL;
if (!mp_update_av_hw_frames_pool(&frames, ctx->av_device_ref,
hw_imgfmt, imgfmt, 128, 128))
hw_imgfmt, imgfmt, 128, 128))
{
MP_WARN(u->f, "failed to allocate pool\n");
continue;
@@ -243,24 +307,31 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
if (av_hwframe_transfer_get_formats(frames,
AV_HWFRAME_TRANSFER_DIRECTION_TO, &fmts, 0) >= 0)
{
int index = u->num_fmts;
MP_TARRAY_APPEND(p, u->fmts, u->num_fmts, imgfmt);
MP_TARRAY_GROW(p, u->fmt_upload_index, index);
MP_TARRAY_GROW(p, u->fmt_upload_num, index);
int index = p->num_fmts;
MP_TARRAY_APPEND(p, p->fmts, p->num_fmts, imgfmt);
MP_TARRAY_GROW(p, p->fmt_upload_index, index);
MP_TARRAY_GROW(p, p->fmt_upload_num, index);
u->fmt_upload_index[index] = u->num_upload_fmts;
p->fmt_upload_index[index] = p->num_upload_fmts;
for (int i = 0; fmts[i] != AV_PIX_FMT_NONE; i++) {
int fmt = pixfmt2imgfmt(fmts[i]);
if (!fmt)
continue;
MP_VERBOSE(u->f, "supports %s\n", mp_imgfmt_to_name(fmt));
if (vo_supports(ctx, hw_imgfmt, fmt))
MP_TARRAY_APPEND(p, u->upload_fmts, u->num_upload_fmts, fmt);
MP_VERBOSE(u->f, " supports %s\n", mp_imgfmt_to_name(fmt));
if (bugs && bugs->force_same_upload_fmt && imgfmt != fmt) {
MP_VERBOSE(u->f, " ... skipping blacklisted format\n");
continue;
}
if (!vo_supports(ctx, hw_imgfmt, fmt)) {
MP_VERBOSE(u->f, " ... not supported by VO\n");
continue;
}
MP_TARRAY_APPEND(p, p->upload_fmts, p->num_upload_fmts, fmt);
}
u->fmt_upload_num[index] =
u->num_upload_fmts - u->fmt_upload_index[index];
p->fmt_upload_num[index] =
p->num_upload_fmts - p->fmt_upload_index[index];
av_free(fmts);
}
@@ -272,7 +343,7 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
if (!p->av_device_ctx)
return false;
return u->num_upload_fmts > 0;
return p->num_upload_fmts > 0;
}
struct mp_hwupload *mp_hwupload_create(struct mp_filter *parent, int hw_imgfmt)
-16
View File
@@ -5,22 +5,6 @@
// A filter which uploads sw frames to hw. Ignores hw frames.
struct mp_hwupload {
struct mp_filter *f;
// Hardware wrapper format, e.g. IMGFMT_VAAPI.
int hw_imgfmt;
// List of supported underlying surface formats.
int *fmts;
int num_fmts;
// List of supported upload image formats. May contain duplicate entries
// (which should be ignored).
int *upload_fmts;
int num_upload_fmts;
// For fmts[n], fmt_upload_index[n] gives the index of the first supported
// upload format in upload_fmts[], and fmt_upload_num[n] gives the number
// of formats at this position.
int *fmt_upload_index;
int *fmt_upload_num;
};
struct mp_hwupload *mp_hwupload_create(struct mp_filter *parent, int hw_imgfmt);
+41
View File
@@ -117,6 +117,7 @@ struct lavfi_pad {
AVFilterContext *buffer;
AVRational timebase;
bool buffer_is_eof; // received/sent EOF to the buffer
bool got_eagain;
struct mp_tags *metadata;
@@ -140,6 +141,7 @@ static void free_graph(struct lavfi *c)
pad->buffer = NULL;
mp_frame_unref(&pad->in_fmt);
pad->buffer_is_eof = false;
pad->got_eagain = false;
}
c->initialized = false;
c->draining_recover = false;
@@ -643,6 +645,9 @@ static bool feed_input_pads(struct lavfi *c)
MP_FATAL(c, "could not pass frame to filter\n");
av_frame_free(&frame);
for (int i = 0; i < c->num_out_pads; i++)
c->out_pads[i]->got_eagain = false;
progress = true;
}
@@ -652,6 +657,26 @@ static bool feed_input_pads(struct lavfi *c)
return progress;
}
// Some filters get stuck and return EAGAIN forever if they did not get any
// input (i.e. we send only EOF as input). "dynaudnorm" is known to be affected.
static bool check_stuck_eagain_on_eof_bug(struct lavfi *c)
{
for (int n = 0; n < c->num_in_pads; n++) {
if (!c->in_pads[n]->buffer_is_eof)
return false;
}
for (int n = 0; n < c->num_out_pads; n++) {
struct lavfi_pad *pad = c->out_pads[n];
if (!pad->buffer_is_eof && !pad->got_eagain)
return false;
}
MP_WARN(c, "Filter is stuck. This is a FFmpeg bug. Treating as EOF.\n");
return true;
}
static bool read_output_pads(struct lavfi *c)
{
bool progress = false;
@@ -669,6 +694,16 @@ static bool read_output_pads(struct lavfi *c)
int r = AVERROR_EOF;
if (!pad->buffer_is_eof)
r = av_buffersink_get_frame_flags(pad->buffer, c->tmp_frame, 0);
pad->got_eagain = r == AVERROR(EAGAIN);
if (pad->got_eagain) {
if (check_stuck_eagain_on_eof_bug(c))
r = AVERROR_EOF;
} else {
for (int i = 0; i < c->num_out_pads; i++)
c->out_pads[i]->got_eagain = false;
}
if (r >= 0) {
#if LIBAVUTIL_VERSION_MICRO >= 100
mp_tags_copy_from_av_dictionary(pad->metadata, c->tmp_frame->metadata);
@@ -941,6 +976,12 @@ static bool is_usable(const AVFilter *filter, int media_type)
is_single_media_only(filter->outputs, media_type);
}
bool mp_lavfi_is_usable(const char *name, int media_type)
{
const AVFilter *f = avfilter_get_by_name(name);
return f && is_usable(f, media_type);
}
static void dump_list(struct mp_log *log, int media_type)
{
mp_info(log, "Available libavfilter filters:\n");
+3
View File
@@ -34,3 +34,6 @@ void print_lavfi_help_list(struct mp_log *log, int media_type);
// Print libavfilter help for the given filter
void print_lavfi_help(struct mp_log *log, const char *name, int media_type);
// Return whether the given filter exists and has the required media_type in/outs.
bool mp_lavfi_is_usable(const char *name, int media_type);
+2 -31
View File
@@ -88,9 +88,6 @@ static void update_output_caps(struct chain *p)
if (allowed_output_formats[n])
mp_autoconvert_add_imgfmt(p->convert, IMGFMT_START + n, 0);
}
if (p->vo->hwdec_devs)
mp_autoconvert_add_vo_hwdec_subfmts(p->convert, p->vo->hwdec_devs);
}
}
@@ -504,33 +501,6 @@ double mp_output_get_measured_total_delay(struct mp_output_chain *c)
return delay;
}
static bool compare_filter(struct m_obj_settings *a, struct m_obj_settings *b)
{
if (a == b || !a || !b)
return a == b;
if (!a->name || !b->name)
return a->name == b->name;
if (!!a->label != !!b->label || (a->label && strcmp(a->label, b->label) != 0))
return false;
if (a->enabled != b->enabled)
return false;
if (!a->attribs || !a->attribs[0])
return !b->attribs || !b->attribs[0];
for (int n = 0; a->attribs[n] || b->attribs[n]; n++) {
if (!a->attribs[n] || !b->attribs[n])
return false;
if (strcmp(a->attribs[n], b->attribs[n]) != 0)
return false;
}
return true;
}
bool mp_output_chain_update_filters(struct mp_output_chain *c,
struct m_obj_settings *list)
{
@@ -551,7 +521,8 @@ bool mp_output_chain_update_filters(struct mp_output_chain *c,
struct mp_user_filter *u = NULL;
for (int i = 0; i < p->num_user_filters; i++) {
if (!used[i] && compare_filter(entry, p->user_filters[i]->args)) {
if (!used[i] && m_obj_settings_equal(entry, p->user_filters[i]->args))
{
u = p->user_filters[i];
used[i] = true;
break;
+4 -9
View File
@@ -40,17 +40,14 @@
#include "filter.h"
#include "filter_internal.h"
int mp_sws_find_best_out_format(int in_format, int *out_formats,
int num_out_formats)
int mp_sws_find_best_out_format(struct mp_sws_filter *sws, int in_format,
int *out_formats, int num_out_formats)
{
if (sws_isSupportedInput(imgfmt2pixfmt(in_format)) < 1)
return 0;
int best = 0;
for (int n = 0; n < num_out_formats; n++) {
int out_format = out_formats[n];
if (sws_isSupportedOutput(imgfmt2pixfmt(out_format)) < 1)
if (!mp_sws_supports_formats(sws->sws, out_format, in_format))
continue;
if (best) {
@@ -151,10 +148,8 @@ struct mp_sws_filter *mp_sws_filter_create(struct mp_filter *parent)
s->f = f;
s->sws = mp_sws_alloc(s);
s->sws->log = f->log;
mp_sws_enable_cmdline_opts(s->sws, f->global);
s->pool = mp_image_pool_new(s);
s->sws->allow_zimg = true;
mp_sws_set_from_cmdline(s->sws, f->global);
return s;
}
+2 -1
View File
@@ -23,7 +23,8 @@ struct mp_sws_filter *mp_sws_filter_create(struct mp_filter *parent);
// formats. This tries to set the output format to the one that will result in
// the least loss. Returns a format from out_formats[], or 0 if no format could
// be chosen (or it's not supported by libswscale).
int mp_sws_find_best_out_format(int in_format, int *out_formats,
int mp_sws_find_best_out_format(struct mp_sws_filter *sws,
int in_format, int *out_formats,
int num_out_formats);
// Whether the given format is supported as input format.
+23
View File
@@ -20,6 +20,14 @@ static bool get_desc_from(const struct mp_user_filter_entry **list, int num,
return true;
}
static bool check_unknown_entry(const char *name, int media_type)
{
// Generic lavfi bridge: skip the lavfi- prefix, if present.
if (strncmp(name, "lavfi-", 6) == 0)
name += 6;
return mp_lavfi_is_usable(name, media_type);
}
// --af option
const struct mp_user_filter_entry *af_list[] = {
@@ -48,11 +56,17 @@ static void print_af_lavfi_help(struct mp_log *log, const char *name)
print_lavfi_help(log, name, AVMEDIA_TYPE_AUDIO);
}
static bool check_af_lavfi(const char *name)
{
return check_unknown_entry(name, AVMEDIA_TYPE_AUDIO);
}
const struct m_obj_list af_obj_list = {
.get_desc = get_af_desc,
.description = "audio filters",
.allow_disable_entries = true,
.allow_unknown_entries = true,
.check_unknown_entry = check_af_lavfi,
.print_help_list = print_af_help_list,
.print_unknown_entry_help = print_af_lavfi_help,
};
@@ -79,6 +93,9 @@ const struct mp_user_filter_entry *vf_list[] = {
#if HAVE_D3D_HWACCEL
&vf_d3d11vpp,
#endif
#if HAVE_EGL_HELPERS && HAVE_GL && HAVE_EGL
&vf_gpu,
#endif
};
static bool get_vf_desc(struct m_obj_desc *dst, int index)
@@ -96,11 +113,17 @@ static void print_vf_lavfi_help(struct mp_log *log, const char *name)
print_lavfi_help(log, name, AVMEDIA_TYPE_VIDEO);
}
static bool check_vf_lavfi(const char *name)
{
return check_unknown_entry(name, AVMEDIA_TYPE_VIDEO);
}
const struct m_obj_list vf_obj_list = {
.get_desc = get_vf_desc,
.description = "video filters",
.allow_disable_entries = true,
.allow_unknown_entries = true,
.check_unknown_entry = check_vf_lavfi,
.print_help_list = print_vf_help_list,
.print_unknown_entry_help = print_vf_lavfi_help,
};
+1
View File
@@ -34,3 +34,4 @@ extern const struct mp_user_filter_entry vf_vdpaupp;
extern const struct mp_user_filter_entry vf_vavpp;
extern const struct mp_user_filter_entry vf_d3d11vpp;
extern const struct mp_user_filter_entry vf_fingerprint;
extern const struct mp_user_filter_entry vf_gpu;
+30 -4
View File
@@ -25,6 +25,7 @@
#include "cmd.h"
#include "input.h"
#include "misc/json.h"
#include "libmpv/client.h"
@@ -413,7 +414,7 @@ static struct mp_cmd *parse_cmd_str(struct mp_log *log, void *tmp,
}
bstr orig = {ctx->start.start, ctx->str.start - ctx->start.start};
cmd->original = bstrdup(cmd, bstr_strip(orig));
cmd->original = bstrto0(cmd, bstr_strip(orig));
*str = ctx->str;
return cmd;
@@ -449,7 +450,6 @@ mp_cmd_t *mp_input_parse_cmd_str(struct mp_log *log, bstr str, const char *loc)
*list = (struct mp_cmd) {
.name = (char *)mp_cmd_list.name,
.def = &mp_cmd_list,
.original = bstrdup(list, original),
};
talloc_steal(list, cmd);
struct mp_cmd_arg arg = {0};
@@ -469,6 +469,16 @@ mp_cmd_t *mp_input_parse_cmd_str(struct mp_log *log, bstr str, const char *loc)
p_prev = &sub->queue_next;
}
cmd->original = bstrto0(cmd, bstr_strip(
bstr_splice(original, 0, str.start - original.start)));
str = bstr_strip(str);
if (bstr_eatstart0(&str, "#") && !bstr_startswith0(str, "#")) {
str = bstr_strip(str);
if (str.len)
cmd->desc = bstrto0(cmd, str);
}
done:
talloc_free(tmp);
return cmd;
@@ -509,8 +519,11 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
ret->args[i].type = cmd->args[i].type;
m_option_copy(ret->args[i].type, &ret->args[i].v, &cmd->args[i].v);
}
ret->original = bstrdup(ret, cmd->original);
ret->original = talloc_strdup(ret, cmd->original);
ret->desc = talloc_strdup(ret, cmd->desc);
ret->sender = NULL;
ret->key_name = talloc_strdup(ret, ret->key_name);
ret->key_text = talloc_strdup(ret, ret->key_text);
if (cmd->def == &mp_cmd_list) {
struct mp_cmd *prev = NULL;
@@ -546,7 +559,14 @@ void mp_cmd_dump(struct mp_log *log, int msgl, char *header, struct mp_cmd *cmd)
char *s = m_option_print(cmd->args[n].type, &cmd->args[n].v);
if (n)
mp_msg(log, msgl, ", ");
mp_msg(log, msgl, "%s", s ? s : "(NULL)");
struct mpv_node node = {
.format = MPV_FORMAT_STRING,
.u.string = s ? s : "(NULL)",
};
char *esc = NULL;
json_write(&esc, &node);
mp_msg(log, msgl, "%s", esc ? esc : "<error>");
talloc_free(esc);
talloc_free(s);
}
mp_msg(log, msgl, "]\n");
@@ -595,6 +615,11 @@ static int parse_cycle_dir(struct mp_log *log, const struct m_option *opt,
return 1;
}
static char *print_cycle_dir(const m_option_t *opt, const void *val)
{
return talloc_asprintf(NULL, "%f", *(double *)val);
}
static void copy_opt(const m_option_t *opt, void *dst, const void *src)
{
if (dst && src)
@@ -604,6 +629,7 @@ static void copy_opt(const m_option_t *opt, void *dst, const void *src)
const struct m_option_type m_option_type_cycle_dir = {
.name = "up|down",
.parse = parse_cycle_dir,
.print = print_cycle_dir,
.copy = copy_opt,
.size = sizeof(double),
};
+4 -1
View File
@@ -40,6 +40,7 @@ struct mp_cmd_def {
bool vararg; // last argument can be given 0 to multiple times
bool scalable;
bool is_ignore;
bool is_noisy; // reduce log level
bool default_async; // default to MP_ASYNC flag if none set by user
// If you set this, handler() must ensure mp_cmd_ctx_complete() is called
// at some point (can be after handler() returns). If you don't set it, the
@@ -99,7 +100,8 @@ typedef struct mp_cmd {
struct mp_cmd_arg *args;
int nargs;
int flags; // mp_cmd_flags bitfield
bstr original;
char *original;
char *desc; // (usually NULL since stripped away later)
char *input_section;
bool is_up_down : 1;
bool is_up : 1;
@@ -114,6 +116,7 @@ typedef struct mp_cmd {
const struct mp_cmd_def *def;
char *sender; // name of the client API user which sent this
char *key_name; // string representation of the key binding
char *key_text; // text if key is a text key
} mp_cmd_t;
extern const struct mp_cmd_def mp_cmds[];
+111 -59
View File
@@ -31,9 +31,6 @@
#include <pthread.h>
#include <assert.h>
#include <libavutil/avstring.h>
#include <libavutil/common.h>
#include "osdep/io.h"
#include "misc/rendezvous.h"
@@ -49,6 +46,7 @@
#include "mpv_talloc.h"
#include "options/options.h"
#include "misc/bstr.h"
#include "misc/node.h"
#include "stream/stream.h"
#include "common/common.h"
@@ -66,6 +64,7 @@ struct cmd_bind {
int num_keys;
char *cmd;
char *location; // filename/line number of definition
char *desc; // human readable description
bool is_builtin;
struct cmd_bind_section *owner;
};
@@ -77,7 +76,6 @@ struct cmd_bind_section {
char *section;
struct mp_rect mouse_area; // set at runtime, if at all
bool mouse_area_set; // mouse_area is valid and should be tested
struct cmd_bind_section *next;
};
#define MP_MAX_SOURCES 10
@@ -140,7 +138,8 @@ struct input_ctx {
double last_wheel_time; // mp_time_sec() of the last wheel event
// List of command binding sections
struct cmd_bind_section *cmd_bind_sections;
struct cmd_bind_section **sections;
int num_sections;
// List currently active command sections
struct active_section active_sections[MAX_ACTIVE_SECTIONS];
@@ -184,7 +183,7 @@ struct input_opts {
const struct m_sub_options input_config = {
.opts = (const m_option_t[]) {
OPT_STRING("input-conf", config_file, M_OPT_FIXED | M_OPT_FILE),
OPT_STRING("input-conf", config_file, 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),
@@ -197,14 +196,14 @@ const struct m_sub_options input_config = {
OPT_FLAG("input-cursor", enable_mouse_movements, 0),
OPT_FLAG("input-vo-keyboard", vo_key_input, 0),
OPT_FLAG("input-media-keys", use_media_keys, 0),
#if HAVE_COCOA
OPT_FLAG("input-appleremote", use_appleremote, 0),
#endif
#if HAVE_SDL2_GAMEPAD
OPT_FLAG("input-gamepad", use_gamepad, 0),
#endif
OPT_FLAG("window-dragging", allow_win_drag, 0),
OPT_REPLACED("input-x11-keyboard", "input-vo-keyboard"),
#if HAVE_COCOA
OPT_REMOVED("input-appleremote", "replaced by MediaPlayer support"),
#endif
{0}
},
.size = sizeof(struct input_opts),
@@ -216,12 +215,6 @@ const struct m_sub_options input_config = {
.use_alt_gr = 1,
.enable_mouse_movements = 1,
.use_media_keys = 1,
#if HAVE_COCOA
.use_appleremote = 1,
#endif
#if HAVE_SDL2_GAMEPAD
.use_gamepad = 1,
#endif
.default_bindings = 1,
.vo_key_input = 1,
.allow_win_drag = 1,
@@ -288,8 +281,8 @@ static void append_bind_info(struct input_ctx *ictx, char **pmsg,
char *msg = *pmsg;
struct mp_cmd *cmd = mp_input_parse_cmd(ictx, bstr0(bind->cmd),
bind->location);
bstr stripped = cmd ? cmd->original : bstr0(bind->cmd);
msg = talloc_asprintf_append(msg, " '%.*s'", BSTR_P(stripped));
char *stripped = cmd ? cmd->original : bind->cmd;
msg = talloc_asprintf_append(msg, " '%s'", stripped);
if (!cmd)
msg = talloc_asprintf_append(msg, " (invalid)");
if (strcmp(bind->owner->section, "default") != 0)
@@ -318,9 +311,9 @@ static mp_cmd_t *handle_test(struct input_ctx *ictx, int code)
talloc_free(key_buf);
int count = 0;
for (struct cmd_bind_section *bs = ictx->cmd_bind_sections;
bs; bs = bs->next)
{
for (int n = 0; n < ictx->num_sections; n++) {
struct cmd_bind_section *bs = ictx->sections[n];
for (int i = 0; i < bs->num_binds; i++) {
if (bs->binds[i].num_keys && bs->binds[i].keys[0] == code) {
count++;
@@ -342,32 +335,32 @@ static mp_cmd_t *handle_test(struct input_ctx *ictx, int code)
return res;
}
static struct cmd_bind_section *find_section(struct input_ctx *ictx,
bstr section)
{
for (int n = 0; n < ictx->num_sections; n++) {
struct cmd_bind_section *bs = ictx->sections[n];
if (bstr_equals0(section, bs->section))
return bs;
}
return NULL;
}
static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx,
bstr section)
{
struct cmd_bind_section *bind_section = ictx->cmd_bind_sections;
if (section.len == 0)
section = bstr0("default");
while (bind_section) {
if (bstrcmp0(section, bind_section->section) == 0)
return bind_section;
if (bind_section->next == NULL)
break;
bind_section = bind_section->next;
}
if (bind_section) {
bind_section->next = talloc_ptrtype(ictx, bind_section->next);
bind_section = bind_section->next;
} else {
ictx->cmd_bind_sections = talloc_ptrtype(ictx, ictx->cmd_bind_sections);
bind_section = ictx->cmd_bind_sections;
}
struct cmd_bind_section *bind_section = find_section(ictx, section);
if (bind_section)
return bind_section;
bind_section = talloc_ptrtype(ictx, bind_section);
*bind_section = (struct cmd_bind_section) {
.section = bstrdup0(bind_section, section),
.mouse_area = {INT_MIN, INT_MIN, INT_MAX, INT_MAX},
.mouse_area_set = true,
};
MP_TARRAY_APPEND(ictx, ictx->sections, ictx->num_sections, bind_section);
return bind_section;
}
@@ -462,7 +455,12 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, char *force_section,
if (ictx->opts->test)
return handle_test(ictx, code);
struct cmd_bind *cmd = find_any_bind_for_key(ictx, force_section, code);
struct cmd_bind *cmd = NULL;
if (MP_KEY_IS_UNICODE(code))
cmd = find_any_bind_for_key(ictx, force_section, MP_KEY_ANY_UNICODE);
if (!cmd)
cmd = find_any_bind_for_key(ictx, force_section, code);
if (!cmd)
cmd = find_any_bind_for_key(ictx, force_section, MP_KEY_UNMAPPED);
if (!cmd) {
@@ -482,6 +480,11 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, char *force_section,
ret->key_name = talloc_steal(ret, mp_input_get_key_combo_name(&code, 1));
MP_TRACE(ictx, "key '%s' -> '%s' in '%s'\n",
ret->key_name, cmd->cmd, ret->input_section);
if (MP_KEY_IS_UNICODE(code)) {
bstr text = {0};
mp_append_utf8_bstr(ret, &text, code);
ret->key_text = text.start;
}
ret->is_mouse_button = code & MP_KEY_EMIT_ON_UP;
} else {
char *key_buf = mp_input_get_key_combo_name(&code, 1);
@@ -559,7 +562,7 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale,
int state = code & (MP_KEY_STATE_DOWN | MP_KEY_STATE_UP);
code = code & ~(unsigned)state;
if (mp_msg_test(ictx->log, MSGL_DEBUG)) {
if (mp_msg_test(ictx->log, MSGL_TRACE)) {
char *key = mp_input_get_key_name(code);
MP_TRACE(ictx, "key code=%#x '%s'%s%s\n",
code, key, (state & MP_KEY_STATE_DOWN) ? " down" : "",
@@ -626,7 +629,7 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale,
cmd->scale = 1;
cmd->scale_units = 1;
// Avoid spamming the player with too many commands
scale_units = FFMIN(scale_units, 20);
scale_units = MPMIN(scale_units, 20);
for (int i = 0; i < scale_units - 1; i++)
mp_input_queue_cmd(ictx, mp_cmd_clone(cmd));
if (scale_units)
@@ -880,8 +883,8 @@ static void adjust_max_wait_time(struct input_ctx *ictx, double *time)
{
struct input_opts *opts = ictx->opts;
if (ictx->last_key_down && opts->ar_rate > 0 && ictx->ar_state >= 0) {
*time = FFMIN(*time, 1.0 / opts->ar_rate);
*time = FFMIN(*time, opts->ar_delay / 1000.0);
*time = MPMIN(*time, 1.0 / opts->ar_rate);
*time = MPMIN(*time, opts->ar_delay / 1000.0);
}
}
@@ -1076,6 +1079,7 @@ static void bind_dealloc(struct cmd_bind *bind)
{
talloc_free(bind->cmd);
talloc_free(bind->location);
talloc_free(bind->desc);
}
// builtin: if true, remove all builtin binds, else remove all user binds
@@ -1119,14 +1123,13 @@ void mp_input_define_section(struct input_ctx *ictx, char *name, char *location,
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) {
for (int n = 0; n < ictx->num_sections; n++) {
struct cmd_bind_section *bs = ictx->sections[n];
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);
}
@@ -1144,7 +1147,7 @@ static bool bind_matches_key(struct cmd_bind *bind, int num_keys, const int *key
static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section,
const int *keys, int num_keys, bstr command,
const char *loc)
const char *loc, const char *desc)
{
struct cmd_bind_section *bs = get_bind_section(ictx, section);
struct cmd_bind *bind = NULL;
@@ -1170,6 +1173,7 @@ static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section,
*bind = (struct cmd_bind) {
.cmd = bstrdup0(bs->binds, command),
.location = talloc_strdup(bs->binds, loc),
.desc = talloc_strdup(bs->binds, desc),
.owner = bs,
.is_builtin = builtin,
.num_keys = num_keys,
@@ -1245,11 +1249,18 @@ static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
}
}
bind_keys(ictx, builtin, section, keys, num_keys, command, cur_loc);
// Print warnings if invalid commands are encountered.
struct mp_cmd *cmd = mp_input_parse_cmd(ictx, command, cur_loc);
const char *desc = NULL;
if (cmd) {
desc = cmd->desc;
command = bstr0(cmd->original);
}
bind_keys(ictx, builtin, section, keys, num_keys, command, cur_loc, desc);
n_binds++;
// Print warnings if invalid commands are encountered.
talloc_free(mp_input_parse_cmd(ictx, command, cur_loc));
talloc_free(cmd);
}
talloc_free(cur_loc);
@@ -1265,7 +1276,7 @@ static int parse_config_file(struct input_ctx *ictx, char *file, bool warn)
file = mp_get_user_path(tmp, ictx->global, file);
s = stream_open(file, ictx->global);
s = stream_create(file, STREAM_ORIGIN_DIRECT | STREAM_READ, NULL, ictx->global);
if (!s) {
MP_ERR(ictx, "Can't open input config file %s.\n", file);
goto done;
@@ -1321,15 +1332,6 @@ static void reload_opts(struct input_ctx *ictx, bool shutdown)
#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) {
@@ -1447,7 +1449,7 @@ void mp_input_run_cmd(struct input_ctx *ictx, const char **cmd)
void mp_input_bind_key(struct input_ctx *ictx, int key, bstr command)
{
struct cmd_bind_section *bs = ictx->cmd_bind_sections;
struct cmd_bind_section *bs = get_bind_section(ictx, (bstr){0});
struct cmd_bind *bind = NULL;
for (int n = 0; n < bs->num_binds; n++) {
@@ -1483,6 +1485,56 @@ void mp_input_bind_key(struct input_ctx *ictx, int key, bstr command)
}
}
struct mpv_node mp_input_get_bindings(struct input_ctx *ictx)
{
input_lock(ictx);
struct mpv_node root;
node_init(&root, MPV_FORMAT_NODE_ARRAY, NULL);
for (int x = 0; x < ictx->num_sections; x++) {
struct cmd_bind_section *s = ictx->sections[x];
int priority = -1;
for (int i = 0; i < ictx->num_active_sections; i++) {
struct active_section *as = &ictx->active_sections[i];
if (strcmp(as->name, s->section) == 0) {
priority = i;
break;
}
}
for (int n = 0; n < s->num_binds; n++) {
struct cmd_bind *b = &s->binds[n];
struct mpv_node *entry = node_array_add(&root, MPV_FORMAT_NODE_MAP);
int b_priority = priority;
if (b->is_builtin && !ictx->opts->default_bindings)
b_priority = -1;
// Try to fixup the weird logic so consumer of this bindings list
// does not get too confused.
if (b_priority >= 0 && !b->is_builtin)
b_priority += ictx->num_active_sections;
node_map_add_string(entry, "section", s->section);
if (s->owner)
node_map_add_string(entry, "owner", s->owner);
node_map_add_string(entry, "cmd", b->cmd);
node_map_add_flag(entry, "is_weak", b->is_builtin);
node_map_add_int64(entry, "priority", b_priority);
if (b->desc)
node_map_add_string(entry, "comment", b->desc);
char *key = mp_input_get_key_combo_name(b->keys, b->num_keys);
node_map_add_string(entry, "key", key);
talloc_free(key);
}
}
input_unlock(ictx);
return root;
}
struct mp_input_src_internal {
pthread_t thread;
bool thread_running;
+2 -3
View File
@@ -23,9 +23,6 @@
#include "cmd.h"
// For mp_input_put_key(): release all keys that are down.
#define MP_INPUT_RELEASE_ALL -1
struct input_ctx;
struct mp_log;
@@ -208,6 +205,8 @@ void mp_input_bind_key(struct input_ctx *ictx, int key, bstr command);
void mp_input_set_repeat_info(struct input_ctx *ictx, int rate, int delay);
struct mpv_node mp_input_get_bindings(struct input_ctx *ictx);
void mp_input_pipe_add(struct input_ctx *ictx, const char *filename);
void mp_input_sdl_gamepad_add(struct input_ctx *ictx);
+1 -1
View File
@@ -387,7 +387,7 @@ done:
struct mp_ipc_ctx *mp_init_ipc(struct mp_client_api *client_api,
struct mpv_global *global)
{
struct MPOpts *opts = mp_get_config_group(NULL, global, GLOBAL_CONFIG);
struct MPOpts *opts = mp_get_config_group(NULL, global, &mp_opt_root);
struct mp_ipc_ctx *arg = talloc_ptrtype(NULL, arg);
*arg = (struct mp_ipc_ctx){
+1 -1
View File
@@ -450,7 +450,7 @@ done:
struct mp_ipc_ctx *mp_init_ipc(struct mp_client_api *client_api,
struct mpv_global *global)
{
struct MPOpts *opts = mp_get_config_group(NULL, global, GLOBAL_CONFIG);
struct MPOpts *opts = mp_get_config_group(NULL, global, &mp_opt_root);
struct mp_ipc_ctx *arg = talloc_ptrtype(NULL, arg);
*arg = (struct mp_ipc_ctx){
+4 -17
View File
@@ -102,21 +102,6 @@ static const struct key_name key_names[] = {
{ MP_MBTN_MID_DBL, "MBTN_MID_DBL" },
{ MP_MBTN_RIGHT_DBL, "MBTN_RIGHT_DBL" },
{ MP_AR_PLAY, "AR_PLAY" },
{ MP_AR_PLAY_HOLD, "AR_PLAY_HOLD" },
{ MP_AR_CENTER, "AR_CENTER" },
{ MP_AR_CENTER_HOLD, "AR_CENTER_HOLD" },
{ MP_AR_NEXT, "AR_NEXT" },
{ MP_AR_NEXT_HOLD, "AR_NEXT_HOLD" },
{ MP_AR_PREV, "AR_PREV" },
{ MP_AR_PREV_HOLD, "AR_PREV_HOLD" },
{ MP_AR_MENU, "AR_MENU" },
{ MP_AR_MENU_HOLD, "AR_MENU_HOLD" },
{ MP_AR_VUP, "AR_VUP" },
{ MP_AR_VUP_HOLD, "AR_VUP_HOLD" },
{ MP_AR_VDOWN, "AR_VDOWN" },
{ MP_AR_VDOWN_HOLD, "AR_VDOWN_HOLD" },
{ MP_KEY_GAMEPAD_ACTION_DOWN, "GAMEPAD_ACTION_DOWN" },
{ MP_KEY_GAMEPAD_ACTION_RIGHT, "GAMEPAD_ACTION_RIGHT" },
{ MP_KEY_GAMEPAD_ACTION_LEFT, "GAMEPAD_ACTION_LEFT" },
@@ -166,6 +151,8 @@ static const struct key_name key_names[] = {
{ MP_KEY_RECORD, "RECORD" },
{ MP_KEY_CHANNEL_UP, "CHANNEL_UP" },
{ MP_KEY_CHANNEL_DOWN,"CHANNEL_DOWN" },
{ MP_KEY_PLAYONLY, "PLAYONLY" },
{ MP_KEY_PAUSEONLY, "PAUSEONLY" },
// These are kept for backward compatibility
{ MP_KEY_PAUSE, "XF86_PAUSE" },
@@ -208,6 +195,7 @@ static const struct key_name key_names[] = {
{ MP_KEY_MOUSE_ENTER, "MOUSE_ENTER" },
{ MP_KEY_UNMAPPED, "UNMAPPED" },
{ MP_KEY_ANY_UNICODE, "ANY_UNICODE" },
{ 0, NULL }
};
@@ -271,8 +259,7 @@ static void mp_input_append_key_name(bstr *buf, int key)
}
}
// printable, and valid unicode range
if (key >= 32 && key <= 0x10FFFF) {
if (MP_KEY_IS_UNICODE(key)) {
mp_append_utf8_bstr(NULL, buf, key);
return;
}
+10 -18
View File
@@ -22,6 +22,10 @@
// Special keys come after this.
#define MP_KEY_BASE (1<<21)
// printable, and valid unicode range (we don't care too much about whether
// certain sub-ranges are reserved and disallowed, like surrogate pairs)
#define MP_KEY_IS_UNICODE(key) ((key) >= 32 && (key) <= 0x10FFFF)
#define MP_KEY_ENTER 13
#define MP_KEY_TAB 9
@@ -76,6 +80,8 @@
#define MP_KEY_RECORD (MP_KEY_MM_BASE+20)
#define MP_KEY_CHANNEL_UP (MP_KEY_MM_BASE+21)
#define MP_KEY_CHANNEL_DOWN (MP_KEY_MM_BASE+22)
#define MP_KEY_PLAYONLY (MP_KEY_MM_BASE+23)
#define MP_KEY_PAUSEONLY (MP_KEY_MM_BASE+24)
/* Function keys */
#define MP_KEY_F (MP_KEY_BASE+0x40)
@@ -137,23 +143,6 @@
#define MP_KEY_MOUSE_BTN_COUNT (MP_MBTN_END - MP_MBTN_BASE)
// Apple Remote input module
#define MP_AR_BASE (MP_KEY_BASE+0xE0)
#define MP_AR_PLAY (MP_AR_BASE + 0)
#define MP_AR_PLAY_HOLD (MP_AR_BASE + 1)
#define MP_AR_CENTER (MP_AR_BASE + 2)
#define MP_AR_CENTER_HOLD (MP_AR_BASE + 3)
#define MP_AR_NEXT (MP_AR_BASE + 4)
#define MP_AR_NEXT_HOLD (MP_AR_BASE + 5)
#define MP_AR_PREV (MP_AR_BASE + 6)
#define MP_AR_PREV_HOLD (MP_AR_BASE + 7)
#define MP_AR_MENU (MP_AR_BASE + 8)
#define MP_AR_MENU_HOLD (MP_AR_BASE + 9)
#define MP_AR_VUP (MP_AR_BASE + 10)
#define MP_AR_VUP_HOLD (MP_AR_BASE + 11)
#define MP_AR_VDOWN (MP_AR_BASE + 12)
#define MP_AR_VDOWN_HOLD (MP_AR_BASE + 13)
/* game controller keys */
#define MP_KEY_GAMEPAD (MP_KEY_BASE+0xF0)
#define MP_KEY_GAMEPAD_ACTION_DOWN (MP_KEY_GAMEPAD+0)
@@ -210,7 +199,10 @@
(MP_KEY_IS_MOUSE_CLICK(code) || MP_KEY_IS_MOUSE_MOVE(code))
// No input source should generate this.
#define MP_KEY_UNMAPPED (MP_KEY_INTERN+4)
#define MP_KEY_UNMAPPED (MP_KEY_INTERN+4)
#define MP_KEY_ANY_UNICODE (MP_KEY_INTERN+5)
// For mp_input_put_key(): release all keys that are down.
#define MP_INPUT_RELEASE_ALL (MP_KEY_INTERN+6)
// Emit a command even on key-up (normally key-up is ignored). This means by
// default they binding will be triggered on key-up instead of key-down.
+9 -3
View File
@@ -29,7 +29,7 @@ struct gamepad_priv {
static Uint32 gamepad_cancel_wakeup;
static void initalize_events()
static void initialize_events(void)
{
gamepad_cancel_wakeup = SDL_RegisterEvents(1);
}
@@ -198,13 +198,19 @@ static void remove_gamepad(struct mp_input_src *src, int id)
static void read_gamepad_thread(struct mp_input_src *src, void *param)
{
if (SDL_WasInit(SDL_INIT_EVENTS)) {
MP_ERR(src, "Another component is using SDL already.\n");
mp_input_src_init_done(src);
return;
}
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)) {
MP_ERR(src, "SDL_Init failed\n");
mp_input_src_init_done(src);
return;
};
}
pthread_once(&events_initialized, initalize_events);
pthread_once(&events_initialized, initialize_events);
if (gamepad_cancel_wakeup == (Uint32)-1) {
MP_ERR(src, "Can't register SDL custom events\n");
Loaded 100 of 272 files, more files were not shown because too many files have changed in this diff. Show more