Compare commits

...
936 Commits
Author SHA1 Message Date
sfan5 0728b51498 Release 0.33.0 2020-11-22 18:46:28 +01:00
sfan5 6bb73040dd file2string: remove question mark from safe chars
Trigraphs such as "??=" (which are enabled by default with -std=c11)
can mess up strings, so avoid them entirely by escaping question marks.

This also drops Python 2 compatibility from file2string, making the
change to the waf rule necessary. The input file is now opened in
binary mode which is also more correct versus the old text mode
which just happened to work even on binary files.
2020-11-22 17:16:57 +01:00
rcombs 4dcaf70b96 Revert "options: disable vsfilter blur compat by default"
This reverts commit 3d17e19c2c.

The effect of turning off this setting is that mpv doesn't tell libass what
the video stream's resolution is. This happens to result in some files having
their transforms scaled in ways that give higher performance (as described
in #7435) because libass happened to guess a video resolution that resulted
in transforms yielding smaller bitmaps, but it's just as easy for the opposite
to happen depending on the resolutions and effects involved.

The option's name is also somewhat misleading: setting the storage size affects
blur, but it also affects stroke (which is far more important for the vast
majority of scripts) and 3D transforms (which look very screwy when done wrong).
2020-11-22 17:37:43 +02:00
Uoti Urpala 2409300d40 build: always run waf with python3
Upstream waf still ships with the default interpreter being "python",
though the script works with both Python 2 and Python 3 (they're not
changing the default choice during 2.0.x releases for compatibility
reasons apparently). Add code to bootstrap.py to change the
interpreter from "python" to "python3" when downloading the "waf"
file.

Running any mpv code under Python 2 should be considered unsupported
in the future (and any code added need not work under Python 2).
2020-11-22 13:59:26 +01:00
der richter 5ae6f04d6b build: fix macOS arm builds
remove the hardcoded swift target version and move the version
restriction to configure. this was a bad idea anyway and could lead to
mismatched object files between obj-c and swift. fix travis 10.12 legacy
build.

also update the SDK version parser to handle the new macOS 11 scheme.

Fixes #8281
2020-11-22 13:44:16 +02:00
Shreesh Adiga 959097c880 vo_sixel: draw osd on the output frame 2020-11-22 13:34:25 +02:00
Shreesh Adiga 8a278c2ddd vo_sixel: return -1 instead of SIXELSTATUS on failure
Currently in mpv functions sixel failures return the
value status which is of type SIXELSTATUS. So changing
it to -1 which is explicit and compatible with mpv.
Also log the errors using MP_ERR/MP_LOG with the
error string returned by libsixel to have more info.
2020-11-22 13:34:25 +02:00
Shreesh Adiga b48e0b11d9 vo_sixel: set --vo-sixel-fixedpalette=yes by default
fixedpalette seems to be slightly faster than dynamic
palette, and also in mlterm it avoids corruption of
too bright values overflowing to black. Hence setting
it to be default choice instead of dynamic palette.
2020-11-22 13:34:25 +02:00
Shreesh Adiga 6ad3e2bfbd vo_sixel: Add aspect ratio based output centering
Resize the image based on the dimensions reported by
vo_get_src_dst_rects to correctly handle aspect ratio
that might be set/ignored.

Added pad-x and pad-y options for padding.
These options will be used to remove the extra padding.
Some terminals report the padding of 2px in the ioctl
dimensions which can't be used for displaying sixel
output. These options can be used for fine tuning
the output video resolution.

Now all the terminal size detection and calculation logic
is done in a single function at resize. Also top and left
values are computed from the dst_rect parameters to simplify
the logic for the aspect ratio based centering.

Additionally vo-sixel-rows and vo-sixel-cols options
have been added to enable the user to override the values
in case of failures with get_terminal_size2.

This commit also adds ability to handle video zoom correctly.
Whenever video-zoom is triggered, the src and dst rects
will be updated. Scaling seems to work well now.
2020-11-22 13:34:25 +02:00
Shreesh Adiga c615e51051 vo_sixel: rename all user options with opt_ prefix
This has no changes to mpv sixel playback behaviour.
This is required because currently the offset values
and the resolutions are being overwritten and not
remembered.
2020-11-22 13:34:25 +02:00
Shreesh Adiga 71b21b9339 vo_sixel: set output resolution based on terminal_get_size2 2020-11-22 13:34:25 +02:00
Shreesh Adiga 670f23f169 osdep/terminal: Add function to get terminal pixel dimensions 2020-11-22 13:34:25 +02:00
Emanuele Torre 38275338ee doc: split BNF definitions of <command> and <argument> in separate lines
Having them in the same line made it hard to read them in the man page
since they are formatted in the same way and they look as though they
are only one definition.
2020-11-22 01:23:42 +02:00
Leo Izen 9b5672ebed manpage: document improved --playlist security
Recent versions of mpv have applied security checks to --playlist
that previously only existed if playlist files were played as an
input directly. This commit documents this change and how to work
around it, in the event that playlist files are trusted.
2020-11-18 17:30:07 -05:00
Avi Halachmi (:avih) 24d6961833 command: mouse: generate MOUSE_{ENTER,LEAVE} if required
Previously the mouse command never ended up in enter/leave keypresses
for the default section even when logically required, because input.c
does not know the area of the default section and relies on something
feeding it ENTER/LEAVE presses - which the VO typically does but the
mouse command didn't.

Now the mouse command feeds it ENTER/LEAVE if required.

It's possible to handle it differently and more consistently by:
1. reverting this commit.
2. Updating the default section area whenever the osd dimensions change.
3. Always ignore MOUSE_ENTER keys because the position is not known yet
   (but MOSE_MOVE typically follows right away).
4. On mouse move: first generate ENTER/LEAVE if required.

That would guarantee consistency between mouse position and enter/leave
events but could be more sensitive to manage (the default section has
"infinite" area which is used to capture any event outside of specific
section areas), while this commit keeps consistency same as before and
depending on correct external feeding - which we now do better, even if
still not optimally (like before, it's still technically possible that
a script recieves MOUSE_ENTER and then reads the position before it got
updated after the ENTER).
2020-11-16 20:29:58 +02:00
Avi Halachmi (:avih) 3710c154d4 docs/input.rst: document the mouse-pos property 2020-11-16 20:29:58 +02:00
Avi Halachmi (:avih) 58004ea2ef command: mouse-pos property: add field "hover"
Add a third field: "hover", which is updated from input.c after input
keys MP_KEY_MOUSE_LEAVE and MP_KEY_MOUSE_ENTER - which are typically
sent by the VO.

It's part of mouse-pos and not a new property because it's highly tied
to mouse-pos - it makes x/y invalid while the cursor doesn't hover the
window.

Unike mouse-move, no dummy command was generated, so we add dummy
command in order for observer notification to work even while nothing
is bound.

Like mouse-pos, clients could not detect whether the mouse pointer
hovers the window because the OSC force-binds the MOUSE_LEAVE key, and
now they can using the hover field.

The lua mp.get_mouse_pos() wrapper still returns only x, y because
that's what osc.lua needs. Other clients can simply read the property.
2020-11-16 20:29:58 +02:00
Avi Halachmi (:avih) 0d5055fe93 lua/js: mp.get_mouse_pos: use the mouse-pos property
mp.get_mouse_pos() is undocumented and is no longer required - the
property can be used officially by any client now, however, osc.lua
uses it, and also some user scripts learnt to rely on it, so we keep
it - as a trivial wrapper around the new mouse-pos property.
2020-11-16 20:29:58 +02:00
Avi Halachmi (:avih) a768667956 command: new property: mouse-pos
This is a read-only MPV_NODE value with integer fields: x, y.
The values are unmodified from mp_input_get_mouse_pos(...).

Observer notification of this property is tied to the INPUT_PROCESSED
event, which fires after mouse move even if no command is bound
(dummy commands are generated if nothing is bound to ensure that
mp_input_get_mouse_pos returns the latest values - see ac927e39 ).

This allows clients such as JSON IPC to observe mouse position even
while the OSC is enabled - the OSC force-binds mouse move for most
of the window area, making it impossible for other clients to bind
mouse move without breaking the OSC.
2020-11-16 20:29:58 +02:00
Avi Halachmi (:avih) 799d3d4557 command: add internal INPUT_PROCESSED event
Fires after a non-empty input queue was processed.

Currently yet unused, but the next commit will use it.
2020-11-16 20:29:58 +02:00
wm4 26fc70dbfd path: do not use old_home for win32 exe dir
Apparently mpv supports loading config files from the same directory as
the mpv.exe. This is a fallback of some sort. It used the old_home
mechanism.

I want to add a warning if old_home exists, but that would always show
the warning on win32. Obviously we don't want that.

Add a separate exe_dir entry to deal with that.

Untested, but probably works.

Mistakenly reverted as part of the default configuration directory
location switch-back in aa18a8e1cd.

Separation of the mpv executable directory from old_path is a
good change now that we warn about the old_config directory also
existing.

Fixes #8232
Fixes #8244
Fixes #8262
2020-11-16 00:44:40 +02:00
Avi Halachmi (:avih) 932c1ada0f js: report scripts CPU/memory usage statistics
This can be viewed at page 4 of the internal stats display (i or I).

CPU time report is the same as at lua.c, but untested - doesn't seem
to work on windows - also not for lua.

TL;DR: Set env MPV_LEAK_REPORT=1 to enable js memory reporting stats.
       This also almost doubles the memory usage by js scripts.

For memory reporting, we don't have enough info by default, because
even when using a custom allocator, mujs doesn't report the old size
(on free or realloc) because it doesn't track this value, and as
a result we can't track the overall size.

Our option are either to track the size of each allocation on our own,
or use talloc which tracks this value.

However, using talloc for mujs allocations adds a considerable
overhead, and almost doubles(!) the overall memory used, because each
individual allocation includes a considerable talloc header, and mujs
does many small allocations.

So our solution is that by default we behave like previously - not
using a custom allocator with mujs, and stats does not display memory
usage for js scripts.

However, if the env var MPV_LEAK_REPORT is set to 1, then we use
a custom allocator with talloc and track/report memory usage.

We can't switch allocator at runtime, so an mpv instance either tracks
or doesn't track js scripts memory usage, according to the env var.
(we could use a property and apply it whenever a new script starts,
so that it could change for newly launched scripts, but we don't).
2020-11-15 20:36:04 +02:00
sfan5 cc25137eae ci: fix mingw build by adding harfbuzz 2020-11-15 17:32:03 +01:00
Ben Kerman f85de9e6d6 command: make subtitle time properties observable 2020-11-11 18:21:54 +00:00
Guido Cella 34f2143e8f manpage: properties fixes
- Explain which properties are writeable.
- Mark edition-list/N/id as writable.
- Remove (R) from some read-only properties since none of the others
have it.
- Add osd-dimension/ to its subproperties.
- options/<name> isn't read-only.
- focused works on macOS because of 82eda2e. Though it shouldn't be
possible to observe it without raising VO_EVENT_FOCUS.
2020-11-11 18:20:33 +00:00
Guido Cella 0ed4d66290 manpage: document the property-change event 2020-11-11 18:20:33 +00:00
Guido Cella fb819f069f manpage: document video-frame-info sub-properties
The picture type is explained in /usr/include/libavutil/avutil.h
Other subproperties in /usr/include/libavutil/frame.h
And there is a more detailed explanation for repeat_pict in
/usr/include/libavcodec/avcodec.h
2020-11-11 18:20:33 +00:00
Guido Cella 39ca957874 manpage: remove redundant "Return(s) "
...from the property descriptions that include it, and reformat the
paragraphs.
And say "Returns" in idle-active.
2020-11-11 18:20:33 +00:00
Guido Cella 5da326a8bb manpage: document demuxer-cache-state better 2020-11-11 18:20:33 +00:00
Guido Cella 81dfaa4962 manpage: be consistent with booleans
When possible, refer to booleans with "Whether..." since it can refer to
both yes (using input.conf and mp.get_property) and true (using the JSON
IPC or mp.get_property_native/bool), else explicitly say yes/true.
Say "true" for subprocess and osd-overlay named arguments since you
can't use them in input.conf and you will typically use them with the
boolean true in the named arguments, like the subprocess example in the
manpage does (though the string "yes" also works).
Subproperties that can't be accessed with the / syntax like
demuxer-cache-state's bof-cached and eof-cached always return true,
never yes.
2020-11-11 18:20:33 +00:00
Shreesh Adiga fd48f0bcb2 vo_sixel: Add fallback terminal width and height
In case terminal_get_size function fails, the
default height of 25 rows and 80 columns will be assumed
2020-11-09 19:44:07 +02:00
Shreesh Adiga baf45b3bc9 vo_sixel: Add checks to prevent null pointer dereferencing. 2020-11-09 19:44:07 +02:00
Jan Ekström 8ddd4547fc ao_alsa: handle -EPIPE XRUNs from snd_pcm_status
Set pcm state to SND_PCM_STATE_XRUN in case -EPIPE is received,
and handle this state as per the usual logic.

This way snd_pcm_prepare gets called, and the loop continued.

Inspired by a patch posted by malc_ on #mpv.
2020-11-09 16:12:49 +01:00
Jan Ekström 976fcf57c1 ao_alsa: always initialize state if passed
Based on ao_play_data's assert, we are always expected to give
non-default values back from an AO's get_state.
2020-11-09 16:12:49 +01:00
Dudemanguy 4c4d9d6d52 wayland: fix buffer overrun in get_mods
Use MP_ARRAY_SIZE and make the mod arrays here const.
2020-11-08 10:59:41 -06:00
Dudemanguy cf00b0b990 wayland: check for modifier keys on pointer events
The pointer button event had no code to handle any modifier keys. So
this meant input combinations like Shift+MTBN_LEFT did not work. Fix
this by ripping out the modifier-checking code in keyboard key event to
a separate function and using it for both the keyboard and mouse events.
In the case of the mouse, it is possible that the keyboard may not exist
so be sure to check before trying to get any modifiers. Fixes #8239.
2020-11-08 15:59:09 +00:00
Dudemanguy dae6b1be96 Revert "wayland: conditionally commit surface on resize"
30dcfbc is a workaround for incorrect border sizes that could occur on
sway/wlroots in certain edge cases. This seemed harmless enough, but it
turns out that on mutter the extra wl_surface_commit somehow causes the
window always go to the top left of the screen after you leave
fullscreen. No idea why this occurs, but the original commit is a
workaround a sway bug and causing regressions for other users isn't
right despite the author being biased towards sway/wlroots.

This reverts commit 30dcfbc9cb.
2020-11-08 09:51:52 -06:00
Dudemanguy 790647314c DOCS: correct interface-changes.rst
delete-watch-later-config was introduced in mpv 0.33.0 not mpv 0.31.0.
2020-11-07 18:55:03 -06:00
der richter d0a2661c5b mac: make focus property observable
i missed the VO_EVENT_FOCUS event and the possibility to observe this
property and didn't include it in my initial focus commit for that
matter.
2020-11-07 21:38:35 +01:00
Shreesh Adiga 19913921eb video/out/vo_sixel.c: Implement sixel as a output device
Based on the implementation of ffmpeg's sixel backend output written
by Hayaki Saito
https://github.com/saitoha/FFmpeg-SIXEL/blob/sixel/libavdevice/sixel.c

Sixel is a protocol to display graphics in a terminal. This commit
adds support to play videos on a sixel enabled terminal using libsixel.
With --vo=sixel, the output will be in sixel format.

The input frame will be scaled to the user specified resolution
(--vo-sixel-width and --vo-sixel-height) using swscaler and then
encoded using libsixel and output to the terminal. This method
requires high cpu and there are high frame drops for 720p and
higher resolution videos and might require using lesser colors and
have drop in quality.  Docs have all the supported options listed
to fine tune the output quality.

TODO: A few parameters of libsixel such as the sixel_encode_policy
and the SIXEL_XTERM16 variables are hardcoded, might want to
expose them as command line options. Also the initialization
resolution is not automatic and if the user doesn't specify the
dimensions, it picks 320x240 as the default resolution which is not
optimal. So need to automatically pick the best fit resolution for
the current open terminal window size.
2020-11-07 18:51:49 +02:00
Leo Izen dfa5ae2ad6 manpage: document av1 addition to --hwdec-codecs default setting
Document the change to add AV1 to the list of default hwdec
codecs, in commit 172146e9f7.
2020-11-05 23:05:54 +02:00
Jan Ekström 172146e9f7 vd_lavc: add AV1 to the default allowed hwdec codec list
Now that the first hwaccel implementations are coming in, it makes
sense to allow this format.
2020-11-03 15:07:26 +01:00
sfan5 73be20143e player: fix external cover file prioritization
Array order was ignored entirely instead of being used as intended.
Fixes: c07089a250
2020-10-28 18:15:34 +01:00
soredake b4d9980870 input.conf: add default keybindings for sub-scale 2020-10-27 17:13:56 +00:00
Guido Cella e49404cba9 console: let type set the cursor position
This allows keybindings such as:

a script-message-to console type "seek :0 absolute" 6
% script-message-to console type "seek  absolute-percent" 6

The cursor position 0 isn't allowed because it has the weird effect of
filling the console with the text twice, leaving the cursor in the
middle.
Negative positions would put the cursor n characters before the end, and
positions greater than the text's length at the end. They seem to work
at first, but the console breaks when you move the cursor, so they
aren't allowed.
It seems that float values don't cause issues, but I'm using the
argument's floor anyway to be safe. Using >= 1 instead of > 0 ignores
values like 0.5.
2020-10-27 17:10:50 +00:00
Ricardo Constantino ad1ecd4350 ytdl_hook: if ytdl not found in config dirs, use ytdl_path as is 2020-10-27 15:42:39 +00:00
Ricardo Constantino 93f84b514a ytdl_hook: support alternative youtube-dl path
Allows using a youtube-dl not in PATH or a compatible fork of
youtube-dl.
2020-10-27 15:42:39 +00:00
sfan5 c07089a250 player: reorder list of external cover files for optimal results 2020-10-25 22:35:53 +01:00
Emmanuel Gil Peyrot a832c22dac build: disable wayland if linux/input-event-codes.h isn’t available
The wl_pointer interface defines button argument as “a button code as
defined in the Linux kernel's linux/input-event-codes.h header file,
e.g. BTN_LEFT.”

We could #define these few buttons ourselves, but there is no system to
test it on, so for now let’s disable Wayland support on them.

This is a call to non-Linux system maintainers, please help test this
backend on your system and report issues you find, or even working
state.
2020-10-25 15:59:16 +02:00
Emmanuel Gil Peyrot 007ace76e2 wayland: use more specific input codes header
Wayland’s wl_pointer interface describes the button event’s argument as
being taken from linux/input-event-codes.h, so there is no need to
include the more generic linux/input.h.
2020-10-25 15:59:16 +02:00
Mia Herkt 49d6a1e77d demux_lavf: initialize ReplayGain data
This was causing undefined behavior when playing streams without RG tags
but with RG enabled. Broken in 585f9ff42f.

Thanks to uau for bisecting.
2020-10-23 14:22:57 +02:00
Vladimir Panteleev a92466c289 command: add delete-watch-later-config
This introduces the delete-watch-later-config command, to complement
write-watch-later-config. This is an alternative to #8141.

The general problem that this change is attempting to help solve has
been described in #336, #3169 and #6574. Though persistent playback
position of a single file is generally a solved problem, this is not
the case for playlists, as described in #8138.

The motivation is facilitating intermittent playback of very large
playlists, consisting of hundreds of entries each many hours
long. Though the current "watch later" mechanism works well - provided
that the files each occur only once in that playlist, and are played
only via that playlist - the biggest issue is that the position is
lost completely should mpv exit uncleanly (e.g. due to a power
failure).  Existing workarounds (in the form of Lua scripts which call
write-watch-later-config periodically) fail in the playlist case, due
to the mechanism used by mpv to determine where within a playlist to
resume playback from.

The missing puzzle piece needed to allow scripts to implement a
complete solution to this problem is simply a way to clean up the
watch-later configuration that the script asked mpv to write using
write-watch-later-config. With that in place, scripts can then
register an end-file event listener, check the stop playback reason,
and in the "eof" and "stop" case, invoke delete-watch-later-config to
delete any saved positions written by write-watch-later-config. The
script can then proceed to immediately write a new one when the next
file is loaded, which altogether allows mpv to resume from the correct
playlist and file position upon next startup.

Because events are delivered and executed asynchronously,
delete-watch-later-config takes an optional filename argument, to
allow scripts to clear watch-later configuration for files after mpv
had already moved on from playing them and proceeded to another file.

A Lua script which makes use of this change can be found here:
https://gist.github.com/CyberShadow/2f71a97fb85ed42146f6d9f522bc34ef
(A modification of the one written by @Hakkin, in that this one takes
advantage of the new command, and also saves the state immediately
when a new file is loaded.)
2020-10-22 19:53:35 +00:00
Niklas Haas dc0e9644cd vo_gpu: improve gamut warning bounds checks
Test for signals exceeding 0.5% of the permitted gamut, in either
direction. (Before, it was 1% above and 0% below)

Should fix https://github.com/mpv-player/mpv/issues/8161
2020-10-21 14:39:59 +02:00
Dudemanguy 9976c83e0f wayland: don't use presentation time if ust is 0
Testing kwinft out (kwin fork), it was discovered that sometimes it
would return a ust value of 0 which subsequently resulted in incorrect
presentation statistics (i.e. large negative numbers which are obviously
impossible). Arguably, it shouldn't return 0s, but a workaround for mpv
in this case is harmless.
2020-10-19 11:04:44 -05:00
sfan5 cbbdb3fae4 stats: display hw pixel format too 2020-10-16 17:48:05 +02:00
sfan5 3d9d041a11 command: expose underlying pixfmt for hwdec 2020-10-16 17:48:05 +02:00
Jan EkströmandJames Ross-Gowan b8104a013d ci/appveyor: attempt to work around outdated msys2
Based on the workarounds utilized in the MAME project:
1. mamedev/mame@4b4016110a
2. mamedev/mame@2d1bf3ed5c

Co-authored-by: James Ross-Gowan <rossy@jrg.systems>
2020-10-17 00:00:35 +11:00
Jan Ekström 925d6e1205 ci/travis: stop installing mingw-w64 packages manually
As we are now on 20.04, these packages are now available in the
repositories. Additionally, they don't need to be separately pulled
in, as gcc-mingw-w64 already does that.
2020-10-16 00:01:54 +02:00
Jan Ekström 9121e8f513 ci/travis: move to a yaml list for required packages for mingw-w64 2020-10-16 00:01:54 +02:00
Jan Ekström f9ed80a12b ci/travis: bump Ubuntu distro version to focal (20.04) 2020-10-16 00:01:54 +02:00
Philip Langdale 9a1942ac95 manpage: Document behaviour of *nix configuration directories
The original documentation here is unclear, so let's describe the
behaviour we actually have. Inspired by wm4's updated docs but
obviously not identical because we're not changing any of the
behaviours.
2020-10-16 00:47:18 +03:00
Philip Langdale 949e06c86c Revert "path: switch back to using non-XDG config dir by default"
This reverts commit 269f0e743e.
2020-10-16 00:47:18 +03:00
Philip Langdale aa18a8e1cd Revert "path: do not use old_home for win32 exe dir"
This reverts commit c3694f0acb.
2020-10-16 00:47:18 +03:00
Philip Langdale 8a2449e3d5 Revert "manpage: reference standard for configuration file location"
This reverts commit 67b4a96e45.
2020-10-16 00:47:18 +03:00
Jan Ekström 3248b073ce build: bump waf to 2.0.20
There have been mentions that there are apparently some bugs with
regards to possible random build failures, so bumping after a few
years sounds like an OK thing to test/do.
2020-10-16 00:01:23 +03:00
Alexandre Iooss 75acc04262 stream_lavf: enable SRT protocol support through FFmpeg
Additionally, announce support for the protocol in Mac and Linux
application metadata.
2020-10-15 23:53:33 +03:00
Dudemanguy f781c00ece vo_gpu: fix segfault when updating render opts
VOCTRL_UPDATE_RENDER_OPTS is supposed to be optional so check if it
actually exists before executing the function. Fixes a segfault when
changing the alpha value at runtime on non-wayland platforms.
2020-10-15 12:18:59 -05:00
Dudemanguy f5a094db04 vo_gpu: EGL: hack for alpha on different platforms
7fb972f fixed transparency on x11/EGL/Mesa but happened to also break it
for wayland and nvidia. Ideally on wayland, you should just be able to
pick the right EGLConfig that has alpha but this doesn't seem to work
because reasons. So just go back to setting the EGL_ALPHA_SIZE bit if
the user asks for alpha. Apparently this worked before for nvidia as
well. The hack is to just run an eglQueryString in the x11egl context.
If it picks up Mesa as the EGL_VENDOR, then force ctx->opts.want_alpha
to 0 and let pick_xrgba_config take care of the rest.
2020-10-15 13:44:07 +00:00
Dudemanguy b60545bdc6 wayland: update opaque region on runtime
Made possible with 00b9c81. 34b8adc let the wayland surface set an
opaque region depending on if alpha was set by the user or not. However,
there was no attempted detection for runtime changes and it is possible
(at least in wayland vulkan) to toggle the alpha on and off. So this
meant, we could be incorrectly signalling an opaque region if the user
happened to change the alpha. Additionally, add a helper function for
this and use it everywhere we want to set the opaque region.
2020-10-15 13:43:45 +00:00
Dudemanguy aacefa4ae5 vo_gpu: update render options on runtime
vo_gpu has a small set of options for ra_ctx that can be set. In
practice, runtime toggling doesn't matter for most of these as they have
no effect while a video is playing. However, changing the alpha option
during runtime can actually work depending on the backend used. mpv
already detected when one of these options changed, but it made no
attempt to update the options in the ra_ctx accordingly (likely because
nothing made any use of this information). Another related change is to
add an update_render_opts to the fns and allow invidiual backends to
(optionally) use it.
2020-10-15 13:43:45 +00:00
Dudemanguy deaea70630 wayland: be less strict about when to render
efb0c5c changed the rendering logic of mpv on wayland and made it skip
rendering when it did not receive frame callback in time. The idea was
to skip rendering when the surface was hidden and be less wasteful. This
unfortunately had issues in certain instances where a frame callback
could be missed (but the window was still in view) due to imprecise
rendering (like the default audio video-sync mode). This would lead to
the video appearing to stutter since mpv would skip rendering in those
cases.

To account for this case, simply re-add an old heuristic for detecting
if a window is hidden or not since the goal is to simply not render when
a window is hidden. If the wait on the frame callback times out enough
times in a row, then we consider the window hidden and thus begin to
skip rendering then. The actual threshold to consider a surface as
hidden is completely arbitrary (greater than your monitor's refresh
rate), but it's safe enough since realistically you're not going to miss
60+ frame callbacks in a row unless the surface actually is hidden.
Fixes #8169.
2020-10-15 13:36:49 +00:00
Christopher Degawa cfead22b80 wscript_build.py: use -Wl,--subsystem,console instead
Fixes an issue with clang not using the -mconsole option if mwindows
is present resulting in mpv.com being a gui program instead of a
console program.

Does not interfere with gcc compilation.

result without this patch

```
file .\mpv.com .\mpv.exe
.\mpv.com: PE32+ executable (GUI) x86-64 (stripped to external PDB)
.\mpv.exe: PE32+ executable (GUI) x86-64 (stripped to external PDB)
```

both executables open the mpv gui with out console output.

result with this patch

```
file .\mpv.com .\mpv.exe
.\mpv.com: PE32+ executable (console) x86-64 (stripped to external PDB)
.\mpv.exe: PE32+ executable (GUI) x86-64 (stripped to external PDB)
```

mpv.com properly outputs text to console instead of instantly opening
a gui

`, for MS Windows` removed from the end of file outputs to reduce col
count

https://github.com/m-ab-s/media-autobuild_suite/issues/1794

Signed-off-by: Christopher Degawa <ccom@randomderp.com>
2020-10-15 01:28:30 +03:00
Tim Gates 2cfeee68d4 docs: fix simple typo, unminimze -> unminimize
There is a small typo in DOCS/man/options.rst.

Closes #8165
2020-10-14 19:45:52 +00:00
Chris Varenhorst 4797594347 DOCS: fix typo on sub-filter-regex-enable 2020-10-12 03:00:29 -04:00
wm4 67b4a96e45 manpage: reference standard for configuration file location 2020-10-09 19:06:27 +02:00
wm4 16b44d93f7 Revert "demux: add a POS"
This reverts commit 4f18e7927b.

It was a mistake, and barely anyone needs this.
2020-10-08 11:17:10 +02:00
wm4 6de25997a1 player: fix another nightmarish corner case
Pretty much fuck this shit.
2020-10-08 00:36:41 +02:00
wm4 4f18e7927b demux: add a POS
I regret doing this so much, it's fucking garbage.

Fixes: #5100
2020-10-08 00:35:37 +02:00
Dudemanguy 5dc16a4a18 Revert "wayland: add wayland-display-socket option"
Pointless feature that can be done with environment variables. It was
also implemented incorrectly and broke autoprobing.

This reverts commit 015b676875.
2020-10-07 08:41:47 -05:00
Dudemanguy 015b676875 wayland: add wayland-display-socket option
As per the client API, a client can connect to any arbitrary wayland
socket. mpv has always just passed NULL which connected to the
compositor currently in use, but one could just as easily pass the name
of a different socket (i.e. the value of WAYLAND_DISPLAY). Here, we just
expose this argument as a user configurable option. If the user passes a
socket name that does not exist, then print a warning and fall back to
NULL.
2020-10-06 17:45:59 +00:00
wm4 39f4fd0dc7 screenshot: add --screenshot-sw option
Probably worthless. As usual, the manpage dumps all the subtle
differences due to implementation details on the user.
2020-10-05 00:16:46 +02:00
Dudemanguy 34b8adc456 wayland: set an opaque region
Apparently a part of the wayland spec. A compositor may use a surface
that has set part of itself as opaque for various optimizations. For
mpv, we simply set the entire surface as opaque as long as the user has
not set alpha=yes (note: alpha is technically broken in the wayland EGL
backend at the time of this commit but oh well). wlshm is always opaque.
Fixes #8125.
2020-10-01 11:12:22 -05:00
Guido Cella dcec6d9556 options: fix --cover-art-file typo
...which makes it not work.
2020-09-30 17:57:44 +02:00
wm4 e1536193cb player: cosmetically change around some code
Is this better?
2020-09-28 00:14:54 +02:00
wm4 55d7f9ded1 player: add automatic loading of external cover art files
Picks up files like "cover.jpg". It's made part of normal external file
loading, so I'm adding 3 new options that are direct equivalents for the
options that control loading of external subtitle and audio files. Even
though I bet nobody wants them and they just increase confusion... I
guess the world is actually hell, so this outcome should be fine.

It prefers non-specific external files like "cover.jpg" over embedded
cover art. Not sure if that's wanted or unwanted.

There's some pain over explicitly marking such files as external
pictures. This is basically an optimization: in most cases, a heuristic
would treat an image file loaded with --external-file the same (it's a
heuristic because ffmpeg can't tell us whether something is an image or
a video). However, even with this heuristic, it would decode the cover
art picture again on each seek, which would essentially slow down
seeking in audio files. This bothered me greatly, which is why I'm
adding these additional options at all, and bothered with the previous
commit.

Fixes: #3056
2020-09-28 00:12:52 +02:00
wm4 102a4a8b06 player: let frontend decide whether to use cover-art mode
Essentially, this lets video.c decide whether to consider a video track
cover art, instead of having the decoder wrapper use the lower level
sh_stream flag.

Some pain because of the dumb threading shit. Moving the code further
down to make some of it part of the lock should not change behavior,
although it could (framedrop nonsense).

This commit should not change actual behavior, and is only preparation
for the following commit.
2020-09-28 00:04:21 +02:00
sfan5 5e4ec15e6c ci: fix spirv-cross build in mingw scripts 2020-09-25 18:23:05 +02:00
der richter 82eda2e5f8 mac: add support for the focused property 2020-09-25 16:48:24 +02:00
der richter 18a35f17e2 mac: add an option to prevent focusing of the window on open
on macOS 10.15 setting the activation policy behaves quite weirdly. the
call changes the current active App to a nameless process, which
probably also the reason that prevents the not focusing to work.
a workaround for that, is to refocus the previous active app.

Fixes #7725
2020-09-25 16:48:24 +02:00
der richter c535dfed66 travis: fix macOS 10.12 legacy build
brew update tries to update the java cask, which it tries to build from
source. this takes too long and leads to a timeout of the job. we can't
manually remove the java cask because of a bug in the too old brew cask
version and the old formula. we just remove the whole cask tap and call
it a day, since we don't need it anyway.
2020-09-22 13:03:39 +02:00
Dudemanguy efb0c5c446 wayland: only render if we have frame callback
Back in the olden days, mpv's wayland backend was driven by the frame
callback. This had several issues and was removed in favor of the
current approach which allowed some advanced features (like
display-resample and presentation time) to actually work properly.
However as a consequence, it meant that mpv always rendered, even if the
surface was hidden. Wayland people consider this "wasteful" (and well
they aren't wrong). This commit aims to avoid wasteful rendering by
doing some additional checks in the swapchain. There's three main parts
to this.

1. Wayland EGL now uses an external swapchain (like the drm context).
Before we start a new frame, we check to see if we are waiting on a
callback from the compositor. If there is no wait, then go ahead and
proceed to render the frame, swap buffers, and then initiate
vo_wayland_wait_frame to poll (with a timeout) for the next potential
callback. If we are still waiting on callback from the compositor when
starting a new frame, then we simple skip rendering it entirely until
the surface comes back into view.

2. Wayland on vulkan has essentially the same approach although the
details are a little different. The ra_vk_ctx does not have support for
an external swapchain and although such a mechanism could theoretically
be added, it doesn't make much sense with libplacebo. Instead,
start_frame was added as a param and used to check for callback.

3. For wlshm, it's simply a matter of adding frame callback to it,
leveraging vo_wayland_wait_frame, and using the frame callback value to
whether or not to draw the image.
2020-09-21 20:42:17 +00:00
wm4 9ba90b4f6f player: add pause state to playback start message
Now the player tells you that audio or video are playing while paused,
or something.
2020-09-21 19:36:25 +02:00
wm4 95e3a6e67e terminal: fix segfault when backgrounding
In the recent terminal commit, I "compressed" the read() error handling,
and messed it up. The return value could be -1 for other non-fatal
errors (such as EIO when trying to read while backgrounded), which
resulted in buf.len getting messed up.

Fixes: 602384348e
2020-09-21 19:31:15 +02:00
wm4 1f21be343a f_decoder_wrapper: make log prefix less verbose 2020-09-20 21:33:40 +02:00
sfan5 63ffa07b44 audio: take paused state into account in ao_start()
It makes no sense to instruct the AO to start the pull callbacks
when we know there's nothing to play (only affects pull AOs).
2020-09-20 18:52:54 +02:00
sfan5 c1db4630e6 audio: move start() calls outside of lock
Pull based AOs might want to call ao_read_data() inside start().
This fixes ao_opensles deadlocking.
2020-09-20 18:52:54 +02:00
der richter 03047a0169 mac: add an option to change the App activation policy
useful to hide the app icon in the Dock if necessary.
2020-09-20 15:28:50 +02:00
der richter e28724d90d mac: add ontop window level for desktop
this puts the window ontop of the desktop but behind the desktop icons.

Fixes #7791
2020-09-20 15:28:50 +02:00
sfan5 3054bcc62c options: simplify --android-surface-size handling 2020-09-20 12:04:25 +02:00
wm4 7831e52238 build: disable GLX
Nobody needs this anymore. If not too many people complain, we'll remove
this completely. Many already consider X11 and OpenGL legacy, so we
don't need TWO X11/OpenGL backends.
2020-09-18 15:17:07 +02:00
Guido Cella a7afc79d8f manpage: fix console keybindings punctuation 2020-09-18 14:29:04 +02:00
wm4 fb3facf052 msg: make --msg-time show time in seconds
More readable, similar to what --log-file will use (although the
terminal code shows microseconds and uses less left padding).
2020-09-18 14:26:41 +02:00
Philip Sequeira f4c39c74d4 build: sort dependencies (to make build deterministic)
Fixes #7855.
2020-09-18 02:02:49 +00:00
wm4 9806e9f82b command, demux: make drop-buffers reset state even harder
Leave nothing left when it's executed.
2020-09-17 15:34:40 +02:00
wm4 602384348e terminal: attempt to handle the ESC key
Due to Unix being legacy garbage, it's not possible to safely detect the
ESC key on terminal. The key sequences are ambiguous. The code for the
ESC key also starts the sequences for other special keys.

Until now, you needed to hit ESC twice for it to be recognized.

Attempt to handle this better by using a timeout to detect the key. If
ESC is in the input buffer, but nothing else arrived after a timeout,
assume it's the ESC key. I think this is the method vim uses. Currently,
the timeout is set at 100ms. This is hardcoded and cannot be changed.
It's possible that this causes problems on slow ssh connections or so.

I'm not sure what exactly happens if you manage to get ESC + another
normal key into the input buffer. If it's a known sequence, it will be
matched and interpreted as such. If not, it'll probably be discarded.
2020-09-17 15:31:19 +02:00
wm4 76fb001c42 client API: update alignment requirements for software rendering
Previous commit fixes it for libswscale. The libzimg path has extra code
to copy by slice, but it still may access pixel groups using normal
memory accesses (for example, reading rgba pixel data via uint32_t), so
document a minimum alignment requirement per pixel format.
2020-09-17 15:25:49 +02:00
wm4 083adf97e1 sws_utils: work around libswscale corrupting memory yet again
If the alignment is less than 16, certain libswscale code paths will
silently corrupt memory outside of the target buffer. This actually
affected the libmpv software rendering API (that was fun to debug).
Rather than passing this problem to the next API user, try to avoid it
within libmpv.

It's unclear which alignment libswscale requires for safe operation. I'm
picking 32 (one more than the observed safe value in the case I
experienced), because libavfilter mostly uses this value.

The way to work this around is slow: just make a full copy of the entire
input or output image. Possibly this could be optimized by using the
slice API, but that would be more effort, and would likely expose
further libswscale bugs. Hope that this is a rarely needed path.

The next commit will update the alignment requirement documentation
bits.
2020-09-17 15:24:27 +02:00
Guido Cella b2f4320d06 manpage: refer to --sub-color for colors
Don't make the user search for --osd-color only to make him search again
for --sub-color.
2020-09-17 10:35:35 +02:00
Guido Cella f825473c7a manpage: mark file-local-options as writable 2020-09-17 10:35:08 +02:00
Mohammad AlSaleh b959a22291 stream_slice: interpret end as offset if it starts with '+'
Example:
    slice://1g-2g@file.ts (1 to 2)
    slice://1g-+2g@file.ts (1 to 3)

Signed-off-by: Mohammad AlSaleh <CE.Mohammad.AlSaleh@gmail.com>
2020-09-17 10:34:57 +02:00
wnoun 49f5c9b482 command: add property track-list/N/main-selection 2020-09-12 13:03:13 +02:00
wm4 eed8b6d47b player: fix inconsistent AO pause state in certain situations
Pause can be changed during a file change, such as with for example
--reset-on-next-file=pause, or in hooks, or by being quick, and in this
case the AO's pause state was not updated correctly. mpctx->ao_chain is
only set if playback is fully initialized, while the AO itself in
mpctx->ao can be reused across files.

Fix this by always running set_pause_state() if the pause option is
changed. Could cause new bugs since running this used to be explicitly
avoided outside of the loaded state. The handling of time_frame is
potentially worrisome.

Regression due to recent audio refactor; before that, the AO didn't have
a separate/persistent pause state.

Fixes: #8079
2020-09-12 00:13:24 +02:00
wm4 98f9d50b30 player: some minor code golf 2020-09-10 23:47:59 +02:00
wm4 4b9d80644d vo_vdpau: remove an unused variable 2020-09-10 23:25:30 +02:00
wm4 09d3a4d39d player: clamp relative seek base time to nominal duration
Since b74c09efbf, audio-only files let you seek to arbitrary points
beyond the end of the file (but still displayed the time clamped to the
nominal file duration). This was confusing and just not wanted. The
reason is probably that the commit removed setting the audio PTS for
data before the seek target, so if you seek past the end of the file,
the audio PTS is never set. This in turn means the logic to determine
the current playback time has no PTS at all, and thus falls back to the
seek PTS.

This happened in the past for other reasons (like efe43d768f). I have
enough of this, so I'm just changing the code to clamp the seek
timestamp to a "known" range. Do this when seeking ends, because in the
fallback case, the playback time shouldn't be stuck at e.g. "end +
seek_argument". Also do it when initiating a new seek (mp_seek), because
if the previous seek hasn't finished yet, it shouldn't add them up and
allow it to go "out of range" either. The latter is especially relevant
for hr-seeks.

Doing this clamping is problematic because the duration is a possibly
invalid value from the demuxer, or just missing. Especially with
timestamp resets, fun sometimes happens, and in these situations it
might be better not to clamp.

One could argue you should just use the last audio timestamp returned by
the decoder or demuxer (even if that directly conflicts with --end), but
that sounds even more hairy.

In summary: what a dumb waste of time, what the fuck.
2020-09-10 23:24:35 +02:00
wm4 78bbd62d3b manpage: "fix" some formatting
Yeah, fuck this retarded garbage.
2020-09-10 23:03:58 +02:00
wm4 f250c29403 terminal-unix: attempt to support more CTRL
Hysterically stupid inconsistent legacy garbage from the 70ies or maybe
even 60ies. What the fuck. I fucking hate computers so much.

Fixes: #8072
2020-09-10 23:03:30 +02:00
wm4 92e7f75bec vo_vdpau: remove deprecated/inactive --vo-vdpau-deint option
I think this has been dead code for quite a while. It was deprecated
anyway.
2020-09-09 15:38:39 +02:00
Guido Cella 9b9ce74afa command: add read-only focused property
Add a property that returns whether the window is focused, currently
only for X11 and Wayland.

My use cause for this is having an equivalent of pause-when-minimize.lua
for tiling window managers: make mpv play only while it's in the current
workspace or is focused (I'm fine with either one but prefer focus).
On X I do this by observing display-names, which is empty when the
rectangles of the display and mpv don't intersect, but on Wayland its
value doesn't change when mpv leaves the current workspace (and the same
check doesn't work since the geometries still intersect).

This could later be made writable as requested in #6252.

Note that on Wayland se shouldn't consider an unactivated window with
keyboard input focused.

The wlroots compositors I tested set activated after changing the
keyboard focus, so if you set wl->focused only in
keyboard_handle_enter() and keyboard_handle_leave() to avoid adding the
"has_keyboard_input" member, focused isn't set to true when first
opening mpv until you focus another window and focus mpv again.

Conversely, if that order can't be assumed for all compositors, we
should toggle wl->focused when necessary in keyboard_handle_enter() and
keyboard_handle_leave() as well as in handle_toplevel_config().
2020-09-08 20:09:17 +02:00
Guido Cella 5a4fc8684e manpage: fix typo
Change 'already by defined' to 'already defined' and reformat the
paragaph.
2020-09-06 10:45:28 -04:00
wm4 f57b90b069 options: fix a flags field 2020-09-04 00:31:59 +02:00
wm4 cf19a0d3cc ao_alsa: make partial writes an error message
And I think "partial write" is easier to understand than "short write".
2020-09-03 22:40:20 +02:00
wm4 1643cb865f audio: fix stream-silence with push AOs (somewhat)
--audio-stream-silence is a shitty feature compensating for awful
consumer garbage, that mutes PCM at first to check whether it's
compressed audio, using formats advocated and owned by malicious patent
troll companies (who spend more money on their lawyers than paying any
technicians), wrapped in a wasteful way to make it constant bitrate
using a standard whose text is not freely available, and only rude users
want it. This feature has been carelessly broken, because it's
complicated and stupid. What would Jesus do? If not getting an aneurysm,
or pushing over tables with expensive A/V receivers on top of them, he'd
probably fix the feature. So let's take inspiration from Jesus Christ
himself, and do something as dumb as wasting some of our limited
lifetime on this incredibly stupid fucking shit.

This is tricky, because state changes like end-of-audio are supposed to
be driven by the AO driver, while playing silence precludes this. But it
seems code paths for "untimed" AOs can be reused.

But there are still problems. For example, underruns will just happen
normally (and stop audio streaming), because we don't have a separate
heuristic to check whether the buffer is "low enough" (as a consequence
of a network stall, but before the audio output itself underruns).
2020-09-03 22:39:23 +02:00
wm4 b5c225382e encode: propagate errors to exit status properly
Don't just let mpv CLI return 0 (success) as exit status if encoding
failed somehow.
2020-09-03 15:44:35 +02:00
wm4 d3afe34c09 ao_lavc: slightly simplify filter use
Create a central function which pumps data through the filter. This also
might fix bogus use of the filter API on flushing. (The filter is just
used for convenience, but I guess the overall result is still simpler.)
2020-09-03 15:39:31 +02:00
wm4 4b3500dd14 client API: inactivate the opengl_cb API
The render API replaced the opengl_cb API over 2 years ago. Since then,
the opengl_cb API was emulated on top of the render API. While it would
probably be reasonable to emulate these APIs until they're removed in an
eventual libmpv 2.0 bump, I have some non-technical reasons to disable
the API now.

The API stubs remain; they're needed for formal ABI compatibility.
2020-09-03 14:52:11 +02:00
wm4 80bf6b26ba encode: disable unsupported media types automatically
If you encode to e.g. an audio-only format, then video is disabled
automatically. This also takes care of the very cryptic error message.
It says "[vo/lavc] codec for video not found". Sort of true, but
obscures the real problem if it's e.g. an audio-only format.
2020-09-03 14:13:17 +02:00
wm4 2761f37fe4 encode: remove early EOF failure handling
I don't see the point of this. Not doing it may defer an error to later.
That's OK? For now, it seems better to reduce the encoding internal API.
If someone can demonstrate that this is needed, I might reimplement it
in a different way.
2020-09-03 12:29:12 +02:00
wm4 b9baa1598a audio: slightly simplify audio_start_ao()
Get rid of an indirection; no behavior change.
2020-09-03 12:22:20 +02:00
wm4 177a88f676 audio: reduce excessive logging of delayed audio start
Since this is a messy and fragile mechanism, I want it logged (even if
it's somewhat in conflict with the verbose logging policy). On the other
hand, it's unconditionally logged on every playloop iteration. So add
some nonsense to log it only on progress.
2020-09-03 12:18:42 +02:00
wm4 5fc34cb4d6 ao_alsa: log more information on short writes 2020-09-02 22:22:45 +02:00
wm4 2f30d5c060 audio: do not show audio draining message when it does not make sense
Just for the redundant message. The function which is called here,
ao_drain(), does not care in which state it is called, and already
handled this gracefully.
2020-09-01 21:28:13 +02:00
wm4 50c998afab audio: do not wake up player when waiting for audio state and paused
Bullshit.
2020-09-01 21:28:13 +02:00
wm4 99cd22af01 audio: fix AVFrame allocation (crash with opus encoding)
AVFrame doesn't have public code for pool allocation, so mpv does it
manually. AVFrame allocation is very tricky, so we added a bug.

This crashed with libopus encoding, but not some other audio codecs,
because the libopus libavcodec wrapper accesses AVFrame.data. Most code
tries to avoid accessing AVFrame.data and uses AVFrame.extended_data,
because using the former would subtly corrupt memory on more than 8
channels. The fact that this problem manifested only now shows that most
AVFrame consuming FFmpeg code indeed uses extended_data for audio.
2020-09-01 21:28:13 +02:00
wm4 d96e2c7313 DOCS/interface-changes: remove encoding mode deprecation entry
It was undeprecated.
2020-09-01 21:28:13 +02:00
Leo Izen cdc5932859 player/playloop.c: reorder included headers per contribute.md
This commit sorts the included headers alphabetically and puts
them in sections, as described by DOCS/contribute.md.
2020-08-31 17:01:22 -04:00
LAGonauta 0ac724f002 ao_openal: restore working condition with new push API 2020-08-31 20:24:14 +02:00
wm4 a805a152c1 ao: remove unused field 2020-08-31 20:23:44 +02:00
wm4 478d39c574 audio: fix inefficient behavior with ao_alsa, remove period_size field
It is now the AO's responsibility to handle period size alignment. The
ao->period_size alignment field is unused as of the recent audio
refactor commit. Remove it.

It turns out that ao_alsa shows extremely inefficient behavior as a
consequence of the removal of period size aligned writes in the
mentioned refactor commit. This is because it could get into a state
where it repeatedly wrote single samples (as small as 1 sample), and
starved the rest of the player as a consequence. Too bad. Explicitly
align the size in ao_alsa. Other AOs, which need this, should do the
same.

One reason why it broke so badly with ao_alsa was that it retried the
write() even if all reported space could be written. So stop doing that
too. Retry the write only if we somehow wrote less.

I'm not sure about ao_pulse.
2020-08-29 16:27:56 +02:00
wm4 3427aa4776 encode: undeprecate
I guess the audio timestamp corruption problem is probably solved now.
2020-08-29 13:12:32 +02:00
wm4 654eef9b82 ring: remove this
The code is OK, and it could be restored if it's needed again. But it is
unused now, so remove it.
2020-08-29 13:12:32 +02:00
wm4 40c2e71d33 audio_buffer: remove this
Unused, was terrible garbage. It was (or at least its implementation
was) always a make-shift solution, and just gross bullshit. It is unused
now, so delete it.
2020-08-29 13:12:32 +02:00
wm4 b74c09efbf audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.

It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.

Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.

Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.

At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.

This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-29 13:12:32 +02:00
Chris Varenhorst bb1f821078 DOCS: fix minor issue on the --video-latency-hacks explanation 2020-08-28 23:36:16 -04:00
crackself dc1a855438 Update compile-windows.md
fix lua5.1-5.2  support with luajit (mxe default upstream lua5.3 )
2020-08-28 23:34:29 -04:00
Guido Cella 7f5c170093 manpage: reorder sentence 2020-08-28 22:27:59 -04:00
wm4 3d0eb4c26c f_async_queue: add various helper functions
Shouldn't change the behavior if not used. Will probably be used in a
later commit.
2020-08-28 20:08:32 +02:00
wm4 71d118733a f_async_queue: don't count EOF frames as samples
That's dumb.
2020-08-28 20:07:12 +02:00
wm4 86068af178 f_async_queue: change reset behavior
Do not make resetting the "access" filters reset the queue itself. This
is more flexible, and will be used in a later commit.

Also, if the queue is not in the reset state while the input access
filter is reset, make it immediately request data again. This is more
consistent, because it'll enter the state it "should" be, rather when
the filter's process function is called at an (essentially) random point
in the future. This means the filter graph will resume work on its own
if the queue was not reset before filter reset.

This could affect the only current user of f_async_queue, the code for
the --vd-queue-enable/--ad-queue-enable feature in f_decoder_wrapper.
But it looks like this already uses it in a compatible way.
2020-08-28 20:06:18 +02:00
wm4 2c7139753d filter: add filter priority thing
This is a kind of bad hack (with bad implementation) to paint over other
problems of the filter system. The main problem is that some filters
might be left with pending frames if the filter runner is "paused",
which we don't want. To be used in a later commit.
2020-08-28 19:57:23 +02:00
wm4 b9f52105ae manpage: slightly improve property list note 2020-08-28 19:53:48 +02:00
Oneric 91ce87bd89 sd_ass: replace deprecated ASS_OVERRIDE_BIT_FONT_SIZE
This requires a slightly more recent libass than before
2020-08-28 19:52:48 +02:00
Oneric 7fa4ce35e7 osd_libass: don't use deprecated ass_set_aspect_ratio 2020-08-28 19:52:48 +02:00
wm4 fc6c209cbd f_demux_in: log EOF "recovery"
For debugging.
2020-08-27 18:40:57 +02:00
wm4 47a5f86829 f_decoder_wrapper: pass through EOF after EOF
It's relevant in some obscure corner cases (EDL file that has a segment
without audio). Didn't test what's actually going on (is ad_lavc.c
behaving wrong? is libavcodec behaving wrong or in an unexpected way? is
lavc_process wrong?) and just patched it over with some bullshit, so the
fix might be too complicated, and could be reworked at some later point.
This sure is a real data flow fuckmess.
2020-08-27 18:40:12 +02:00
wm4 ab6dbf0a29 player: fix video paused condition on VO creation
Doesn't take paused_for_cache into account. For consistency; unlikely to
matter at all in practice.
2020-08-27 11:55:20 +02:00
wm4 5f89b230c7 filter: add a helper
Not used yet; probably will, just dumping this to get it out of my
sight.
2020-08-27 11:55:20 +02:00
wm4 a7413aff22 audio: clarify set_pause() documentation 2020-08-27 11:55:20 +02:00
wm4 b0fe01d55c audio: adjust frame clipping for spdif formats
Allow mp_aframe_clip_timestamps() to discard a spdif frame if it's
entirely out of the timestamp range. Just a minor thing that might make
handling these dumb formats easier.
2020-08-27 11:55:20 +02:00
wm4 6b13d71cdc audio: remove unused ring.h includes
From what I can tell, this has been copy-pasted from times when
ao_coreaudio still used its own ringbuffer, instead of the common code.
2020-08-27 11:55:20 +02:00
wm4 2a23105c1b player: fix swapped debug output
Such failure.
2020-08-27 11:55:20 +02:00
wm4 7fb972fd39 vo_gpu: EGL: fix transparency on X11/EGL/Mesa
Transparent windows on X11/EGL/native Mesa GL didn't work for various
reasons. From what I remember, the current code did work with nvidia at
least. Mesa has made attempts to fix this, but they never really made it
in.

But it turns out you can make EGL/Mesa list the EGLConfigs that use X11
RGBA visuals, and context_x11egl.c contains code that explicitly selects
them if alpha is requested (see pick_xrgba_config()).

The reason EGL/Mesa did not list them (and thus breaking transparency)
is because we requested a EGL_ALPHA_SIZE != 0 if alpha is requested. But
the transparent EGLConfigs use EGL_ALPHA_SIZE == 0. That's because EGL
doesn't actually support the concept of transparent windows; the alpha
size parameter is something else (memory rendering without FBOs or
something, I don't care enough to look up the real reasons).

This still won't work on Wayland. Every EGL backend needs platform
specific code. (Good job, EGL, such an awesome platform independent
standard.)

Fixes: #6590
2020-08-27 11:55:20 +02:00
wm4 b5b83a1ed5 vo_gpu: EGL: slightly better debug logging of EGL configs 2020-08-27 11:55:20 +02:00
sfan5 fb736b49f1 ao/pulse: create the stream corked
Previously get_state() would keep setting the cork status
while paused, but it only does for that after underflows now.
Correct this oversight by creating the stream corked for start()
to uncork it at a later time.

fixes #8026
2020-08-26 16:14:29 +02:00
Dudemanguy f3f49de918 wayland: always update sbc for presentation time
Oversight in b0f0be7. The user_sbc value would update but not last_sbc
if no presentation events were received. This would result in an
incorrect sbc_passed value (in practice, this should always be 1 since,
as far I know, all wayland compositors are currently only capable of
double buffering). When bring the window back into view, it would result
in a single frame of very high vsync jitter. Although in most cases it
was imperceptible, rarely I was able to completely break playback (i.e.
constant mistimed/dropped frames). Fix this by simply incrementing
last_sbc by 1 if the window is hidden. The buffer swap call did still
occur. The user just didn't see it.
2020-08-24 11:11:39 -05:00
wm4 74e62ed2d1 Revert "demux_lavf: always give libavformat the filename when probing"
This reverts commit 41243e7c4f.

This fixes image format detection. FFmpeg has an utter called "image2",
which is designed to read patterns in filenames (so you can play
something like "%*.jpg" for all jpg files in the current directory).
"image2" is not what we want; it's just broken with custom I/O like
mpv uses it, and we don't want to "accidentally" interpret filenames
as pattern. That's why mpv blacklists it.

Unfortunately, "image2" is sometimes the format that FFmpeg's probe API
returns as best match. Thus demux_lavf fails to detect the file type,
and after some more futile attempts, we end up at demux_mf, which uses
detection by file extension. (Not sure why. I guess MPlayer did that,
and foudn that sufficient.) If the file extension is wrong (which
happens a lot because apparently the world is full of idiots who don't
manage to get the most simple things right), the image "loads", but
decoding obviously fails.

There's no easy way around this. The FFmpeg API has no mechanism to
exclude a specific format from probing (like image2, which breaks stuff
for us). Out of the 5 probe functions the API provides, none can probe
a specific format or include or exclude specific formats. The main
problem is that AVInputFormat.read_probe is a private symbol.

FFmpeg itself has no problem opening such files. It turns out that it
works, because even though image2 by itself uses detection by file
extension, it uses private API to further probe the exact format. It
explicitly excludes itself to prevent recursion.

But fortunately, that also means that it's impossible to get the image2
format if no filename is passed to the prober. (No filename, no file
extension.) Apparently we pass it in because it helps in corner cases.
Until almost 3 years ago, we passed the filename only when normal
probing already failed. Restore this by this revert. It makes
incorrectly named files work. The revert also makes the (apparently
forgotten) comment above the touched line of code true again.

Yes, quite possible that this breaks some mp3s again. You can't win
with FFmpeg. Thanks FFmpeg for making us fail at opening simple image
files and/or the most widely used file format for audio.
2020-08-23 12:44:54 +02:00
wm4 c9c01a07f8 audio: remove delay debug logging
Some absurd useless stuff.
2020-08-23 11:49:11 +02:00
Dudemanguy b0f0be7678 wayland: simplify presentation time
Why on earth did I ever bother with this dumb crap? If we do not have
any presentation statistics, just set the relevant vo_sync_info values
to -1 to disable it. It's much simpler than using mp deltas and trying
to keep up with mpv's clock. This also appears to fix audio/video
desynchronization if you start a video with the pause flag, move it out
of view, and then unpause it. Technically harmless since the video
wasn't even in view and putting back in view recovered it, but a quieter
terminal is better.
2020-08-22 20:43:49 +00:00
wm4 85f38a9765 demux_mf: actually report errors
Well, whatever. Only results in an error message being printed, because
there is no other error reporting mechanism, and the general policy is
to keep trying with the rest of the data (i.e. not report EOF).
2020-08-22 20:46:45 +02:00
wm4 c06577e291 player: do not loop if there's nothing to loop
This can happen if a file contains headers only, or if decoding of all
data failed, and such. Interestingly, it also happened when doing "mpv
--loop emptyfile.png", because demux_mf still detects file formats by
file extension.

In this situation, the player burned a lot of CPU by restarting playback
after doing nothing. Although such "degenerate" behavior can't be
avoided in all situations (what if you loop a file with 1 audio
sample?), detecting this seems to make sense.

For now, this actually decrements the loop count by 1, and then errors
out with a warning. Works for --loop and --ab-loop, while
--loop-playlist already avoids this situation with an existing
mechanism.
2020-08-22 20:43:15 +02:00
wm4 b3758db128 options: do not accept ":" as separator anymore in key/value lists
Accepting ":" in addition to "," seems confusing and dumb. It only
causing problems when you want to pass a value that contains ":". Remove
support for ":", it is now treated like any other normal character. This
affects all options that are listed as "Key/value list" in the option
list.

It's possible that this breaks for someone who happened to use ":" as
separator. But this was undocumented, and never recommended. Originally,
the option treated many other characters in a special way, but this was
changed in commit a3d561f950. I'm, not sure why ":" was explicitly
included. Maybe because -the absurd -vf/--af syntax uses ":" as list
separator. But "," was always recommended and used in examples for
key/value options.

Fixes: #8021 (if you consider it a bug)
2020-08-22 20:25:20 +02:00
der richter 0cea7b9ffb cocoa-cb: force layer update on resize
this fixes some race condition where the content of the layer wasn't
updated because the size didn't changed and the layer was already marked
as updated. just force an update on reconfig.

Fixes #7989
2020-08-22 14:22:49 +02:00
der richter 6c83e91e11 mac: add icc profile and ambient light sensor support
this is preparation for new backends. currently this is done via the
libmpv API but for future new new VOs not based on libmpv we need these
VOCTRL events.
2020-08-22 14:22:49 +02:00
der richter 5fb0f36937 mac: use config cache und wakeup for mac option runtime changes
remove the libmpv observer for the macOS specific options and use a
config cache + change callback for runtime changes. this is also a
preparation for new backends and generalises even more, since libmpv
functions can't and shouldn't be used in usual vo backends. for feature
parity the config cache is used.
2020-08-22 14:22:49 +02:00
der richter 9035a51b13 mac: make ontop level runtime changeable
this was requested on an old issue, but the comment has since been
deleted. i though it was useful enough to add it. it's also just a one
line change.
2020-08-22 14:22:49 +02:00
der richter fa982a7cbe mac: properly guard and unwrap an optional value
i don't know what i was thinking there, but force unwrapping is a very
bad idea.
2020-08-22 14:22:49 +02:00
der richter f79a591ae4 cocoa-cb: generalisation of backend independent parts
move all backend independent code parts in their own folder and files,
to simplify adding new backends. the goal is to only extend one class
and add the backend dependent parts there. usually only the (un)init,
config and related parts need to be implemented per backend. furthermore
all needed windowing and related events are propagated and can be
overwritten. the other backend dependent part is usually the surface for
rendering, for example the opengl oder metal layer.

in the best case a new backend can be added with only a few hundred
lines.
2020-08-22 14:22:49 +02:00
wm4 b16a6cb6c6 client API: note about libswscale corrupting memory
The software rendering API makes libswscale directly write into supplied
user memory. As such, weird memory corruption bugs on non-optimal buffer
configurations are exposed to the user.
2020-08-20 20:37:17 +02:00
Dudemanguy 30dcfbc9cb wayland: conditionally commit surface on resize
It was possible for sway to get incorrectly sized borders if you resized
the mpv window in a creative manner (e.g. open a video in a non-floating
mode, set window scale to 2, then float it and witness wrong border
sizes). This is possibly a sway bug (Plasma doesn't have these border
issues at least), but there's a reasonable workaround for this.

The reason for the incorrect border size is because it is possible for
mpv to ignore the width/height from the toplevel listener and set its
own size. This new size can differ from what sway/wlroots believes the
size is which is what causes the sever side decorations to be drawn on
incorrect dimensions.

A simple trick is to just explicitly commit the surface after a resize
is performed. This is only done if mpv is not fullscreened or maximized
since we always obey the compositor widths/heights in those cases.
Sending the commit signals the compositor of the new change in the
surface and thus sway/wlroots updates its internal coordinates
appropriately and borders are no longer broken.
2020-08-20 16:57:37 +00:00
rcombs c9474dc9ed player: add --subs-with-matching-audio option
This allows users to control whether full dialogue subtitles are displayed
with an audio track already in their preferred subtitle language.

Additionally, this improves handling for the forced flag, automatically
selecting between forced and unforced subtitle streams based on the user's
settings and the selected audio.
2020-08-19 23:44:54 -05:00
Dudemanguy db0f9fab67 wayland: refactor geometry/window handling
The original goal was to simplify all this logic to make it less fragile
and breaky. Unfortunately, that didn't exactly happen and things might
actually be more complicated in some ways (well in other ways it's
simplier). There's a lot of negotiation back and forth between the
client and the compositor regarding sizes. The client (aka mpv) can do a
resize on its own. But also the compositor can request its own resize
(which we should be nice and listen to of course). The older method had
a lot of breakfalls/edgecases that were gradually patched up as time
went on, but that approach is really fragile. This refactor should,
hopefully, be on a more solid foundation.

Don't call any of the xdg toplevel state changing functions
(fullscreen, maximized, etc.) directly. Use the toggle wrapper
functions. These signal that the state was changed which is later
handled in the toplevel listener.

Introduce a new vdparams variable that stores the actual dimensions of
the video. This does create some new (but neccesary) complexity.
wl->vdparams stores what the actual dimensions of the video are
(according to mpv). wl->window_size stores the last size of the window
(so it includes any manual resizes for instance). wl->geometry is the
actual size of the output that gets displayed on the screen.
2020-08-20 01:34:45 +00:00
Mohammad AlSaleh ffa9aaa2e4 stream: Implement slice:// for reading slices of streams
Add support for reading a byte range from a stream via
 the `slice://` protocol.

 Syntax is `slice://start[-end]@URL` where end is a maximum
 (read until end or eof).

 Size suffixes support in `m_option` is reused so they can
 be used with start/end.

 This can be very useful with e.g. large MPEGTS streams with
 corruption or time-stamp jumps or other issues in them.

Signed-off-by: Mohammad AlSaleh <CE.Mohammad.AlSaleh@gmail.com>
2020-08-19 17:22:53 +02:00
Dudemanguy 19aa5659f6 wayland: reset geometry on reconfig if fullscreen
Fixes #8014.
2020-08-18 08:11:05 -05:00
Dudemanguy 0216f8c787 wayland: soften GNOME warning
We've had some serious issues with GNOME in the past, but since then
their compositor has undergone some major internal improvements. The
most severe one [1], random vsync spikes and mistimed frames, can no
longer be reproduced by the original author of the issue. There are some
minor UI-related things (lack of window decorations for instance since
there is no xdg-decoration support), but users don't seem to complain
about that too much and they aren't revelant to playback.

3.38 isn't out quite yet, but that should also fix playback issues when
on a multimonitor setup (the fix is in the master branch at the moment).
In terms of playback, the only real concerning issue is the lack of idle
inhibit so a warning is still displayed. But GNOME has their own
workaround that users can use for that so if anyone happens to complain,
we can just point them to that.

[1] https://gitlab.gnome.org/GNOME/mutter/-/issues/957
2020-08-17 19:36:04 +03:00
Dudemanguy 486516f723 wayland: don't rely on presentation discarded
When using presentation time, we have to be sure to update the ust when
no presentation events are received to make sure playback is still
smooth and in sync. Part of the recent presentation time refactor was to
use the presentation discarded event to signal that the window is
hidden. Evidently, this doesn't work the same everywhere for whatever
reason (drivers?? hardware??) and at least one user experienced issues
with playback getting out of sync since (presumably) the discarded event
didn't occur when hiding the window. Instead, let's just go back to the
old way of checking if the last_ust is equal to the ust value of the
last member in the wayland sync queue. Fixes #8010.
2020-08-16 16:29:00 -05:00
Dudemanguy e9cde72536 wayland: refactor presentation time
The motivation for this change was a segfault caused by e107342 which
has complicated reasons for occuring (i.e. I'm not 100% sure but I think
it is a really weird race). The major part of this commit is moving the
initialization of presentation listener to the frame_callback function.
Calling it in swap_buffers worked fine but in practice it meant a lot of
meaningless function calls if a window was hidden (the presentation
would just be immediately discarded). By calling it in frame_callback,
we ensure the listener is only created when it is possible to receive a
presentation event.

Of course calling the presentation listener in feedback_presented or
feedback_discarded was considered, but ultimately these events are too
slow. Receiving the ust/msc/sbc triplet here and then passing it to mpv
results in higher vsync judder since there is (likely) not enough time
before the next pageflip. By design, the frame callback is meant to give
us as much time as possible before the next repaint so calling it here
is probably optimal.

Additionally, we can make better use of the feedback_discarded event.
The wp_presentation_feedback should not be destroyed here. It will be
taken care of either when we get feedback again or when the player
quits. Instead what we can do is set a bool that tells wayland_sync_swap
to update itself based on mp_time delta. In practice, the result is not
any different than before, but it should be more understandable what is
going on now.

Of course, the segfault mentioned at the beginning is fixed with this as
well.
2020-08-16 18:34:09 +00:00
Avi Halachmi (:avih) 8ec61c366a DOCS/vo.rst: TCT: add note on interleaved output 2020-08-16 12:26:27 +03:00
Avi Halachmi (:avih) 557e9d9531 win32: scripting utils.get_env_list(): use UTF-8
lua/js utils.get_env_list() uses `environ' which was ANSI, thus
it broke any unicode names/values.

mpv already has an internal utf8_environ for win32, but it's used
only at the getenv(..) wrapper and not exposed in itself, and also it
has lazy initialization - on first getenv() call.

Now `environ' maps to a function which ensures initialization while
keeping it an l-value (like posix expects).

The cost of this fuglyness is that files should include osdep/io.h
(which now declares environ as extern) rather than declaring it
themselves, or else the build will break on mingw.
2020-08-16 12:24:19 +03:00
wm4 7f67c5250a lua: pass strings with embedded zeros as byte arrays
This was a vague idea how to handle passing byte arrays from Lua to the
mpv command interface in a somewhat reasonable way. The idea was
cancelled, but leave the Lua part of it, since it might get useful
later, and prevents passing (and silently cutting off) such byte
strings.

Barely tested, let's say not tested at all.
2020-08-16 02:57:26 +02:00
wm4 e27c523a10 command: extend subprocess command stdin, change behavior
Make it possible to feed a string to stdin of a subprocess. Out of
laziness, it can't be an arbitrary byte string. (Would require adding an
option type that takes in a Lua byte string.)

Do not set stdin of a subprocess to fd 0 (i.e. mpv's stdin) anymore,
because it makes things more consistent. Enabling stdin didn't make too
much sense in the first place, so this behavior change seems
justifiable.

win32 support missing.

Fixes: #8003
2020-08-16 02:54:44 +02:00
wm4 d6bf3880d7 demux_mkv: warn against some other aspects of mismatching codec data
Such files violate the specification. Unfortunately, I could not test
whether it really works correctly, since I don't have a sample at hand
that is not broken in this regard.
2020-08-16 01:00:29 +02:00
wm4 112d2a2c50 command: export alpha type in format properties 2020-08-15 12:05:11 +02:00
Dudemanguy e107342ff9 wayland: destroy presentation feedback on uninit
Nothing major but it's technically possible for the
wp_presentation_feedback struct to still be allocated when quitting the
player. Just destroy it if it exists like all of the other wayland
objects.
2020-08-14 18:22:58 -05:00
Dudemanguy 6573e0a0af wayland: actually resize videos in a playlist
In a playlist of videos with different sizes, going to the next video
would not properly resize the window. This actually broke way back in
7170910 (oops), but somehow nobody ever complained. The fix is simple.
If a window isn't maximized, be sure to set the window geometry again.
2020-08-14 15:20:40 -05:00
wm4 cf573797ee sd_ass: remove debug print
It's not even spelled correctly.
2020-08-14 21:28:29 +02:00
Dudemanguy 9bce236714 wayland: expose wayland-app-id as a user option
This is extremely similar to x11's WM_CLASS. This commit allows users to
set mpv's app-id at runtime for any of the wayland backends.
2020-08-14 13:02:01 +00:00
Dudemanguy 4b5ead0834 wayland: tweak xdg_surface creation
Just some small changes when creating the xdg_surface. Don't set the
toplevel title (or app id) in create_xdg_surface anymore because it's
entirely pointless. Also make it possible for create_xdg_surface to
return something other than 0 so the error checking is somewhat
meaningful. It's not really clear if these xdg functions can even fail
in the first place (perhaps some weird proxy marshalling crap could
possibly go wrong somehow), but it can't hurt. Note that all app id
stuff has been removed (temporarily) in this commit. See the next commit
which adds it back in.
2020-08-14 13:02:01 +00:00
wm4 dec98ad00e command: fix current-tracks property notification
Also for track-list, because it contains the "selected" flag.
2020-08-13 15:19:50 +02:00
Wessel Dankers 1dac111268 sub: add application/font-sfnt to the list of font mime types
According to both file(1) and
https://www.iana.org/assignments/media-types/application/font-sfnt
application/font-sfnt is also a valid mime type for (at least some) .ttf
files.
2020-08-13 15:02:50 +02:00
Alcaro 57a0b897a2 client API: fix misleading remark 2020-08-13 12:38:15 +02:00
Dudemanguy bba00c133d manpage: document a couple of wayland options
--wayland-edge-pixels-pointer and --wayland-edge-pixels-touch were both
left out of the manual.
2020-08-12 15:33:06 -05:00
wm4 5dcfe32ff2 ytdl_hook: sort subtitle list by language
The subtitle list is returned in randomized order, because a table (i.e.
JSON object) is used. To make the order stable across repeated
invocations, sort it by language.
2020-08-12 20:16:13 +02:00
wm4 69c6b244a1 client API: fix incorrect documentation in sw renderer
This was incorrect, and grossly misleading. It created the impression
that the buffer is passed to mpv_render_context_create(), instead of
mpv_render_context__render().
2020-08-12 19:59:43 +02:00
wm4 f0b4ad5808 sd_ass: fix converted subtitles path
Commit cda8f1613f broke this.
2020-08-12 19:29:10 +02:00
wm4 2f0bd53c8c DOCS/contribute.md: add a CCoC
(The recommendation is to add the document to the project git root, but
I'm against dumping such things into git. I'd rather replace the
Copyright full text files with links and move contribute.md to the wiki
than add the CCoC text as a file.)
2020-08-12 17:32:02 +02:00
wm4 ed2e2894ab sub: extend range of --sub-pos option
Seems like this is requested all the time.

It seems libass allows out of range values, but does allows the subtitle
to go out of the screen at the bottom (only when moving it to the top
it's "clamped"). Too bad, don't do that then. The bitmap sub rendering
code on the other hand is under our control, and will not move a
subtitle out of the screen.

Fixes: #7986
2020-08-12 17:30:30 +02:00
wm4 cda8f1613f sd_ass: force full reinit if certain options change at runtime
Options like --sub-ass-force-style and others could not be changed at
runtime (the changes didn't take any effect). Fix this by using the
brutal approach, and completely reinit the subtitle state when this
happens. Maybe a bit clunky, but for now I'd rather not put more effort
into this.

Fixes: #7689
2020-08-12 17:28:25 +02:00
wm4 720bcd79d0 command: add a way to access properties of a current track
Requested. Should be good for simple use cases. "sub2" is technically
inconsistent (since the option is called --secondary-sid), but fuck the
consistent name.
2020-08-12 17:23:13 +02:00
wm4 45cc47a68b TOOLS/file2string: change to python3
The same was done to matroska.py before, so at least it's consistent.
Doesn't matter for waf, because it imports this script (rather than
executing it).
2020-08-12 17:21:49 +02:00
James Ross-Gowan bb231889fd win32: request the UTF-8 code page for Windows APIs
This sets the activeCodePage property in the manifest, which forces the
ANSI code page to be UTF-8 in Windows 10 1903 and up. It shouldn't make
a difference for mpv itself, since mpv already uses the wide-char APIs
for most functions, however some of mpv's dependencies, such as Lua,
rely on the ANSI codepage. Hence this change enables support for Unicode
file names in Lua's I/O library.

Thanks @avih for finding this property.

See:
https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page
2020-08-08 15:00:25 +03:00
ekisu cdd8ba7224 ao/lavc: add channels and channel_layout to AVFrame
FFmpeg expects those fields to be set on the AVFrame when
encoding audio, not doing so will cause the avcodec_send_frame
call to return EINVAL (at least in recent builds).
2020-08-07 19:42:42 +02:00
wm4 4c72202eb1 auto_profiles: unapply conditional profiles if declared
Uses the mechanism introduced in the previous commit. The hope was to
make auto-profiles easier to use, and to get rid of the need for
manually created inverse profiles. Not sure if the end result is useful.
2020-08-07 19:41:56 +02:00
wm4 1f132c675a options: add some way to more or less "unapply" profiles
Make it possible to restore from profiles by backing up the option
values before profile application. This is sort of like unapplying a
profile. Since there might be multiple ways to do this, a profile needs
to explicitly provide the "profile-restore" option, which specifies how
exactly this should be done.

This is a big mess. There is not natural way to do this. Profile
application is "destructive" and simply changes the values of the
options. Maybe one could argue that the option system should have
hierarchical "overlays" of profiles instead, where unset options will
use the value of the lower profiles. Options set interactively by the
user would be the top profile. Default values would be in the lowest
profile. You could unapply a profile by simply removing it from this
overlay stack.

But uh, let's not, so here's something stupid. It reuses some code used
for file local options to reduce code size. At least the overlay idea
would still be possible in theory, and could be added as another
profile-restore mode.

This is used by the following commit.
2020-08-07 19:41:56 +02:00
Avi Halachmi (:avih) d5a02dd934 js: hooks: allow deferred continuation (match d0ab562b)
The callback now gets an object argument with defer/cont functions.

Like the lua code, the behavior is that each hook event allows at
most one continue, but nothing enforces the order of continuations
if more hook events arrive before prior ones were continued - which
is possible now with the defer option, but wasn't possible before
(continuation was synchronous from the hook event handler).
2020-08-07 15:12:20 +03:00
wm4 53ee1ae417 auto_profiles: register hooks for more synchronous profile application
The property observation mechanism is fairly asynchronous to the player
core, and Lua scripts also are (they run in a separate thread). This may
sometimes lead to profiles being applied when it's too load.

For example, you may want to change network options depending on the
input URL - but most of these options would have to be set before the
HTTP access is made. But it could happen that the profile, and thus the
option, was applied at an slightly but arbitrary later time.

This is generally not fixable. But for the most important use-cases,
such as applying changes before media opening or playback
initialization, we can use some of the defined hooks.

Hooks make it synchronous again, by allowing API users (such as scripts)
to block the core because it continues with loading.

For this we simply don't continue a given hook, until we receive an idle
event, and have applied all changes. The idle event is in general used
to wait for property change notifications to settle down. Some of this
relies on the subtle ways guarantees are (maybe) given. See commit
ba70b150fb for the messy details. I'm not quite sure whether it
actually works, because I can't be bothered to read and understand my
bullshit from half a year ago. Should provide at least some improvement,
though.
2020-08-05 23:28:24 +02:00
wm4 d0ab562b1f lua: make hook processing more flexible
This can now opt to not continue a hook after the hook callback returns.
This makes it easier for scripts, and may make it unnecessary to run
reentrant event loops etc. for scripts that want to wait before
continuing while still running the event loop.
2020-08-05 23:19:41 +02:00
wm4 13d354e46d auto_profiles: add this script
This is taken from a somewhat older proof-of-concept script. The basic
idea, and most of the implementation, is still the same. The way the
profiles are actually defined changed.

I still feel bad about this being a Lua script, and running user
expressions as Lua code in a vaguely defined environment, but I guess as
far as balance of effort/maintenance/results goes, this is fine.

It's a bit bloated (the Lua scripting state is at least 150KB or so in
total), so in order to enable this by default, I decided it should
unload itself by default if no auto-profiles are used. (And currently,
it does not actually rescan the profile list if a new config file is
loaded some time later, so the script would do nothing anyway if no auto
profiles were defined.)

This still requires defining inverse profiles for "unapplying" a
profile. Also this is still somewhat racy. Both will probably be
alleviated to some degree in the future.
2020-08-05 22:37:47 +02:00
Dudemanguy f457f3839a manpage: clarify requirements for boxvideo
The osc must not auto-hide for this option to do anything.
2020-08-04 15:20:24 -05:00
Dudemanguy fb55ee99e3 wayland: don't set mouse pos on state change
Sway 1.5 started sending more pointer motion events to mpv which broke
the autohiding behavior. The cursor would appear again if you
fullscreened. Sway had a good reason to do this because certain
applications had inconsistencies between hardware cursor and software
cursor without rebasing on state changes[1]. So mpv needs to take this
special case into consideration.

Initially, simply checking mouse coordinates for changes was considered,
but this doesn't work. All coordinates are surface-local in wayland so
something can appear to move in the local coordinate space but not
globally. You're not allowed to know global mouse coordinates in
wayland, and we don't care about local coordinate changes in mpv so this
approach isn't viable.

Instead, let's just keep track of a local state change. If the toplevel
surface changes in some way (fullscreen, maximized, etc.), then just set
a bool that lets us ignore the mp_input_set_mouse_pos function. This
keeps the cursor from appearing simply because the state was changed
(i.e. fullscreening). For compositors that don't send pointer motion
events on a state change, this does technically mean that the initial
mp_input_set_mouse_pos is never set. In practice, this isn't a
noticeable difference though because moving a mouse generates a ton of
motion events so you'll immediately see it on the second motion event.

[1] https://github.com/swaywm/sway/issues/5594
2020-08-02 17:06:51 -05:00
Eva 359261c50c stats: fix crash when aspect ratio is unavailable
When switching between files it's possible that r["aspect"] returns nil, resulting in a crash.
2020-08-03 00:50:57 +03:00
Derek Guenther b238897614 ytdl_hook: fix typo in unexpected error message 2020-08-01 15:02:39 +03:00
Dudemanguy 10e11834e5 wayland: avoid potential deadlocks
wl_display_dispatch is dangerous because it will block forever if the
event queue is empty. Any direct calls to this function should just be
replaced with wl_display_dispatch_pending which accomplishes the same
thing for mpv's purposes without any chance of blocking.

The other potential trap is wl_display_roundtrip. It can internally call
wl_display_dispatch which in certain circumstances could potentially
block. There are cases where we need the server to finish processing
client requests before doing anything else so this can not be cleanly
avoided. The dangerous call is the usage of wl_display_roundtrip in
vo_wayland_wait_frame. In the majority of cases, this shouldn't be a
problem because the previous wl_display_read_events should always queue
up some events on the fd for wl_display_roundtrip to send. However, the
compositor could potentially send us an error in the display queue that
could lead to bad behavior when wl_display_roundtrip is called.

The wl_display_roundtrip can't be removed because we are relying on its
semi-blocking capabilities, but the logic can be slightly adjusted to be
safer. The obvious thing to do is to make sure we check the pollfd for
any errors. If one is returned, then we call wl_display_cancel_read and
try again. The less obvious trick is to call wl_display_dispatch_pending
and move wl_display_roundtrip outside of the blocking + timeout loop.

This change has some subtle but important differences. Previously,
vo_wayland_wait_frame would read an event and wait on the server to
process it one-by-one. With this change, the events are dispatched as
soon as possible to the server and then we wait on all of those
(potentially multiple) events to be processed after we have either
received frame callback or the loop times out.

After that is done, we can then check for if there are any errors on the
display. If it's all clear, we can run wl_display_roundtrip without any
worries. If some error happens, then don't execute the function at all.
2020-07-31 21:23:45 +00:00
der richter bb800352f5 travis: update macOS image from 10.14 to 10.15 2020-07-31 13:22:37 +02:00
der richter 3586ef77f3 travis: make macOS builds faster
the problem here is that with time, and because the macOS VMs don't get
updated, the homebrew update is getting longer since more and more
changes have to be pulled. to prevent that, we cache the homebrew
installation folder after the update. that way we don't have to update
several months worth of updates every build. for the legacy build we
have to check put master again to actually cache the newest homebrew
version.

additionally to that, we also do the same as on the legacy build, with
the addition of not removing all installed formulas but only the ones
we don't need. so we don't need to reinstall those.
2020-07-31 13:22:37 +02:00
der richter 16a08e87c8 travis: fix macOS 10.12 legacy build
just remove all pre installed formulas, since we don't need the majority
of it. after that install what we need. this also fixes the brew update
of those formulas where the source links were broken like popt.

this also helps when the build times out due to building some formulas
from source that are not dependencies we need.
2020-07-31 13:22:37 +02:00
Dudemanguy 700f4ef5fa wayland: correctly signal the end of drag-and-drop
Previously, the compositor was signaled that a drag-and-drop ended with
wl_data_offer_finish in check_dnd_fd. This is, however, erroneous
because it is outside of the data_device_listener and in some cases
caused errors with certain compositors. check_dnd_fd itself does not
need to know or care about anything that happens in wayland. It just
needs to read data from an fd. The simple fix is to just always signal
the end of a drag-and-drop in data_device_handle_drop. check_dnd_fd can
free memory and close the fd later, but it should not talk to the
compositor. Fixes #7954.
2020-07-29 18:36:54 -05:00
Dudemanguy 36951ab6a7 wayland: fix a potential race in wait_events
The read of the wayland display fd in vo_wayland_wait_events was
incorrect and technically vulnerable to race conditions. The correct
usage as per the client api is to use wl_display_prepare_read as well as
wl_display_read_events.
2020-07-29 17:45:42 +00:00
Dorian Rudolph 6e3d4aa94b af_scaletempo2: fix bug where speed was not set
the --speed parameter did not work with
mpv --no-config whatever.mp3 --video=no --speed=2 --af=scaletempo2
(https://github.com/mpv-player/mpv/pull/7865#issuecomment-664243401)
2020-07-27 18:12:05 +02:00
wm4 1fe6def066 af_scaletempo2: M_PI is always defined
I forgot why/how (C99?), but other code also uses it.
2020-07-27 00:59:37 +02:00
Dorian Rudolph 785a2b1261 audio: add scaletempo2 filter based on chromium
scaletempo2 is a new audio filter for playing back
audio at modified speed and is based on chromium
commit 51ed77e3f37a9a9b80d6d0a8259e84a8ca635259.
It sounds subjectively better than the existing
implementions scaletempo and rubberband.
2020-07-27 00:57:22 +02:00
Avi Halachmi (:avih) b5368980a8 js: add mp.utils.get_env_list() (match 0e7f53a5, 9301cb78) 2020-07-26 02:26:37 +03:00
Avi Halachmi (:avih) 9301cb78a8 lua: change mp.get_env_list() to utils.get_env_list()
It's documented (twice) at utils, and logically it's the correct place
for it.
2020-07-26 02:25:59 +03:00
sfan5 b67c7a23b8 stats: fix single invocation keybindings 2020-07-21 19:34:41 +02:00
Jan Beich f89c7404d1 manpage: drop --sdl-bufcnt after 346c687d5a 2020-07-21 15:08:47 +02:00
Eva 1732fb0555 external_files: add .pgs subtitle extension 2020-07-21 15:07:17 +02:00
James Ross-Gowan 83fec9bafb subprocess-win: update to mp_subprocess2
This fixes the "run" and "subprocess" commands on Windows, including
youtube-dl support.

Unix-like FD inheritance is emulated on Windows by using an undocumented
data structure[1] that gets passed to the newly created process in
STARTUPINFO.lpReserved2. It consists of two sparse arrays listing the
HANDLE and internal CRT flags corresponding to each FD. This structure
is used and understood primarily by MSVCRT, but there are other runtimes
and frameworks that can write it, like libuv.

The code for creating asynchronous "anonymous" pipes in Windows has been
enhanced and moved into windows_utils.c. This is mainly an artifact of
an unfinished future change to support anonymous IPC clients in Windows.
Right now, it's still only used in subprocess-win.c

[1]: https://www.catch22.net/tuts/undocumented-createprocess
2020-07-20 21:02:17 +02:00
wm4 4476911d45 manpage: add named arguments "subprocess" example
At the same time, this is an example for a command with named arguments.
2020-07-20 21:02:17 +02:00
wm4 d5959df2be client API: comment about signal handlers
Sharing a process sure is hard in POSIX.

The rationale is that you'd have to handle EINTR on every single
blocking syscall. stream_file.c does not seem to handle it on read()
calls.

It appears that on most modern systems, this can happen only if you call
sigaction(), and incompetently forget to add SA_RESTART. signal()
usually adds it.
2020-07-20 21:02:17 +02:00
wm4 0a796e9840 command: add another variant of revert-seek
Requested. See manpage additions. Not sure if it actually deserves to be
a first class feature, rather than an external script or so.

Fixes: #7913
2020-07-20 21:02:17 +02:00
wm4 0e7f53a5bc lua: add mp.get_env_list() function
Because Lua is too stupid to provide this directly, and I sort of need
it.
2020-07-20 21:02:17 +02:00
wm4 0279a44d93 command: extend subprocess command
Add env and detach arguments. This means the command.c code must use the
"new" mp_subprocess2(). So also take this as an opportunity to clean up.
win32 support gets broken by it, because it never made the switch to the
newer function.

The new detach parameter makes the "run" command fully redundant, but I
guess we'll keep it for simplicity. But change its implementation to use
mp_subprocess2() (couldn't do this earlier, because win32).

Privately, I'm going to use the "env" argument to add a key binding that
starts a shell with a FILE environment variable set to the currently
playing file, so this is very useful to me.

Note: breaks windows, so for example youtube-dl on windows will not work
anymore. mp_subprocess2() has to be implemented. The old functions are
gone, and subprocess-win.c is not built anymore. It will probably work
on Cygwin.
2020-07-20 21:02:17 +02:00
Dudemanguy c9742413ac wayland: remove unused declaration
Should have been removed in 055a490 but was forgetten.
2020-07-19 15:21:05 -05:00
Dudemanguy 63ae6037df build: actually install the 128x128 icons
mpv has generated this icon size for a while now, so go ahead and
install it in the usual place like the other icon sizes.
2020-07-19 12:15:48 -05:00
Niklas Haas c53a47eda3 vo_gpu: clip highlights before tone-mapping
Rather than after tone-mapping. This prevents overflow when the
pre-tonemapped signal contains inputs exceeding sig_peak. I also
realized that with this clipping in place, post-clipping no longer needs
to be done, so this isn't even particularly slower.

The only two exceptions to the rule are "clip" and "linear", which
relied on the post-clipping to do their tone mapping properly.

Fixes #7929
2020-07-19 08:07:48 +02:00
Niklas Haas 96cdf5315e vo_gpu: vulkan: print libplacebo API ver
This normally gets printed by libplacebo itself when initializing the
context, but due to the way our code is structured (for convenience) we
don't have the log hook enabled by the time this function call is
relevant. So instead just print it manually as an easier work-around
than restructuring the code.
2020-07-16 09:41:09 +02:00
wm4 2a89da0c85 zimg: add slice threading and use it by default
This probably makes it much faster (I wouldn't know, I didn't run any
benchmarks ). Seems to work as well (although I'm not sure, it's not
like I'd perform rigorous tests).

The scale_zimg test seems to mysteriously treat color in fully
transparent alpha differently, which makes no sense, and isn't visible
(but makes the test fail). I can't be bothered with investigating this
more. What do you do with failing tests? Correct, you disable them. Or
rather, you disable whatever appears to cause them to fail, which is the
threading in this case.

This change follows mostly the tile_example.cpp. The slice size uses a
minimum of 64, which was suggested by the zimg author. Some of this
commit is a bit inelegant and weird, such as recomputing the scale
factor for every slice, or the way slice_h is managed. Too lazy to make
this more elegant.

zimg git had a regressio around active_region (which is needed by the
slicing), which was fixed in commit 83071706b2e6bc634. Apparently, the
bug was never released, so just add a warning to the manpage.
2020-07-15 22:59:17 +02:00
wm4 f1290f7095 zimg: refactor (move around fields)
The intention is to add slice-threading to the wrapper. For that
purpose, move all zimg related state to a new struct mp_zimg_state.
There is now an array of instances of this struct. The intention is to
have one instance for each thread. As of this commit, this is hardcoded
to 1 thread; the following commit extends this.
2020-07-15 22:59:17 +02:00
Oleg Oshmyan d086421ca4 osd_libass: set ScaledBorderAndShadow
libass recently switched the default from 1 to 0 for compatibility
with ASS scripts that rely on the historical/VSFilter default of 0.

libass does attempt to detect and avoid breaking scripts that rely
on the historic libass-only default of 1, but it doesn't cover tracks
created directly through the API, so set the header explicitly.

Fixes https://github.com/mpv-player/mpv/issues/7900.
2020-07-15 15:49:03 +03:00
Philip Langdale fba1c681b8 vo_gpu: hwdec_vaapi: handle lack of object size with AMD drivers
It turns out that the AMD driver doesn't bother to set the size
field in the descriptor for an exported VA surface. I guess they
assume the caller can always use lseek() and don't bother. So, we
need to use lseek() in these situations.

Modified-by: Niklas Haas <git@haasn.xyz>

Guarded this behind PL_API_VER >= 88 to prevent it from exploding on
older libplacebo versions, where vaapi support does not yet work
properly on AMD due to lack of DRM modifiers.
2020-07-14 07:32:04 +02:00
Niklas Haas 22e7c700dd vo_gpu: hwdec_vaapi: add support for DRM format modifiers
This is required to get non-corrupted textures when importing vaapi
planes on AMD drivers.
2020-07-14 07:32:04 +02:00
sfan5 7a7a0a78b5 ao/pulse: fix reporting of playing state
When get_state() corks the stream after an underrun happens
priv->playing is incorrectly reset to true, which can cause the
player to miss the underrun entirely. Stop resetting priv->playing
during corking (but not uncorking) to fix this.
2020-07-12 23:44:41 +02:00
sfan5 f3b29a680c ao/pulse: flush stream on underrun
The underflow callback introduced in d27ad96 can be called
when the buffer is still full, causing playback to never
resume afterwards since get_state() reports free_samples == 0.
Fix this by fully resetting on underrun, which flushes
the stream and ensures free buffer space.

fixes #7874
2020-07-12 23:34:08 +02:00
der richter c82abb3a65 cocoa-cb: fix unfs window size when toggling out of fullscreen
we properly set the unfs window size on live resize end. due to a race
condition in the fullscreen events, which is also a live resize, the
unfs window size is incorrectly set to a fullscreen size. this happens
when the end fs screen event triggers before the end of live resize one.

this just adds a second condition to not be un fullscreen when updating
the unfs window size.
2020-07-12 12:06:56 +02:00
wm4 4a93b046e9 x11: add option to make window appear on a specific workspace
Mess this into the --geometry option, because I like to be
irresponsible. I considered adding a separate option, but at least this
allows me to defer the question how the hell this should work as
property (geometry simply and inherently does not).

Tested on IceWM only. Option equality test and string output not tested.
2020-07-12 00:12:55 +02:00
wm4 06033df715 demux_lavf: workaround reading gif from unseekable streams
FFmpeg, being the pile of trash as usual, recently broke this. Add our
own trash hack to trashily workaround this shit.

Fixes: #7893
2020-07-09 12:29:22 +02:00
wm4 adbd28b1db player: fix outdated comment 2020-07-09 12:26:54 +02:00
wm4 b961efb0af sws_utils: do not mutate src/dst parameters
Probably did not cause any practical problems, but it sure seems
unclean. sws_utils users might also rely on these fields being exactly
the same as the actual input/output. It's better to avoid this.
2020-07-08 22:45:12 +02:00
wm4 c498b2846a x11: remove terrible xdg-screensaver hack
I'm tired of dealing with this frequent spawning of xdg-screensaver when
debugging and what not. xdg-screensaver was never a serious tool anyway,
it's more like some self-deprecating joke by FDO folks.

This will affect X11 on GNOME and other DEs. I'm singling out GNOME
though, because they are the ones actively sabotaging any sane
technical solutions and community cooperation.

I have been accused of taking it out on innocent GNOME users, while none
of this will reach GNOME developers. Of course that is not the
intention.
2020-07-08 22:45:07 +02:00
wm4 b93f142011 client API: add software rendering API
This can be used to make vo_libmpv render video to a memory buffer. It
only adds a new backend API that takes memory surfaces. All the render
API (such as frame rendering control and so on) is reused.

I'm not quite convinced of the usefulness of this, and until now I
always resisted providing something like this. It only seems to
facilitate inefficient implementation. But whatever.

Unfortunately, this duplicates the software rendering glue code yet
again (like it exists in vo_x11, vo_wlshm, vo_drm, and probably more).
But in theory, these could reuse this backend in the future, just like
vo_gpu could reuse the render_gl API.

Fixes: #7852
2020-07-08 22:42:05 +02:00
Avi Halachmi (:avih) 688251bc66 path: fix broken exe-dir[/mpv] config locations
This is a regression since c3694f0, at least on Windows.

Fixes #7889
Fixes #7881
2020-07-08 12:14:54 +03:00
wm4 cdaa496314 Warn if on GNOME
GNOME actively fights the standard we try to rely on.
2020-07-07 21:22:19 +02:00
sfan5 8fbc4b1737 ci: add d3d11 to mingw build 2020-07-01 00:44:40 +03:00
Niklas Haas ace249acc5 vo_gpu: vulkan: add ability to disable events
libplacebo exposes this feature already, because this particular type of
bug is unusually common in practice. Simply make use of it, by exposing
it as an option.

Could probably also bump the libplacebo minimum version to get rid of
the #if, but that would break debian oldoldstable or something.

Fixes #7867.
2020-06-30 20:42:52 +02:00
wm4 22a27c6720 player: warn if both proper and compat. config directories exist
No idea why there's logic to add them all to the search path, so "both"
are used. In any case, this isn't something anyone should use.
2020-06-25 17:56:16 +02:00
wm4 c3694f0acb path: do not use old_home for win32 exe dir
Apparently mpv supports loading config files from the same directory as
the mpv.exe. This is a fallback of some sort. It used the old_home
mechanism.

I want to add a warning if old_home exists, but that would always show
the warning on win32. Obviously we don't want that.

Add a separate exe_dir entry to deal with that.

Untested, but probably works.
2020-06-25 17:56:16 +02:00
wm4 269f0e743e path: switch back to using non-XDG config dir by default
XDG is stupid, so change back to the standard behavior. Unfortunately,
most users will now have the XDG one, so we will still need to load
this. (This is exactly the same problem as when XDG support was
introduced, just the other way around).

This should not affect any normal users. Hopefully I tested this well
enough; my intention is not to torment miserable XDG fans; they can keep
using their config dir if they want it.

This changes behavior in two cases:
- new users (now creates ~/.mpv/ instead of ~/.config/mpv/)
- users which have both directories

The latter case will behave subtly or obviously different, not sure.
Just fix your shit.

Extend the manpage with all the messy details, as far as I could reverse
engineer them from the code.
2020-06-25 17:56:16 +02:00
sfan5 afe2b83183 vo_gpu: fix typo in struct name 2020-06-24 08:58:50 +02:00
wm4 1194ecd154 manpage: --demuxer-seekable-cache is useless
De-emphasize it, since a user should usually not use it. This _could_ be
used to make the cache seekable with --cache=no, but it's better and
more intuitive to use --cache=yes. As such, the only use of this is for
debugging. I'm not quite sure if this should be removed entirely, but I
still see some value in it (for example if you want the cache lookahead,
but you're using a stream where cache seeking is somehow broken).
2020-06-23 20:47:22 +02:00
sfan5 0e2d4ee595 ci: replace mingw build scripts 2020-06-22 23:57:15 +03:00
Stephen Salerno 5141662427 vo_gpu: use highp float if available for GLES
Using mediump float on GLES causes problems with kernel resampling,
PQ HDR, and possibly others. The issues are fixed by using highp,
which is available when GL_FRAGMENT_PRECISION_HIGH is defined.
2020-06-21 19:14:16 +03:00
Niklas Haas dc24a437fb vo_gpu: add better gamut clipping option
See https://code.videolan.org/videolan/libplacebo/-/commit/d63eeb1ecc204

Enabled by default because I think it looks better. YMMV.
2020-06-19 08:09:19 +02:00
Niklas Haas ae5ac7e90a vo_gpu: fix scaler/window validation to allow unsetting
--dscale= and --*scale-window= (i.e. an empty string) are respectively
valid settings for their options (and, in fact, the defaults).

This fixes the bug that it was impossible to reset e.g. tscale-window
back to the default "unset" setting after setting it once.

Credit goes to @CounterPillow for locating the cause of this bug.
2020-06-18 02:02:45 +02:00
wm4 b97f57bfd4 vo_x11: partially restore operation on bad endian systems
For testing in VMs I guess?

This features a very broken hack that probably works. Though I didn't
test the packed format case. Again, the mismatch is essentially due to
big endian byte addresses decreasing as bit addresses increase, so you
can't represent a bit position in a byte stream with a single address,
which the mpv metadata does.

OSD is broken because repack.c doesn't support big endian. You'll have
to live with it.
2020-06-17 19:44:50 +02:00
wm4 fd9c570f22 video: some concessions to big endian hosts
The recent changes to the image format metadata broke big endian, and
that was intentional. Some things are inherent to little endian (like
the idea to coalesce bit and byte offsets into a single bit offset), and
they don't be fixed. But some obvious things can be fixed, such as
marking LE vs. BE formats the right way around on BE hosts.

The metadata is formally still in LE, except that if the LE/BE flag
matches the host endian, the host endian can be used when accessing
packed formats with bit shifts, or when computing byte aligned component
byte offsets. The former may work because formats with LE/BE variants
use the same bit offsets after byte swapping, the latter may work
because little endian is the natural concept for addressing memory. But
it will "subtly" fail to do the right thing in some cases, and code
using this can't know, so have fun.

Many things are broken, but this makes e.g. vo_gpu mostly work.

My general opinion about BE computers is that you should get a better
computer, you can get one for free from any garbage dump.
2020-06-17 19:44:45 +02:00
wm4 1ffa83ea92 test: update to new ffmpeg pixfmts
Mainly, X2RGB10BE is added. Add our own unpack test for this format.
Also, swscale seems to have added support for GBRPF conversion.
2020-06-17 19:43:09 +02:00
wm4 6ff20c71ab video: alias IMGFMT_RGB30 to AV_PIX_FMT_X2RGB10
IMGFMT_RGB30 was added first; FFmpeg added AV_PIX_FMT_X2RGB10 later.
This is exactly the same, so treat them as such. For some reason,
libswscale still seems to output incompatible data - not sure what this
is about, but I'm not going to debug it.
2020-06-17 19:43:09 +02:00
wm4 b9069c9dbf repack: handle endian in a more general way
Instead of applying this only to "regular" formats, do it with all
formats.

For some reason, some repackers still have their own endian code. These
could probably be removed, but whatever.
2020-06-17 19:43:09 +02:00
wm4 7d755020f3 img_format: fight ffmpeg pixdesc some more
This change attempts to fix detection of how endian swapping is to be
performed. Details can be found in the code comments.

It should not change anything, other than fixing handling of the
X2RGB10BE ffmpeg pixel format. This format was detected incorrectly, and
the component location metadata was discarded due to an internal
consistency check. With this commit, it is handled correctly. At first I
thought the X2RGB10BE ffmpeg pixdesc metadata was wrong, but it appears
to be correct. The problem with this format is that it's the first
packed RGB format that requires bit shift to access, and where the
endian word size is larger than the (rounded up) component size, all
while pixdesc would "require" you to perform 3 memory accesses (instead
of 1), and the code tries to reverse this.

It appears that trying to use the pixdesc metadata is much, much more
work than just duplicating it in a saner form. To be fair, most problems
are with big endian, and the mpv internal format does not care much
about endian _hosts_.
2020-06-17 19:43:09 +02:00
Kevin Mitchell 5e323333cf audio: don't lock ao_control for pull mode drivers
The pull mode APIs were previously required to have thread-safe
ao_controls. However, locks were added in b83bdd1 for parity with push
mode. This introduced deadlocks in ao_wasapi.

Instead, only lock ao_control for the push mode APIs.

fixes #7787

See also #7832, #7811. We'll wait for feedback to see if those should
also be closed.
2020-06-17 02:22:51 -07:00
Niklas Haas b16d8865b7 vo_gpu: placebo: add fallback code for stride mismatch
For cases in which the requirements of the GPU API prevent directly
uploading a texture with a given stride, we need to fix the stride
manually in host memory. This incurs an extra memcpy, but there's not
much we can do about it. (Even in `ra_gl` land, the driver will just
hide this memcpy from the user)

Note: This code could be done better. It could only copy as many texels
as needed, and it could pick a stride that's a multiple of
`gpu->limits.align_tex_xfer_stride` for better performance. Patches
welcome (tm)

Fixes #7759
2020-06-16 02:54:59 +02:00
Niklas Haas c9f6c458ea vo_gpu: add BT.2390 tone-mapping
Implementation copy/pasted from:
https://code.videolan.org/videolan/libplacebo/-/commit/f793fc0480f

This brings mpv's tone mapping more in line with industry standard
practices, for a hopefully more consistent result across the board.

Note that we ignore the black point adjustment of the tone mapping
entirely. In theory we could revisit this, if we ever make black point
compensation part of the mpv rendering pipeline.
2020-06-15 01:24:09 +02:00
Niklas Haas ef6bc8504a vo_gpu: reinterpret SDR white levels based on ITU-R BT.2408
This standard says we should use a value of 203 nits instead of 100 for
mapping between SDR and HDR.

Code copied from https://code.videolan.org/videolan/libplacebo/-/commit/9d9164773

In particular, that commit also includes a test case to make sure the
implementation doesn't break roundtrips.

Relevant to #4248 and #7357.
2020-06-15 01:24:04 +02:00
Niklas Haas c7fe4ae73a vo_gpu: move coherent specifier to the correct location
glslang accepted this, perhaps erronneously, but mesa does not. It seems
to be incorrect. A caveat is that this means *all* SSBOs are now
coherent, but since we only use SSBOs for peak detection, that's a
non-issue. (And besides, marking something as coherent when we don't
perform any synchronization commands on it should be a no-op anyway)

Fixes #7823
2020-06-10 17:16:43 +02:00
wm4 44ad00ba10 player: make unpausing directly after seek work with --keep-open (again)
Commit fcf0b80dc9 fixed this the first time. Commit 85576f31a9
"accidentally" removed this code again. The commit message justifying
the removal is correct, except it doesn't take other side-effects of the
state machine into account. I obviously didn't remember what exactly
this was about. So add a comment explaining it this time.

Just apply it again; the thing the latter commit fixed still works.

Fixes: #7819
2020-06-10 11:44:47 +02:00
wm4 d5de79d10f audio: require certain AOs to set device_buffer
AOs which use the "push" API must set this field now. Actually, this was
sort of always required, but happened to work anyway. The future
intention is to use device_buffer as the pre-buffer amount, which has to
be available right before audio playback is started. "Pull" AOs really
need this too conceptually, just that the API is underspecified.

From what I can see, only ao_null did not do this yet.
2020-06-09 16:49:05 +02:00
Nicolas F 0fb02f181f ao/pulse: properly set device_buffer
Previously, device_buffer defaulted to 0 on pulse. This meant that
commit baa7b5c would always wait with a timeout of 0, leading to
high CPU usage for PulseAudio users.

By setting device_buffer to the number of samples per channel that
PulseAudio sets as its target, this commit fixes this behaviour.
2020-06-07 22:16:49 +03:00
der richter 12415db3a6 cocoa-cb: properly reset window isMoving state on title bar clicks
since the title bar catches the mouse up and down events, the underlying
events view doesn't reset the isMoving state and no mouse movements are
signalled to the core. now we also reset the state in mouse up events
on the title bar.

Fixes #7807
2020-06-06 14:33:22 +02:00
wm4 5ad73ccbe9 vo_gpu: fix display corruption with window screenshots
The "screenshot window" command (ctrl+s by default) somehow broke video
colors with --gpu-api=vulkan --profile=gpu-hq when playback was paused.
I don't know the cause, but the rest of the code seems to imply
gl_video_reset_surfaces() needs to be called manually to flush some
caches, and it fixes the issue, so I assume there's no great mystery
here.
2020-06-06 12:26:37 +02:00
Niklas Haas 7174c063de vo_gpu: mark peak detection buffer coherent
This is required for buffer memory barriers to actually work
2020-06-06 02:20:43 +02:00
Niklas Haas 03171b19a9 vo_gpu: make storage images/buffers as restrict
This informs the GPU that we don't alias it with any other descriptors
(which we don't).
2020-06-06 02:19:32 +02:00
Daniel Bermond 8a725ec951 vulkan/wayland: fix another build breakage
Commit 07b0c18 introduced some build breakages. Some breakages
were fixed on c1fc535 and a1adafe. This one is still remaining.

This commit fixes the following build error:

[153/521] Compiling video/out/vulkan/context_wayland.c
../video/out/vulkan/context_wayland.c:26:10: fatal error: video/out/wayland/presentation-time.h: No such file or directory
   26 | #include "video/out/wayland/presentation-time.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

Relevant to: #7802
2020-06-05 13:43:50 +02:00
wm4 a1adafe966 build: fix another breakage
The build was still broken. Feel free to look for a better maintainer if
you don't like it.

Fixes: #7802 (maybe now?)
2020-06-04 20:43:37 +02:00
wm4 c1fc5354c3 wayland: fix build
Broken by previous commit. I've split a commit incorrectly.

Fixes: #7802
2020-06-04 20:15:43 +02:00
wm4 07b0c18bad build: change filenames of generated files
Force them into a more consistent naming schema.
2020-06-04 16:59:05 +02:00
wm4 c67f36dd18 audio: fix deadlock on draining
The playback thread may obviously still fill the AO'S entire audio
buffer, which means it unset p->draining, which makes no sense and broke
ao_drain(). So just don't unset it here.

Not sure if this really fixes this, it was hard to reproduce. Regression
due to the recent changes. There are probably many more bugs like this.
Stupid asynchronous nightmare state machine. Give me a language that
supports formal verification (in presence of concurrency) or something.
2020-06-04 12:42:36 +02:00
wm4 5f49009849 options: add --video-scale-x/y
Requested.

Fixes: #6303
2020-06-03 17:26:44 +02:00
wm4 baa7b5c8dd audio: adjust wait duration
I feel like this makes slightly more sense. At least it doesn't include
the potentially arbitrary constant latency that is generally included in
the delay value. Also, the buffer status doesn't matter - either we've
filled the entire buffer (then we can wait this long), or there's not
enough data anyway (then the core will wake up the thread if new data is
available).

But ultimately, we have to guess, unless the AO does notify us with
ao_wakeup_playthread().

Draining may now wait for no reason up to 1/4th of the total buffer
time. Shouldn't be a disimprovement in practice.
2020-06-03 15:22:18 +02:00
wm4 416d3f2c00 vaapi: correct broken NULL check
Clearly, we want to check whether vaGetDisplayDRM() returned NULL.
out_display itself is already implied non-NULL.

Fixes: #7739
2020-06-03 15:12:08 +02:00
wm4 68ade4e5a5 audio: avoid possible deadlock regression for some AOs
It's conceivable that ao->driver->reset() will make the audio API wait
for ao_read_data() (i.e. its audio callback) to return. Since we
recently moved the reset() call inside the same lock that ao_read_data()
acquires, this could deadlock. Whether this really happens depends on
how exactly the AO behaves. For example, ao_wasapi does not have this
problem. "Push" AOs are not affected either.

Fix by moving it outside of the lock. Assume ao->driver->start() will
not have this problem.

Could affect ao_sdl, ao_coreaudio (and similar rotten fruit AOs). I'm
unsure whether anyone experienced the problem in practice.
2020-06-02 20:43:49 +02:00
wm4 08b198aab4 audio: further simplify internal audio API somewhat
Instead of the relatively subtle underflow handling, simply signal
whether the stream is in a playing state. Should make it more robust.

Should affect ao_alsa and ao_pulse only (and ao_openal, but it's
broken).

For ao_pulse, I'm just guessing. How the hell do you query whether a
stream is playing? Who knows. Seems to work, judging from very
superficial testing.
2020-06-02 20:43:49 +02:00
wm4 0d3474c6c0 audio: slightly better condition for still_playing
Just a detail. If wrong (not unlikely because I'm just guessing my own
messy state machine), this will make the player freeze due to waiting
for something that never happens. Enjoy.
2020-06-02 20:43:49 +02:00
wm4 0edeb0899a af_scaletempo: handle obscure integer overflow
Saw it once, not really reproducible. This should fix it, and in any
case it's harmless.
2020-06-02 20:43:49 +02:00
ヒカリ 376aea36eb TOOLS/autocrop.lua: automatically crop at startup 2020-06-01 23:07:26 -07:00
wm4 c5158b057c audio: reduce extra wakeups caused by recent changes
The feeder thread basically woke up the core and itself too often, and
caused some CPU overhead. This was caused by the recent buffer.c
changes.

For one, do not let ao_read_data() wake up the core, and instead rely on
the feeder thread's own buffer management. This is a bit strange, since
the change intended to unify the buffer management, but being more
consequent about it is better deferred to later, when the buffer
management changes again anyway. And also, the "more" condition in the
feeder thread seems outdated, or at least what made it make sense has
been destroyed, so do something that may or may not be better. In any
case, I'm still not getting underruns with ao_alsa, but the wakeup
hammering is gone.
2020-06-01 15:48:45 +02:00
wm4 5746258018 vo: refine wakeup condition, and wake up more in audio sync mode
Commit 6a13954d67 lowered the frequency of wakeups with this
condition. But it seems it sometimes the audio sync mode really should
get the wakeup before the frame is rendered. Normally, vo_thread is
supposed to perform this wakeup. Now the wakeup frequency is twice of
what should be needed - whatever, maybe it can be fixed properly once or
if timing is moved to the VO entirely in the future.

Fixes: #7777 (probably, untested)
2020-06-01 15:21:41 +02:00
wm4 d27ad96542 audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.

ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).

ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).

No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.

This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-06-01 01:08:16 +02:00
wm4 d448dd5bf2 audio: fix unpausing with some AOs
wasapi/coreaudio/sdl were affected, alsa/pusle were not.

The confusion here was that resume() has different meaning with pull and
push AOs.

Fixes: #7772
2020-05-31 14:43:13 +02:00
James Ross-Gowan 102a083171 terminal-win: handle 'Change Window Title' OSC sequence
This should make --term-title work in Windows 8.1 and below.

OSC sequences are defined in ECMA-48. The 'Change Window Title' command,
as far as I can tell, is a de-facto standard defined by xterm[1]. In
either case, this code is probably still not standards-compliant.

This also changes mp_write_console_ansi to convert to UTF-16 before
parsing control sequences, because that made it easier to pass the OSC
param to SetConsoleTitleW. I think it's also more correct to do it this
way, even though it doesn't really matter much for our limited terminal
parsing. As a side-effect of this, mp_write_console_ansi no longer
mutates its argument.

[1]: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
2020-05-29 19:48:51 +10:00
wm4 27e41c69aa ao_null: remove unreferenced function
Forgot in the previous commit to this file.
2020-05-27 21:29:43 +02:00
wm4 a4b7fcc183 audio: stop applying volume twice for some AOs
Regression since the recent refactor. How did nobody notice?

This happened because the push code now calls the function for the pull
code. Both the former and latter apply the volume, so oops.
2020-05-27 21:11:46 +02:00
wm4 9885952c2a audio: remove ao_driver.drain
The recent change to the common code removed all calls to ->drain. It's
currently emulated via a timed sleep and polling ao_eof_reached(). That
is actually fallback code for AOs which lacked draining. I could just
readd the drain call, but it was a bad idea anyway. My plan to handle
this better is to require the AO to signal a underrun, even if
AOPLAY_FINAL_CHUNK is not set. Also reinstate not possibly waiting for
ao_lavc.c. ao_pcm.c did not have anything to handle this; whatever.
2020-05-27 21:04:32 +02:00
wm4 1b03970d79 lua: windows got what users crave
It's got '\r's.

Fixes: #7733
2020-05-27 15:01:39 +02:00
wm4 b1d16a2300 player: add --term-title option
This simply printf()s a concatenation of the provided string and the
relevant escape sequences. No idea what exactly defines this escape
sequence (is it just a xterm thing that is now supported relatively
widely?), and this simply uses information provided on the linked github
issue.

Not much of an advantage over --term-status-msg, though at least this
can have a lower update frequency. Also I may consider setting a default
value, and then it shouldn't conflict with the status message.

Fixes: #1725
2020-05-25 20:39:37 +02:00
wm4 b83bdd1d17 audio: merge pull/push ring buffer glue code
This is preparation to further cleanups (and eventually actual
improvements) of the audio output code.

AOs are split into two classes: pull and push. Pull AOs let an audio
callback of the native audio API read from a ring buffer. Push AOs
expose a function that works similar to write(), and for which we start
a "feeder" thread. It seems making this split was beneficial, because of
the different data flow, and emulating the one or other in the AOs
directly would have created code duplication (all the "pull" AOs had
their own ring buffer implementation before it was cleaned up).
Unfortunately, both types had completely separate implementations (in
pull.c and push.c). The idea was that little can be shared anyway. But
that's very annoying now, because I want to change the API between AO
and player.

This commit attempts to merge them. I've moved everything from push.c to
pull.c, the trivial entrypoints from ao.c to pull.c, and attempted to
reconcile the differences. It's a mess, but at least there's only one
ring buffer within the AO code now. Everything should work mostly the
same. Pull AOs now always copy the audio data under a lock; before this
commit, all ring buffer access was lock-free (except for the decoder
wakeup callback, which acquired a mutex). In theory, this is "bad", and
people obsessed with lock-free stuff will hate me, but in practice
probably won't matter. The planned change will probably remove this
copying-under-lock again, but who knows when this will happen.

One change for the push AOs now makes it drop audio, where before only a
warning was logged. This is only in case of AOs or drivers which exhibit
unexpected (and now unsupported) behavior.

This is a risky change. Although it's completely trivial conceptually,
there are too many special cases. In addition, I barely tested it, and
I've messed with it in a half-motivated state over a longer time, barely
making any progress, and finishing it under a rush when I already should
have been asleep. Most things seem to work, and I made superficial tests
with alsa, sdl, and encode mode. This should cover most things, but
there are a lot of tricky things that received no coverage. All this
text means you should be prepared to roll back to an older commit and
report your problem.
2020-05-25 01:54:37 +02:00
wm4 afb6f1c7e9 audio: add frame alloc function
Meh, why is this so roundabout?
2020-05-25 01:54:37 +02:00
Jan Beich 7c9543577a CI: add FreeBSD job 2020-05-25 01:35:58 +03:00
sfan5 bf6afbc299 osdep: remove confstr() fallback for subprocess spawning
It doesn't exist on bionic (Android) and accurately emulating
execvpe's behaviour isn't all that important.
2020-05-25 00:30:35 +03:00
Arthur Williams 4d5688dc9a x11_common: added ICCCM WM_HINTS
When the window is mapped, some ICCCM WM_HINTS are set.
The input field is set to true and state is set to NormalState.

To quote the spec, "The input field is used to communicate to the window
manager the input focus model used by the client" and "[c]lients with
the Passive and Locally Active models should set the input flag to True".
mpv falls under the Passive Input model, since it expects keyboard input,
but only listens for key events on its single, top-level window instead
of subordinate windows (Locally Active) or the root window (Globally
Active).

From the end users prospective, all EWMH/ICCCM compliant WMs (especially
the minimalistic ones) will allow the user to focus mpv, which will allow
mpv to receive key events. If the input field is not set, WMs are
allowed to assume that mpv doesn't require focus.
2020-05-24 13:35:57 +02:00
wm4 685bd6a5f5 manpage: document "vf remove"
And mention it on "vf del" as non-deprecated alternative.
2020-05-23 23:33:15 +02:00
wm4 502e7987d8 player: remove some display-adrop leftovers
Forgotten in one of the previous commits. Also undeprecates
display-adrop since it's out of sight now.
2020-05-23 04:24:04 +02:00
wm4 e822207ab4 command: fix dump-cache parameter parsing
Commit 9d32d62b61 broke this when it changed OPT_TIME. I simply forgot
to adjust the command definition. The effect was that "no" was not
accepted as value.
2020-05-23 04:15:11 +02:00
wm4 448a964070 README: remove trolling
I guess this qualifies as trolling. It's becoming increasingly clear
that Microsoft will not be able to deliver on this promise, at least not
in the way they made it seem at first. I'm not sure if Microsoft was the
one who did the trolling, or me. I actually expected that we'd get full
GUI integration of Linux applications including accelerated graphics,
but it was always clear that it wasn't going to work as well as
natively.

In any case, there is no need to frighten any users. The time when you
can run only "Windows Store Apps" on Windows (== the end for mpv and
many other applications on Windows) will come soon enough.

The "faster than native" statement is based on other people's real
experience of software running faster in Linux VMs than native windows
ports, by the way.
2020-05-23 04:12:41 +02:00
wm4 ab4e0c42fb audio: redo video-sync=display-adrop
This mode drops or repeats audio data to adapt to video speed, instead
of resampling it or such. It was added to deal with SPDIF. The
implementation was part of fill_audio_out_buffers() - the entire
function is something whose complexity exploded in my face, and which I
want to clean up, and this is hopefully a first step.

Put it in a filter, and mess with the shitty glue code. It's all sort of
roundabout and illogical, but that can be rectified later. The important
part is that it works much like the resample or scaletempo filters.

For PCM audio, this does not work on samples anymore. This makes it much
worse. But for PCM you can use saner mechanisms that sound better. Also,
something about PTS tracking is wrong. But not wasting more time on
this.
2020-05-23 04:04:46 +02:00
wm4 43a67970b6 af_scaletempo: fix theoretical UB
Passing NULL to memset() is undefined behavior, even if the size
argument is 0. Could happen on init errors and such.
2020-05-23 03:49:46 +02:00
wm4 1826e69af2 options: add option to control display-sync factor
Can be useful to force it to adapt to extreme speed changes, while a
higher limit would just use a fraction closer to the original video
speed.

Probably useful for testing only.
2020-05-23 03:48:51 +02:00
wm4 d62131d3ae vo_x11: allow OSD rendering outside of video region
I'm not sure why it only rendered OSD inside the video. Since OSD
rendering was always done on the X image (after software scaling and
color conversion), there was no technical reason for this. Maybe it was
because the code started out this way, and it was annoying to change it.
Possibly, one reason was that it didn't normally have to clear the black
bars in every frame (if video didn't cover the entire window).

Anyway, simply render OSD to the full window. This gets rid of some
rather weird stuff. It seems to look mostly like vo_wlshm now. The
uncovered regions are cleared every frame, which could probably be
avoided by being clever with the OSD renderer code, but this is where
I'm decidedly losing interest.

There was some mysterious code for aligning the image width to 8 pixels.
Replace that by attempting to align it to SIMD alignment (might matter
for libswscale, or if repack.c gets SIMD). Why are there apparently 4
different ways representing a pixel format (depth, VisualID, Visual,
XVisualInfo), but none of them seem to provide the XImage.bits_per_pixel
value (the actual size of a pixel, including padding)? Even after 33
years, X11 still seems overengineered, confusing, and inconvenient. So
just call X11 a heap of shit, and assume the worst case for alignment.
2020-05-22 14:24:16 +02:00
wm4 77f730f63c mp_image: add helper for clearing regions outside of a rectangle
Not sure if generally useful; the following commit uses it.
2020-05-22 14:18:35 +02:00
wm4 1be32529b1 common: add helper for subtracting rectangles
Not sure if generally useful; the following commit uses it.
2020-05-22 14:17:46 +02:00
wm4 320fa3bbe7 video: add AV_PIX_FMT_UYYVYY411 conversion support
It may be completely useless, and I can't verify it as no known samples
or other known/accessible software using it, but why not?

Putting this together with he 422 code requires making it slightly more
generic. I'm still staying with a "huge" if tree instead of a table to
select the scanline worker callback, because it's actually small and not
huge (although it not being generic still feels slightly painful).
2020-05-22 02:26:05 +02:00
wm4 756ae0321b repack: use new imgfmt metadata in more cases
Now everything is super generic and super undebuggable. Some awkwardness
because the new metadata is basically a transposed version of the
mp_regular_imgfmt metadata, which was used for component info before.
2020-05-21 02:51:54 +02:00
wm4 2525aa3393 img_format: expose another helper 2020-05-21 02:29:05 +02:00
wm4 8f22aefae1 mp_image: reimplement mp_image_clear()
The old code ignored many corner cases, and even wrote "blacker than
black" to YUV images. Use the new pixel format metadata and other
recently added gimmicky crap, which should make this more correct. Even
the almighty fuckup of a format AV_PIX_FMT_UYYVYY411 should work,
although that couldn't be tested for obvious reasons.

This doesn't work for "monow", but this is so extremely fringe while at
the same time painful that I just won't care. In theory, it could be
modeled as some sort of inverted gray colorspace or something.
2020-05-21 02:07:08 +02:00
wm4 eb27baf5ec video: remove useless mp_imgfmt_desc.avformat field
Had 1 user; easily replaced.
2020-05-20 18:38:19 +02:00
wm4 d291673d40 vo_x11: minor improvement in format matching
Make sure to accept only native endian mpv formats. Previously, it
didn't check, and simply matched LE, because these are usually defined
before the BE formats.

red_mask etc. are defined as unsigned long, so use that instead of
hardcoding a 32 bit limit.
2020-05-20 18:38:19 +02:00
wm4 086953a9da video: clean up pixel metadata stuff some more
A repeat of the previous useless commits.

Pondered whether to use separate fields or just a flags integer for
color and component types; the latter won for now.

Functions like mp_imgfmt_get_component_type() are now discouraged, and
mp_imgfmt_desc.flags is back for defining all information. Some days ago
I felt like the opposite would be the better design. Fortunately, it
doesn't matter.

With this, I think all image format properties that mpv needs are
exhaustively defined all in one place.
2020-05-20 18:38:15 +02:00
Mikhail Rudenko a078d07ea2 command: save state on stop when user requested save-position-on-quit
Execution of "stop" command in the case when idle mode was not enabled
resulted in player termination scenario not honoring user setting
"save-position-on-quit" from config file. This patch addresses the
issue by checking for "save-position-on-quit" in cmd_stop and saving
state when idle mode is not enabled.
2020-05-20 15:48:48 +02:00
wm4 20403abcfa vo_x11: use imgfmt metadata instead of hardcoded format table
Useless, but super generic! Actually may add support for other fringe
formats, however vo_x11 in itself is useless, so nothing won here. Also
I didn't bother with big endian support.
2020-05-20 00:14:09 +02:00
wm4 176f422213 video: shuffle imgfmt metadata code around
I guess I decided to stuff it all into mp_imgfmt_desc (the "old"
struct). This is probably a mistake. At first I was afraid that this
struct would get too fat (probably justified, and hereby happened), but
on the other hand mp_imgfmt_get_desc() (which builds the struct) calls
the former mp_imgfmt_get_layout(), and the separation doesn't make too
much sense anyway. Just merge them.

Still, try to keep out the extra info for packed YUV bullshit. I think
the result is OK, and there's as much information as there was before.

The test output changes a little. There's no independent bits[] array
anymore, so formats which did not previously have set this now show it.
(These formats are mpv-only and are still missing the metadata. To be
added later). Also, the output for the cursed packed formats changes.
2020-05-20 00:02:27 +02:00
wm4 a20ae0417f README: looks like we won't need win32 support anymore 2020-05-19 19:09:55 +02:00
wm4 bd911efdcd repack: make generic weird pixfmt shit even more generic and obfuscated
Use the new pixfmt metadata to replace the format tables with weird
generic code.

As you can see, this removes the tables that essentially duplicate
information (which is baaaaaaaaaad), in exchange for code which is
probably more fragile and has less of a chance of being understood by
someone new to the code (which is probably even worse from a maintenance
and robustness point of view, but LALALA I CAN'T HEAR YOU).

There are some more formats which can be handled like this (RGB30 and
packed YUV I guess), maybe later.
2020-05-18 20:15:03 +02:00
wm4 2256a9e42b video: fix AV_PIX_FMT_UYYVYY411 allocation
My previous commit added support for this format, but it was still
broken, and prevented the allocation code from working. It's unknown
whether it's correct now (because this pixfmt is so obscure and useless,
there are no known samples around), but who cares.
2020-05-18 19:29:25 +02:00
Dudemanguy 55f6ba62be wayland: only use presentation on CLOCK_MONOTONIC
Trying to use anything other than CLOCK_MONOTONIC here would be a
disaster. No idea if it's even possible for the clockid here to be
something other than CLOCK_MONOTONIC in this function but it's better
safe than sorry. Closes #7740.
2020-05-18 11:01:40 -05:00
Jan Beich 82ded968aa build: allow wlshm on more Wayland platforms after a6000d3114 2020-05-18 01:57:20 +02:00
wm4 27e5416c12 video: add pixel component location metadata
I thought I'd probably want something like this, so the hardcoded stuff
in repack.c can be removed eventually. Of course this has no purpose at
all, and will not have any. (For now, this provides only metadata, and
nothing uses it, apart from the "test" that dumps it as text.)

This adds full support for AV_PIX_FMT_UYYVYY411 (probably out of spite,
because the format is 100% useless). Support for some mpv-only formats
is missing, ironically.

The code goes through _lengths_ to try to make sense out of the FFmpeg
AVPixFmtDescriptor data. Which is even more amazing that the new
metadata basically mirrors pixdesc, and just adds to it. Considering
code complexity and speed issues (it takes time to crunch through all
this shit all the time), and especially the fact that pixdesc is very
_incomplete_, it would probably better to have our own table to all
formats. But then we'd not scramble every time FFmpeg adds a new format,
which would be annoying. On the other hand, by using pixdesc, we get the
excitement to see whether this code will work, or break everything in
catastrophic ways.

The data structure still sucks a lot. Maybe I'll redo it again. The text
dump is weirdly differently formatted than the C struct - because I'm
not happy with the representation. Maybe I'll redo it all over again.

In summary: this commit does nothing.
2020-05-18 01:54:59 +02:00
wm4 caee8748da video: clean up some imgfmt related stuff
Remove the vaguely defined plane_bits and component_bits fields from
struct mp_imgfmt_desc. Add weird replacements for existing uses. Remove
the bytes[] field, replace uses with bpp[].

Fix some potential alignment issues in existing code. As a compromise,
split mp_image_pixel_ptr() into 2 functions, because I think it's a bad
idea to implicitly round, but for some callers being slightly less
strict is convenient.

This shouldn't really change anything. In fact, it's a 100% useless
change. I'm just cleaning up what I started almost 8 years ago (see
commit 00653a3eb0). With this I've decided to keep mp_imgfmt_desc,
just removing the weird parts, and keeping the saner parts.
2020-05-18 01:54:59 +02:00
wm4 00ac63c37b test: explicitly test repacking for all packed RGB variants
This stuff is very annoying, so it's good to have full coverage.
2020-05-18 01:54:59 +02:00
Julian c7b94c03f1 stats: UP/DOWN scrolling on page 2 (frame stats)
Code contributed by @avih with only minor modifications to comments by
me.
Fixes #7727.
2020-05-17 20:11:50 +02:00
Michael Forney 3cb9e93cdf vo_wlshm, vo_drm: set image size with mp_image_set_size
The image w and h members must match params.w and params.h, so
should not be changed directly. The helper function mp_image_set_size
is designed for this purpose, so just use that instead.

This prevents an assertion error with the rewritten draw_bmp.

Fixes #7721.
2020-05-17 12:53:26 +02:00
Ed Santiago 43cb89fca3 zsh completion: helper functions in private namespace
The generate_xxx() helpers, once defined, would appear as
user-visible functions; this would lead to unexpected and
confusing completion suggestions for gene<tab> after having
once run mpv in that shell.

This PR adds the prefix '_mpv_' to all completion functions
as a convention to make them less user-visible and less likely
to collide with other packages.
2020-05-17 12:47:12 +02:00
wm4 152b0e2a8c osc: fix hovering timestamp sticking around when moving mouse away
The OSC calls this "tooltip" (and although a general mechanism, there's
only one instance using it). One particular problem was that with the
default OSC layout, moving the mouse down and out of the window, the
tooltip stuck around, because the returned mouse position was the last
pixel row in the window, which still overlaps with the seek bar.

Instead of introducing mouse_in_window, you could check last_mouse_X for
nil, but I think this is clearer.

This returns (-1, -1) to the caller if the mouse is outside. Kind of
random, but works.
2020-05-16 13:45:16 +02:00
Niklas Haas 09b68648f1 vo_gpu: ra_pl: add timers support
Added in libplacebo v60, unfortunately with some changes in design that
make it a bit of an awkward fit for the way timers are used in mpv.

Timer queries in libplacebo don't support "start" and "stop"-style
operations, and instead are attached directly to operations. The only
sane way of implementing this in the ra API is to have a single 'active
timer' that gets attached to every pass, taking care to sort distinct
operations into distinct pl_timer queries within that ra_timer.

This design unfortunately doesn't let us have multiple 'active timers'
concurrently, similar to the current such limitation in ra_gl. But it's
also not a big deal.
2020-05-16 06:18:44 +02:00
wm4 5ebb498b7a scripting: make socket FD number for subprocesses dynamic
Before this, we pretty much guaranteed that --mpv-ipc-fd=3 would be
passed. The FD  was hardcoded, so scripts started by this mechanism
didn't need to actually parse the argument. Change this to using a
mostly random FD number instead.

I decided to do this because posix_spawnp() and the current replacement
cannot "guarantee" a FD layout. posix_spawn_file_actions_adddup2() just
runs dup2() calls, so it may be hard to set FD 3/4 if they are already
used by something else. For example imagine trying to map:

    {.fd = 3, .src_fd = 4},
    {.fd = 4, .src_fd = 3},

Then it'd do dup2(4, 3), dup2(3, 4) (reminder: dup2(src, dst)), and the
end result is that FD 4 really maps to the original FD 4.

While this was not a problem in the present code, it's too messy that I
don't want to pretend it can always done this way without an unholy
mess. So my assumption is that FDs 0-2 can be freely assigned because
they're never closed (probably...), while for all other FDs only
pass-through is reasonable.
2020-05-15 16:37:41 +02:00
wm4 c4d0d7a194 sub: fix incorrect commit
Commit c6369933f1 accidentally added an old version of this comment.
2020-05-15 16:37:41 +02:00
wm4 810b37fc3f ipc: mark client sockets as CLOEXEC
I suppose it would have left the socket open if the client closed its
FD.
2020-05-15 16:37:41 +02:00
wm4 1c66e03ae5 scripting: correct passing FDs
For external scripts/processes which use IPC. The mistake didn't really
matter.
2020-05-15 16:37:41 +02:00
wm4 60f8cd4072 osdep: remove posix_spawn() helpers and wrappers
See previous commit. Farewell, useless shitty POSIX function.
2020-05-15 16:37:41 +02:00
wm4 5309497727 subprocess: replace posix_spawnp() with fork()
This code runs posix_spawnp() within a fork() in some cases, in order to
"disown" processes which are meant as being started detached. But
posix_spawnp() is not marked as async-signal-safe, so what we do is not
allowed. It could for example cause deadlocks, depending on
implementation and luck at runtime. Turns out posix_spawnp() is useless
crap.

Replace it with "classic" fork() to ensure correctness.

We could probably use another mechanism to start a process "disowned"
than doing a double-fork(). The only problem with "disowning" a process
is calling setsid() (which posix_spawnp() didn't support, but maybe will
in newer revisions), and removing as as parent from the child process
(the double-fork() will make PID 1 the parent). But there is no good way
to either remove us as parent, or to "reap" the PID in a way that is
safe and less of a mess than the current code. This is because
POSIX/UNIX is a miserable heap of shit. (Less shit than "alternatives"
like win32, no doubt.)

Because POSIX/UNIX is a miserable heap of shit, execvp() is also not
specified as async-signal-safe. It's funny how you can run a full
fledged HTTP server in an async-signal-safe context, but not start a
shitty damn process. Unix is really, really, really extremely bad at
this process management stuff. So we reimplement execvp() in an
async-signal-safe way.

The new code assumes that CLOEXEC is a thing. Since POSIX/UNIX is such a
heap of shit, O_CLOEXEC and FD_CLOEXEC were (probably) added at
different times, but both must be present. io.h defines them to 0 if
they don't exist, and in this case the code will error out at runtime.
Surely we could do without CLOEXEC via fallback, but I'll do that only
if at least 1 bug is reported wrt. this issue.

The idea how to report exec() failure or success is from musl. The way
as_execvpe() is also inspired by musl (for example, the list of error
codes that should make it fail is the same as in musl's code).
2020-05-15 16:37:41 +02:00
wm4 a58b2df3f8 command: add input-key-list property
Fixes: #7698
2020-05-14 22:22:33 +02:00
wm4 c6369933f1 command: add property to return text subtitles in ASS
See manpage additions. This was requested, sort of. Although what has
been requested might be something completely different. So this is
speculative.

This also changes sub_get_text() to return an allocated copy, because
the buffer shit was too damn messy.
2020-05-14 22:14:49 +02:00
wm4 0049ea38be ipc: exit client if the FD is invalid
This does not normally happen. But since the --input-ipc-client option
can pass in raw FDs, it's probably a good thing in the interest of
making mistakes obvious. Without this, it just burned a core on invalid
FDs (poll() always returned immediately).
2020-05-14 21:42:46 +02:00
wm4 26bd8479d0 ipc: make --input-ipc-client terminate player on connection close
As discussed in the referenced issue. This is quite a behavior change,
bit since this option is new, and not included in any releases yet, I
think it's OK.

Fixes: #7648
2020-05-14 21:40:43 +02:00
wm4 edaefd6b47 vo_x11: add 10 bit support
Requires zimg.
2020-05-14 17:23:48 +02:00
Jan Palus 727b1bff57 build: link against single EGL provider
when building with rpi EGL is provided by librcmegl library and libEGL
should not be linked then
2020-05-14 15:08:33 +02:00
Jan Palus 65fd6c8ae9 build: fallback to default pc file locations on rpi 2020-05-14 15:08:33 +02:00
Jan Palus ac1634360b drm: add typedef for PFNEGLGETPLATFORMDISPLAYEXTPROC (#7314)
extension is not mandatory and is not provided on ie Raspberry Pi
2020-05-14 15:07:58 +02:00
wm4 fd8e856afe vo_direct3d: dumb down OSD rendering
Render most of the OSD on the CPU, then draw it using a relatively
simple method. Do this for minimum code maintenance overhead. (While it
doesn't matter for vo_direct3d, and the effort spent here is probably
more than this would ever hope, I do hope to simplify the internal OSD
API for all these fringe VOs. Only vo_gpu should be allowed to do more
sophisticated things.)

If your GPU is shit (which it will be if you "want" to use vo_direct3d),
this might actually improve performance... is what I'd say, but out of
laziness a full screen sized texture gets uploaded on every OSD/subtitle
change, so maybe not.
2020-05-13 23:16:32 +02:00
wm4 97706a2aec draw_bmp: make another small guarantee to users
Mostly self-evident.
2020-05-13 22:46:29 +02:00
wm4 b36484063f vo_direct3d: rip out texture video rendering path
This isn't useful anymore. We have a much better d3d11 renderer in
vo_gpu. D3D11 is available in all supported Windows versions. The
StretchRect path might still be useful for someone (???), and leaving it
at least evades conflict about users who want to keep using this VO for
inexplicable reasons. (Low power usage might be a justified reason, but
still, no.)

Also fuck the win32 platform, it's a heap of stinky shit. Microsoft is
some sort of psycho clown software company. Granted, maybe still better
than much of the rest of Silly Con Valley.
2020-05-13 22:19:00 +02:00
wm4 baabd5fce3 draw_bmp: use command line options for any used scalers 2020-05-13 20:07:59 +02:00
Niklas Haas 6d8b3f9333 vo_gpu: un-fix storable fbo format check
The original solution for #7017 was sort of a hack, but this hack is no
longer needed because c05e5d9d fixed the underlying issue causing this
error to be spammed in the first place. So just remove the "fix" that
apparently introduced about as many issueas it fixed.

Fixes #7719, hopefully.
2020-05-13 18:54:30 +02:00
wm4 0ff839d467 draw_bmp: add integer blending for 8 bit formats
Whatever it's worth. Instead of doing a pretty stupid conversion to
float, just blend it directly. This works for most RGB formats that are
8 bits per component or below (the latter because we expand packed
fringe RGB formats for simplicity). For higher bit depth RGB this would
need extra code.
2020-05-12 23:10:14 +02:00
wm4 1e75f442b1 repack: fix incorrect assert()
Used the output of the first step instead of the input when checking the
real input.
2020-05-12 23:08:10 +02:00
wm4 c4b2ca83d6 draw_bmp: don't make strange decisions on broken iknput csp params
This checked params->color.space for being RGB. If the colorspace is
unset, this did dumb things because even if the imgfmt was a RGB one,
the colorspace was not set to RGB. This actually also happened to the
tests.

(Short-cutting RGB like this is actually wrong, since RGB could still
have strange gamma or primaries, which would warrant a full conversion.
So you'd need to check for these other parameters as well. To be fixed
later.)
2020-05-12 22:43:29 +02:00
wm4 3451908a34 vo_vaapi: use new overlay API
This will probably make it slower. But since I don't care about
vo_vaapi, that's perfectly OK. It serves mostly as a test for the
previous commit. In addition, this code was pretty bad (custom broken
scaling and not-blending that probably broke in some situation). If that
wasn't enough, some vaapi drivers also provide only a single overlay at
a time, while this code required a bunch.

There also seems to be a Mesa bug: the overlay gets stretched when
src_x/y was not 0. Or maybe I misunderstood how this is supposed to
work. A bug is probably more likely? Nobody cares about this API.
2020-05-11 19:57:34 +02:00
wm4 55e1f15cdb draw_bmp: add a function to return a single-texture OSD overlay
Maybe this is useful for some of the lesser VOs. It's preferable over
bad ad-hoc solutions based on the more complex sub_bitmap data
structures (as observed e.g. in vo_vaapi.c), and does not use that much
more code since draw_bmp already created such an overlay internally.

But I still wanted something that avoids having to upload/render a full
screen-sized overlay if for example there's only a tiny subtitle line on
the bottom of the screen. So the new API can return a list of modified
pixels (for upload) and non-transparent pixels (for display). The way
these pixel rectangles are computed is a bit dumb and returns dumb
results, but it should be usable, and the implementation can change.
2020-05-11 19:57:34 +02:00
wm4 6db890ebab video: remove RGB32/BGR32 aliases
They are sort of confusing, and they hide the fact that they have an
alpha component. Using the actual formats directly is no problem, sicne
these were useful only for big endian systems, something we can't test
anyway.
2020-05-11 19:57:34 +02:00
Avi Halachmi (:avih) b5284a6829 js: mp.set_osd_ass: ignore identical inputs (match ccbb8b1c) 2020-05-10 21:20:28 +03:00
wm4 4e94b2177a vo: fix forgotten debug code
This was not intended to be committed in 0e3f893606. It disables
the extra wakeup if working==true. I've convinced myself that the wakeup
was really needed at the time, so no idea how I didn't notice this until
someone pointed it out on the commit diff on github (lol).
2020-05-10 17:00:11 +02:00
wm4 a7d11b2fc0 lua: do not use Lua filesystem functions for loading scripts
Bill Gates did not only create COVID, he's also responsible for the
world's worst OS, where you have to literally jump through hoops of fire
to open files with Unicode file names. Lua did not care to implement any
jumping, so it's our turn to jump.

Untested (on win32).

Fixes: #7701
2020-05-10 17:00:07 +02:00
wm4 ad9f3bfe96 stream: make stream_read_file() more robust
Change it to strictly accept local paths only. No more http://, no more
$HOME expansion with "~/" or mpv config path expansion with "~~/". This
should behave as if passing a path directly to open().

Reduce annoying log noise to further facilitate it using as open()
replacement.
2020-05-10 16:44:35 +02:00
wm4 a600d152d2 msg: add function to reduce log level
Sometimes it's helpful to override this for specific mp_log instances,
because in some specific circumstances you just want to suppress log
file noise you never want to see.

-1 is an allowed value (for suppressing MSGL_FATAL==0). It looks like
the libplacebo wrapper still does this wrong, so it will probably
trigger UB in some cases. I guess I don't care, though.
2020-05-10 16:40:26 +02:00
wm4 0b09771ba9 vo_gpu: manually resolve user shader prefixes
This resolves prefixes such as "~/" and "~~/" at the caller, instead of
relying on stream_read_file() to do it. One of the following commits
will remove this from stream_read_file() itself.

Untested.
2020-05-10 16:36:47 +02:00
wm4 caf228b218 player: make external subtitle auto-loading stricter
By default --sub-auto uses "exact". This was far from an "exact" match,
because it added anything that started with the video filename (without
extension), and seemed to end in something that looked like a language
code.

Make this stricter. "exact" still tolerate a language code, but the
video's filename must come before it without any unknown extra
characters. This may not load subtitles in some situations where it
previously did, and where the user might think that the naming
convention is such that it should be considered an exact match.

The subtitle priority sorting seems a bit worthless. I suppose it may
have some value in higher "fuzz" modes (like --sub-auto=fuzzy).

Also remove the mysterious "prio += prio;" line. I probably shouldn't
have checked, but it goes back to commit f16fa9d31 (2003), where someone
wanted to "refine" the priority without changing the rest of the code or
something.

Mostly untested, so have fun.

Fixes: #7702
2020-05-09 23:31:33 +02:00
wm4 327302bdb9 options: update OSD when writing some OSD-related options
Just the usual change notification mess.

Fixes: #7697
2020-05-09 22:36:06 +02:00
wm4 0e3f893606 vo: another minor wakeup reduction
The caller of render_frame() re-iterates without waiting if this
function returns true. That's normally meant for DS, where we draw
frames as fast as possible to let the driver perform waiting.
2020-05-09 22:32:28 +02:00
wm4 2446f5f43b vo: always reset redraw flag to avoid immediate wakeups wasting CPU time
This could temporarily hog the core or something because it's a stupid
fragile state machine that should best be wiped out.

Fixes: #7699
2020-05-09 22:23:18 +02:00
wm4 c1a961ad78 draw_bmp: rewrite
draw_bmp.c is the software blender for subtitles and OSD. It's used by
encoding mode (burning subtitles), and some VOs, like vo_drm, vo_x11,
vo_xv, and possibly more.

This changes the algorithm from upsampling the video to 4:4:4 and then
blending to downsampling the OSD and then blending directly to video.
This has far-reaching consequences for its internals, and results in an
effective rewrite.

Since I wanted to avoid un-premultiplying, all blending is done with
premultiplied alpha. That's actually the sane thing to do. The old code
just didn't do it, because it's very weird in YUV fixed point.
Essentially, you'd have to compensate for the chroma centering constant
by subtracting src_alpha/255*128. This seemed so hairy (especially with
correct rounding and high bit depths involved) that I went for using
float.

I think it turned out mostly OK, although it's more complex and less
maintainable than before. reinit() is certainly a bit too long. While it
should be possible to optimize the RGB path more (for example by
blending directly instead of doing the stupid float conversion), this is
probably slower. vo_xv users probably lose in this, because it takes the
slowest path (due to subsampling requirements and using YUV).

Why this rewrite? Nobody knows. I simply forgot the reason. But you'll
have it anyway. Whether or not this would have required a full rewrite,
at least it supports target alpha now (you can for example hard sub
transparent PNGs, if you ever wanted to use mpv for this).

Remove the check in vf_sub. The new draw_bmp.c is not as reliant on
libswscale anymore (mostly uses repack.c now), and osd.c shows an
error message on missing support instead now.

Formats with chroma subsampling of 4 are not supported, because FFmpeg
doesn't provide pixfmt definitions for alpha variants. We could provide
those ourselves (relatively trivial), but why bother.
2020-05-09 18:02:57 +02:00
wm4 9190b3c469 repack: add support for converting from/to float formats
Will be needed by draw_bmp.c. The tests cross-check this with zimg to
control whether we're getting it right.
2020-05-09 18:02:57 +02:00
wm4 bf19f34960 csputils: add function for getting uint/float transformation
This provides a way to convert YUV in fixed point (or pseudo-fixed
point; probably best to say "uint") to float, or rather coefficients
to perform such a conversion. Things like colorspace conversion is out
of scope, so this is simple and strictly per-component.

This is somewhat similar to mp_get_csp_mul(), but includes proper color
range expansion and correct chroma centering. The old function even
seems to have a bug, and assumes something about shifted range for full
range YCbCr, which is wrong.

vo_gpu should probably use the new function eventually.
2020-05-09 18:02:57 +02:00
wm4 56dbbc3847 video: add yuv float formats
Adding all these so I can use them for obscure processing purposes (see
later draw_bmp commit).

There isn't really a reason why they should exist. On the other hand,
they're just labels for formats that can be handled in a generic way,
and this commit adds support for them in the zimg wrapper and vo_gpu
just by making the formats exist. (Well, vo_gpu had to be fixed in the
previous commit.)
2020-05-09 18:02:57 +02:00
wm4 9e48085043 vo_gpu: fix green shit with float yuv input
This was incorrect at least because the colorspace matrix attempted to
center chroma at (conceptually) 0.5, instead of 0. Also, it tried to
apply the fixed point shift logic for component sizes > 8 bit.

There is no float yuv format in mpv/ffmpeg yet, but see next commit,
which enables zimg to output it. I'm assuming zimg defines this format
such that luma is in range [0,1] and chroma in range [-0.5,0.5], with
the levels flag being ignored. This is consistent with H264/5 Annex E (I
think...), and it sort of seems to look right, so that's it.
2020-05-09 18:02:57 +02:00
wm4 4019c11314 video: fix rgb30 component order
Was broken with a zimg wrapper refucktor before the previous commit. In
addition, it seems this didn't match the vo_drm format, or the format
naming convention. So the order actually changes, and the format is
redefined. (The img_format.h comment was probably wrong.)

Change vo_gpu to the new format as well, so we can still test it.
2020-05-09 18:02:57 +02:00
wm4 d8002f1dde video: separate repacking code from zimg and make it independent
For whatever purpose. If anything, this makes the zimg wrapper cleaner.

The added tests are not particular exhaustive, but nice to have. This
also makes the scale_zimg.c test pretty useless, because it only tests
repacking (going through the zimg wrapper). In theory, the repack_tests
things could also be used on scalers, but I guess it doesn't matter.

Some things are added over the previous zimg wrapper code. For example,
some fringe formats can now be expanded to 8 bit per component for
convenience.
2020-05-09 18:02:57 +02:00
wm4 d61ced37ae sws_utils: allow setting zimg options directly
One could wonder, why not just use the zimg wrapper directly?
2020-05-09 18:02:57 +02:00
wm4 43591ba96b img_format: make component order in comment more logical 2020-05-09 18:02:57 +02:00
wm4 488c0b4de5 sd_lavc: fix occasional problems with certain VOs when changing scaling
The OSD is passed to VOs via struct sub_bitmaps, which has a change_id
field. This field is incremented whenever there is a (potential) change
to the other struct contents. If not, the VO can rely on it not having
changed. This must include for example sub_bitmap.x and sub_bitmap.dw.
If these two fields (and y equivalents) change, change_id must change,
even if the subtitle bitmap data might still be the same.

sd_lavc.c stopped respecting this at some unknown point. It could
sometimes cause problems, though usually only with bad and old VOs which
somehow relied on this more than vo_gpu. (I've actually encountered this
before with sd_lavc subtitle scaling, as indicated by a nasty comment,
though probably didn't track this down, since said old VOs can die in a
fire.)

Fix this by maintaining the change_id explicitly. Unfortunately adds
even more code. Instead of comparing the result we could track property
changes, but I think this is better. The number of parts is always very
low with this subtitle decoder, so there's no actual performance issue
to worry about.

This could be triggered by scaling changes (video-zoom etc.), but
probably also changing bitmap subtitle position or scaling.
2020-05-09 18:02:57 +02:00
wm4 b3a9058c0d osd: add change timestamp and screen size to struct sub_bitmap_list
Should be somewhat helpful. (All VOs are full of code trying to
compensate for this, more or less, and this will allow simplifying
some code later. Maybe.)

The screen size is mostly for robustness checks.
2020-05-09 18:02:57 +02:00
wm4 b727600d1f osd: add subtitle software blending to stats 2020-05-09 18:02:57 +02:00
wm4 a1812e2a46 build: add -fno-math-errno
glibc/gcc make certain math functions set errno by default. This is not
required by the standard, and makes everything complexer and slower
(well done glibc). It typically prevents inlining certain math functions
too, where the compiler can turn a function call to a single
instruction, such as observed with lrint().

So this has possibly some minor performance advantages, and no
disadvantages.
2020-05-09 18:02:57 +02:00
Anton Kindestam 9dfcc496a5 drm_prime: fallback to drmModeAddFB2
Fallback to drmModeAddFB2 if drmModeAddFB2WithModifiers fails. I've
observed it failing on a pinebook pro running manjaro. We also got "0"
as modifiers from FFmpeg anyway, which might or might not have
something to do with this.

Instead of trying to find the source of the problem, just add this
fallback.
2020-05-08 21:26:25 +02:00
Anton Kindestam 6c04eb0508 drm_prime: get the modifier for all planes
Untested (I don't have a platform that requires modifiers to work
here). Might break something, or might fix something. At least this
looks more intuitive to me.
2020-05-08 21:26:25 +02:00
Anton Kindestam c0bc8bf5d3 drm_prime: print out errno in error message
It is interesting to know why drmModeAddFB2WithModifiers failed.
2020-05-08 21:26:25 +02:00
Piotr Gasior 5676e5ba39 w32_common: Scale window when moving to display with different DPI
For applications that are DPI aware WM_DPICHANGED message contains
suggested size and position of window
2020-05-08 21:47:32 +10:00
RealDolos 8bce6d0b89 w32_common: Support HiDPI on Windows 2020-05-08 21:46:45 +10:00
James Ross-Gowan 326c55a571 vo_gpu: d3d11: only use presentation feedback with flip model
The current implementation of presentation feedback was designed to be
used with flip model presentation. With the bitblt model,
GetFrameStatistics returns totally different values and it's not clear
if we can use them at all. Previously, this wasn't a problem because
with the bitblt model, GetFrameStatistics only worked in exclusive
fullscreen. Now that mpv supports exclusive fullscreen, we should
explicitly check for a flip model swapchain before using presentation
feedback.
2020-05-07 00:17:50 +10:00
wm4 ebac24efe6 client API: correct an outdated comment 2020-05-06 15:27:25 +02:00
wm4 f77a4450b4 options: don't trigger bool "compact" path for --loop-file
In theory an incompatible change, but I think it's for the better.
Impact should be relatively low. I hope.

Fixes: #7676
2020-05-06 15:27:25 +02:00
wm4 12451ac7eb vf:format: don't error when using convert=yes and not specifying fmt 2020-05-06 15:27:25 +02:00
wm4 e567d06377 test: fix some idiotic UB 2020-05-06 15:27:25 +02:00
wm4 b2720dba0f mp_image: add some helpers
This is really basic for planar image data access; not sure why there
weren't such helpers before.

They also handle trickier formats that use bit-packing, or they would be
mich simpler. (This affects only BGR4/BGR4/MONOW/MONOH, I hope whoever
invented them is proud of triggering so many special cases for so little
gain.)
2020-05-06 15:27:25 +02:00
Niklas Haas 349eb0b7fc vo_gpu: suppress PL_FATAL logs during probing
These were still mapped to MP errors during probing, but they also get
triggered when instance creation fails due to lack of support for e.g.
wayland. Since waylandvk is probed above x11vk, we should probably
suppress these by default.

Closes #7626
2020-05-03 16:27:37 +02:00
Emanuele Torre cae2ffb6eb documentation: fix some ReST syntax mistakes in lua.rst 2020-05-01 20:48:51 +02:00
Ricardo Garcia d061f28397 player: round position percentage to the nearest integer
This brings the displayed percentage closer to the exact number and
allows mpv to more frequently display 100% when it finishes playing a
typical video or audio file.
2020-05-01 20:48:16 +02:00
wm4 92db8731dd DOCS/contribute.md: add some blabla about fixup commits in pull requests
I have to say this in PR reviews all the time, so maybe I should make i
explicit. In too many words of course, many, many, too many words which
nobody will read, I get it, now shut up. Sneak in some subtle or not so
subtle comments about how I think that github is ruining code quality.
2020-05-01 01:13:20 +02:00
wm4 ccbb8b1c9b lua: restore change detection with legacy OSD function
mp.set_osd_ass() (which was undocumented, or in other words, was not
supposed to be used by external scripts) used to do change detection in
the mpv C code. If the resolution or payload did not change, it was not
re-rendered on the lower levels.

Apparently this made some people sad, so fix it. (But only after I told
them to fuck off.) (Well I didn't put it this way, but still.)
2020-05-01 00:59:57 +02:00
wm4 008faa3d7f zimg: remove C11 aligned_alloc() requirement
It's not available on Windows because MinGW is fucking horrible and
Microsoft are fucking assholes.
2020-05-01 00:59:57 +02:00
Niklas Haas 4f0206ab04 vo_gpu: enable frame caching for still frames
For some reason this was never done? Looking through the code, it was
never the case that the frame cache was hit for still frames. I have no
idea why not. It makes a lot of sense to do so.

Notably, this massively improves the performance of updating the OSC
when viewing e.g. large still images, or while paused. (Tested on a
4000x8000 image, the OSC now responds smoothly to user input)
2020-04-30 00:23:13 +02:00
Kevin Mitchell 2aa5964b43 stream_libarchive: remember archive headers from initial open
The header probing hacks were previously all broken. They only worked
the first time the archive file was open. Since subsequent opens (on
seek) occured in the middle of the source stream rather than at the
beginning, the stream_read_peek calls meant to retrieve the headers were
instead returning random bytes in the middle of the file.

Perhaps the worst manifestation of this was when seeking within a
multi-volume .rar archive with the "legacy" file naming pattern. If the
seek required a reopen, the fact that the archive was multi-volume would
be forgotten and the file would appear truncated terminating playback.

To solve this, only perform the header probling the first time the
archive is opened. Save the results and reuse them on subsequent
reopens. Put this in a wrapper so this is transparent to
demux_libarchive.
2020-04-28 22:13:03 -07:00
Kevin Mitchell 9285a1c05e stream_libarchive: simplify multi-volume rar hate message
I couldn't find any reason for this message to be so far dispalced from
where it's necessity was determined. That necessity is not however in
question.

Also improve the wording and line breaking.
2020-04-27 21:11:31 -07:00
Kevin Mitchell 430b6f9f12 stream_libarchive: put multi_rar check in a function 2020-04-27 21:10:58 -07:00
wm4 027ae815ec ta: add ta_get_parent()
Sometimes useful for debugging. Also fix a random typo elsewhere.
2020-04-26 23:38:54 +02:00
wm4 729843b85e ta: change debug ifdeffery
TA_MEMORY_DEBUGGING always defined. But allow defining it from the
compiler command line (-D), because maybe that's useful for someone?
2020-04-26 23:37:29 +02:00
wm4 e9e883e3b2 video: make OSD/subtitle bitmaps refcounted (sort of)
Making OSD/subtitle bitmaps refcounted was planend a longer time ago,
e.g. the sub_bitmaps.packed field (which refcounts the subtitle bitmap
data) was added in 2016. But nothing benefited much from it, because
struct sub_bitmaps was usually stack allocated, and there was this weird
callback stuff through osd_draw().

Make it possible to get actually refcounted subtitle bitmaps on the OSD
API level. For this, we just copy all subtitle data other than the
bitmaps with sub_bitmaps_copy(). At first, I had planned some fancy
refcount shit, but when that was a big mess and hard to debug and just
boiled to emulating malloc(), I made it a full allocation+copy. This
affects mostly the parts array. With crazy ASS subtitles, this parts
array can get pretty big (thousands of elements or more), in which case
the extra alloc/copy could become performance relevant. But then again
this is just pure bullshit, and I see no need to care. In practice, this
extra work most likely gets drowned out by libass murdering a single
core (while mpv is waiting for it) anyway. So fuck it.

I just wanted this so draw_bmp.c requires only a single call to render
everything. VOs also can benefit from this, because the weird callback
shit isn't necessary anymore (simpler code), but I haven't done anything
about it yet. In general I'd hope this will work towards simplifying the
OSD layer, which is prerequisite for making actual further improvements.

I haven't tested some cases such as the "overlay-add" command. Maybe it
crashes now? Who knows, who cares.

In addition, it might be worthwhile to reduce the code duplication
between all the things that output subtitle bitmaps (with repacking,
image allocation, etc.), but that's orthogonal.
2020-04-26 23:34:32 +02:00
wm4 640db1ed3f zimg: don't assume zimg reads are 64 byte aligned
Only _writes_ are aligned, so the assumption doesn't work for reads. But
it's easy to fix by rounding down x0 to the next byte boundary. Writing
pixels outside of the read area is allowed, and we don't go out of
buffer bounds.

Patch by anon32, permission to do anything with it.
2020-04-25 17:38:54 +02:00
der richter 4deae5e4b5 cocoa-cb: report actual unfs window size for current window scale 2020-04-25 11:37:53 +02:00
wm4 71295fb872 video: add alpha type metadata
This is mostly for testing. It adds passing through the metadata through
the video chain. The metadata can be manipulated with vf_format. Support
for zimg alpha conversion (if built with zimg after it gained alpha
support) is implemented. Support premultiplied input in vo_gpu.

Some things still seem to be buggy.
2020-04-24 14:41:50 +02:00
wm4 8909bf3317 sws_utils: remove unused brightness etc. controls
Used to be used by vo_x11, and some other situations where software
conversion was employed. Haven't seen anyone complain about how software
brightness controls went away (originating from mplayer), so whatever,
it won't be needed again.
2020-04-24 14:31:11 +02:00
Avi Halachmi (:avih) 77738ac6f5 win32: SGR emulation: minor fixup on invalid sequence
This fixes two issues with invalid value after 38/48:
- It was not detected correctly and ended up skipping 4 instead of 0.
- The intent was to skip 0, but it's better to skip the rest.

Behavior with valid 2/5 after 38/48 was correct and is unaffected.
2020-04-24 10:14:33 +03:00
Avi Halachmi (:avih) b036e56e67 video/out/vo_tct: query terminal size generically
terminal_get_size also works on windows. This is useful because now
tct also works on Windows with native VT console.
2020-04-23 23:25:41 +03:00
Avi Halachmi (:avih) b5b266c38c osdep/terminal-win: native VT: report exact width
The narrower-by-1 width is not required with a native VT console
because the wrapping behavior is the same as on *nix on such case.
2020-04-23 23:25:41 +03:00
Dudemanguy ca531b1cb2 wayland: explictly send an UP event for left click
In the wayland code, the left mouse click is treated a bit differently.
Dragging the left click allows mpv to request a window move to the
compositor. In some cases, this can also request a window resize if the
osc-windowcontrols are enabled. These functions had the strange side
effect of messing up mpv's deadzone (it seemed to disappear completely).
A harmless enough workaround is to just explictly send an UP event for
left click after the move/resize functions are finished executing. The
xdg_toplevel move and resize functions both finish after the button
press is let go, so we are guarenteed to have the left click in the UP
state here. Sending this event probably unconfuses some calculation
somewhere thus fixing the deadzone bug. It feels a little silly, but
it's safe and works. Fixes #7651.
2020-04-23 14:49:18 -05:00
Avi Halachmi (:avih) 8e50430eaa win32: native VT: logic fixup
We want basemode unmodified so that we can use it if setting VT mode
fails.
2020-04-23 17:51:20 +03:00
Avi Halachmi (:avih) 5ff215c4df stats.lua: don't disable terminal escape sequences on windows
When stats.lua is used without a video window then it uses the terminal.
On Windows, however, so far it disabled ansi escape sequences and used
plaintext unless ANSICON env is set.

It's unclear why it's disabled on windows, because at the time it was
added it only used bold by default and mpv ansi emulation on windows
already supported bold at that time.

We can guess that it was disabled because if the same config is used on
both linux and Windows, and it had complex escape sequences for
stats.lue, then it would be emulated incorrectly on Windows.

This shouldn't be an issue anymore, as the last two commits both enhance
the emulation to be quite complete (and graceful where it's not), and
also enable the much-more complete native VT terminal when possible
(Windows 10).

Just remove this windows exception at stats.lua.
2020-04-23 17:02:38 +03:00
Avi Halachmi (:avih) 1c8506d9c8 win32: use windows 10 native virtual-terminal if available
This enables native and more complete escape-sequence handling instead
of our emulation. E.g. it supports 256/true colors, and more.

This should get enabled automatically on Windows 10 build 16257
(August 2017) or later.
2020-04-23 17:02:38 +03:00
Avi Halachmi (:avih) 67b7a8adaf win32: improve console SGR escape sequence emulation
Previously an SGR sequence was emulated correctly only if:
- It had exactly 1 or 2 numeric values (not 0).
- Only reset, bold, and foreground colors were supported.
- 256/true colors were not skipped correctly with their sub-values.

Now it supports the same as before, plus:
- 0-16 (inclusive) numeric values, e.g. \e[m now resets correctly.
- Supports also codes for background color, reverse, underline* .
- Supports also codes for default intensity/fg/bg/reverse/underline.
- 256/true colors are recognized and skipped gracefully.

* Reverse/underline seem to work only on windows 10.
2020-04-23 17:02:38 +03:00
Jan Palus da314d3db2 rpi: use "brcm" variant of libGLESv2 2020-04-23 14:05:32 +02:00
Jan Palus 3023837fb9 egl_helpers: add typedef for EGLAttrib (#7314)
part of EGL 1.5 which is not present ie on Raspberry Pi
2020-04-23 14:04:26 +02:00
Jan Beich 9cbacefbb0 build: restore BSD thread names after 9f461b85bf
On FreeBSD non-POSIX threading functions are in a separate header.
DragonFly and OpenBSD adopted FreeBSD header and extensions.

../test.c:3:3: error: implicit declaration of function 'pthread_set_name_np' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
{ pthread_set_name_np(pthread_self(), "ducks"); return 0; }
  ^
../osdep/threads.c:47:5: error: implicit declaration of function 'pthread_set_name_np' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    pthread_set_name_np(pthread_self(), tname);
    ^

Signed-off-by: Jan Beich <jbeich@FreeBSD.org>
2020-04-23 13:58:16 +02:00
wm4 ca83080fff zimg: get rid of special "override" fields for low depth RGB/gray
This makes it use the previously added fringe image formats. What is the
purpose of this change? Who knows.
2020-04-23 13:26:07 +02:00
wm4 a854aa234d zimg: slightly cleanup some mpv format handling nonsense
Move lookup GBRP or planar gray/alpha formats to separate functions in
some cases.

Make setup_regular_rgb_packer() not use a 4:4:4 YUV format to "pass"
RGB. This was used as a "trick" to avoid the stupid GBRP plane
permutation, but it confused severely, so get rid of it. Just do the
reordering, even if the zimg wrapper itself will reorder it back (which
is so stupid that I used the other approach at first). The comment
saying IMGFMT_420P was bogus of course; typically it was IMGFMT_444P.
2020-04-23 13:26:07 +02:00
wm4 89329f44a4 f_swscale: let common code guess color levels when RGB->YUV
Probably doesn't matter anywhere.
2020-04-23 13:26:04 +02:00
wm4 28e4fe3010 img_format: treat both monow and monob as RGB
This was inconsistent for unknown reason. monob was the way we wanted
it, and handling of monow was missing.

See the previous "img_format: add some mpv-only helper formats" commit.

Matters for the zimg wrapper.
2020-04-23 13:24:35 +02:00
wm4 fe2178160d img_format: remove duplication in FFmpeg yuv vs. rgb pixfmt check
mp_imgfmt_get_forced_csp() should be consistent with the MP_CSP_RGB/YUV
flags.

At least the different handling of the XYZ exception was a mess, even if
the result was the same.
2020-04-23 13:24:35 +02:00
wm4 8767c46873 img_format: add some mpv-only helper formats
Utterly useless, but the intention is to make dealing with corner case
pixel formats (forced upon us by FFmpeg, very rarely) less of a pain.
The zimg wrapper will use them. (It already supports these formats
automatically, but it will help with its internals.)

Y1 is considered RGB, even though gray formats are generally treated as
YUV for various reasons. mpv will default all YUV formats to limited
range internally, which makes no sense for a 1 bit format, so this is a
problem. I wanted to avoid that mp_image_params_guess_csp() (which
applies the default) explicitly checks for an image format, so although
a bit janky, this seems to be a good solution, especially because I
really don't give a shit about these formats, other than having to
handle them. It's notable that AV_PIX_FMT_MONOBLACK (also 1 bit gray,
just packed) already explicitly marked itself as RGB.
2020-04-23 13:24:35 +02:00
wm4 3e84b48a6f filters: fix a typo in a comment 2020-04-23 13:24:35 +02:00
wm4 0f8f6a665b video: change chroma_w/chroma_h fields to use shift instead of size
When I added mp_regular_imgfmt, I made the chroma subsampling use the
actual chroma division factor, instead of a shift (log2 of the actual
value). I had some ideas about how this was (probably?) more intuitive
and general. But nothing ever uses non-power of 2 subsampling (except
jpeg in rare cases apparently, because the world is a bad place).

Change the fields back to use shifts and rename them to avoid mistakes.
2020-04-23 13:24:35 +02:00
wm4 7cb83593c2 img_format: add format description table for mpv-only formats
Make this slightly less ad-hoc. Also correct the missing alpha flag for
yap8/yap16.

Despite reduced redundancy, the LOC is going up anyway... whatever.
2020-04-23 13:24:35 +02:00
Jan Beich 90737ec77d drm_common: set frsig to a valid signal
On FreeBSD and DragonFly kernel checks if `frsig` is valid and aborts
with `EINVAL` if not. However, `frsig` was never implemented.

$ build/mpv --gpu-context=drm /path/to/video.mkv
[...]
[vo/gpu] VT_SETMODE failed: Invalid argument
[vo/gpu/opengl] Failed to set up VT switcher. Terminal switching will be unavailable.
[...]
2020-04-22 11:27:18 +02:00
Jan Beich 427709575d build: detect VT_GETMODE on FreeBSD and DragonFly
$ ./waf configure
Checking for vt.h                       : no
Checking for DRM                        : vt.h not found
[...]
 ../test.c:1:10: fatal error: 'sys/vt.h' file not found
 #include <sys/vt.h>
          ^~~~~~~~~~

$ build/mpv --gpu-context=drm /path/to/video.mkv
Error parsing option gpu-context (option parameter could not be parsed)
Setting commandline option --gpu-context=drm failed.

Exiting... (Fatal error)
2020-04-22 11:27:18 +02:00
Dudemanguy 055a490cef wayland: use mp_time deltas for presentation time
One not-so-nice hack in the wayland code is the assumption of when a
window is hidden (out of view from the compositor) and an arbitrary
delay for enabling/disabling the usage of presentation time. Since you
do not receive any presentation feedback when a window is hidden on
wayland (a feature or misfeature depending on who you ask), the ust is
updated based on the refresh_nsec statistic gathered from the previous
feedback event.

The flaw with this is that refresh_nsec basically just reports back the
display's refresh rate (1 / refresh_rate * 10^9). It doesn't tell you
how long the vsync interval really was. So as a video is left playing
out of view, the wl->last_queue_display_time becomes increasingly
inaccurate. This led to a vsync spike when bringing the mpv window back
into sight after it was hidden for a period of time. The hack for
working around this is to just wait a while before enabling presentation
time again. The discrepancy between the "bogus"
wl->last_queue_display_time and the actual value you get from the
feedback only happens initially after a switch. If you just discard
those values, you avoid the dramatic vsync spike.

It turns out that there's a smarter way to do this. Just use mp_time_us
deltas. The whole reason for these hacks is because
wl->last_queue_display_time wasn't close enough to how long it would
take for a frame to actually display if it wasn't hidden. Instead, mpv's
internal timer can be used, and the difference between wayland_sync_swap
calls is a close enough proxy for the vsync interval (certainly better
than using the monitor's refresh rate). This avoids the entire conundrum
of massive vsync spikes when bringing the player back into view, and it
means we can get rid of extra crap like wl->hidden.
2020-04-20 21:02:02 +00:00
wm4 a09c7691d7 draw_bmp: silence another ridiculous ubsan warning
UB sanitizer complains that aval<<24 (if >=128) cannot be represented as
int. Indeed, we would shift a bit into the sign of an int, which is
probably UB or implementation defined (I can't even remember, but the
stupidity of it burns). So technically, ubsan might be right.

Change aval to uint32_t, which I don't think has a chance of getting
promoted to int. Change the other *val to uint32_t too for cosmetic
symmetry.

So we have to obscure the intention of the code (*val can take only 8
bits) out of language stupidity. How nice. (What a shitty language.)
2020-04-18 00:16:52 +02:00
wm4 ab201ce042 sd_lavc: mitigate evil rounding issue that could lead to off-by-1 frames
A mkv sample file was provided to me, which contained a moving PGS
subtitle track, with the same track rendered into the video as
reference. The subtitle track appeared to stutter (while the video one
was smooth). It turns out this was a timestamp rounding issue in mpv.

The subtitle timestamps in the file match the video ones exactly.
They're the same within the mpv demuxer too. Unfortunately, the
conversion from and to libavcodec timestamps is lossy, because mpv uses
a non-integer timebase, while libavcodec supports integers only. See
mp_pts_to_av() and mp_pts_from_av(). The recovered timestamp is almost
the same, but is off by a very minor part. As a result, the timestamps
won't compare equal, and if that happens, display of the subtitle frame
is skipped. Subtitle timestamps don't go through this conversion
because... libavcodec is special? The libavcodec subtitle API is
special.

Fix this by giving it a microsecond of slack. This is basically as if we
used an internal microseconds integer timebase, but only for the purpose
of image subtitle display.

The same could happen to sd_ass, except in practice it doesn't. ASS
subtitles (well, .ass files) inherently use a timebase incompatible to
video, so to ensure frame exactness, ASS timestamps are usually set to
slightly before the video frame's.

Discussion of better solutions:

One could rewrite mpv not to use float timestamps. You'd probably pick
some integer timebase instead (like microseconds), which would avoid the
libavcodec interop issue. At the very least this would be a lot of work.

It would be interesting to know whether the rounding in ther mpv<->lavc
timestamp conversion could be fixed to round-trip in this case. The
conversion tries to avoid problems by using the source timebase (e.g.
milliseconds with mkv). But in general some rounding is unavoidable,
because something between decoder and lowest demuxer layer could
transform the timestamps.

One could extend libavcodec to attach arbitrary information to avpacket
and return it in the resulting avframe. To some degree, such a mechanism
already exists (side data). But there are certain problems that make
this unfeasible and broken.

One could pass through exact mpv float timestamps by reinterpret-casting
them to int64_t, the FFmpeg timestamp type. Actually mpv used to do
this. But there were problems, such as FFmpeg (or things used by FFmpeg)
wanting to interpret the timestamps. Awful shit that make mpv change to
the current approach.

There's probably more but I'm getting bored. With some luck I wasted
precious seconds of your life with my nonsense.
2020-04-18 00:10:34 +02:00
LaserEyess 34e7d9c2f4 stats: move chapter/edition info below title
It is more consistent for editions/chapters to go below either
the title or filename. They are all descriptive strings about
the media itself and not file metadata like filesize.

Suggested by Argon-
2020-04-16 23:13:46 +02:00
LaserEyess c364879e9f stats: add edition information to page 1
Edition information is conditional based on there being more than
one edition present. It is printed on the same line as Chapters to
save vertical space.
2020-04-16 23:13:46 +02:00
wm4 ace169ad0f demux_mkv: add png intra support
Evil, non-standard shit.

Sample file and script:
https://github.com/mpv-player/random-stuff/tree/master/matroska/png
2020-04-16 00:03:26 +02:00
wm4 cc2ee06e57 player: remove duplicated track option setter code
Well whatever.
2020-04-15 17:10:01 +02:00
wm4 6c02555397 player: slightly improve use of secondary track selection limits
Apparently, this was a bit of a mess, which caused the bug fixed by
commit ec7f2388af. Try to improve this, and only use track selection
entries that exist.
2020-04-15 17:04:00 +02:00
wm4 dae0652e19 player: remove mysterious declaration
??????????
2020-04-15 16:51:28 +02:00
Murray Campbell caa5d8170e terminal-unix: add key_entry defs for DECCKM mode
zsh often sets DECCKM (i.e. Cursor Key Mode) meaning the arrow keys
send `SS3 A/B/C/D` instead of `CSI A/B/C/D`.

Add `key_entry` definitions for this alongside the existing DECCKM Reset
definitions.
2020-04-15 16:46:25 +02:00
Niklas Haas ec7f2388af player: don't segfault when unloading tracks
e1e714ccc introduced a regression here when unloading a track (e.g. on
VO/AO initilization error), due to no corresponding option existing for
video/audio tracks with orders above 0, but the loop in
`mp_deselect_track` being hard-coded to clear tracks up to NUM_PTRACKS.

Introduce the simplest possible hackaround.
2020-04-15 08:02:28 +02:00
Niklas Haas 7e52e72746 vo_gpu: opengl: make sure to always clean up debug callbacks
In theory this mostly happens automatically, especially after the 5
vsync limit disables this already. But if we uninit before 5 vsyncs are
rendered, this can get left in a dangling 'enabled' state, which leaks a
debug report callback.

Always explicitly disable it just to be on the safe side.
2020-04-15 07:21:36 +02:00
wm4 d669c67149 manpage: fix wrong option name for --fbo-format
Fixes: #7609
2020-04-14 20:29:08 +02:00
wm4 dd30f2658a zimg: fix swapped chroma planes with packed YUV bullshit
I must have messed this up when I actually added the Y210 format
(because that one is correct). So my comment in the commit adding this
about the FFmpeg pixfmt doxygen being wrong was wrong.

I'd like to use this opportunity to complain once more about the
existence of these terrible pixel formats.
2020-04-14 00:28:44 +02:00
wm4 0d792857c5 zimg: fix build with older FFmpeg (troublesome Intel dude format) 2020-04-14 00:01:46 +02:00
wm4 7832204c99 zimg: add support for 1 bit per pixel formats
Again worthless, slow, and only for libswscale parity.

With this, we support all formats libswscale supports, except bayer
input, and rgb4/bgr4 output. We even support some formats libswscale
doesn't.

It's possible that the zimg wrapper isn't always as fast as libswscale.
But there is optimization potential: the inner repack loops are
self-contained enough that they could be reasonably be implemented in
assembler (probably), and doing everything slice-wise should reduce the
overhead of the separate pack/unpack stages.
2020-04-13 20:42:34 +02:00
wm4 afedaf3b61 zimg: add packed YUV bullshit
Just lazily tested.

The comment on AV_PIX_FMT_Y210LE seems to be wrong. It claims it's "like
YUYV422", bit it seems more like YVYU422, at last the way libswscale
input treats it. Maybe Intel pays its developers too much?

The repacker inner lop is probably rather inefficient. In theory we
could optimize it by reading the packed pixels as words, doing the
component reshuffling using compile time values etc., but I'd rather
keep the code size small. It's already bad enough that we have to
support 16 bit per component variants, just because this one Intel guy
couldn't keep it in his pants. In general, I can't be bothered to spend
time on optimizing it; I'm only doing this for fun (i.e. masochistic
obligation).
2020-04-13 20:05:38 +02:00
wm4 30855638df demux_mkv: concatenate multiple tags
Instead of just picking the last tag that was encountered. The order of
the tags still depends on the file order.

This is probably wrong, and we should respect TargetTypeValue. But
despite staring at the spec, I have no idea what the hell this should
do, so fuck that.

Fixes: #7604
2020-04-13 16:28:15 +02:00
wm4 56cac2be46 test: add list of zimg/sws conversions
Generic statement about how this is not really appropriate, etc., and
only useful for temporary debugging things, and how I commit it anyway
despite violating my own principles (and how I'd reject this change if
it came from you).
2020-04-13 15:57:05 +02:00
wm4 f6c81047fa player: do not fall back to a default track with explicit selections
Consider e.g. --aid=2 with a file that has only 1 track. Then it would
fall back to selecting track 1. Stop doing this. If no matching track is
found, this will not select any track now.

Note that the fingerprint stuff (track_layout_hash in the source)
prevents softens the impact of this change. Without the fingerprint,
playing a dual-audio file with the second track selected, and then a
single-audio file, would play the second file without audio. But the
fingerprint resets it due to differences in the track list.

Try to exhaustively document this and tricky interactions between the
other features. What a damn mess, I think it's simply cursed. Of course
it's still my fault.

See: #7608
2020-04-13 15:56:52 +02:00
wm4 e1e714ccc3 player: mess with track selection details again
Some time ago, properties and options were mostly unified. However, the
track selection properties/options semantics are incompatible to this
change. I'm still trying to handle the fallout.

There are two things that are in the way:
1. Track properties somehow return the runtime selection, not the option
   value (all while properties are supposed to be aliases to options
   with the same name).
2. The user's track options are not supposed to be changed without
   interaction. If a track is auto-selected, the property should return
   its ID, but the option value should remain at "auto". Only if the
   user actually writes to the property the option should change. E.g.
   playing e.g. an audio-only file and then a normal video file not play
   the video file with --vid=no just because the audio file had no video
   track.

In addition to each of them being in conflict with the property/option
unification, attempt to fix one of them breaks the other one.

Today, we're trying to fix parts of this and avoiding an unfortunate
case where you can get a conflicting option/property value, and where
trying to select a track does nothing if the track to select has the
same ID as the option value.

This breaks 2. from above in certain situations. See manpage additions.

See: #7608
2020-04-13 15:56:52 +02:00
wm4 dc9135b164 demux: don't let --sub-create-cc-track add a track for attached pictures
Unfortunately, attached pictures (from tags etc.) are treated as video
tracks. That meant --sub-create-cc-track added a CC track for them as
well. Stop doing that.

See: #7608
2020-04-13 15:56:52 +02:00
wm4 f7f947f960 zimg: add support for some RGB fringe formats
This covers 8 and 16 bit packed RGB formats. It doesn't really help with
any actual use-cases, other than giving the finger to libswscale.

One problem is with different color depths. For example, rgb565 provides
1 bit more resolution to the green channel. zimg can only dither to a
uniform depth. I tried dithering to the highest depth and shifting away
1 bit for the lower channels, but that looked ugly (or I messed up
somewhere), so instead it dithers to the lowest depth, and adjusts the
value range if needed. Testing with bgr4_byte (extreme case with 1/2/1
depths), it looks more "grainy" (ordered dithering artifacts) than
libswscale, but it also looks cleaner and smoother. It doesn't have
libswscale's weird red-shift. So I call it a success.

Big endian formats need to be handled explicitly; the generic big endian
swapper code assumes byte-aligned components.

Unpacking is done with shifts and 3 LUTs. This is symmetric to the
packer. Using a generated palette might be better, but I preferred to
keep the symmetry, and not having to mess with a generated palette and
the pal8 code.

This uses FFmepg pixfmts constants directly. I would have preferred
keeping zimg completely separate. But neither do I want to add an IMGFMT
alias for every of these formats, nor do I want to extend our imgfmt
code such that it can provide a complete description of each packed RGB
format (similar to FFmpeg pixdesc).

It also appears that FFmpeg pixdesc as well as the FFmpeg pixfmt doxygen
have an error regarding RGB8: the R/B bit depths are swapped. libswscale
appears to be handling them differently. Not completely sure, as this is
the only packed format case with R/B havuing different depths (instead
of G, the middle component, where things are symmetric).
2020-04-13 15:56:52 +02:00
wm4 a8b84c9a1a zimg: add support for big endian input and output
One of the extremely annoying dumb things in ffmpeg is that most pixel
formats are available as little endian and big endian variants. (The
sane way would be having native endian formats only.) Usually, most of
the real codecs use native formats only, while non-native formats are
used by fringe raw codecs only. But the PNG encoders and decoders
unfortunately use big endian formats, and since PNG it such a popular
format, this causes problems for us. In particular, the current zimg
wrapper will refuse to work (and mpv will fall back to sws) when writing
non-8 bit PNGs.

So add non-native endian support to zimg. This is done in a fairly
"generic" way (which means lots of potential for bugs). If input is a
"regular" format (and just byte-swapped), the rest happens
automatically, which happens to cover all interesting formats.

Some things could be more efficient; for example, unpacking is done on
the data before it's passed to the unpacker. You could make endian
swapping part of the actual unpacking process, which might be slightly
faster. You could avoid copying twice in some cases (such as when
there's no actual repacker, or if alignment needs to be corrected). But
I don't really care. It's reasonably fast for the normal case.

Not entirely sure whether this is correct. Some (but not many) formats
are covered by the tests, some I tested manually. Some I can't even
test, because libswscale doesn't support them (like nv20*).
2020-04-13 15:56:27 +02:00
wm4 c99d95ac17 vf_format: add gross mechanism for forcing scaler for testing
This sucks, but is helpful for testing.

Obviously, it would be much nicer if there were a way to specify _all_
scaler options per filter (if the user wanted), instead of always using
the global options. But this is "too hard" for now. For testing, it is
extremely convenient to select the scaler backend, so add this option,
but make clear that it could go away. We'd delete it once there is a
better mechanism for this.
2020-04-13 15:56:27 +02:00
wm4 28f2d7454d ta: minor simplification for talloc_steal
Since commit f6615f00ee, it can't fail anymore.
2020-04-13 15:56:27 +02:00
wm4 55f16bad76 ta: remove a macro indirection
No idea what purpose this was supposed to serve.
2020-04-13 15:56:27 +02:00
wm4 835137a0e5 player, ta: remove use of an old macro
I thought that would make a nice idiom, but it ended up being useless or
clunky.
2020-04-13 15:56:27 +02:00
LaserEyess e796fe4bfc command: print edition title to OSD when cycling
Edition title is already exposed in demux_edition, it was just never
added to the display. If no edition title exists it will fall back
to the edition number.
2020-04-13 01:04:32 +02:00
Jan Ekström 6e82f36f92 DOCS/interface-changes: add d3d11-exclusive-fs to list of changes
Was forgotten in finishing up the pull request.
2020-04-12 21:41:52 +03:00
Jan Ekström b885f803e2 vo_gpu: d3d11: also utilize config cache for d3d11-specific options
Update the cache whenever we utilize p->opts, as recommended by
wm4.
2020-04-12 21:18:50 +03:00
James Ross-Gowan 2a542b7f19 vo_gpu: d3d11: add support for exclusive fullscreen
Lets the application fully control the rendering onto the screen
instead of the compositor.
2020-04-12 21:18:50 +03:00
Avi Halachmi (:avih) 530a0863b8 stats: support UP/DOWN to scroll at page 4 (perf)
Keys and lines-to-scroll are configurabe, and the scroll keys are only
bound on pages which support scrolling (currently only page 4) - also
during oneshot (like the page-switching keys).

Scroll offset is reset for all pages on any key - except scroll keys, so
that entering or switching to a page resets the scroll, as well as when
"re-entering" the same page or "re-activating" the stats oneshot view.

TODO: print_page(..) is highly associated with extending the oneshot
timer if required. The timer handling can probably move into print_page
and removed from all the places which boilerplate its management.
2020-04-11 16:04:46 +03:00
Oliver Freyermuth b4c1554f7a stream_dvb: Remove call to stream_drop_buffers in fill_buffer.
The call was hidden very well, via
dvb_streaming_read -> dvb_update_config
-> dvb_streaming_start -> dvb_set_channel,
and broke the stream buffering logic.
Dropping that call does not noticeably slow down channel switches.
2020-04-10 17:12:53 +02:00
wm4 c2ee7bce4c console: reduce memory usage in default mode
This used 1 MB due to building the complete command and property list
when starting the script. These are needed only for auto-completion, so
build them only on demand. Since building them is fast enough, rebuild
them every time.

The key bindings table is not that much, but saves some KBs. Oddly, the
code to build it uses less memory than the table at runtime (???), so
build it at runtime as well.

Add 2 tactic collectgarbage() calls as well. This frees unused heap when
it is known that the script is going to be completely inactive until
re-enabled by the user.
2020-04-10 13:36:10 +02:00
wm4 e5d49f662e common: fix mp_round_next_power_of_2()
Who write this dumb shit¹? It didn't handle 1<<31, and was unnecessarily
slow.

¹ it was me
2020-04-10 13:10:18 +02:00
wm4 40c8df8a54 stream: actually drop unneeded buffer
The buffer can be larger than the normal size when "peeking" is used
(such as done with some file formats, where a large number of bytes masy
need to be "peeked" at the beginning, because FFmpeg). Once normal
operation resumes, it's supposed to free this buffer again. Apparently
this didn't happen as intended, because normal reading did have no way
to discard back buffer before/while resizing the buffer. There's only a
path for discarding the back buffer when actually reading.

It seems like this unfortunately needs 2 code paths for discarding old
data. Just put it into stream_resize_buffer(), where it's rather
non-tricky (discarding can be done by adjusting the copy offset when
moving data to the new allocation). The function now drops old data if
it doesn't fit into the allocation. The caller must ensure that the new
size is sufficient; the function signature changes only so the size of
the implicitly guaranteed kept part can be checked with assert().
2020-04-10 12:37:12 +02:00
wm4 c3f40e513b stream: add assert, a cosmetic change
This shouldn't change anything.
2020-04-10 12:23:10 +02:00
wm4 8e74b08538 stream: minor adjustment to buffer size limit logic
Instead of having 2 inconsistent limits on the upper possible buffer
size (option limit and allocation code), use a shared constant for them.
2020-04-10 10:59:18 +02:00
wm4 217c47ecb2 stream: fix whitespace within comment
arrrrrrrghh
2020-04-10 10:50:54 +02:00
wm4 6a13954d67 vo: further reduce redundant wakeups
In display-sync mode, the core doesn't need to woken up every vsync, but
only every time a new actual video frame needs to be queued. So don't
wake up if there are still frames to repeat.

In audio-sync mode, the wakeup is simply redundant, since there's a
separate timer (in->wakeup_pts) to control when to queue a new frame. I
think.

This finally brings the required playloop iterations down to almost the
number of video frames. (As originally intended, really.)

Also a fairly risky change.
2020-04-10 01:45:45 +02:00
wm4 0c9ac5835b video: remove another redundant wakeup
The wakeup at the end of VO frame rendering seems redundant, because
after rendering almost no state changes. The player core can queue a new
frame once frame rendering begins, and there's a separate wakeup for
this. The only thing that actually changes is in->rendering. The only
thing that seems to depend on it and can trigger a wakeup is the
vo_still_displaying() function. Change it so that it needs an explicit
call to a new API function, so we can avoid wakeups in the common case.

The vo_still_displaying() code is mostly just moved around due to
locking and for avoiding forward declarations.

Also a somewhat risky change (tasty new bugs).
2020-04-10 01:33:38 +02:00
wm4 a1771ed0d4 video: avoid redundant self-wakeup on each queued frame
This should be unnecessary, since the VO itself performs wakeups once a
new frame can be queued. The only situation I can think of where this
might be required are EOF situations (which are always strange).

If I'm wrong, there'll be fun new bugs, probably causing frame drops or
temporary stalls.
2020-04-10 01:28:06 +02:00
wm4 a2846faa32 player, stats: more silly debug stuff
In addition to stats.c being gross, I don't think master branch code
should be littered with debug code. But it's a helpful abomination.
2020-04-10 00:55:39 +02:00
wm4 437a46d443 filter: reduce redundant re-iterations
When the player core requests new frames from the filter, this is called
external/recursive filtering, which acts slightly differently from when
filters request new data internally. Mainly this is so the external user
doesn't have to call mp_filter_graph_run() just to get a frame. This
causes a number of complications, and the short version is that until
now, mp_filter_graph_run() has unnecessarily returned true in the
current common case, which made the playloop run too often for no
reason.

The problem is that when a mp_pin is read externally, updating the same
mp_pin during recursive filtering flagged external_pending when the
result was written, which made mp_filter_graph_run() return true, which
made the playloop call mp_filter_graph_run() again. This is redundant
because the caller is obviously checking the new state of the mp_pin
immediately.

The only situation in which external_pending really must be set is if
_another_ pin is changed. In theory, we could also unset it if the set
of "external" pins that are not in a signaled state becomes empty, but
we don't track that in a convenient way.

This commit removes the redundant signaling, and avoids running the
playloop an additional time for each video and audio frame (as it
actually was planned from the beginning, but duh).
2020-04-10 00:52:41 +02:00
wm4 c3b2e7ec07 filter: process asynchronous wakeups during filtering
If a filter receives an asynchronous wakeup during filtering, then
process newly pending filters resulting from that as well, before
returning to the user. Might possibly skip some redundant playloop
cycles.

There is an explicit comment in the code about how this shouldn't be
done, but I think it makes no sense. Filters have no business trying to
interrupt the mainloop, and mp_filter_graph_interrupt() provides a
proper mechanism to do this (though intended to be used by the filter
user, not filters).
2020-04-10 00:34:20 +02:00
wm4 73e565dc0f stats: fix crash if both plot_vsync_* options are disabled
In this case, init_buffers() was not called, and the unrelated cache
sample buffers were not initialized. It appears they are indeed
completely unrelated, so move their initialization away. Not sure what
exactly the purpose of calling init_buffers() is, maybe clearing old
data when displaying stats again. The new place for initializing the
cache sample buffers should achieve the same anyway.

Fixes: #7597
2020-04-09 15:03:17 +02:00
wm4 7df9f81d22 player: do not deinitialize AO on track switching
This should make it behave roughly like when switching from a file to
the next (clearing audio buffers, keeping AO, but closing AO if the
audio format seems to have changed and gapless mode is "weak").

Not necessarily useful, but harmless and may help with #7579 (untested).
2020-04-09 11:45:46 +02:00
wm4 bc1a18ee24 options: cleanup .min use for OPT_CHANNELS
Replace use of .min==1 with a proper flag. This is a good idea, because
it has nothing to do with numeric limits (also see commit 9d32d62b61
for how this can go wrong).

With this, m_option.min/max are strictly used for numeric limits.
2020-04-09 11:27:38 +02:00
wm4 823e5205ea options: make imgfmt options always accept "no"
This was optional, with the intention that normally such options require
a valid format. But there is no reason for this (at least not anymore),
and it's actually more logical to accept "no" in all situations this
option type is used. This also gets rid of the weird min field special
use.
2020-04-09 11:20:45 +02:00
wm4 9d32d62b61 options: fix ab-loop-* properties
These used ".min = MP_NOPTS_VALUE" to indicate certain exceptions. This
broke with the recent change to how min/max are handled, which made
setting min or max mean that a value range is used, thus setting max=0.

Fix this by not using magic a value in .min; replace it with a proper
flag.

Fixes: #7596
2020-04-09 11:13:38 +02:00
Niklas Haas a67bda2840 lua: wrap existing allocator instead of reimplementing it
This is the proper fix for 1e7802. Turns out the solution is dead
simple: we can still set the allocator with lua_getallocf /
lua_setalloc.

This commit makes memory accounting work on luajit as well.
2020-04-09 02:21:09 +02:00
Niklas Haas 1e780251ae lua: disable memory accounting for luajit
This is a stopgap measure. In theory we could maybe poll the memory
usage on luajit, but for now, simply reverting this part of fd3caa26
makes Lua work again. (And we can still collect cpu usage metrics)

Proper solution pending (tm)
2020-04-09 01:56:41 +02:00
wm4 71d22ee268 manpage: finish a sentence 2020-04-09 01:07:12 +02:00
wm4 1bdc3bed00 ipc: add --input-ipc-client option
While --input-file was removed for justified reasons, wanting to pass
down socket FDs this way is legitimate, useful, and easy to implement.

One odd thing is that

Fixes: #7592
2020-04-09 01:05:51 +02:00
wm4 fd3caa264e stats: some more performance graphs
Add an infrastructure for collecting performance-related data, use it in
some places. Add rendering of them to stats.lua.

There were two main goals: minimal impact on the normal code and normal
playback. So all these stats_* function calls either happen only during
initialization, or return immediately if no stats collection is going
on. That's why it does this lazily adding of stats entries etc. (a first
iteration made each stats entry an API thing, instead of just a single
stats_ctx, but I thought that was getting too intrusive in the "normal"
code, even if everything gets worse inside of stats.c).

You could get most of this information from various profilers (including
the extremely primitive --dump-stats thing in mpv), but this makes it
easier to see the most important information at once (at least in
theory), partially because we know best about the context of various
things.

Not very happy with this. It's all pretty primitive and dumb. At this
point I just wanted to get over with it, without necessarily having to
revisit it later, but with having my stupid statistics.

Somehow the code feels terrible. There are a lot of meh decisions in
there that could be better or worse (but mostly could be better), and it
just sucks but it's also trivial and uninteresting and does the job. I
guess I hate programming. It's so tedious and the result is always shit.
Anyway, enjoy.
2020-04-09 00:33:38 +02:00
sfan5 c5f8ec76b1 input: add binding to quit on ctrl+w
Other GUI applications typically handle this as "close document" or "close window".
2020-04-04 14:22:52 +02:00
wm4 f9cc29ec91 stats: fix previous commit
The previous commit included a rendering error of the "Speed:" line,
caused by incorrect copy&paste.
2020-04-03 23:26:51 +02:00
wm4 516934b233 stats: move input speed to cache page, make it a graph
I think that makes more sense.

And also remove the graph from the total cache usage, since that wasn't
very interesting. So there's still a total of 2 graphs.
2020-04-03 14:54:32 +02:00
wm4 28edf2d0f0 command: make input speed available as part of cache statge property
That's where it comes from after all. The other property does not have
much of a reason to exist anymore, but there's no real reason to remove
it either.
2020-04-03 13:20:21 +02:00
wm4 eeb711f5f3 umpv: convert to python 3
Sigh.
2020-04-03 12:57:24 +02:00
wm4 b6655dd72c player: make a function static 2020-04-03 12:56:50 +02:00
Nicolas F 5824ac7d36 build: only check for EGL pc in one build option
Previously, EGL as provided by a pkg-config was checked for independently
in several places. The effect this had is that --disable-egl would not
actually disable EGL from the build, as this only affected the "egl" option
relied upon by egl-x11. wayland-gl and egl-drm did their own EGL checks.

By making wayland-gl and drm-egl depend on egl instead, we fix this
behaviour and can simplify egl-helpers a bit, as we can now simply
check whether egl or one of the other features providing some non-pc egl
is enabled, instead of checking every single thing that might be pulling
in egl.

Future work could make the "egl" option just be a catchall for any
EGL implementation, so that brcmegl and angle and Android can piggyback
on the egl option as well.
2020-04-02 12:06:53 +02:00
sfan5 c8e5a615e9 ytdl_hook: enable runtime changes of script options 2020-03-29 17:45:59 +02:00
wm4 bca917f6d2 ao_oss: remove this audio output
Ancient Linux audio output. Apparently it survived until now, because
some BSDs (but not all) had use of this. But these should work with
ao_sdl or ao_openal too (that's why these AOs exist after all). ao_oss
itself has the problem that it's virtually unmaintainable from my point
of view due to all the subtle (or non-subtle) difference. Look at the
ifdef mess and the multiple code paths (that shouldn't exist) in the
removed source code.
2020-03-28 20:59:31 +01:00
wm4 4583bd8cc7 ao_rsound: remove this audio output
I wonder what this even is. I've never heard of anyone using it, and
can't find a corresponding library that actually builds with it. Good
enough to remove.
2020-03-28 20:59:00 +01:00
wm4 71d218eae4 ao_sndio: remove this audio output
It was always marked as "experimental", and had inherent problems that
were never fixed. It was disabled by default, and I don't think anyone
is using it.
2020-03-28 20:58:56 +01:00
wm4 27b4bdfe4c manpage: clarify some event/hook details 2020-03-28 00:41:56 +01:00
wm4 b8daef5d8b input: remove deprecated --input-file option
This was deprecated 2 releases ago. The deprecation changelog entry says
that there are no plans to remove it short-term, but I guess I lied.
2020-03-28 00:41:38 +01:00
wm4 518bd4c306 umpv: change from legacy FIFO to socket
--input-file is deprecated, and the JSON IPC is saner anyway.
2020-03-28 00:38:29 +01:00
wm4 df0d8cda08 client API: report IDs of inserted playlist entries on loading playlist
May or may not help when dealing with playlist loading in scripts. It's
supposed to help with the mean fact that loading a recursive playlist
will essentially edit the playlist behind the API user's back.
2020-03-27 00:57:11 +01:00
wm4 d3be6a6163 client API: another minor clarification for convenience
The previous commit actually makes use of this.
2020-03-27 00:09:51 +01:00
wm4 88194d05d3 ipc: fix recently added memory leak
Sucks.
2020-03-27 00:07:03 +01:00
wm4 1a72037720 scripting: remove race condition when toggling internal scripts
Scripts such as the OSC can be loaded and unloaded at runtime by
toggling the option that enables them. (It even works, although normally
it's only used to control initial loading.)

Unloading was racy because it used the client name; fix this.

The load-script change is an accidental feature. And probably useless.
2020-03-26 23:59:44 +01:00
wm4 9bda301eb4 command: use client IDs for hooks
Removes weird potential race conditions when a client is removed and a
new one with the same name is created.
2020-03-26 23:40:25 +01:00
wm4 ca34922130 client API: add a per client unique ID
I mostly intend this for internal purposes. Probably pretty useless for
external API users, but on the other hand trivial to expose. While it
makes a lot of sense internally, I'll probably regret exposing it.
2020-03-26 23:39:35 +01:00
wm4 0405b575d8 client API: update MPV_EVENT_PLAYBACK_RESTART docs
Ordered chapters haven't used user-visible seeks for over 4 years.
2020-03-26 22:51:25 +01:00
wm4 953983ad31 command: make revert seek command use time from end of seek
This time is set on every seek (but when initiating it). A new seek
longer than 2 seconds after this is counted as separate seek for the
sake of the revert seek command. If a seek takes a bit longer, this
removes time from these 2 seconds. This commits resets it on the end of
the seek. (Doing anything special for seeks that take longer than 2
seconds is out of scope of this commit.)
2020-03-26 22:50:21 +01:00
wm4 537f011c6d video: report negative subtitle/OSD margins if necessary
Until now, it used only coordinates clipped to the screen for this,
which meant no negative margins were ever reported to libass. This broke
proper rendering of explicitly positioned ASS events (libass simply
could not know the real video size in this case.)

Fix this by reporting margins even if they're negative. This makes it
apparently work correctly with vo_gpu at least.

Note that I'm not really sure if anything in the rendering chain
required non-negative margins. If so, and that code implicitly assumed
it, I suppose crashes and such are possible.
2020-03-26 12:23:32 +01:00
der richter 30f6f27976 travis: reactivate notifications on failure 2020-03-25 23:50:29 +02:00
der richter 570839c68e travis: fix config validation warnings
private keys should be prefixed with an underscore (_). the sudo key is
deprecated and doesn't influence anything anymore.
2020-03-25 23:50:29 +02:00
wm4 e31fbbeeee vd_lavc: make hwdec fallback message more consistent
The "rule" is that a fallback warning message should be shown only shown
if software decoding was used before, or in other words when either
hwdec was enabled before, but the stream suddenly falls back, or it was
attempted to enable it at runtime, and it didn't work.

The message wasn't printed the first time in the latter case, because
hwdec_notified was not set in forced software decoding mode. Fix it with
this commit. Fortunately, the logic becomes simpler.
2020-03-24 23:40:01 +01:00
Avi Halachmi (:avih) 7768452f2d lua: mp.get_property[_osd] don't need special handling anymore
Because they recently became normal autofree functions.
2020-03-23 01:26:01 +02:00
Avi Halachmi (:avih) 5a2fa3f29a lua: readdir: fix double closedir, use one more autofree
The double closedir is a regression from the previous commit, which also
forgot to use the autofree context with the fullpath string.
2020-03-22 23:49:51 +02:00
Avi Halachmi (:avih) 8deffd9fbb lua: autofree: use in few more places where it could leak
This also uses talloc destructors- like the JS autofree does.

The lua autofree is now used at the same places where the JS autofree
is used.
2020-03-22 23:34:19 +02:00
Avi Halachmi (:avih) fb984a3609 lua: autofree: the ctx is now an argument
There's no more need to call mp_lua_PITA to get the ctx, and the
autofree prototype is now enforced at the C level at compile time.

Also remove the redundant talloc_free_children at these functions
since it's now freed right after the function completes.

Also, rename auto_free_node to steal_node_allocations to be more
explicit and to avoid confusion with the autofree terminology.
2020-03-22 23:34:19 +02:00
Avi Halachmi (:avih) eb5635131d lua: use an autofree wrapper instead of mp_lua_PITA
Advantages of this approach:

- All the resources are released right after the function ends
  regardless if it threw an error or not, without having to wait
  for GC.

- Simpler code.

- Simpler lua setup which most likely uses less memory allocation and
  as a result should be quicker, though it wasn't measured.

This commit adds the autofree wrapper and uses it where mp_lua_PITA
was used. It's not yet enforced at the C level, there are still
redundant talloc_free_children leftovers, and there are few more
places which could also use autofree. The next commits will address
those.
2020-03-22 23:34:19 +02:00
wm4 6169fba796 encode: fix occasional init crash due to initialization order issues
Looks like the recent change to this actually made it crash whenever
audio happened to be initialized first, due to not setting the
mux_stream field before the on_ready callback. Mess a way around this.

Also remove a stray unused variable from ao_lavc.c.
2020-03-22 21:08:44 +01:00
wm4 37f441d61b lua: restore recent end-file event, and deprecate it
Lua changed behavior for this specific event. I considered the change
minor enough that it would not need to go through deprecation, but
someone hit it immediately and ask on the -dev channel.

It's probably better to restore the behavior. But mark it as deprecated,
since it's problematic (mismatch with the C API). Unfortunately, no
automatic warning is possible. (Or maybe it is, by playing sophisticated
Lua tricks such as setting a metatable and overriding indexing, but
let's not.)
2020-03-22 19:42:59 +01:00
Jan Ekström 3fedf61532 ci: remove missed remnants of libass from the macOS script as well 2020-03-22 14:58:22 +02:00
Jan Ekström 038f2213e1 ci: remove libass enablement
This is no longer a configurable option.
2020-03-22 14:33:41 +02:00
wm4 078e4bd023 travis: shut the fuck up
Travis is currently having "problems" and is spamming IRC all the time
with pointless failure notifications. Make it so that it hopefully sends
a message only when it goes from success to failure, which should
exclude these cases.

While I'm at it, I'd like to complain how idiotic it is to store CI
configuration in a project's source repository. Such a repository should
only contain things that are inherently part of the code's function, not
part of the organization. You don't store bug reports, build results,
the website, developer access controls, etc. in this repository either.
But for CI it's supposed to be OK? I'm all for this "configuration as
code" thing, but what it should mean is that you store configuration
files in some git managed repository, NOT necessarily that you dump them
into the main source code repo. There are many arguments why it should
not be there, such as this very commit. I have a feeling this is mostly
just because all these idiotic web services just want to advertise their
shit and bind customers by not giving easy ways to treat source code and
CI service configuration orthogonal. And so, the source code repo gets
clobbered with stupid shit (both in the set of files and the commit
history). It's fairly idiotic and my tolerance for it is waning. (Oh, of
course you could probably jump through hoops to make it a separate repo,
but I bet that is complicated and has all kinds of downsides because it
won't be the way "it's meant to be used".)
2020-03-22 13:28:50 +01:00
wm4 019f95cf99 encode: deprecate encoding mode
While I'd like to keep it, I'm apparently the maintainer now, and I have
no idea what the heck some of this code does, so it's deprecated.
2020-03-22 13:09:34 +01:00
wm4 63311762ed encode: add some shit that does some shit
?????????????

Makes no sense, can endless loop, but whatever.

Part of #7524.
2020-03-22 13:07:36 +01:00
wm4 de53155971 encode: restore audio muxer timebase use
Seems to crash hard if an error happens somewhere at init. Who cares.

Part of #7524.
2020-03-22 13:06:59 +01:00
wm4 b572f116da encode: fix whitespace 2020-03-22 13:05:50 +01:00
Avi Halachmi (:avih) ee70e8ce50 js: make wait_event autofree
The VM could throw at pushnode and before mpv_free_node_contents, which
would have resulted in leaked content.

Now this case is handled without leaks.

Note: the lua code still leaks on such case, but mp_lua_PITA doesn't
have destructors like the JS autofree has, which, specifically here,
can do mpv_free_node_contents. So TODO: enhance the lua PITA code to
behave more similar to the JS autofree.
2020-03-22 00:53:30 +02:00
Avi Halachmi (:avih) c4cc48c83d js: use unified events (match 218d6643, 8a58a699) 2020-03-21 23:35:51 +02:00
wm4 8a58a69930 lua: simplify further
As suggested by avih. Obviously this was unnecessarily convoluted.
2020-03-21 22:17:05 +01:00
wm4 d375cc304a client API, lua: unify event code further
Move some parts that can be generic to the client API code. It turns out
lua.c doesn't need anything special.

This adds the "id" field. I think this was actually missing from the
JSON IPC code (i.e. it's a very recent regression that is fixed with
this commit).
2020-03-21 22:09:07 +01:00
wm4 0fbe7f9e54 command: fix accidental stack dumping 2020-03-21 22:05:50 +01:00
wm4 218d6643e9 client API, lua, ipc: unify event struct return
Both Lua and the JSON IPC code need to convert the mpv_event struct (and
everything it points to) to Lua tables or JSON.

I was getting sick of having to make the same changes to Lua and IPC. Do
what has been done everywhere else, and let the core handle this by
going through mpv_node (which is supposed to serve both Lua tables and
JSON, and potentially other scripting language backends). Expose it as
new libmpv API function.

The new API is still a bit "rough" and support for other event types
might be added in the future.

This silently adds support for the playlist_entry_id fields to both Lua
and JSON IPC.

There is a small API change for Lua; I don't think this matters, so I
didn't care about compatibility. The new code in client.c is mashed up
from the Lua and the IPC code. The manpage additions are moved from the
Lua docs, and made slightly more "general".

Some danger for unintended regressions both in Lua and IPC. Also damn
these node functions suck, expect crashes due to UB.

Not sure why this became more code instead of less compared to before
(according to the diff stat), even though some code duplication across
Lua and IPC was removed. Software development sucks.
2020-03-21 19:33:48 +01:00
wm4 7e885a3bc3 client API: add a playlist entry unique ID
This should make dealing with some async. things easier.

It's intentionally not a globally unique ID.
2020-03-21 19:33:03 +01:00
wm4 956a5d9ac6 player: add potentially forgotten property change trigger
Unfortunately, merely changing the playlist current position affects the
flags returned by the "playlist" property, so the entirely thing needs
to be marked as changed. Seems to be a design mistake.
2020-03-21 19:32:50 +01:00
wm4 e9e93b4dbe player: add a number of new playlist contol commands/properties
Should give a good deal more explicit control and insight over the
player state.

Some feel a bit pointless, and/or expose internal weirdness. However,
it's not like the existing weirdness didn't exist before, or can be made
go away. (In part, the weirdness is because certain in-between states
are visible. Hiding them would make things simpler, but less flexible.)

Maybe this actually gives users a better idea how the API _should_ look
like, too.

On a side note, this tries to really guarantee that mpctx->playing is
set between playback start/end. For that, the loadfile.c changes assume
that mpctx->playing is set (guaranteed by code above the change), and
that playing->filename is set (probably could never be false; was broken
before and actually would have crashed if that could ever happen; in any
case, also add an assert to playlist.c for this).

playlist_entry_to_index() now tolerates playlist_entrys that are not
part of the playlist. This is also needed for mpctx->playing.
2020-03-21 19:32:50 +01:00
wm4 68d9d11ddf player: playlist-pos now use -1 for "no entry selected"
It's odd that this state is observable, but is made implicit by making
the property unavailable. It's also odd that an API user cannot directly
put the player into such a state.

Just allow reading/writing -1 (or in fact, any out of bounds index) for
this case.

I'm also refraining from using OPT_CHOICE for the "no selection" case,
because although that would be cleaner in theory, it would cause only
problems to API users due to the more complex property type (worse is
better).

One reason for not restricting the integer range on the input property
anymore is that if there are no playlist elements, the range would
contain only 1 integer, which cannot be represented anymore since the
recent m_option change. This was actually broken with 1 element
playlists before (and still is, with the constricted type for OSD and
the add/cycle commands). Doesn't matter too much.
2020-03-21 19:32:50 +01:00
wm4 2de783125b demux: average reported download speed some more
Currently, this reported the number of received bytes per second.
Improve this slightly by averaging over 2 seconds (but still updating
every second).
2020-03-21 19:32:50 +01:00
wm4 c892eff929 manpage: improve loadfile description 2020-03-21 19:32:50 +01:00
wm4 9815887435 osc: avoid using a deprecated event
The new code is pretty much equivalent.
2020-03-21 19:32:50 +01:00
wm4 4a2fd2daf6 client API: actually warn against enabling any deprecated events
Like it was done for the "tick" event, but for all deprecated events.

Not entirely effective, since the C API enables all events by default.
2020-03-21 19:32:50 +01:00
wm4 26ac6ead91 player: fix subtle idle mode differences on early program start
If the user manages to run a "loadfile x append" command before the loop
in mp_play_files() is entered, then the player could start playing
these. This isn't expected, because appending files to the playlist in
idle mode does not normally start playback. It could happen because
there is a short time window where commands are processed before the
loop is entered (such as running the command when a script is loaded).

The idle mode semantics are pretty weird: if files were provided in
advance (on the command line), then these should be played immediately.
But if idle mode was already entered, and something is appended to the
playlist using "append", i.e. without explicitly triggering playback,
then it should remain in idle mode.

Try to follow this by redefining PT_STOP to strictly mean idle mode.
Remove the playlist->current check from idle_loop(), since only the
stop_play field counts now (cf. what mp_set_playlist_entry() does).

This actually introduces the possibility that playlist->current, and
with it playlist-pos, are set to something, even though playback is not
active or being started. Previously, this was only possible during state
transitions, such as when changing playlist entries.

Very annoyingly, this means the current way MPV_EVENT_IDLE was sent
doesn't work anymore. Logically, idle mode can be "active" even if
idle_loop() was not entered yet (between the time after mp_initialize()
and before the loop in mp_play_files()). Instead of worrying about this,
redo the "idle-active" property, and deprecate the event.

See: #7543
2020-03-21 19:32:50 +01:00
wm4 2a85e8a186 player: remove additional newline before exit message
What was this even for? Also, most times, the cleared status line will
show up as an empty new line anyway, so this commit reduces the empty
new lines from 2 to 1.
2020-03-21 13:09:41 +01:00
wm4 a5af126f91 player: actually report an exit error if encoding mode fails on closing
The code that determines the process exit code ignores all stop_play
values other than PT_QUIT. Generally, PT_ERROR is meaningless outside of
play_current_file(), and is mostly equivalent to PT_NEXT_ENTRY.

Do something that makes it report a non-0 exit code, and indicates in
the terminal exit message that something went wrong.

Untested.
2020-03-21 13:03:38 +01:00
Jan Ekström 33519d61aa wayland: simplify mouse wheel direction calculation
Based on an idea by sfan5. Remove abs usage, and instead just
check for negative value, and set variable to either +/-1.
2020-03-19 20:27:55 +00:00
Kevin Mitchell 3aad89829f ao_wasapi: try mix format except for chmap
In shared mode, we previously tried to feed the full native format to
IsFormatSupported in the hopes that the "closest match" returned was
actually that.

Turns out, IsFormatSupported will always return the mix format if we
don't use the mix format's sample rate. This will also clobber our
choice of channel map with the mix format channel map even if our
desired channel map is supported due to surround emulation.

The solution is to not bother trying to use anything other than the mix
format sample rate. While we're at it, we might as well use the mix
format PCM sample format (always float32) since this conversion will
happen anyway and may avoid unecessary dithering to intermediate
integer formats if we are already resampling or channel mixing.
2020-03-19 20:39:44 +02:00
Kevin Mitchell 609d0ef478 ao_wasapi: handle S_FALSE in mp_format_res_str
IsFormatSupported may return S_FALSE (considered SUCCESS) if the
requested format is not suppported, but is close to one that is.
2020-03-19 20:39:44 +02:00
wm4 433c9a90a5 win32: pthread: define PTHREAD_MUTEX_ERRORCHECK
mpv uses it now. Doesn't need to do anything.
2020-03-19 00:11:23 +01:00
wm4 0b9ed9c274 build: make libass non-optional
Using mpv without libass isn't really supported, since it's not only
used to display ASS subtitles, but all text subtitles, and even OSD.

At least 1 user complained that the player printed a warning if built
without libass. Avoid trying to create the impression that using this
software without libass is in any way supported or desirable, and make
it fully mandatory.

(As far as making dependencies optional goes, I'd rather make ffmpeg
optional, which is an oversized and bloated library, rather than
something tiny like libass.)
2020-03-18 22:45:59 +01:00
wm4 cb82cbbbae osdep: add a pthread debugging wrapper
Because pthread failures are virtually undebuggable (which sure is
pretty strange, given all these heavy instrumentation tools these days).

Of course it affects only files which include osdep/threads.h.

I'm departing from the usual way to add symbols with config.h and using
"#if", and defining it on the compiler command line + "#ifdef" because I
don't want to include config.h from a header (which would be necessary
in this case) to keep things slightly cleaner. Maybe this is misguided,
but still.

This would have been easier if mpv defined its own wrappers for all
thread functions. But we don't (which to be honest is probably better
than e.g. going crazy like VLC and essentially reimplementing
everything). This seems to be a good compromise. Since it's off by
default and basically a developer tool, the minor undefined behavior
(redefining reserved symbols) isn't much of an issue.
2020-03-18 22:42:13 +01:00
wm4 373dad9962 f_decoder_wrapper: fix use of destroyed mutex
After calling the main filter's destroy callback, all child filters are
destroyed. But one of them still tried to access the cache_lock mutex
(which is destroyed in said destroy callback). This actually caused a
crash on Android with _FORTIFY_SOURCE.

Fix this by destroying the child filters first.
2020-03-18 22:31:17 +01:00
wm4 41e96d8b6b options: fix OPT_BYTE_SIZE upper limits
As an unfortunate disaster, min/max values use the type double, which
causes tons of issues with int64_t types. Anyway, OPT_BYTE_SIZE is often
used as maximum for size_t quantities, which can have a size different
from (u)int64_t.

OPT_BYTE_SIZE still uses in64_t, because in theory, you could use it for
file sizes. (demux.c would for example be capable of caching more than
2GB on 32 bit platforms if a file cache is used. Though for some reason
the accounting code still uses size_t, so that use case is broken. But
still insist that it _could_ be used this way.)

There were various inconsistent attempts to set m_option.max to a value
such that the size_t/int64_t upper limit is not exceeded. Due to the
double max field, this didn't really work correctly. Try to fix this
with the M_MAX_MEM_BYTES constant. It's a good approximation, because on
32 bit it should allow 2GB (untested, also would probably exhaust
address space in practice but whatever), and something "high enough" in
64 bit.

For some reason, clang 11 still warns. But I think this might be a clang
bug, or I'm crazy. The result is correct anyway.
2020-03-18 20:51:38 +01:00
wm4 a550bf4927 demux_mkv: fix another integer/float conversion warning
This code could assign INT64_MAX+1 (as double) to int64_t.
2020-03-18 20:44:54 +01:00
wm4 f73db96077 client API: fix MPV_FORMAT_DOUBLE => MPV_FORMAT_INT64
(Why can it do this conversion at all? This is  shitshow anyway.)
2020-03-18 20:43:56 +01:00
wm4 5a81de59a8 m_option: attempt to fix two rounding issues
Since double has a mantissa too small to hold INT64_MAX in full
precision, converting INT64_MAX to double rounds up. Insert some casts
to silence corresponding warnings (as shown by clang 11).

Also, the comparison in multiply_int64() was incorrect (I think...),
because if v==(double)INT64_MAX, then v==(1<<64), which cannot be
represented as int64_t.

There are probably better ways to solve this.
2020-03-18 20:19:13 +01:00
wm4 26f4f18c06 options: change option macros and all option declarations
Change all OPT_* macros such that they don't define the entire m_option
initializer, and instead expand only to a part of it, which sets certain
fields. This requires changing almost every option declaration, because
they all use these macros. A declaration now always starts with

   {"name", ...

followed by designated initializers only (possibly wrapped in macros).
The OPT_* macros now initialize the .offset and .type fields only,
sometimes also .priv and others.

I think this change makes the option macros less tricky. The old code
had to stuff everything into macro arguments (and attempted to allow
setting arbitrary fields by letting the user pass designated
initializers in the vararg parts). Some of this was made messy due to
C99 and C11 not allowing 0-sized varargs with ',' removal. It's also
possible that this change is pointless, other than cosmetic preferences.

Not too happy about some things. For example, the OPT_CHOICE()
indentation I applied looks a bit ugly.

Much of this change was done with regex search&replace, but some places
required manual editing. In particular, code in "obscure" areas (which I
didn't include in compilation) might be broken now.

In wayland_common.c the author of some option declarations confused the
flags parameter with the default value (though the default value was
also properly set below). I fixed this with this change.
2020-03-18 19:52:01 +01:00
Dudemanguy cdd6eb0994 wayland: notify vo if an output changes
Previously, the vo wasn't always informed if something about the output
changed during playback. For instance, changing a display's refresh rate
during playback would not update mpv's display fps. Fix this by simply
using VO_EVENT_WIN_STATE in output_handle_done which executes whenever
something about the output is changed.
2020-03-15 12:42:33 -05:00
wm4 281f5c63c1 m_option: remove debug code
Forgot to remove this. Here you see my confusion and realization how
casting INT64_MAX to double becomes INT64_MAX+1 (due to mantissa
precision and rounding), so some things seemed not to make sense at
first.
2020-03-14 19:08:47 +01:00
Avi Halachmi (:avih) 8861bfa913 vo_gpu: warn if correct-downscaling is ignored
And document that it's ignored with bilinear scaler.
2020-03-14 19:47:12 +02:00
wm4 cb2b5553bf osc: fix updating message when paused
The message_timeout field was basically polled. But ever since the OSC
was changed to work more event based, this didn't quite work. It was
quite visible when switching subtitle or audio tracks while paused (and
with caching disabled, since the cache update triggered some extra
redrawing).

Fix by using a proper timer.

I noticed that changing tracks with the message call commented didn't
redraw properly either, but, uh, I guess the message is always triggered
anyway, and happens to take care of this.
2020-03-14 15:15:44 +01:00
der richter ea13ec6d98 github: additionally ask for log files on build problems and questions 2020-03-14 14:16:31 +01:00
wm4 9d04e76f3f ao_pcm: fix double free on exit
This seems to be an older bug. It set priv->outputfilename to a new
talloc-allocated string, but the field is also managed as string option,
so talloc will free it first, then m_option_free() is called on the
dangling pointer. Possibly this is caused by the earlier ta destruction
order change.
2020-03-14 13:50:04 +01:00
der richter cd22e93fee cocoa-cb: support maximize/minimize on startup
Allow the --window-maximized and --window-minimized flags to actually
work when the player is started. since macOS doesn't like using both at
the same time the minimized state takes precedence over the maximized
state.
2020-03-14 12:23:42 +01:00
wm4 c784820454 options: introduce bool option type, use it for --fullscreen
The option code is very old and was added to MPlayer in the early 2000s,
when C99 was still new. MPlayer did not use the "bool" type anywhere,l
and the logical option equivalent to bool, the "flag" option type, used
int, with the convention that only the values 0 and 1 are allowed.

mpv may have hammered many, many additional tentacles to the option
code, but some of the basics never changed, and m_option_type_flag still
uses int. This seems a bit weird, since mpv uses bool for booleans. So
finally introduce an m_option_type_bool. To avoid duplicating too much
code, change the flag code to bool, and "reimplement" m_option_type_flag
on top of m_option_type_bool.

As a "demonstration", change the --fullscreen option to this new type.
Ideally, all options would be changed too bool, and m_option_type_flag
would be removed. But that is a lot of monotonous thankless work, so I'm
not doing it, and making it a painful years long transition.

At the same time, I'm introducing a new concept for option declarations.
Instead of OPT_BOOL(), which define the full m_option struct contents,
there's OPTF_BOOL(), which only takes the option field name itself. The
name is provided via a normal struct field initializer. Other fields
(such as flags) can be provided via designated initializers.

The advantage of this is that we don't need tons of nested vararg
macros. We also don't need to deal with 0-sized varargs being a pain
(and in fact they are not a thing in standard C99 and probably C11).
There is no need to provide a mandatory flags argument either, which is
the reason why so many OPT_ macros are used with a "0" argument. (The
flag argument seems to confuse other developers; they either don't
immediately recognize what it is, and sometimes it's supposed to be the
option's default value.)

Not having to mess with the flag argument in such option macros is also
a reason for the removal of M_OPT_RANGE etc., for the better or worse.

The only place that special-cased the _flag option type was in
command.c; change it to use something effectively very similar that
automatically includes the new _bool option type. Everything else should
be transparent to the change. The fullscreen option change should be
transparent too, as C99 bool is basically an integer type that is
clamped to 0/1 (except in Swift, Swift sucks).
2020-03-14 02:23:38 +01:00
wm4 7c4a550c0e DOCS/interface-changes.rst: add note about property notification changes
Commits ba70b150fb and 8a4f812b76 should have mentioned this. These
things should be quite useful for client API users, and thus should be
mentioned in a prominent place.

Although I'm not sure if anyone will understand from this gibberish what
this really means.
2020-03-14 01:40:54 +01:00
wm4 314a4a572b command: disable edition switching if there are no editions
Commit 8d965a1bfb changed option/property min/max handling. As a
consequence, ranges that contain only 1 or 0 elements are not possible
anymore. Normally that's fine, because it makes no sense to have an
option that has only one or none allowed value (statically).

But edition switching used some sort of mechanism where the property can
return a different, dynamically decided range at runtime. That meant
that if there were <2 editions, edition switching with the "cycle"
command would always pick the same value. But with the recent commit,
this changed to having "no range set" and would cycle through all
integer values.

Work this around with a simple change. Now, edition switching on a file
without editions shows "edition: auto" instead of "edition: 0", which
may appear odd. But the former is the --edition default value, and
previous mpv versions rendered the edition property like this when not
using switching.

(Who the fuck uses editions?)
2020-03-14 01:32:27 +01:00
wm4 8d965a1bfb options: change how option range min/max is handled
Before this commit, option declarations used M_OPT_MIN/M_OPT_MAX (and
some other identifiers based on these) to signal whether an option had
min/max values. Remove these flags, and make it use a range implicitly
on the condition if min<max is true.

This requires care in all cases when only M_OPT_MIN or M_OPT_MAX were
set (instead of both). Generally, the commit replaces all these
instances with using DBL_MAX/DBL_MIN for the "unset" part of the range.

This also happens to fix some cases where you could pass over-large
values to integer options, which were silently truncated, but now cause
an error.

This commit has some higher potential for regressions.
2020-03-13 17:34:46 +01:00
wm4 5d5a7e1953 ao_lavc: don't spam underrun warnings
Like ao_pcm, this is (conceptually) in perpetual underrun, as long as
dumping is fast enough.
2020-03-13 16:50:27 +01:00
wm4 28de668173 options: more pushing code around
Try to remove m_config implementation details from m_config_frontend.
Not sure if I like it. Seems to be ~100 lines of awkward code more, and
not much is gained from it. Also it took way too long to do it, and
there might be bugs.
2020-03-13 16:50:27 +01:00
wm4 eb381cbd4b options: split m_config.c/h
Move the "old" mostly command line parsing and option management related
code to m_config_frontend.c/h. Move the the code that enables other part
of the player to access options to m_config_core.c/h. "frontend" is out
of lack of creativity for a better name.

Unfortunately, the separation isn't quite clean yet. m_config_frontend.c
still references some m_config_core.c implementation details, and
m_config_new() is even left in m_config_core.c for now. There some odd
functions that should be removed as well (marked as "Bad functions").
Fixing these things requires more changes and will be done separately.

struct m_config is left with the current name to reduce diff noise.
Also, since there are a _lot_ source files that include m_config.h, add
a replacement m_config.h that "redirects" to m_config_core.h.
2020-03-13 16:50:27 +01:00
wm4 d3ad4e2308 options: remove intpair option type
This was mostly unused, and has certain problems. Just get rid of it.

It was still used in CDDA (--cdda-span) and a debug option for OpenGL
(--opengl-check-pattern). Replace both of these with 2 options, where
each sets the start/end values of the former span. Both were
undocumented somehow (normally we require all options to be documented),
so I'm not caring about compatibility, and not bothering to add it to
the API changelog.
2020-03-13 16:50:27 +01:00
wm4 3006c4ba5d options: remove min/max support from strings and string lists
We don't really use this anymore. Only --playlist and vf_lavfi filter
names did (to error on empty parameters), but it doesn't really matter.
2020-03-13 16:50:27 +01:00
wm4 06718da79c build: make C11 atomics mandatory
The emulation is pretty bad, and C11 compilers are everywhere now. It's
time to retire the emulation, which was always meant as temporary hack
for transition.

In theory, a user can still use --disable-stdatomic to enable the
emulation code, but that's sort of hidden. Actual support will be
removed after the next release or so.
2020-03-13 13:47:11 +01:00
Aman Gupta 5105a3b05a video/out/android_common: use jni helpers
Signed-off-by: Aman Gupta <aman@tmm1.net>
2020-03-12 22:08:25 +01:00
Niklas Haas c05e5d9d78 vo_gpu: generally allow non-storable FBOs
We have this cap now thanks to e2976e662, but we don't actually make
sure our FBOs are storable before we blindly attempt using them with
compute shaders.

There's no more need to unconditionally set `storage_dst = true` as long
as we make sure to include an extra condition on the `fbo_format`
selection to prevent users from accidentally enabling
compute-shader-only features with non-storable FBOs, alongside some
other miscellaneous adjustments to eliminate instances of "assumed
storability" from vo_gpu.
2020-03-08 21:41:16 +01:00
Niklas Haas c145c80085 vo_gpu: avoid error spam when ra_fbo fmt is non-storable
This simply makes the "is the destination FBO format bad?" check a tiny
bit less awful, by making sure we prefer storable FBO formats over
non-storable FBO formats. I'd love to make this also conditional on
whether or not we actually *need* a storable FBO format, but that logic
is decided later, in `pass_draw_to_screen`, and I don't want to
replicate the logic.

Fixes #7017.
2020-03-08 21:32:06 +01:00
wm4 3b4641a5a9 filter: minor cosmetic naming issue
Just putting some more lipstick on the pig, maybe it looks a bit nicer
now.
2020-03-08 19:38:10 +01:00
wm4 048334c396 command: add libass-version property
A bit of a mess with that ifdeffery, but fuck it.
2020-03-08 19:38:10 +01:00
wm4 6bf086fc15 sub: log libass version
Sometimes helpful. Would be even nicer if libass logged it themselves,
including git hash, I guess.
2020-03-08 19:38:10 +01:00
wm4 62c1d79724 player: rearrange libav* library check
No need to be nice. Also hopefully breaks idiotic distro patches.
2020-03-08 19:38:10 +01:00
wm4 d0d9ace421 stream_file: mark fd protocols as "unsafe"
Whatever good or bad that might do. In any case, they can easily trigger
UB-like behavior.
2020-03-08 19:38:10 +01:00
Dudemanguy 7170910f4c wayland: always use the fs-screen id for fs
Previously if the --fs-screen option was set, it would only use the
screen if mpv was launched with --fs and only on startup. During
runtime, the toggle would ignore it. Rework the logic here so that mpv's
fullscreen always uses --fs-screen if it is set. Additionally, cleanup
some unneeded cruft in vo_wayland_reconfig and make find_output more
useful.
2020-03-08 16:08:29 +00:00
wm4 28ea1ed296 stream_lavf: use smb:// for ffmpeg libsmbclient support
If you really want that, you can get it through FFmpeg, I guess.
2020-03-07 13:55:20 +01:00
wm4 3471476f3f ci: remove libsmblient
This was forgotten.
2020-03-07 13:53:56 +01:00
wm4 5524ba9d47 player: move on_unload hook after frame step pausing
Really minor detail that doesn't really matter. If frame stepping pauses
playback on end (why does this special case even exist), it should
probably be done after on_unload, because all works is supposed to be
finished at that point.
2020-03-07 12:47:46 +01:00
wm4 a56d5bdb53 client API: always reset new_property_events fields
This was not reset in the num_properties==0 case. This didn't really
matter, but for debugging it's slightly nicer to see new_property_events
reset once the client thread is done with it.
2020-03-07 12:47:46 +01:00
wm4 7f1bd0f30b manpage: explicitly mention "tick" event as deprecated
Just. Don't. Use. It.
2020-03-07 12:47:46 +01:00
wm4 d6f282e162 demux: bump --cache-secs default value
Change to it 1000 hours, which is "infinite" enough. (Hesitant to use
INFINITY, as that is not in the option's range. The option parser
rejects it because it causes only problems in API users and so on.)
2020-03-07 12:47:46 +01:00
wm4 f20dfef880 demux: mark recently added debug option as deprecated
It was the intention to remove it again after a release or two; mark it
was deprecated so nobody thinks it gets to stay.
2020-03-07 12:47:46 +01:00
Avi Halachmi (:avih) a23869379c js: osd-overlay update: return the command result (match 7a76b577)
Currently only useful for the new 'compute_bounds' command key.
2020-03-07 12:37:35 +02:00
Avi Halachmi (:avih) 9cf45d8300 js: osd-overlay update: support arbitrary key names
Until now the 'update' method used mp.command_native with a hardcoded
list of key names.

Change it to use whatever keys the user set to this object, so that
we can remain oblivious to new keys which 'osd-overlay' may support.

This is how the lua code did it from the begining. We didn't, and now
we pay the price.

Note: could be implemented either as we have now (clone `this`
excluding the methods) or by moving the methods up the prototype chain
(i.e. class methods) so they don't get enumerated and use `this` as
the command object itself.

However, in the latter approach we'll have to save the values which we
change (name, res_x, res_y) and restore them after the command, so it's
simpler to just clone `this`.
2020-03-07 12:37:35 +02:00
wm4 ba70b150fb client API: provide ways to finish property changes on file changes
When the current file changes (or rather, when starting/finishing
playback of a playlist entry), clients tend to have the problem that
it's hard to tell whether a property change notification (via
mpv_observe_property() and mechanisms layered on top of it) is from the
previous or new playlist entry. The previous commit probably helps, but
all the asynchronity is still a bit unhelpful.

Try to make this better by adding new hooks, that are run before/after
playback init/deinit. This is similar to the existing hooks, except
they're outside of "initialized" playback, which excludes that you might
accidentally get an overlap between the current and the previous/next
playlist entry.

That still doesn't seem quite enough, since normally, property change
notifications come after the hook event. So basically a client would
have to explicitly "drain" the event queue within the hook, and make the
hook continue only after that is done. Knowing when property
notifications are done is another asynchronous nightmare (how exactly it
works keeps changing within client.c, and an API user probably can't
tell anymore when all pending properties are truly done). So introduce
another guarantee: properties that were changed before the hook happens
will be returned before the hook event is returned. That means the
client will have received all pending property notifications from the
previous playlist entry (or whatever) before the hook is entered.

As another minor complication, we shouldn't just keep the hook pending
until _all_ property notifications are done, since the client's hook
could produce new ones. (Or just consider things like the demuxer thread
hammering the client with cache update events, while the "on_preloaded"
hook is run.) So there is some extra untested, fragile logic in client.c
to handle this (the waiting_for_hook flag).

This probably works, but was barely tested. Not sure if this helps
anyone, but I think it's fine for my own purposes. (I really hated this
aspect of the API whenever I used it myself.)
2020-03-07 02:52:10 +01:00
wm4 8a4f812b76 client API: avoid returning stale value on property notifications
This could happen if a property was flagged as changed, then updated,
then flagged again, but gen_property_change_event() was called before
the value was updated a second time. Then the function simply returned
the old value, and would later trigger a new change event again.

This was considered acceptable before, since property notifications are
asynchronous anyway (so they may always be "outdated", it just mattered
whether the most recent value was eventually delivered).

But consider ordering with events. It seems desirable that specific
important events (e.g. MPV_EVENT_START_FILE) should not be followed by
property updates that happened before it, because that would make
application logic really a mess, and property notification near-useless
in certain cases.

Avoid this by never returning a value if it was marked changed, but not
updated yet.

Unfortunately, this could lead to clients never receiving a value (or
receiving it with a high random delay), if they're too slow to read it
(or the property simply updates too often). Note that this is done for
_all_ property notifications, not just returned events. Hopefully not a
problem in practice. If it turns out to be one, this mechanism could be
restricted to actually returned events, for which this really matters.
2020-03-06 23:59:21 +01:00
wm4 575197ff8b client API: remove deprecated qthelper.hpp header
No replacement. Qt or C++ code has no business in this repository, and
new code (even if it uses Qt) should not use it. Get rid of it.

We consider the libmpv API itself as stable. Symbols can be deprecated,
but not be removed. However, qthelper.hpp was never considered part of
the libmpv API. There no ABI implications either, since it's a header-
only implementation that uses C API symbols only. It's just a header
provided for convenience for Qt/C++ programs (i.e. extremely limited
usefulness).
2020-03-06 19:37:44 +01:00
wm4 2337fa4e02 command: remove legacy hook API
Hopefully nothing uses this. (I know one exception, but, well, what can
I do.)
2020-03-06 19:23:14 +01:00
wm4 7a76b577d8 command: extend osd-overlay command with bounds reporting
This is more or less a minimal hack to make _some_ text measurement
functionality available to scripts. Since libass does not support such a
thing, this simply uses the bounding box of the rendered text.

This is far from ideal. Problems include:
- using a bitmap bounding box
- additional memory waste and/or flushing caches
- dependency on window size
- odd small deviations with different window sizes (run osd-test.lua and
  resize the window after each timer update; the bounding boxes aren't
  adjusted in an overly useful way)
- inability to query the size _after_ actual rendering

But I guess it's a start. Since I'm aware that it's crap, add a threat
to the manpage that this may be changed/removed again. For now, I'm
interested whether anyone will have use for it in its current form, as
it's an often requested feature.
2020-03-06 18:20:11 +01:00
wm4 c6822b853d manpage: fix typos 2020-03-06 18:12:13 +01:00
wm4 c032db6185 player: force update of cache properties even on inactive demuxer cache
When the demuxer cache read until the end of the stream, and was
finished and completely inactive, the cache properties were not updated
anymore via MP_EVENT_CACHE_UPDATE.

Unfortunately, many cache properties depend on the current playback
position, such as cache-duration or fw-bytes. This is especially visible
on the OSC. If everything was cached, seeking around didn't update the
displayed forward cache duration.

That means checking demuxer_reader_state.idle is not enough. You also
need to check whether the current playback position changed.

Fix this by explicitly using the current playback position, and update
the properties if it changed "enough". "Enough" is 1 second of media
time in this example, which may or may not be appropriate.

In general, this could probably be done better. There are many other
triggers that change the cache state and that are not covered. For now
I'm content with getting rid of the obvious problems.

I think the OSC problem in particular was caused by changing it from
polling to using property change notifications.
2020-03-05 22:23:43 +01:00
wm4 777615f1a3 build: disable RPI vendor blob auto-detection
Apparently this bit-rotted a lot, and now causes more problems that it
helps. In particular picking up broadcom EGL instead of Mesa EGL will
break things. With RPI getting proper Mesa/DRM/V4L support, this problem
should solve itself as well.
2020-03-05 22:00:50 +01:00
wm4 8427292eb7 demux: deprecate --cache-secs
Because it's confusing and useless. If nobody complains, we'll have one
weird cache configuration option less.
2020-03-05 22:00:50 +01:00
wm4 f06bf8c073 player: reduce impact of blocking filters
Some filters may block the playloop for a longer time. For example, if a
decoder fails to decode anything and somehow just discards packets, the
filter graph would run (in a blocking manner) until all packets are
read, which could take a longer time if the demuxer thread is fast
enough.

Make it exit every 100ms. That should at least give the user a chance to
stop playback.

Filtering could run on a different thread, but I don't see much value in
doing that in the general case. It would just waste a thread. Although
being able to use mp_filter_graph_interrupt() would be slightly nicer
than such a timeout mechanism. Decoding in particular can actually use a
separate thread (--vd-queue-enable), but again, this is not enabled by
default, because it just wastes a thread.

Like the previous f_decoder_wrapper commit, this is probably a sin.
2020-03-05 22:00:50 +01:00
wm4 443ed2cb56 manpage: make suggestion for --vd-queue dynamic config 2020-03-05 22:00:50 +01:00
wm4 c5eb2f2ac4 f_decoder_wrapper: make decoder thread responsive while filling queue
The mp_filter_run() invocation blocks as long as the demuxer provides
packets and the queue can be filled. That means it may block quite a
long time of the decoder queue size is large (since we use libavcodec in
a blocking manner; it regrettably does not have an async. API).

This made the main thread freeze in certain situations, because it has
to wait on the decoder thread.

Other than I suspected (I wrote that code, but that doesn't mean I know
how the hell it works), this did not freeze during seeking: seek resets
flushed the queue, which also prevented the decoder thread from adding
more frames to it, thus stopping decoding and responding to the main
thread in time. But it does fix the issue that exiting the player waited
for the decoder to finish filling the queue when stopping playback.
(This happened because it called mp_decoder_wrapper_set_play_dir()
before any resets. Related to the somewhat messy way play_dir is
generally set. But it affects all "synchronous" decoder wrapper API
calls.)

This uses pretty weird mechanisms in filter.h and dispatch.h. The
resulting durr hurr interactions are probably hard to follow, and this
whole thing is a sin. On the other hand, this is a _very_ user visible
issue, and I'm happy that it can be fixed in such an unintrusive way.
2020-03-05 22:00:50 +01:00
wm4 12375f67b4 f_decoder_wrapper: use proper log prefix for all involved filters
p->log has a prefix set that gives some context and distinguishes audio
and video decoders. The "public" wrapper filter didn't use it, which is
a regression since commit a3823ce0e0.
2020-03-05 22:00:50 +01:00
wm4 8a1bd15216 filter: add functions to suspend filtering temporarily
Filtering is integrated into an event loop, which is something the
filter API user provides. To make interacting with the event loop
easier, and in particular to avoid filtering to block event handling,
add functions the event loop code can suspend filtering.

While we cannot actually suspend a single filter, it's pretty easy to
suspend the filter graph run loop itself, which is responsible for
selecting which filter to run next.

This commit shouldn't change behavior at all, but the functions will be
used in later commits.
2020-03-05 22:00:50 +01:00
wm4 670610bc1d atomic: add atomic_exchange_explicit() fallback
Apparently I want to use this in a later commit. Untested, because this
is a pre-C11 fallback, and I only test with real <stdatomic.h>.
2020-03-05 22:00:50 +01:00
wm4 50177aaa3b dispatch: add strange mechanism for making worker threads responsive
This is probably a sin for the sake of user experience. See a following
commit that wires up f_decoder_wrapper with it.
2020-03-05 22:00:50 +01:00
wm4 c1ff54e2e4 f_decoder_wrapper: enable DR and hwdec with --vd-queue-enable
This was forgotten.

Hardware decoding typically breaks immediately, because many hw decoding
APIs require allocating all surfaces in advance (and/or libavcodec was
not made flexible enough to add new surfaces later). If the queue is
large enough, it will run out of surfaces, fail decoding, and fall back
to software decoding. We consider this the user's fault.

--hwdec-extra-frames can be used to avoid this, if you have enough GPU
memory, and the needed number of frames is lower than the arbitrary
mpv-set maximum limit of that option.
2020-03-05 22:00:50 +01:00
wm4 23f560daa3 manpage: document how final queue size is determined
Believe it or not, users were confused about this.
2020-03-05 22:00:50 +01:00
wm4 e7de0e718c manpage: clarify writes to playlist-pos
I don't know what should happen when the same value is written to the
property. It seems that it would be more natural if it were ignored
(since that's also what is done with options now), but you could argue
the other way around as well. In any case, changing it silently could
leads to user scripts etc. breaking, so don't change it now.

Instead, add blabla to the manpage to put the responsibility on the
user, so when we suddenly change it one day, we can blame any breakages
on someone else.

See: #7501
2020-03-05 22:00:50 +01:00
wm4 3b8b7cb9d4 stream_smb: remove this
This required libsmbclient, which is a heavy dependency, and as a
library, has all kinds of problems. For one, the API requires completely
unacceptable global state (in particular, leaks auth state), and is not
thread-safe (meaning concurrent reads to multiple files block each
other).

There are better replacements: you can use the Linux kernel's builtin
CIFS support, fusesmb, or contribute supoport for libdsm.
2020-03-05 22:00:50 +01:00
Sven Kroeger fc8c1fcfb2 drm_prime: double free bug
This commit fixes a bug where handle for a framebuffer gets double
freed.
It seems to happen that the same prime fd gets two framebuffers.
As the prime fd is the same the resulting prime handle is also the
same.
This means one handle but 2 framebuffers and can lead to the following
chain:

1. The first framebuffer gets deleted the handle gets also freed via
the ioctl.

2. In startup phase not all 4 dumb buffers for overlay drawing
are set up. It can happen that the last dumb buffer gets the
handle we freed above.

3. The second framebuffer gets freed and the handle will be
freed again resulting that the 4's dumb buffer handle is not
backed by a buffer.

4. Drm prime continues to assign handles to its prime fds an
will lead to have this handle which was just freed to
reassign again but to an prime buffer.

5.Now the overlay should be drawn into dumb buffer 4 which
still has the same handle but is backed by the wrong buffer.
This leads to two different behaviors:

- MPV crashes as the drm prime buffers size als calculated
by the decoder output format. The overlay output format
differs and it takes more space. SO the size check
in kernel fails.

- MPV is continuing play. This happens when the decoders
allocates a bigger buffer than needed for the overlay.
For example overlay is Full HD and decoder output is 4k.
This leads to the behavior das the overlay wil be drawn
into the wrong buffer as its a drm prime buffer and results
in a flicker every fourth step.
2020-03-05 18:12:57 +01:00
Sven Kroeger 8b24510388 drm_prime: forward modifiers from FFMPEG to drm API
* Change drmModeAddFB2 to drmModeAddFB2WithModifiers
* Set modifiers flag in API call
* fetch and set modifiers according to kernel constraints
2020-03-03 19:54:15 +01:00
mg 24acddbdc4 demuxer-lavf: udp_multicast rtsp-transport option 2020-03-03 18:31:20 +01:00
wm4 e7bab0025f manpage: suggest using the decoding queue with backward playback 2020-03-01 00:40:03 +01:00
wm4 872794be90 f_decoder_wrapper: make most queue options runtime changeable
Why not.
2020-03-01 00:38:34 +01:00
wm4 ae1aeab7aa options: make decoder options local to decoder wrapper
Instead of having f_decoder_wrapper create its own copy of the entire
mpv option tree, create a struct local to that file and move all used
options to there.

movie_aspect is used by the "video-aspect" deprecated property code. I
think it's probably better not to remove the property yet, but
fortunately it's easy to work around without needing special handling
for this option or so.

correct_pts is used to prevent use of hr-seek in playloop.c. Ignore
that, if you use --no-correct-pts you're asking for trouble anyway. This
is the only behavior change.
2020-03-01 00:28:09 +01:00
wm4 b31a5e3a58 demux: another hack to deal with track switching refresh
The demuxer cache employs a strange method to make track switching
instant with caching enabled. Normally this would mean you have to wait
until the cache has played out (and you get new packets, including
packets from the newly selected track), or you have to perform a slow
high level seek (decoding video again etc.). The strange method is that
it performs a demuxer-level seek without a high level seek so it looks
like a continuous stream to the decoder, and the newly select stream
gets packets at the current playback position. This is called a refresh
seek.

This works only if some weird heuristics work. It needs a packet "unique
ID", for which it uses either dts or pts. The value must be strictly
monotonic increasing. If this doesn't work, the referesh seek can't be
executed, and the user has to wait until the end of the cache. Sometimes
there are files that simply do not work.

In the present case, there's actually a hack that we can extend. Packets
with unset position are likely generated by the parser, and the hack
which this commit touches simply attempts to make up a new (hopefully
unique) position value, even if the value itself makes no sense. It only
ha to be deterministic.

It turns out libavcodec sometimes output packets with repeating position
values. This commit tries to handle this case too with the same hack.

Fixes: #7498
2020-02-29 23:03:39 +01:00
wm4 faf24a286f ad_lavc: disable decoder downmix by default
Let's see how much everyone hates this. Leaving it enabled seems
problematic, because libavcodec returns an unspecific error if it
doesn't like it.

Fixes: #6300
2020-02-29 22:08:38 +01:00
wm4 a3823ce0e0 player: add optional separate video decoding thread
See manpage additions. This has been a topic in MPlayer/mplayer2/mpv
since forever. But since libavcodec multi-threaded decoding was added,
I've always considered this pointless. libavcodec requires you to
"preload" it with packets, and then you can pretty much avoid blocking
on it, if decoding is fast enough.

But in some cases, a decoupled decoder thread _might_ help. Users have
for example come up with cases where decoding video in a separate
process and piping it as raw video to mpv helped. (Or my memory is
false, and it was about vapoursynth filtering, who knows.) So let's just
see whether this helps with anything.

Note that this would have been _much_ easier if libavcodec had an
asynchronous (or rather, non-blocking) API. It could probably have
easily gained that with a small change to its multi-threading code and a
small extension to its API, but I guess not.

Unfortunately, this uglifies f_decoder_wrapper quite a lot. Part of this
is due to annoying corner cases like legacy frame dropping and hardware
decoder state. These could probably be prettified later on.

There is also a change in playloop.c: this is because there is a need to
coordinate playback resets between demuxer thread, decoder thread, and
playback logic. I think this SEEK_BLOCK idea worked out reasonably well.

There are still a number of problems. For example, if the demuxer cache
is full, the decoder thread will simply block hard until the output
queue is full, which interferes with seeking. Could also be improved
later. Hardware decoding will probably die in a fire, because it will
run out of surfaces quickly. We could reduce the queue to size 1...
maybe later. We could update the queue options at runtime easily, but
currently I'm not going to bother.

I could only have put the lavc wrapper itself on a separate thread. But
there is some annoying interaction with EDL and backward playback shit,
and also you would have had to loop demuxer packets through the
playloop, so this sounded less annoying.

The food my mother made for us today was delicious.

Because audio uses the same code, also for audio (even if completely
pointless).

Fixes: #6926
2020-02-29 21:52:00 +01:00
wm4 485f335b69 filter: add async queue filter
This is supposed to enable communication between filter graphs on
separate threads. Having multiple threads makes only sense if they can
run concurrently with each other, which requires such an asynchronous
queue as a building block. (Probably.)

The basic idea is that you have two independent filters, which can be
each part of separate filter graphs, but which communicate into one
direction with an explicit queue. This is rather similar to unix pipes.
Just like unix pipes, the queue is limited in size, so that still some
data flow control enforced, and runaway memory usage is avoided.

This implementation is pretty dumb. In theory, you could avoid avoid
waking up the filter graphs in quite a lot of situations. For example,
you don't need to wake up the consumer filter if there are already
frames queued. Also, you could add "watermarks" that set a threshold at
which producer or consumer should be woken up to produce/consume more
frames (this would generally serve to "batch" multiple frames at once,
instead of performing high-frequency wakeups). But this is hard, so the
code is dumb. (I just deleted all related code when I still got
situations where wakeups were lost.)

This is actually salvaged and modified from a much older branch I had
lying around. It will be used in the next commit.
2020-02-29 21:52:00 +01:00
wm4 f29623786b filter: decide how multi-threading is supposed to work
Instead of vague ideas about making different filter graphs on different
threads interact directly, this have no direct support. Instead, helpers
are required (such as added with the next commit).

Document it. Different root filters (i.e. separate filter graphs) are
now considered to be part of separate threads, so assert() if they're
found to accidentally interact.
2020-02-29 21:49:14 +01:00
wm4 d45d4f86e1 skip-logo.lua: remove lua 5.2 warning message
(OK, I tested it.)
2020-02-29 21:49:14 +01:00
wm4 d852ad2ae7 build: pick up Lua 5.2 by default
Previously: 5.1 > 5.2 > luajit
Now:        5.2 > luajit > 5.1

I randomly decided that this should be done, since I suspect most
environments will prefer the highest Lua version anyway. There is not
much of a point picking the older one by default.

Maybe 5.1 should be dropped fully, but considering we need to stay
compatible with luajit, there is no particular incentive for this.
2020-02-29 21:49:14 +01:00
wm4 c79619f110 demux: add a way to block reading after seeks
Preparation for a future commit. The demuxer queues might be read from
other threads than the one to issue the seek, and passing SEEK_BLOCK
with such a seek will provide a convenient way to synchronize this.
2020-02-29 21:49:00 +01:00
wm4 8fc2bc1422 ta: fix logging of unfreed child allocations
Broken since commit f6615f00ee. This traversed the data
structure incorrectly, and caused a stack overflow due to infinite
recursion.
2020-02-29 20:12:31 +01:00
wm4 84fe9c2a47 filter: fix possibly lost async wakeups
mp_filter_mark_async_progress() can asynchronously mark a filter for
processing, without waking up the filter thread. (It's some sort of
idiotic micro-optimization I guess?) But since it sets async_pending
without doing the wakeup, a mp_filter_wakeup() after this will do
nothing, and the wakeup is lost. Fix it by checking for the needed
wakeup separately.

Fortunately, nothing used this function yet, so there is no impact.
2020-02-29 20:12:31 +01:00
wm4 b0b5de3063 f_decoder_wrapper: replace most public fields with setters/getters
I may (optionally) move decoding to a separate thread in a future
change. It's a bit attractive to move the entire decoder wrapper to
there, so if the demuxer has a new packet, it doesn't have to wake up
the main thread, and can directly wake up the decoder. (Although that's
bullshit, since there's a queue in between, and libavcodec's
multi-threaded decoding plays cross-threads ping pong with packets
anyway. On the other hand, the main thread would still have to shuffle
the packets around, so whatever, just seems like better design.)

As preparation, there shouldn't be any mutable state exposed by the
wrapper. But there's still a large number of corner-caseish crap, so
just use setters/getters for them. This recorder thing will inherently
not work, so it'll have to be disabled if threads are used.

This is a bit painful, but probably still the right thing. Like
speculatively pulling teeth.
2020-02-29 01:23:20 +01:00
wm4 a8f4ca587d test: update img_formats.txt
This explicitly depends on the pixfmt list from FFmpeg (done so to
easily spot regression, incompatible changes, and other unexpected
things).

Some local changes in mpv change some of the output. For pal8 an alias
was added back, and the [GENERIC] markers are removed because the mpv
aliases are not dependent on the mpv config anymore (which was
unnecessary).

The other changes are due to ffmpeg adding some new formats.
2020-02-29 01:23:20 +01:00
wm4 c10ca137a8 player: remove delayed audio seek thing
This was a hack that attempted to line up external audio tracks with
video. The problem is that if you do a keyframe seek backwards, video
will usually seek much farther back than audio (due to much higher
keyframe aka seek point distances). The hack somehow made seeking a 2
step process.

This existed in 4 different forms in the history of this code base, and
it was always very cumbersome. We mostly needed this for ytdl_hook (I
think?), which uses the 4th form, which is nicely confined to
demux_timeline and is unrelated to the "external" audio tracks in the
high level player.

Since this is (probably) not really widely needed anymore, get rid of
it. Better do this now, than when somehow rewriting all the seeking code
(which might happen in this decade or the next or so) and when it
wouldn't be easily revertable anymore in case we find we "really" need
it unlike expected.

There is no issue if hr-seeks are used. Also, you can still use edl
files to "bundle" multiple streams as if it was a single stream (this is
what ytdl_hook does now).
2020-02-29 01:23:05 +01:00
wm4 d32ce14d2c demux_lavf: don't interpret errors as EOF
It seems sporadic errors are possible, such as connection timeouts.
Before the recent demuxer change, the demuxer thread retried many times
even on EOF, so an error was only interpreted as EOF once the decoder
queues ran out.

Change it to use EOF only. Since this may actually lead to the demuxer
thread being "stuck" and retrying forever (depending on libavformat API
behavior), I'm also adding a heuristic to prevent this, using a random
retry counter. This should not be necessary, but libavformat cannot be
trusted. (This retrying forever could be stopped by the user, but
obviously it would still heat the CPU for a longer time if the user is
not present.)
2020-02-28 17:25:07 +01:00
wm4 7e2bb7b439 osc: use default hr-seek when dragging progress bar to seek
The "seekbarkeyframes" option is now interpreted such if it's true, the
player default is used. Too lazy to make this a choice option or
whatever; the Lua option parser doesn't have support for that anyway.
Someone who cares can adjust this.
2020-02-28 17:17:42 +01:00
wm4 679e4108f2 player: dumb seeking related stuff, make audio hr-seek default
Try to deal with various corner cases. But when I fix one thing, another
thing breaks. (And it's 50/50 whether I find the breakage immediately or
a few months later.) So results may vary.

The default for--hr-seek is changed to "default" (not creative enough to
find a better name). In this mode, audio seeking is exact if there is no
video, or if the video has only a single frame. This change is actually
pretty dumb, since audio frames are usually small enough that exact
seeking does not really add much. But it gets rid of some weird special
cases.

Internally, the most important change is that is_coverart and is_sparse
handling is merged. is_sparse was originally just a special case for
weird .ts streams that have the corresponding low-level flag set. The
idea is that they're pretty similar anyway, so this would reduce the
number of corner cases. But I'm not sure if this doesn't break the
original intended use case for it (I don't have a sample anyway).

This changes last-frame handling, and respects the duration of the last
frame only if audio is disabled. This is mostly "coincidental" due to
the need to make seeking past EOF trigger player exit, and is caused by
setting STATUS_EOF early. On the other hand, this might have been this
way before (see removed chunk close to it).
2020-02-28 17:15:07 +01:00
wm4 85576f31a9 player: attempt to fix playback end on hr-seeking past EOF again
This tries to fix #7206 (hr-seeking past EOF does not stop playback)
again. Commit 57fbc9cd76 should have fixed this, but trying it again
(using that git revision), it often did not work. Whatever the fuck.

So add another dumb special case that will break within weeks. Note that
the check in handle_eof() had no effect, since execute_queued_seek() is
called later, which cancels EOF in the same case.
2020-02-28 15:41:45 +01:00
wm4 efe43d768f player: set playback_pts in hr-seek past EOF case
Hr-seek past the last frame instantly enters EOF, which means
handle_playback_time() will not set playback_pts to the video PTS (as
all video frames are skipped), which leads to the playback time being
taken from the last seek target. This results in confusing behavior,
especially since the seek time will be clipped to the file duration for
display, but not for further relative seeks.

Obviously, the time should be set to the last video frame, so use the
last video frame as fallback if both audio and video have ended. Also,
since the same problem exists with audio-only playback, add a fallback
for audio PTS too. We don't know which was the "last" fragment of media
played (to decide whether to use the audio or video PTS as the
fallback), but it doesn't matter since the maximum works.

This could lead to some undesired effects. In particular the audio PTS
is basically a bad guess, and is for example not clipped against --end.
(But the ridiculous way audio syncing and clamping currently works, I'm
not going to touch that shit unless I rewrite it completely.) The cover
art case is slightly broken: using --keep-open with keyframe seeks will
result in 0 as playback PTS (the video PTS). OK, who cares, it got late.

Also casually get rid of last_vo_pts, since that barely made any sense
at all.

Fixes: #7487
2020-02-28 02:14:12 +01:00
wm4 009d1ffda6 player: remove stale last frame references
The seeking logic saves the last video frame it has seen (for example
for being able to seek to the last frame, or backstepping).
Unfortunately, the frame was fed back to the filtering pipeline in
situations when it shouldn't have. Then it's an out of order frame,
because it really saves the last _discarded_ frame.

For example, seeking to the end of a file with --keep-open, shift+up,
shift+down => invalid video pts warning due to saved_frame being fed
back.

Explicitly discard saved_frame when it's obviously not needed anymore.

The removed accesses to "r" are strictly speaking unrelated (just
const-propagating them).
2020-02-28 01:26:08 +01:00
wm4 3ae4094ec0 demux: make seek ranges work for static images + audio
In this case the video track has seek_start == seek_end, and due to the
"seek_start >= seek_end" condition, this was considered broken, and no
seek range was created, breaking cached seeking.

Fix this by allowing the case if they're equal, and a valid timestamp.

(NB: seeking backward in this will still jump to position 0, because it
is the video timestamp. This is unfortunately how it's supposed to work.
HR-seeks will also do this, but decode and skip the entire audio until
the seek target, so it will mostly appear to work.)
2020-02-28 00:59:11 +01:00
wm4 2b628d4352 demux_timeline: fix bad EOF reporting
Exposed by commit b56e2efd5f. demux_timeline reported a bogus EOF if
"parallel" streams were used. If a virtual source reported EOF, it was
propagated as global EOF, without serving packets of other virtual
sources that have not ended yet.

Fix this by not reporting global EOF just because a source has not
returned a packet. Instead make the reader retry by returning no packet
and no EOF state, which will call d_read_packet() again with a different
source. Rely on the eof_reached flags to signal global EOF.

Since eof_reached is now more important, set it in a certain other case
when it apparently should have been set. do_read_next_packet()'s return
value is now ignored, so get rid of it.
2020-02-28 00:08:36 +01:00
wm4 1e57f457b0 command: remove unintended newline
This just made it print a blank line.
2020-02-27 22:30:46 +01:00
wm4 05564af1ac demux_mkv: document probe-start-time option and enable it by default
This is useful with live streams, and it's not much worse than the h264
first packet hack, which reads some data anyway.

For some reason, the option wasn't even documented, so do that.

In addition, print the start time even if it's negative. That should not
be possible, but for some reason, the field is an int64_t copied from an
uint64_t so... whatever. Keeping the logging slightly more straight
forward is better anyway.
2020-02-27 22:30:46 +01:00
wm4 b56e2efd5f demux: simplify some internals, stop trying to read packets after EOF
Remove some redundant fields that controlled or indicated whether the
demuxer was/could/should prefetch. Redefine how the eof/reading fields
work.

The in->eof field is now always valid, instead of weirdly being reset to
false in random situations. The in->reading field now corresponds to
whether the demuxer thread is working at all, and is reset if it stops
doing anything.

Also, I always found it stupid that dequeue_packet() forced the demuxer
thread to retry reading if it was EOF. This makes little sense, but was
probably added for files that are being appended to (running downloads).
It makes no sense, because if the cache really tried to read until file
EOF, it would encounter partial packets and throw errors, so all is lost
anyway. Plus stream_file now handles this better. So stop this behavior,
but add a temporary option that enables the old behavior.

I think checking for ds->eager when enabling prefetching never really
made sense (could be debated, but no, not really). On the other hand,
the change above exposed a missing wakeup in the backward demuxing code.

Some chances of regressions that could make it stuck in certain states
or so, or incorrect demuxer cache state reporting to the player
frontend.
2020-02-27 22:30:46 +01:00
jnozsc 611c92ef1d *.py: cosmetic changes 2020-02-27 21:36:21 +01:00
wm4 c4440db744 sub: do not ignore demuxer wakeups
Setting demux_set_stream_wakeup_cb() will make all sh_stream (i.e.
track) specific wakeups go to this callback. But the callback takes care
of only the sub_preload() case (where it tries to pre-load subtitles
from already parsed and memory-present subtitles in a blocking way).

The old code assumed that the normal demuxer wakeup callback is called.
This was disregarded when the newer code was added. (And actually, the
original plan was to make _all_ per-sh_stream wakeups go to specialized
callbacks to avoid wasted work. dec_sub really should set the callback
always, and propagate wakeups to the playloop code. But it's too far
into the night to write coherent code.)

I couldn't actually observe any manifestation of this bug. Normally, the
playloop wakes up for other reasons (such as driving audio and video
decoding), so the lost wakeups rarely matter.
2020-02-27 02:33:51 +01:00
wm4 423323170b sub: fix typo in comment
Reading this commit and this commit message is a waste of time. I
guarantee it.
2020-02-27 02:24:43 +01:00
wm4 cf2b7a4997 sub, demux: improve behavior with negative subtitle delay/muxed subs
A negative subtitle delay means that subtitles from the future should be
shown earlier. With muxed subtitles, subtitle packets are demuxed along
with audio and video packets. But since they are demuxed "lazily",
nothing guarantees that subtitle packets from the future are available
in time.

Typically, the user-observed effect is that subtitles do not appear at
all (or too late) with large negative --sub-delay values, but that using
--cache might fix this.

Make this behave better. Automatically extend read-ahead to as much as
needed by the subtitles. It seems it's the easiest to pass the subtitle
render timestamp to the demuxer in order to guarantee that everything is
read. This timestamp based approach might be fragile, so disable it if
no negative sub-delay is used.

As far as the player frontend part is concerned, this makes use of the
code path for external subtitles, which are not lazily demuxed, and may
already trigger waiting.

Fixes: #7484
2020-02-27 02:23:58 +01:00
wm4 b873f1f8e5 demux: avoid some queue management corner cases with subtitles
Subtitle tracks are usually "lazy" (ds->eager=false), There are a number
of weird special cases associated with it. One of them is that they have
some sort of "temporary" EOF (to signal that there isn't a packet right
now, and the decoder should not block playback by waiting for more
packets). In a the next commit, I want to call mark_stream_eof() in case
of (some) of these temporary EOFs.

The problem is that mark_stream_eof() also calls the functions touched
by this commit. Basically they shouldn't do any complex work due to
these temporary EOFs (because they might happen very often). It turns
out that lazy tracks barely matter here: they do not extend the seek
range of a packet/EOF happens on them, they do not trigger seek range
joining, and they do not support backward demuxing.

This change should enable the following commit, while not causing any
behavior changes (i.e. bugs) with the current state.
2020-02-27 02:15:21 +01:00
wm4 c43fd88f59 scripting: fix racy crash if loading .run files fails
args->client was deallocated if the FDs were closed and nothing
referenced it (IPC socket codes detected the closed sockets and
asynchronously killed the mpv_handle in args->client). The problem was
that args->log depended on it, and was also destroyed.

Fix this by duplicating the mp_log.
2020-02-25 22:41:09 +01:00
linkmauve 322eb72679 OpenGL: Also detect softpipe as a software driver
Because it is.
2020-02-25 21:32:04 +02:00
wm4 c418aa3807 ipc: allow sending commands with named arguments
This has been part of the libmpv for a while, so the implementation in
the IPC code is quite simple: just pass the mpv_node representing the
value of the "command" field without further checks to
mpv_command_node().

The only problem are the IPC-specific commands, which essentially have
their own dispatch mechanism. They expect an array. I'm not going to
rewrite the dispatch mechanism, so these still work only with an array.
I decided make the other case explicit with cmd==NULL. (I could also
have set cmd=="", which would have avoided changing each if condition
since "" matches no existing command, but that felt dirty.)
2020-02-24 00:31:46 +01:00
wm4 67311af05f ipc: add more blabla that nobody reads 2020-02-24 00:16:10 +01:00
wm4 b05550fe55 ipc: implement asynchronous commands
I decided to make this explicit. The alternative would have been making
all commands asynchronous always, like a small note in the manpage
threatened. I think that could have caused compatibility issues.

As a design decision, this does not send a reply if an async command
started. This could be a good or bad idea, but in any case, it will make
async command look almost like synchronous ones, except they don't block
the IPC protocol.
2020-02-24 00:14:54 +01:00
wm4 a9e6b9ea36 client API: minor clarification when asynchronous commands send events 2020-02-24 00:09:51 +01:00
wm4 0ec036bfd8 ta: remove two pointless wrappers 2020-02-23 19:48:25 +01:00
wm4 758082a1f2 ta: minor simplification
Due to the ta_header.parent invariant, the "h->parent->child==h" check
is always true.
2020-02-23 19:45:25 +01:00
wm4 4839106a99 client API: fix race condition on client exit
The relatively recently added property update code has a race condition
when clients exit. It still tried to access mpv_handle during and after
it was destroyed.

The reason is that it unlocks the lock for the mpv_handle list (while
mpv_handle is locked), but nothing in mp_destroy_client() cares about
this case. The latter function locks mpv_handle only before/while it
makes sure all of its activity is coming to an end, such as asynchronous
requests, and property updates that are in progress. It did not include
the case when mp_client_send_property_changes() was still calling
send_client_property_changes() with mpv_handle locked.

Fix this by checking the mpv_handle.destroying field. This field can be
set only when mpv_handle is locked. While we're checking the lock, the
mpv_handle list is still locked, so at worst we might be at the point
before mp_destroy_client() locks the list again and finally destroys the
mpv_handle.

This is a hard to reproduce race condition which I spotted only once in
valgrind by chance, so the fix is unconfirmed.
2020-02-23 17:52:21 +01:00
wm4 bc3678da65 ta: change API; ta_set_parent() and ta_set_destructor() never fail
The previous change ensured that these cannot fail anymore (much like in
original talloc). Change the APIs to not return a success value anymore,
to "cement" this.
2020-02-23 17:45:05 +01:00
wm4 f6615f00ee ta: remove seperate internal "ext" header
The ta_ext_header was allocated on demand for allocations which have
child-allocations or destructors. In theory, it saved 2 words for every
TA leaf allocation. It had the very API-visible problem that setting a
parent or destructor could fail. (Although in most cases, the failure
was part of an allocation call anyway. Also, mpv code generally used the
early-failure variants, so it didn't matter.)

I think this was a bit too complex. These 2 words don't really matter;
if you have memory allocations where you are worried about overhead,
then these simply shouldn't use TA. Also, we never added new features to
TA that would have needed more "optional" header fields, which would
have justified the use of such a separately allocated header struct.

This uses quite straight-forward data structures. The only strange thing
is that ta_header.parent is NULL for most child allocations. That is
because we don't want to iterate over all children when the parent is
reallocated (yes, that is allowed, yes mpv makes use of it).

The new code has a few more special cases, because the list sentinel
concept isn't used anymore. Using it would have made the code more
unnatural/complex, because ta_ext_header doesn't exist anymore.
2020-02-23 17:36:27 +01:00
wm4 a9586625d1 ta: remove ta_find_parent()
Some mpv code once needed this, but it was removed in 2015.
2020-02-23 14:32:15 +01:00
sfan5 57ecfb4da2 ytdl_hook: fix URL extraction for manifests 2020-02-23 12:04:55 +01:00
der richter ee6ad403a7 cocoa-cb: fix crash with some japanese characters
the actual character that made mpv crash is IDEOGRAPHIC COMMA
(U+3001, UTF-8: E3 80 81, 、) and that only in some specific
circumstances that could be reliably reproduced on my end.

using an NSString instead of the Swift String actually fixes that issues
even though they should technically do the exact same thing. i tested
all the other String initialisers, but they all had had the same issue.
this is kinda only a workaround till i can find a different way of
handling it.
2020-02-22 14:21:06 +01:00
der richter 327b092bfc mac, cocoa: fix UI updates on none main queue threads
injecting the Apple Main Thread Checker via
DYLD_INSERT_LIBRARIES=libMainThreadChecker.dylib identified several
problems that needed fixing.
2020-02-22 13:56:31 +01:00
der richter 8e1ceaba34 cocoa-cb: remove unnecessary semicolons 2020-02-22 13:56:31 +01:00
der richter b8f2811f8d mac: fix media key support for libmpv users
this basically moves the remote command center to our mac events instead
of keeping it our Application, which is only available when started from
mpv itself. also make it independent of the NSApplication.

this also prevents a runtime crash
2020-02-22 13:56:31 +01:00
wm4 c1d744328e x11: switch back to StaticGravity
This was changed 6 years ago (444e583b6) and seemed to work fine. But it
does seem to cause issues with IceWM sometimes, while with StaticGravity
the problem is gone. Comparing both gravity values, reading the confused
source code comment, and reading the referenced commit message, I can't
determine what it even does, I just remove it.

Reproduction:
- start mpv in windowed mode, with 2 videos of different size
- switch to second video
- switch window with alt+tab
- switch back to mpv with alt+tab
- window moves to X=0

There's probably a better way to fix this. Please send a patch.
2020-02-22 01:35:12 +01:00
wm4 c68b813678 ytdl_hook: prefer "format" over "format_note" field for track titles
Much more verbose, but on the other hand format_note is useless for the
alphabetic site with fragmented DASH streams.
2020-02-21 22:23:17 +01:00
wm4 dc82921012 ytdl_hook: use "format" as fallback for "format_note" for stream titles
"format_note" normally contains a semi-informative description of the
format. But some extractors, confusingly, have it in the "format" field.
2020-02-21 16:38:17 +01:00
wm4 2b9b77fcf3 ytdl_hook: fix audio codec with some extractors
E.g. soundcloud. While it still worked, not having the audio codec was
pretty annoying.
2020-02-21 16:27:56 +01:00
wm4 c1f7b0c535 ytdl_hook: fix Lua escapes
This was obviously nonsense. In Lua 5.1 this appeared to work correctly,
but it really turned "\." into "." (making the pattern accept any
character). The proper way is using "%" for escaping.
2020-02-21 16:23:43 +01:00
wm4 605e1fb766 ytdl_hook, edl: add fps, samplerate codec parameters
Well, didn't help much in the case I was interested it.
2020-02-21 14:48:23 +01:00
wm4 2eab35fdf7 manpage: directly link interface-changes.rst in changelog section 2020-02-21 14:34:02 +01:00
wm4 6337c1cc14 ytdl_hook: make codec mapping more declarative 2020-02-21 14:29:55 +01:00
wm4 04118eefb8 ytdl_hook: remove some old playlist redirection hack
Should not be needed anymore. In fact, it's probably dangerous.
2020-02-21 14:19:01 +01:00
wm4 4c32468241 ytdl_hook: enable default selection via --ytdl-format with all_formats
In all_formats mode, we've ignored what --ytdl-format did so far, since
we've converted the full format list, instead of just the formats
selected by youtube-dl.

But we can easily restore --ytdl-format behavior: just mark the selected
tracks as default tracks.
2020-02-21 14:18:35 +01:00
wm4 a77780e6be edl: make it possible to set the track "default" flag
Also, the forced flag (and in the future, potentially a number of other
flags not implemented yet). See next commit for purpose.
2020-02-21 14:16:26 +01:00
wm4 1cda73356d manpage: fix some path description details 2020-02-21 12:13:54 +01:00
wm4 1edb57159f manpage: suggest using PuTTY for accessing mpv IPC named pipes on win32 2020-02-21 12:09:16 +01:00
wm4 daa3c11e1b ytdl_hook: add length parameter to delay-loaded tracks only once
This was done for each media type, so muxed tracks had it twice, which
logged a dumb warning. Move it out of the per-media type loop.
2020-02-21 12:06:18 +01:00
wm4 9f5b9011d6 demux_edl: correct warning on duplicate parameters
A parameter that is actually used is removed from the param_names[]
array, so we can report unused parameters. This also happened on
duplicate parameters, so adjust the warning to make it less confusing.

(In any case, you're not supposed to provide duplicate parameters.)
2020-02-21 12:05:29 +01:00
wm4 3d225ad275 ytdl_hook: remove bitrate estimation from file size
I think this is unnecessary, and at worst done by youtube-dl itself
(didn't check).
2020-02-21 11:57:57 +01:00
wm4 76aaf74d30 ytdl_hook: use tbr for all tracks if vbr/abr not available
vbr and abr are the video and audio bitrates. Sometimes there is a weird
mix of any of them available, but in these cases, it's not good to fall
back to tbr if a specific track has no vbr/abr.

For example, the alphabetic site provides tbr only for the muxed
fallback stream, but using tbr would make the primitive mpv hls_bitrate
selection pick the compatibility stream for audio, because it appears to
have a higher bitrate than the other audio-only streams (because the
bitrate includes video). So we must not use tbr in this case.

On the other hand, formats coming from youtube-dl HLS master playlist
use will only have tbr set.

So as a heuristic, use the tbr only if it's the only bitrate available
in any track entry.
2020-02-21 11:57:21 +01:00
wm4 6d09a042e6 ytdl_hook: replace skip_muxed with force_all_formats option
I don't think the skip_muxed option was overlay useful. While it was
nice to filter out the low quality muxed versions (as it happens on the
alphabetic site, I suspect it's compatibility stuff), it's not really
necessary, and just makes for another tricky and rarely used
configuration option. (This was different before muxed tracks were also
delay-loaded, and including the muxed versions slowed down loading.)

Add the force_all_formats option instead, which handles the HLS case.
Set it to true because they are also delay-loaded now, and don't slow
down startup as much.
2020-02-21 11:50:58 +01:00
wm4 fbbfbfc772 manpage: reorganize ytdl_hook option descriptions
Make it a proper list, instead of a paragraph soup.
2020-02-21 00:30:41 +01:00
wm4 390e995b6a ytdl_hook: delay-load interleaved files
(Or if it's about HLS, just "muxed"/multiplexed streams.)

This only affects all_formats=yes,skip_muxed=no modes.
2020-02-21 00:20:22 +01:00
wm4 6f0297dff4 edl: make it possible to delay-load files with multiple tracks
Until now, delay-loading was for files with single tracks only
(basically what DASH and HLS like to expose, so adaptive streaming and
codec selection becomes easier - for sites, not for us). But they also
provide some interleaved versions, probably for compatibility. Until
now, we were forced to eagerly load it (making startup slightly slower).

But there is not much missing. We just need a way to provide multiple
metadata entries, and use them to represent each track.

A side effect is now that the "track_meta" header can be used for normal
EDL files too.
2020-02-21 00:19:17 +01:00
wm4 6726b7a1ba demux_lavf: signal no seeking for RTSP streams without duration
RTSP supports seeking, but at least the libavformat implementation makes
this dependent on runtime behavior. So you have to perform a seek, and
check if it fails. But even if you do this, the stream is interrupted
and restarted, and there seem to be other issues.

Assume that RTSP with unknown duration means it's a live stream, and
disable seeking in this case, as suggested by the issue reporter.

Fixes: #7472
2020-02-20 15:28:49 +01:00
wm4 bd6d8d320f demux_timeline: don't open every delayed-open track on seeking
Now this was stupid. To seek a source, it obviously has to be opened...
so just don't try to seek any unused source. If the track is actually
selected during playback, a seek to the correct position is performed
anyway.
2020-02-20 15:21:27 +01:00
wm4 0020b47ffd demux: fix seek range caching with delay_open hack
These have ->segmented set (so the codec can be initialized properly),
but have no segment start or end times. This code was (probably) the
only thing which didn't handle this case.
2020-02-20 15:11:46 +01:00
wm4 f321d8da99 ytdl_hook: signal duration in all_formats mode
If all streams were delay loaded, there was actually no duration present
at all in the EDL metadata. So the length was considered unknown by the
player frontend.
2020-02-20 14:55:14 +01:00
wm4 89203cc994 ytdl_hook: attempt to filter out muxed streams if all_formats is used
See manpage additions. We would have to extend delay_open to support
multiple sub-tracks (for audio and video), and we'd still don't know (?)
whether it might contain more than one stream each (thinking of HLS
master streams). And if it's a true interleaved file (such as a "normal"
mp4 file provided as fallback for more primitive players), we'd either
have to signal such "bundled" tracks, or waste bandwidth.

This restructures a lot. The if/else tree in add_single_video for format
selection was a bit annoying, so it's split into separate if blocks,
where it checks each time whether a URL was determined yet.
2020-02-20 14:54:09 +01:00
wm4 c2e62817f6 ytdl_hook: remove forgotten debug message
It even has a typo.
2020-02-20 14:40:01 +01:00
wm4 af9403577a ytdl_hook: use bitrate fields for bitrate metadata instead of file sizes
If available.
2020-02-20 12:34:06 +01:00
wm4 f5c1d71639 ytdl_hook: try to skip interleaved streams with all_formats
If a "format" has both audio and video codec set, it might contain both
audio and video. all_format assumes that each format is just a quality
variant containing a single track.

This seems to happen with sites that provide a HLS master URL.
youtube-dl tends to "butcher" it, and the result isn't very ideal. I
guess HLS "renditions" simply don't map well to youtube-dl's output
format and what mpv expects. Playing master HLS directly is also less
than ideal, because of libavformat's stupid probing.

Fix this by not using the delay-opening mechanism if it appears like we
detected such a case. Add a metadata override to set the track titles to
"muxed-N", to indicate that they form a single unit. (Mostly helpful for
testing.)
2020-02-20 12:25:45 +01:00
wm4 eaa10a25c7 ytdl_hook: iterate format list by array order
Shouldn't have any consequences. Probably makes the user-visible order
more stable.
2020-02-20 12:17:59 +01:00
wm4 e64645540a demux_timeline: warn if streams are invisible
ytdl_hook.lua can do this with all_formats and when delay_open is used,
and if the source stream actually contains both audio and video. In this
case, it might accidentally hide a media type completely, or waste
bandwidth (if the stream has true interleaved audio/video). So it's
important to warn.
2020-02-20 12:16:32 +01:00
wm4 4e11ac82aa player: change bitrate in track listing back to kilobits
Because the --hls-bitrate option takes the same unit.
2020-02-20 12:13:32 +01:00
wm4 3db8715f70 manpage: minor fixes
In particular, all_formats description split away the example section of
an unrelated option, so move that to its proper place.
2020-02-19 23:11:02 +01:00
wm4 e2ab6b7f35 scripting: add a way to run sub processes as "scripts"
This is just a more convenient way to start IPC client scripts per mpv
instance.

Does not work on Windows, although it could if the subprocess and IPC
parts are implemented (and I guess .exe/.bat suffixes are required).
Also untested whether it builds on Windows. A lot of other things are
untested too, so don't complain.
2020-02-19 22:18:15 +01:00
wm4 d06ebe2251 client API: document requirement about PID management
Basically, UNIX sucks. (Not as much as the other POS of course.)
2020-02-19 22:16:26 +01:00
wm4 e22b771ff8 build: remove fchmod() check
This is UNIX-only code, and this function has been in POSIX since
forever. Even Android has it. The test should be unnecessary, so remove
it.
2020-02-19 20:38:12 +01:00
wm4 6d8b4ca742 ytdl_hook: add all_formats option
Pretty worthless I guess. I only tested one site (and 2 videos), it's
somewhat likely that it will break with other sites. Even if you leave
the option disabled (the default).

Slightly related to #3548. This will allows you to use the bitrate
stream selection mechanism, that was added for HLS, with normal videos.
2020-02-19 16:33:48 +01:00
wm4 43c13e5ea2 ytdl_hook: add a way to not pass --format to the command line
Might be helpful for... whatever.
2020-02-19 16:31:04 +01:00
wm4 b8f80b3854 player: print manifest per-stream bitrate information to terminal
Aka hls-bitrate. In turn, remove the demux_lavf.c hack, which made the
track title use this.
2020-02-19 16:26:22 +01:00
wm4 2567997ecf input: log commands with parameter names 2020-02-19 16:25:18 +01:00
wm4 a4d95fe98b audio: remove outdated comment
Neither does it (directly) mess with filters, nor does it return a bool.

As noticed by a comment in #6333.
2020-02-19 14:50:54 +01:00
xPMo 238acbad84 manpage: deprecated options in examples
example config and default term-status-msg
2020-02-19 14:37:14 +01:00
wm4 0df0a847f4 video: drop NV24 alias
Caused build failures with still supported FFmpeg versions. It's
unreferenced, so it's not needed.

Fixes: #7471
2020-02-18 18:03:42 +01:00
wm4 36ca0e0030 options: remove deprecation warning for "-foo bar" syntax
It's still deprecated, but I guess users who preferred typing a space
instead of a '=' can use it.
2020-02-17 00:31:19 +01:00
wm4 fbc226af51 demux: cosmetic change
This was sort of asymmetric and annoying.
2020-02-17 00:04:56 +01:00
wm4 26ec5862b3 demux: update file-size property even when paused
While paused, the decoders typically stop reading data from the demuxer.
But for some reason, the file size is returned as a public field in
struct demuxer (wat...), and updated only when the packet reading
function is called. This caused the file size property to always return
the same value when paused, even though the demuxer thread was reading
new data, and the internal file size was updated.

Fix with a simple hack.
2020-02-16 23:59:21 +01:00
wm4 aafc434f00 stream_file: remove file size caching
With the last 3 commits, this caching should be completely unnecessary.
2020-02-16 23:51:21 +01:00
wm4 1a54339705 demux: only query stream size at most once per second
Instead of every packet. Doing it every packet led to the performance
regression mentioned in the fstat() commit. This should now be over, but
out of being careful, don't query the file size that often. This is only
used for user interface things, so this should not cause any problems.

For the sake of leaving the code compact, abuse another thing that is
updated only every second (speed statistics).
2020-02-16 23:49:42 +01:00
wm4 27bf978e75 demux: invert update_cache() locking
Equivalent, just slightly more convenient for the following change.
2020-02-16 23:43:13 +01:00
wm4 20eead1813 stream_file: use fstat() instead of lseek() to determine file size
It appears using lseek() to seek to the end and back to determine file
size is inefficient in some cases.

With CIFS, this restores the performance regression that happened when
the stream cache was removed (which called read() from a thread). This
is probably faster than the old code too, because it's the seeking that
was slowing down CIFS.

According to the user who tested this, the size caching does not help
with fstat() (although it did with the old method).

Fixes: #7408, #7152
2020-02-16 23:36:05 +01:00
wm4 249bb091d4 manpage: improve command_native_async description 2020-02-16 23:03:14 +01:00
wm4 f2c7c641b3 subprocess: implement proper detached processes on POSIX
The previous method for this sucked: for every launched detached
process, it started a thread, which then would leak if the launched
process didn't end before the player uninitialized. This was very racy
(although I bet the race condition wouldn't trigger in a 100 years), and
wasteful (threads aren't a cheap resource).

Implement it for POSIX directly. posix_spawn() has no direct support for
this, so we need to do it ourselves with fork(). We could probably do it
without fork(), and attempt to collect the PID in another thread. But
then we'd either have a waiting thread again, or we'd need to do an
unsafe waitpid(-1, ...) call. (POSIX process management sucks so badly,
how did they even manage this. Hopefully I'm just missing something, but
I'm not.) So now we depend on both posix_spawn() _and_ fork(), isn't it
fun?

Also call setsid(), to essentially detach the child process from the
terminal. (Otherwise it can receive various signals from the terminal,
which is probably not what you want.) posix_spawn() adds
POSIX_SPAWN_SETSID in newer POSIX releases, but we don't want to rely on
this yet.

The posix_spawnp() call is duplicated, but this is better than somehow
trying to unify the code paths.

Only somewhat tested, so enjoy the bugs.
2020-02-16 22:08:48 +01:00
wm4 92fee4ebc4 subprocess: change to a fancier API
Introduce mp_subprocess() and related definitions. This is a bit more
flexible than the old stuff. This may or may not be used for a more
complicated feature that involves starting processes, and which would
require more control.

Only port subprocess-posix.c to this API. The player still uses the
"old" API, so for win32 and dummy implementations, the new API is simply
not available, while for POSIX, the old APIs are emulated on top of the
new one. I'm hoping the win32 code can be ported as well, so the ifdefs
in subprocess.c can be dropped, and the player can (if convenient or
needed) use the new API.
2020-02-16 21:27:34 +01:00
wm4 a4b12c54b6 f_lavfi: don't propagate filter failure if creation fails
Filters that fail to create are not supposed to do this. Generally it
should happen in process() only.

This fixes the previous commit. If a filter could not be created, it
"trashed" the wrapper filter with the failure. (Even if the wrapper were
to handle were to handle failures of sub-filter, it couldn't handle init
failure because it cannot call mp_filter_set_error_handler() before the
newly created filter is actually returned.)

Fixes: #7465 (attempt 2)
2020-02-16 16:21:03 +01:00
wm4 a19d918816 f_auto_filters: always fall back to hw-download+yadif if no hw deint filter
If hw decoding is used, but no hw deinterlacer is available, even though
we expect that it is present, fall back to using hw-download and yadif
anyway. Until now, it was over if the hw filter was somehow missing; for
example, yadif_cuda apparently requires a full Cuda SDK, so it can be
missing, even if nvdec is available. (Whether this particular case works
was not tested with this commit.)

Fixes: #7465
2020-02-16 15:28:57 +01:00
wm4 7d11eda72e Remove remains of Libav compatibility
Libav seems rather dead: no release for 2 years, no new git commits in
master for almost a year (with one exception ~6 months ago). From what I
can tell, some developers resigned themselves to the horrifying idea to
post patches to ffmpeg-devel instead, while the rest of the developers
went on to greener pastures.

Libav was a better project than FFmpeg. Unfortunately, FFmpeg won,
because it managed to keep the name and website. Libav was pushed more
and more into obscurity: while there was initially a big push for Libav,
FFmpeg just remained "in place" and visible for most people. FFmpeg was
slowly draining all manpower and energy from Libav. A big part of this
was that FFmpeg stole code from Libav (regular merges of the entire
Libav git tree), making it some sort of Frankenstein mirror of Libav,
think decaying zombie with additional legs ("features") nailed to it.
"Stealing" surely is the wrong word; I'm just aping the language that
some of the FFmpeg members used to use. All that is in the past now, I'm
probably the only person left who is annoyed by this, and with this
commit I'm putting this decade long problem finally to an end. I just
thought I'd express my annoyance about this fucking shitshow one last
time.

The most intrusive change in this commit is the resample filter, which
originally used libavresample. Since the FFmpeg developer refused to
enable libavresample by default for drama reasons, and the API was
slightly different, so the filter used some big preprocessor mess to
make it compatible to libswresample. All that falls away now. The
simplification to the build system is also significant.
2020-02-16 15:14:55 +01:00
wm4 a4eb8f75c0 sub: add an option to filter subtitles by regex
Works as ad-filter. I had some more plans, for example replacing
matching text with different text, but for now it's dropping matches
only. There's a big warning in the manpage that I might change
semantics. For example, I might turn it into a primitive sed.

In a sane world, you'd probably write a simple script that processes
downloaded subtitles before giving them to mpv, and avoid all this
complexity. But we don't live in a sane world, and the sooner you learn
this, the happier you will be. (But I also want to run this on muxed
subtitles.)

This is pretty straightforward. We use POSIX regexes, which are readily
available without additional pain or dependencies. This also means it's
(apparently) not available on win32 (MinGW). The regex list is because I
hate big monolithic regexes, and this makes it slightly better.

Very superficially tested.
2020-02-16 02:07:24 +01:00
wm4 0b35b4c917 sub: make filter_sdh a "proper" filter, allow runtime changes
Until now, filter_sdh was simply a function that was called by sd_ass
directly (if enabled).

I want to add another filter, so it's time to turn this into a somewhat
more general subtitle filtering infrastructure.

I pondered whether to reuse the audio/video filtering stuff - but better
not. Also, since subtitles are horrible and tend to refuse proper
abstraction, it's still messed into sd_ass, instead of working on the
dec_sub.c level. Actually mpv used to have subtitle "filters" and even
made subtitle converters part of it, but it was fairly horrible, so
don't do that again.

In addition, make runtime changes possible. Since this was supposed to
be a quick hack, I just decided to put all subtitle filter options into
a separate option group (=> simpler change notification), to manually
push the change through the playloop (like it was sort of before for OSD
options), and to recreate the sub filter chain completely in every
change. Should be good enough.

One strangeness is that due to prefetching and such, most subtitle
packets (or those some time ahead) are actually done filtering when we
change, so the user still needs to manually seek to actually refresh
everything. And since subtitle data is usually cached in ASS_Track (for
other terrible but user-friendly reasons), we also must clear the
subtitle data, but of course only on seek, since otherwise all subtitles
would just disappear. What a fucking mess, but such is life. We could
trigger a "refresh seek" to make this more automatic, but I don't feel
like it currently.

This is slightly inefficient (lots of allocations and copying), but I
decided that it doesn't matter. Could matter slightly for crazy ASS
subtitles that render with thousands of events.

Not very well tested. Still seems to work, but I didn't have many test
cases.
2020-02-16 02:07:24 +01:00
Thomas Carmichael e162bcb5a0 TOOLS/lua/autoload.lua: update script comments
The example configuration uses values of true/false for the script
options. As per DOCS/man/lua.rst boolean values should be represented
with yes/no and using true/false will result in an error.

This updates the comments and changes the true/false values under the
example configuration to yes/no.
2020-02-15 20:41:07 +01:00
wm4 2160306b31 manpage: fix a case of broken indentation
This renders incorrectly in the html output. I suspect you need one more
level here. Increase the indentation level. No other changes, other than
re-breaking some lines.
2020-02-15 20:01:20 +01:00
wm4 29e15e6248 ytdl_hook.lua: delay load subtitles
Uses the infrastructure added in the previous commits. This is
admittedly a bit weird (constructing EDL URLs and such). But on the
other hand, adding this as "first class" mechanism directly to the
sub-add command or so would increase weirdness and unexpected behavior
in other places, or at least that's what I think.

To reduce confusion, this goes through the effort of mapping the webvtt
codec, so it's shown "properly" in the codec list. Without this it would
show "null", but still work. In particular, any non-webvtt codecs should
still work if libavcodec supports it.

Not sure if I should remove the --all-subs hack from the code. But I
guess it does no harm.
2020-02-15 18:30:42 +01:00
wm4 e54ebaec52 f_decoder_wrapper, sd_add: accept "null" codec
This is for easier use with the "delay_open" feature added in the
previous commit. The "null" codec is reported if the codec is unknown
(because the stream was not opened yet at time the tracks were added).
The rest of the timeline mechanism will set the correct codec at
runtime. But this means every time a delay-loaded track is selected, it
wants to initialize a decoder for the "null" codec.

Accept a "null" decoder. But since FFmpeg has no such codec, and out of
my own laziness, just let it fall back to "common" codecs that need no
other initialization data.
2020-02-15 18:30:42 +01:00
wm4 c92c08edc6 edl: add mechanism for delay loading streams
Add something that will access an URL embedded in EDL only when the
track it corresponds to is actually selected. This is meant to help with
ytdl_hook.lua and to improve loading speeds.

In theory, all this stuff is available to any mpv user, but discourage
using it, as it's so specialized towards ytdl_hook.lua, that there's
danger we'll just break this once ytdl_hook.lua stops using it, or
similar.

Mostly untested.
2020-02-15 18:29:44 +01:00
wm4 1d53a8f2e7 demux_edl: warn if no_clip is used with multiple parts
Well whatever.
2020-02-15 15:25:12 +01:00
wm4 921f316281 demux_edl: allow a redundant new_stream at the beginning
Normally, the first sub-stream is implicitly created. This change lets
the user use more orthogonal syntax, and use a new_stream header for
every sub-stream, instead of having to skip the header for the first
one.
2020-02-15 15:22:05 +01:00
wm4 64c4c59770 demux_edl: accept protocol entries in EDL entries again
Accidentally broken by commit 99700bc52c. mp_path_join() does not
check for this, because it's supposed to work on filesystem strings (and
e.g. "http://fubar" is a valid relative path in UNIX).
2020-02-15 15:11:05 +01:00
wm4 96ef62161a demux_edl: improve parsing slightly
Add a mp_log context to the parse_edl() function, and report some
errors. Previously, this just told you that something was wrong. Add
some error reporting to make it slightly less evil.

Put all parameters in a list before processing them. This makes adding
parameters for special headers easier, and we can report parameters that
were not understood. (For "compatibility", which probably doesn't matter
at all, still don't count them as errors; as before.)
2020-02-15 15:07:52 +01:00
wm4 121bc6ad62 demux_timeline: fix another cursed memory management issue
The timeline stuff has messed up memory management because there are no
clear ownership rules between a some demuxer instances (master or
demux_timeline) and the timeline object itself.

This is another subtle problem that happened: apparently,
demux_timeline.open is supposed to take over ownership of timeline, but
only on success. If it fails, it's not supposed to free it. It didn't
follow this, which lead to a double-free if demux_timeline.open failed.
The failure path in demux.c calls both timeline_destroy() and
demux_timeline.close on failure.
2020-02-15 14:07:46 +01:00
wm4 64a03b03ea demux_timeline: fix a comment 2020-02-15 13:55:54 +01:00
wm4 d5de8ddb65 demux_timeline: reorder some functions
Move them around in the source code to get rid of the forward
declarations. Other than rearranging the lines and removing the 2
forward declarations, there are no other changes at all.
2020-02-15 13:55:37 +01:00
wm4 641d102101 msg: slightly improve --msg-time output
Cut the arbitrary offset, and document what unit/timesource it uses.
2020-02-14 16:12:37 +01:00
wm4 5793cb40c8 stream: early-out in stream_seek_skip() if nothing is skipped
stream_seek() might somewhat show up in the profiler, even if it's a
no-OP, because of the MP_TRACE() call. I find this annoying. Otherwise,
this should be of no consequence, and should not break or improve
anything.
2020-02-14 16:08:54 +01:00
wm4 c59ca06a0f stream_file: cache file size
Some cache logic in demux.c queries the raw byte stream size on every
packet read. This is because it reports the value to the user. (It has
to be polled like this because there is no change notification in most
underlying I/O APIs, and also the user can't just block on the demuxer
thread to update it explicitly.)

This causes a very high number of get_size calls with low packet sizes,
so cache the size, and update it on every read. Reads only happen
approximately all 64KB read with default settings, which is way less
frequent than every packet in such extreme cases.

In theory, this could in theory cause problems in some cases. Actually
this is whole commit complete non-sense, because why micro-optimize for
broken cases like patent troll codecs. I don't need to justify it
anyway.

As a minor detail, off_t is actually specified as signed, so the off_t
cast is never needed.
2020-02-14 16:07:13 +01:00
wm4 777c046b35 manpage: clarify --player-operation-mode
options.rst to clarify the option, some more text in mpv.rst to separate
out the compatibility stuff a little.

Fixes: #7461 (options.rst change only)
2020-02-14 12:58:45 +01:00
Dudemanguy 83efdb5a01 wayland: make resizing better
Resizing the window while preserving the aspect ratio actually kind of
sucked. The window size could make big dramatic changes which was pretty
unintuitive with respect to where the mouse was actually located.
Instead, let's just do some math to ensure that the window size is
always contained inside the width/height reported by
handle_toplevel_config while preserving the aspect ratio. Fixes #7426.
2020-02-13 20:28:59 +00:00
wm4 cc52a03401 audio: slightly simplify pull underrun message printing
A previous commit moved the underrun reporting to report_underruns(),
and called it from get_space(). One reason was that I worried about
printing a log message from a "realtime" callback, so I tried to move it
out of the way. (Though there's little justification other than a bad
feeling. While an older version of the pull code tried to avoid any
mutexes at all in the callback to accommodate "requirements" from APIs
like jackaudio, we gave up on that. Nobody has complained yet.)

Simplify this and move underrun reporting back to the callback. But
instead of printing the message from there, move the message into the
playloop. Change the message slightly, because ao->log is inaccessible,
and without the log prefix (e.g. "[ao/alsa]"), some context is missing.
2020-02-13 18:02:16 +01:00
Dudemanguy 374c6aff7b wayland: fix autofit and rotating issues
Fixes #7441. Just set screenrc to be equal to current_output's geometry.
Also remove some pointless/extra variables and print a warning/fallback
to screen 0 if a bad id is passed to --fs-screen.
2020-02-13 16:01:59 +00:00
wm4 5bf433b16f player: consider audio buffer if AO driver does not report underruns
AOs can report audio underruns, but only ao_alsa and ao_sdl (???)
currently do so. If the AO was marked as not reporting it, the cache
state was used to determine whether playback was interrupted due to slow
input.

This caused problems in some cases, such as video with very low video
frame rate: when a new frame is displayed, a new frame has to be
decoded, and since there it's so much further into the file (long frame
durations), the cache gets into an underrun state for a short moment,
even though both audio and video are playing fine. Enlarging the audio
buffer didn't help.

Fix this by making all AOs report underruns. If the AO driver does not
report underruns, fall back to using the buffer state.

pull.c behavior is slightly changed. Pull AOs are normally intended to
be used by pseudo-realtime audio APIs that fetch an audio buffer from
the API user via callback. I think it makes no sense to consider a
buffer underflow not an underrun in any situation, since we return
silence to the reader. (OK, maybe the reader could check the return
value? But let's not go there as long as there's no implementation.)
Remove the flag from ao_sdl.c, since it just worked via the generic
mechanism. Make the redundant underrun message verbose only.

push.c seems to log a redundant underflow message when resuming (because
somehow ao_play_data() is called when there's still no new data in the
buffer). But since ao_alsa does its own underrun reporting, and I only
use ao_alsa, I don't really care.

Also in all my tests, there seemed to be a rather high delay until the
underflow was logged (with audio only). I have no idea why this happened
and didn't try to debug this, but there's probably something wrong
somewhere.

This commit may cause random regressions.

See: #7440
2020-02-13 01:32:58 +01:00
wm4 f3c498c7f1 ao: avoid unnecessary wakeups
If ao_add_events() is used, but all events flags are already set, then
we don't need to wakeup the core again.

Also, make the underrun message "exact" by avoiding the race condition
mentioned in the comment.

Avoiding redundant wakeups is not really worth the trouble, and it's
actually just a bonus in the change making the ao_underrun_event()
function return whether a new underrun was set, which is needed by the
following commit.
2020-02-13 01:28:14 +01:00
wm4 7e6ea02183 zimg: fix previous odd sizes commit
Obviously, we don't want to lose fractions, and the zimg active_region
fields in fact have the type double. The integer division was wrong.

Also, always set active_region.width/height. It appears zimg behavior
does not change if they're set to the normal integer values, so the
extra check to not set them in this case was worthless.
2020-02-13 01:26:51 +01:00
wm4 ffd89f5ff4 manpage: fix typo on sub-end
Fixes: #7455
2020-02-12 19:13:05 +01:00
wm4 c3f93f5fdd sws_utils: use zimg by default if available
This seems stable enough to use. Change the default, and remove it from
the sw-fast profile.
2020-02-12 18:06:53 +01:00
wm4 7c8b40c38a zimg: correct output to odd (chroma un-aligned) sizes
As suggested by the zimg author: active_region is not supported on
outputs (and the API returns an error), so instead scale to the "full"
surface, but adjust the source rectangle such that the cropped output
image happens to cover the correct region.

Does this even work? Since Balmer Peak doesn't work, I can't really say,
but it seems to look correct.
2020-02-12 18:01:22 +01:00
wm4 0848f3f832 zimg: fix typos in a comment
Also remove the "o" case, which was never implemented (probably was an
idea to output alpha formats, now obsoleted by zimg's full alpha
support).
2020-02-12 17:54:35 +01:00
wm4 5a45a4ca39 vo_drm, wo_wlshm: mention that it's software scaling
(But does anyone even read --vo=help output?)
2020-02-11 21:45:16 +01:00
wm4 2337e2861f vo_x11: don't call X11 "crap"
X11 is in fact beautiful and superior to Wayland. Instead, just state
what the problem is in most cases: software scaling. (We have
accelerated X11 rendering in vo_gpu and others.)
2020-02-11 21:43:53 +01:00
wm4 8c2179becf zimg: add pal8 unpacker
Some pngs are paletted, so this is vaguely interesting.
2020-02-10 19:01:21 +01:00
wm4 d699893dbd img_format: add alias for ffmpeg pal8 format
For the next commit.
2020-02-10 18:59:59 +01:00
wm4 a8404ed0a0 manpage: add some blabla about zimg speed vs. libswscale
Of course nobody will read this. I'm just putting it there so I can
blame users, who run into problems, for not having read it.
2020-02-10 18:59:34 +01:00
wm4 83f070dfb8 zimg: rename zplanes field
This was a confusing name, because 1. there's also a z_planes[] field,
and 2. it was not specific to zimg indexes.

Possibly there used to be an idea involved about supporting alpha to
non-alpha formats by discarding the alpha plane, but zimg does this now
(and zimg will correctly blend the alpha component too).
2020-02-10 17:59:13 +01:00
wm4 a9116ddd38 zimg: support gray/alpha conversion
The special thing about this format is

1. mpv assigns the component ID 4 to alpha, and component IDs 2 and 3
   are not present, which causes some messy details.
2. zimg always wants the alpha plane as plane 3, and plane 1 and 2 are
   not present, while FFmpeg/mpv put the alpha plane as plane 1.

In theory, 2. could be avoided, since FFmpeg actually doesn't have a any
2 plane formats (alpha is either packed, or plane 3). But having to skip
"empty" planes would break expectations.

zplanes is not equivalent to the mpv plane count (actually it was always
used this way), while zimg does not really have a plane count, but does,
in this case, only use plane 0 and 3, while 2 and 3 are unused and
unset. z_planes[] (not zplanes) is now always valid for all 4 array
entries (because it uses zimg indexes), but a -1 entry means it's an
unused plane.

I wonder if these conventions taken by mpv/zimg are not just causing
extra work. Maybe component IDs should just be indexes by the "natural"
order (e.g. R-G-B-A, Y-U-V-A, Y-A), and alpha should be represented as a
field that specifies the component ID for it, or just strictly assume
that 2/4 component formats always use the last component for alpha.
2020-02-10 17:57:01 +01:00
wm4 c31661466b zimg: fix some confusion about plane permutation
We reorder the planes between mpv and zimg conventions. It turns out the
code still confused when which convention was used.

So the way it actually works is that the _only_ place where zimg order
is used is the zimg_image_buffer.plane[] array. plane_aligned[] and
zmask[] were accessed incorrectly, although I guess it rarely had a
reason to fail (plane reordering is mostly for RGB, which has planes of
all the same size).

Adjust some comments accordingly too.
2020-02-10 17:45:20 +01:00
wm4 a841fe9484 img_format: add gray/alpha planar formats
The zimg wrapper "needs" these formats as intermediary when repacking
the normal gray/alpha packed format. The packed format is used by the
png decoder and encoder, and is thus interesting.

Unfortunately, mpv-only formats are a mess right now, because all the
existing code is focused around using the FFmpeg metadata for pixel
formats. This should be improved, but not now, so make the mess worse.

This commit doesn't add support for it to the zimg wrapper yet.
2020-02-10 17:38:54 +01:00
wm4 cca02e51ef zimg: add alpha support
libzimg recently added direct alpha support and new API for it. (The API
change is rather minimal, and it turns out we can easily support old and
new zimg versions.)

This does not support _all_ alpha formats. For example, gray + alpha is
not supported yet, because my stupid design in the zimg wrapper would
require a planar gray + alpha format, while ffmpeg provides only a
packed one.
2020-02-09 19:16:54 +01:00
wm4 c9963c1368 vo: fix typo in comment 2020-02-09 18:32:28 +01:00
wm4 ee4a8f0d57 vf_format: add w, h parameters
Yes, this thing became vf_scale through the back door.
2020-02-09 18:23:22 +01:00
Dan Oscarsson eb1d50ba20 sub: enhance SDH filtering
It is not uncommon with a speaker label with [xxxx] inside.
They should also be filtered out.
2020-02-09 16:18:34 +01:00
der richter a8553578eb github: fix a typo in the contact links info 2020-02-09 13:25:29 +01:00
der richter c3298ad416 github: ask users to first reproduce the issue with --no-config 2020-02-09 13:25:29 +01:00
der richter 1881698543 mac: always include the macOS config when cocoa is available
the macOS config was only used in cocoa-cb before and only included when
it was available. since this config is meant for general macOS options
and backend independent options we include it when cocoa is available.
one of the options is already used in the old cocoa backend, which broke
using it when build without swift or cocoa-cb support.

Fixes #7449
2020-02-09 11:45:55 +01:00
Philip Langdale 6799f8e0e9 bash completion: complete ao/af/vo/vf options
I didn't handle these originally, but it turns out that they can be
handled with the samel logic as Choice options.
2020-02-08 09:50:58 -08:00
Philip Langdale 8676f4616c bash completion: Cache the options list
The bash completion seems to be working decently at this point, so I
feel comfortable caching the options output to improve the performance
of the completion.
2020-02-08 09:50:58 -08:00
Dan Oscarsson 18070f7405 sub: fix SDH filtering after change
The change, in an earlier commit, in format for ass to handle results
in a different number of fields to skip. Correct that so SDH filtering
works.

Should fix issue #7188
2020-02-08 18:10:04 +01:00
wm4 e9fc53a10b player: add ab-loop-count option/property
As requested I guess. It behaves quite similar to the --loop* options.

Not quite happy with the idea that 1) the option is mutated on each
operation (but at least it's consistent with --loop* and doesn't require
more properties), and 2) the ab-loop command will do nothing once all
loop iterations are done. As a concession, the OSD shows something about
"disabled".

Fixes: #7360
2020-02-08 15:01:33 +01:00
wm4 3fb0cc203b DOCS/interface-changes.rst: mention it's for incompatible changes
This is not really a changelog, but rather a list of potentially
breaking changes API- and normal users should be aware of, and to help
with migration from older mpv releases.
2020-02-08 14:44:53 +01:00
wm4 27d84de2f4 DOCS/interface-changes.rst: mention OSX bundle logging 2020-02-08 14:43:01 +01:00
der richter 5d7f0edfeb cocoa-cb: fix auto-selection of title bar style with older SDKs
returning a nil value only works when build with a +10.14 SDK otherwise
we need to fallback to the old mechanism.
2020-02-08 11:00:55 +01:00
der richter 3ad9c32a5f cocoa-cb: simplify cursor hiding and make it less greedy
for reasons unknown to me the NSCursor (un)hide functions can be
completely unreliable and the cursor can have an unknown state. this
only happens on some system and wasn't able to reproduce this. it's
probably some dumb race condition that might be possible to work around,
though because of the lack of reproducibility on my end it's hard to
test.

i decided to rework the cursor hiding code yet again and make it a lot
less greedy. the cursor will now always unhide when moved and there
will never be a situation again the cursor can't be unhidden again.
on the other hand there might be edge cases now where the cursor won't
hide immediately and you have to move it slightly to make it disappear
again. this should be an acceptable tradeoff.

Fixes #6886
2020-02-08 10:56:11 +01:00
der richter 2607a2b892 mac: activate logging when started from the bundle
this creates a default log for the last mpv run when started from the
bundle. that way one can get a log of what happened even after an issue
occurred. also add a menu entry under Help to show the current log, but
only when the bundle is used.

Fixes #7396
Fixes #2547
2020-02-08 10:55:07 +01:00
der richter b7b8a772f2 mac: remove stdout and stderr redirect for logging
this was kinda useless anyway since the bundle was started with
terminal=no and no logging was done anyway.

Fixes #1590
2020-02-08 10:55:07 +01:00
Dudemanguy af021a2891 wayland: adjust vo_wayland_wait_frame logic
Wayland uses vo_wayland_wait_frame plus some polling with a timeout for
blocking on vsync. Here are a couple of changes that seem to be
improvements. First, the poll time is always rounded up instead of
truncated. When rendering frames longer than the standard 16.666 ms
timeout, it seems that truncating the poll time slightly early may cause
some vsync jitter spikes. Waiting longer, even if it's too long, appears
to behave better.

The second change is to use wl_display_roundtrip instead of
wl_display_dispatch_pending. wl_display_dispatch_pending dispatches all
events immediately. This is good to avoid blocking, but it's not
guaranteed to wait long enough for all events to be processed on the
display fd. The preceding wl_display_read_events routine ensures that
all events on the display fd are queued. We just need a semi-blocking
routine to dispatch them for the most reliable vsync.

wl_display_roundtrip will dispatch any events for us, but also wait for
a reply from the display server. This makes it ideal for this role. If
the compositor doesn't reply to the client something else is probably
horribly broken and wrong anyway. It's also not a permanently blocking
call like wl_display_dispatch. If there's no frame callback (i.e. the
window is hidden), then it does not dispatch any events and returns
immediately.
2020-02-07 18:33:32 +00:00
Avi Halachmi (:avih) c4570be3b8 DOCS: js: minor update for require 2020-02-07 19:24:00 +02:00
Avi Halachmi (:avih) 756960bf3c js: require: directory-scripts: first look at <dir>/modules/
Also, add the function mp.get_script_directory() to let scripts know if
they're loaded as a directory and where.
2020-02-07 18:22:12 +02:00
Avi Halachmi (:avih) 68a1b47d4d js: require: don't use ~~/scripts/modules.js/
Directories inside ~~/scripts/ are now loaded as scripts, so don't use
it also for modules. Now there are no default module paths.

To compensate, we now try to run ~~/.init.js right after defaults.js,
so the user may extend the js init procedure via this script, e.g. for
adding default paths to mp.module_paths .
2020-02-07 18:20:33 +02:00
wm4 10a97f7cc3 osc: use cache state cache-duration field
Avoids an additional property access; see previous commit.
2020-02-07 16:16:18 +01:00
wm4 11d223228c command: add cache-duration to cache state property
Convenience; see following commit.
2020-02-07 16:15:55 +01:00
wm4 27d5d32020 demux: add option to disable "sharing" between back and forward buffers
As requested. I guess option name and manpage text could be better and
clearer.

Closes: #7442
2020-02-07 15:58:13 +01:00
wm4 c48fd48f1e console: fix typo in previous commit
Now keypad enter actually works.
2020-02-07 14:05:04 +01:00
wm4 f659cfd6e3 console: manually map numeric keypad (KP*) bindings
While mpv normally uses the text a key produces (as opposed to physical
key mappings), this is different with the keypad. This is for the sake
of making it possible to distinguish between these keys and the normal
number keys on the left side of a full size keyboard.

There were complaints that the keypad doesn't interact with console.lua,
so manually map them. This ignores numlock (behaves as if it's always
on), and maps KP_DEC to "." (even though it's mapped to "," on some
keyboards). The /*-+ keys produce ASCII on mpv (at least with X11) as an
inexplicable inconsistency, so there are no mappings for these.

Fixes: #7431
2020-02-07 13:51:25 +01:00
wm4 c33bbc8694 screenshot: fix typo in comment
It was not meant to imply that screenshots are male. Female (and other)
screenshots are also welcome to this project.
2020-02-07 13:42:42 +01:00
wm4 a3bd8c3b5f player: make screenshot each-frame mode more accurate
Due to asynchronicity, we generally can't guarantee that a video frame
matches up with other events such as playback time change exactly (since
decoding, presentation, and property update all happen at different
times). This is a complaint in the referenced bug report, where
screenshot filenames in each-frame screenshot did not use the correct
timestamp, and instead was lagging behind by 1 frame.

But in this case, synchronicity was already pretty much forced with wait
calls. The only problem was that the playback time was updated at a
later time, which results in the observed 1 frame lag. Fix this by
moving the place where the screenshot is triggered in this mode.

Normal screenshots may still have the old problem. There is no effort
made to guarantee the timestamps absolutely line up, same as with the
OSD. (If you want a guarantee, you need to use a video filter, such as
libavfilter's drawtext. These will obviously use the proper timestamp,
instead of going through the somewhat asynchronous property etc. system
in the player frontend.)

Fixes: #7433
2020-02-07 13:32:21 +01:00
wm4 3d17e19c2c options: disable vsfilter blur compat by default
See #7435 and related for context.

Basically, it seems that while the original vsfilter processed subtitles
like with this option set to "yes", many current players (mpc-hc
default, vlc, probably most libass users) treat them like with "no". In
the linked issue, this makes rendering severely slower, and can consume
a lot of memory (or just overflow libass memory calculations). It seems
that changing this to "no" will lead to more good than bad, especially
because newer subtitles may be authored for the "no" behavior.

Most libass users seem to use "no" exactly because they do not call
ass_set_storage_size() at all. This API was needed because the scaling
of the subtitles depends on the video size (vsfilter bugs, or
something). In addition, it's my personal opinion that rendering should
not depend on the video at all, so I like setting the default of this to
"no".
2020-02-07 00:50:25 +01:00
wm4 4bdf03779f lua: fix typo in comment 2020-02-06 23:02:23 +01:00
Oscar Manglaras c99cc13526 options.lua: avoid unnecessary on_update calls
The script was set up to only call on_update when the changelist
was non-empty. However, since the size operator does not operate
on dicts, it always returned 0 (which is truthy), thus on_update
would always be called when the script-opts property changed.
2020-02-06 22:57:53 +01:00
sfan5 a2eee88ccc stats: fix incorrect ass formatting on 3rd page when vo was switched
When switching between having a video visible or not,
stats.lua now picks up the required formatting changes
for the cache stats page to display correctly.
2020-02-06 22:57:53 +01:00
wm4 c58f9a6579 scripting: give proper name to scripts using a directory
The recently added feature to load scripts from a sub-directory. A
problem was that the script name was still derived from the actual
script source file that was loaded, which was always "main.lua" (or
similar), resulting in "main" as name.

Fix this by using the directory name.

One odd corner case is that you can do "--script=/path/foo////". As by
POSIX semantics, the extra "/" are ignored. However, the newly added
code strips only one separator, so mp_basename() returns "" (as it
should), and the empty name makes mp_new_client() fail in turn. I don't
really care about this, just don't do it. But mp_new_client() failure
was silent (since it normally never happens), so add at least an error
message for that, instead of being entirely silent.
2020-02-06 19:38:22 +01:00
Dudemanguy 2aaf531720 wayland: toplevel config fixes
There were a couple of erroneous things in the handle_toplevel_config
function. Firstly, looping through the different states was not handled
correctly. Launching a window as maximized (can happen in sway for
example) was always stuck on true and would never be set to false. Fix
this by always checking if XDG_TOPLEVEL_STATE_MAXIMIZED is found or not.
Also do a similar thing for the fullscreen state.

Additionally, there were some issues with resizing windows and
window-scale going back to old sizes. The root of this problem is that
the width and height arguments of handle_toplevel_config aren't actually
guarenteed to be the actual width and height of the surface. There are
times when mpv will set the surface size on its own (like with
window-scale) which will be unknown to the toplevel listener. To
complicate matters, there are times when we do want to use the width and
height arguments (like when resizing with the mouse).

Fix this by checking if the width and height arguments reported by
handle_toplevel_config changed from the previous call of the function.
If the value is different, then we go ahead and use them when setting
mpv's geometry. If not, then we just ignore it.
2020-02-06 16:17:25 +00:00
wm4 7c5c057717 lua: use mp_path_is_absolute() for checking package paths
This makes it work with the shitty OS. Behavior on Linux should be the
same.
2020-02-06 14:15:31 +01:00
wm4 1dc3507474 path: add mp_path_is_absolute()
Just move it from mp_path_join_bstr() to this new function.
2020-02-06 14:14:35 +01:00
wm4 31acec5438 path: change win32 semantics for joining drive-relative paths
win32 is a cursed abomination which has "drive letters" at the root of
the filesystem namespace for no reason. This requires special handling
beyond tolerating the idiotic "\" path separator.

Even more cursed is the fact that a path starting with a drive letter
can be a relative path. For example, "c:billsucks" is actually a
relative path to the current working directory of the C drive. So for
example if the current working directory is "c:/windowsphone", then
"c:billsucks" would reference "c:/windowsphone/billsucks".

You should realize that win32 is a ridiculous satanic trash fire by the
point you realize that win32 has at least 26 current working
directories, one for each drive letter.

Anyway, the actual problem is that mpv's mp_path_join() function would
return a relative path if an absolute relative path is joined with a
drive-relative path. This should never happen; I bet it breaks a lot of
assumptions (maybe even some security or safety relevant ones, but
probably not).

Since relative drive paths are such a fucked up shit idea, don't try to
support them "properly", and just solve the problem at hand. The
solution produces a path that should be invalid on win32.

Joining two relative paths still behaves the same; this is probably OK
(maybe).

The change isn't very minimal due to me rewriting parts of it without
strict need, but I don't care.

Note that the Python os.path.join() function (after which the mpv
function was apparently modeled) has the same problem.
2020-02-06 14:10:40 +01:00
wm4 1293c40623 test: add some path handling tests
Exhaustive tests would be nice, but I'm only adding a test for a
function I'm going to change.
2020-02-06 13:50:41 +01:00
wm4 cce7062a8a lua: fix highly security relevant arbitrary code execution bug
It appears Lua's package paths try to load .lua files from the current
working directory. Not only that, but also shared libraries.

  WHAT THE FUCK IS WHOEVER IS RESPONSIBLE FOR THIS FUCKING DOING?

mpv isn't setting this package path; currently it's only extending it.
In any sane world, this wouldn't be a default. Most programs use
essentially random working directories and don't change it.

I cannot comprehend what bullshit about "convenience" or whatever made
them do something this broken and dangerous. Thousands of programs using
Lua out there will try to randomly load random code from random
directories.

In mpv's case, this is so security relevant, because mpv is normally
used from the command line, and you will most likely actually change
into your media directory or whatever with the shell, and play a file
from there. No, you don't want to load a (probably downloaded) shared
library from this directory if a script try to load a system lib with
the same name or so.

I'm not sure why LUA_PATH_DEFAULT in luaconf.h (both upstream and the
Debian version) put "./?.lua" at the end, but in any case, trying to
load a module that doesn't exist nicely lists all package paths in
order, and confirms it tries to load files from the working directory
first (anyone can try this). Even if it didn't, this would be
problematic at best.

Note that scripts are _not_ sandboxed. They're allowed to load system
libraries, which is also why we want to keep the non-idiotic parts of
the package paths.

Attempt to fix this by filtering out relative paths. This is a bit
fragile and not very great for something security related, but probably
the best we can do without having to make assumptions about the target
system file system layout. Also, someone else can fix this for Windows.

Also replace ":" with ";" (for the extra path). On a side note, this
extra path addition is just in this function out of laziness, since
I'd rather not have 2 functions with edit the package path.

mpv in default configuration (i.e. no external scripts) is probably not
affected. All builtin scripts only "require" preloaded modules, which,
in a stroke of genius by the Lua developers, are highest priority in the
load order. Otherwise, enjoy your semi-remote code execution bug.

Completely unrelated this, I'm open for scripting languages and
especially implementations which are all around better than Lua, and are
suited for low footprint embedding.
2020-02-06 11:59:24 +01:00
wm4 65cd9efa85 lua: add mp.get_script_directory() function
And add some clarifications/suggestions to the manpage.
2020-02-04 20:40:16 +01:00
wm4 6a83187b06 player: partially fix backward playback display of cached text subtitles
This simply didn't set the direction flag in most situations, which
meant the timestamps used in the subtitle renderer were nonsense,
leading to invisible subtitles.

This works only for text subtitles that are cached in the ASS_Track
state. Reading new subtitles is broken because the demuxer layer has
trouble returning subtitle packets backwards, and I think for rendering
bitmap subtitles, the pruning direction would have to be adjusted. (Not
sure if reversing the timestamps before the subtitle renderer backend is
even the right thing to do. At least for sd_ass.c, it seems to make
sense, because it caches subtitles with "normal" timestamps.)
2020-02-04 20:26:35 +01:00
wm4 2b851933e0 options: stop hiding deprecated options
I think this was annoying. It shouldn't be dishonest about which options
exist. List them as "[deprecated]" instead.
2020-02-04 20:10:38 +01:00
wm4 cbee577d0a cue: tolerate NBSP as whitespace
Apparently such .cue files exist. They fail both probing and parsing. To
make it worse, the sample at hand was encoded as Latin1.

One part of this is replacing bstr_lstrip() with a version that supports
NBSP. One could argue that bstr_lstrip() should always do this, but I
don't want to overdo it. There are many more unicode abomination which
it could be said it's supposed to handle, so it will stay ASCII instead
of going down this rabbit hole. I'm just assuming this cue sheet was
generated by some stupid software that inexplicably liked NBSPs (which
is how we justify a one-off fix). The new lstrip_whitespace() doesn't
look particularly efficient, but it doesn't have to be.

The second part is dealing with the fact that the charset is not
necessarily UTF-8. We don't want to do conversion before probing thinks
it knows it's a cue sheet (would probably make it more fragile all
around), so just make it work with Latin1 by assuming invalid code
points are Latin1. This fallback is part of why lstrip_whitespace() is
sort of roundabout.

(You could still rewrite it as much more efficient state machine,
instead of using a slow and validating UTF-8 parser that is called per
codepoint. Starting to overthink this.)

Multimedia is terrible. Legacy charsets are terrible. Everything is
terrible.

Fixes: #7429
2020-02-03 19:13:44 +01:00
wm4 13624b5c7a stream_libarchive: disable tar support
Unfortunately, libarchive detects a stream of 0s as tar, as demonstrated
by "mpv /dev/zero". This is inconvenient in some cases.

One example is the .cue demuxer trying to open a raw audio .bin file,
which it allows only if probing fails (as .bin is raw and normally will
not look like any real file format). Although this use-case is
worthless.
2020-02-02 17:35:57 +01:00
Anton Kindestam 19e5155147 drm_atomic: do not set immutable properties
On some platforms the ZPOS property might exist, but be immutable.
This is at least the case on Intel Sandy Bridge since Linux kernel
5.5.0. Trying to set an immutable property will cause.
drmModeAtomicCommit to fail with -EINVAL.

On other platforms we might want to set ZPOS to tweak the layering of
planes.

To reconcile these two, simply have drm_object_set_property check if a
property is immutable before attempting to add it to the atomic
commit, instead returning an error code (which is, as previously,
ignored in the case of ZPOS as we don't strictly need it)
2020-02-02 18:01:55 +02:00
wm4 f304a79935 stream_cdda: fix operation
The cdio API always reads in sectors (fixed CDIO_CD_FRAMESIZE_RAW
blocks). In the past, mpv/MPlayer streams had a way for a stream to
signal a sector size, so the stream's fill_buffer implementation could
ignore the length argument. Later, that was removed, but stream_cdda.c
was left with assuming that the read size was always larger than the
sector size (rightfully at the time). Even later, this assumption was
broken with commit f37f4de, when it was suddenly possibly that smaller
reads were performed (at ring buffer boundaries). It returned EOF if the
buffer size was too small, so playback stopped very early.

Fix this by explicitly handling arbitrary sizes.

Tested with a .cue/.bin file only.

Fixes: #7384
2020-02-02 02:15:51 +01:00
wm4 77a74d9eb5 manpage: --sub-codepage cannot do muxed subs
mpv actually used to be able to, from what I remember, but this was
changed for simplicity and because of problems with FFmpeg.
2020-02-01 18:52:30 +01:00
wm4 b86bfc907f lua: set package path if loaded from a script directory
And document the shit.

This uses code from commit bc1c024ae0.
2020-02-01 18:43:27 +01:00
wm4 da38caff9c scripting: load scripts from directories
The intention is to provide a slightly nicer way to distribute scripts.
For example, you could put multiple source files into the directory, and
then import them from the actual script file (this is still
unimplemented).

At first I wanted to require a config file (because you need to know at
least which scripting backend it should use). This wouldn't have been
too hard (could have reused/abused the mpv config file parsing
mechanism, and I already had working code that was just 2 function
calls). But probably better to do this without new config files, because
it might become a pain in the distant future.

So this just probes for "main.lua", "main.js", etc., until an existing
file is found.

Another important change is that this skips all directory entries whose
name starts with ".". This automatically excludes the "." and ".."
special directories, and is probably useful to exclude random crap that
might be lying around in the directory (such as editor temporary files,
or OSX, in its usual hrmful, annoying, and idiotic modus operandi,
sharting all over any directories opened by "Finder").

Although the changelog mentions the docs, they're added only in a later
commit.
2020-02-01 18:09:40 +01:00
wm4 66a979bd75 options: remove unused set_defaults callback
Was only needed for an ancient version of af_lavfrresample, which is
gone now.
2020-02-01 16:00:44 +01:00
Rafael Rivera c40554295a ao_wasapi_utils: remove invalid audio session icon path (fixes #7269) 2020-01-31 23:08:47 +11:00
dudemanguy b926f18938 wayland: remove wayland-frame-wait-offset option
This originally existed as a hack for weston. In certain scenarios, a
frame taking too long to render would cause vo_wayland_wait_frame to
timeout which would result in a ton of dropped frames. The naive
solution was to just to add a slight delay to the time value. If a
frame took too long, it would likely to fall under the timeout value and
all was well. This was exposed to the user since the default delay
(1000) was completely arbitrary.

However with presentation time, this doesn't appear to be neccesary.
Fresh frames that take longer than the display's refresh rate (16.666 ms
in most cases) behave well in Weston. In the other two main compositors
without presentation time (GNOME and Plasma), they also do not
experience any ill effects. It's better not to overcomplicate things, so
this "feature" can be removed now.
2020-01-31 00:40:44 +00:00
wm4 6c2cc20a53 msg: move central msg lock to mp_log_root
This is a central lock (that is to stay and has no reason to go away),
and it was simply made global. This reduces complexity when the original
MPlayer code was changed from single thread + global state to a context
handle.

Having the global lock was still a bit silly if there were multiple mpv
instances in the process, because it would make the instances wait for
each other for no reason. So move it to the per-instance context, which
is trivial enough.
2020-01-30 14:16:20 +01:00
wm4 355bb5b1e6 msg: fix some locking issues
The wakeup_log_file callback was still assuming that mp_msg_lock was
used to control the log file thread, but this changed while I was
writing this code, and forgot to update it. (It doesn't change any
state, which is untypical for condition variable usage. The state that
is changed is protected by another lock instead. But log_file_lock still
needs to be acquired to ensure the signal isn't sent while the thread is
right before the pthread_cond_wait() call, when the lock is held, but
the signal would still be lost.)

Because the buffer's wakeup callback now acquires the lock, the wakeup
callback must be called outside of the buffer lock, to keep the lock
order (log_file_lock > mp_log_buffer.lock). Fortunately, the wakeup
callback is immutable, or we would have needed another dumb leaf lock.

mp_msg_has_log_file() made a similar outdated assumption. But now access
to the log_file field is much trickier; just define that it's only to be
called from the thread that manages the msg state. (The calling code
could also just check whether the log-file option changed instead, but
currently that would be slightly more messy.)
2020-01-30 14:13:35 +01:00
wm4 2fd34889fe msg: make --log-file buffered through a thread
Until now --log-file performed a blocking write to the log file, which
made any calling thread block for I/O. It even explicitly flushed after
every line (to make it tail-able, or to ensure a hard crash wouldn't
lose any of the output). This wasn't so good, because it could cause
real playback problems, which made it infeasible to enable it by
default.

Try to buffer it through a ring buffer and a thread. There's no other
choice but to use a thread, since async I/O on files is generally a big
and unportable pain. (We very much prefer portable pain.) Fortunately,
there's already a ring buffer (mp_log_buffer, normally for the client
API logging hook). This still involves some pretty messy locking. Give
each mp_log_buffer its own lock to make this easier.

This still makes calling threads block if the log buffer is full (unlike
with client API log buffers, which just drop messages). I don't want log
messages to get lost for this purpose. This also made locking pretty
complicated (without it, mp_log_buffer wouldn't have needed its own
lock). Maybe I'll remove this blocking again when it turns out to be
nonsense.

(We could avoid wasting an entire thread by "reusing" some other thread.
E.g. pick some otherwise not real time thread, and make it react to the
log buffer's wakeup callback. But let's not. It's complicated to abuse
random threads for this. It'd also raise locking complexity, because we
still want it to block on a full buffer.)
2020-01-29 23:34:59 +01:00
wm4 1caf90a3f7 options: merge split_opt functions
There wasn't really much of a reason to keep split_opt and
splot_opt_silent apart. It made sense before the latter also had a log
call (which was silenced by using mp_null_log if necessary).

Just merge them back into one, and always rely on mp_null_log to silence
unwanted output.

Shouldn't have any functional changes.
2020-01-29 23:20:04 +01:00
wm4 f526797a16 options: suggest not using the syntax that was recently disabled 2020-01-29 18:32:23 +01:00
der richter cbfcd3e703 manpage: update force dedicated gpu on macOS option
was forgotten in commit 3275cd0
2020-01-27 01:01:29 +01:00
sfan5 0c32e919a8 Update VERSION 2020-01-26 21:35:20 +01:00
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
412 changed files with 29450 additions and 17368 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 -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. If the issue is a build failure, upload build/config.log instead.
If this is a normal runtime bug, and no log is provided, the issue 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.
### 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,49 @@
---
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
Try to reproduce your issue with --no-config first. If it isn't reproducible
with --no-config try to first find out which option or script causes your issue.
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,51 @@
---
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
Try to reproduce your issue with --no-config first. If it isn't reproducible
with --no-config try to first find out which option or script causes your issue.
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. If you use the Bundle
from a version later than 0.32 a default log is created for your last run at
~/Library/Logs/mpv.log. You can jump to that file via the Help > Show log File…
menu. Paste the log 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,47 @@
---
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
Try to reproduce your issue with --no-config first. If it isn't reproducible
with --no-config try to first find out which option or script causes your issue.
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.
+43
View File
@@ -0,0 +1,43 @@
---
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
Try to reproduce your issue with --no-config first. If it isn't reproducible
with --no-config try to first find out which option or script causes your issue.
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,22 @@
---
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
### Log file
Even if you think it's not necessary at first, it might help us later to find
possible issues. 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.
+25
View File
@@ -0,0 +1,25 @@
---
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
### Log file
Even if you think it's not necessary at first, it might help us later to find
possible issues. 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.
+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 questions here irc://irc.freenode.net/mpv
- name: mpv irc developer channel
url: https://mpv.io/community/
about: Ask questions related to the development of mpv here
irc://irc.freenode.net/mpv-devel
+120 -29
View File
@@ -1,15 +1,49 @@
language: c
_macbase:
- &mac
os: osx
compiler: clang
env:
- HOMEBREW_NO_AUTO_UPDATE=1
- HOMEBREW_NO_INSTALL_CLEANUP=1
before_cache:
- brew cleanup -s
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
_mingwbase:
- &mingw
os: linux
addons:
apt:
packages:
- 'autoconf'
- 'automake'
- 'pkg-config'
- 'gcc-mingw-w64'
- 'gcc-multilib'
- 'nasm'
- 'yasm'
cache:
directories:
- mingw_prefix/
matrix:
include:
- os: osx
osx_image: xcode11
compiler: clang
- os: osx
- <<: *mac
osx_image: xcode11.6
- <<: *mac
osx_image: xcode10.1
compiler: clang
- os: osx
- <<: *mac
osx_image: xcode9.2
env:
- HOMEBREW_NO_AUTO_UPDATE=1
- HOMEBREW_NO_INSTALL_CLEANUP=1
- CI_SWIFT_FLAGS="\-target x86_64-apple-macosx10.12"
- os: freebsd
compiler: clang
- os: linux
compiler: gcc
@@ -17,17 +51,19 @@ matrix:
- os: linux
compiler: clang
env: CONTAINER=registry.cirno.systems/kiwi/containers/mpv-ci:stable-deps CI_SCRIPT=ci/build-tumbleweed.sh
- os: linux
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
- <<: *mingw
env: CI_SCRIPT=ci/build-mingw64.sh TARGET=i686-w64-mingw32
- <<: *mingw
env: CI_SCRIPT=ci/build-mingw64.sh TARGET=x86_64-w64-mingw32
allow_failures:
- os: osx
osx_image: xcode9.2
fast_finish: true
dist: bionic
dist: focal
services:
- docker
sudo: required
env:
global:
# Coverity token
@@ -45,18 +81,86 @@ branches:
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 [ -n "$CONTAINER" ]; then docker pull $CONTAINER; fi
- |
if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
# Requested in ci/build-freebsd.sh
sudo pkg install -y \
evdev-proto \
ffmpeg \
libplacebo \
libxkbcommon \
luajit \
openal-soft \
pkgconf \
python3 \
sdl2 \
vulkan-headers \
wayland-protocols \
$NULL
# Optionally auto-enabled
sudo pkg install -y \
alsa-lib \
jackit \
libXv \
libarchive \
libbluray \
libcaca \
libcdio-paranoia \
libdvdnav \
mujs \
pulseaudio \
rubberband \
sekrit-twc-zimg \
uchardet \
v4l_compat \
$NULL
fi
- |
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
remove=$(brew list)
keep="gettext pcre2 git"
install="autoconf automake pkg-config libtool python freetype fribidi little-cms2 luajit libass ffmpeg"
for formula in ${keep[@]}; do remove=("${remove[@]/$formula}"); done
for formula in ${install[@]}; do remove=("${remove[@]/$formula}"); done
brew remove --force $remove --ignore-dependencies
if [[ "$TRAVIS_OSX_IMAGE" == "xcode9.2" ]]; then
brew untap caskroom/cask
fi
brew update
if [[ "$TRAVIS_OSX_IMAGE" == "xcode9.2" ]]; then
pushd "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core"
git checkout --force 55e02323812604add9a69bab8730319b9255a697
fi
brew install $install
brew link --overwrite python
if [[ "$TRAVIS_OSX_IMAGE" == "xcode9.2" ]]; then
git checkout master
popd
fi
fi
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
- |
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ -n "$CONTAINER" ]; then
docker run --env CC --env TARGET -v $TRAVIS_BUILD_DIR:/build $CONTAINER /bin/sh -c "cd /build && $CI_SCRIPT"
else
$CI_SCRIPT
fi
fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./ci/build-macos.sh; fi
- if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then ./ci/build-freebsd.sh; fi
after_failure: cat ./build/config.log
after_script: TOOLS/travis-rebuild-website
notifications:
email: false
irc:
if: fork = false
channels:
- "irc.freenode.org#mpv-devel"
on_success: change
@@ -71,16 +175,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
-1
View File
@@ -53,7 +53,6 @@ The following files are still GPL only (--enable-lgpl disables them):
stream/stream_cdda.c unknown
stream/stream_dvb.* must stay GPL
stream/stream_dvdnav.c unknown
stream/stream_smb.c will stay GPLv3
video/out/vo_caca.c unknown
video/out/vo_direct3d.c unknown
video/out/vo_vaapi.c probably impossible (some company's code)
+20
View File
@@ -32,6 +32,26 @@ API changes
::
--- mpv 0.33.0 ---
1.109 - add MPV_RENDER_API_TYPE_SW and related (software rendering API)
- inactivate the opengl_cb API (always fails to initialize now)
The opengl_cb API was deprecated over 2 years ago. Use the render API
instead.
1.108 - Deprecate MPV_EVENT_IDLE
- add mpv_event_start_file
- add the following fields to mpv_event_end_file: playlist_entry_id,
playlist_insert_id, playlist_insert_num_entries
- add mpv_event_to_node()
- add mpv_client_id()
1.107 - Remove the deprecated qthelper.hpp. This was obviously not part of the
libmpv API, only an "additionally" provided helper, thus this is not
considered an API change. If you are maintaining a project that relies
on this header, you can simply download this file and adjust the
include statement to use it instead:
https://raw.githubusercontent.com/mpv-player/mpv/v0.32.0/libmpv/qthelper.hpp
It is a good idea to write better wrappers for your use, though.
--- mpv 0.31.0 ---
1.107 - Deprecate MPV_EVENT_TICK
+1 -1
View File
@@ -68,7 +68,7 @@ echo "MXE_TARGETS := i686-w64-mingw32.static" >> settings.mk
# Build required packages. The following provide a minimum required to build
# a reasonable mpv binary (though not an absolute minimum).
make gcc ffmpeg libass jpeg lua
make gcc ffmpeg libass jpeg lua luajit
# Add MXE binaries to $PATH
export PATH=/opt/mxe/usr/bin/:$PATH
+20 -1
View File
@@ -100,6 +100,22 @@ Split changes into multiple commits
as possible. Commits should form logical steps in development. The way you
split changes is important for code review and analyzing bugs.
Always squash fixup commits when making changes to pull requests
----------------------------------------------------------------
- If you make fixup commits to your pull request, you should generally squash
them with "git rebase -i". We prefer to have pull requests in a merge
ready state.
- We don't squash-merge (nor do we use github's feature that does this) because
pull requests with multiple commits are perfectly legitimate, and the only
thing that makes sense in non-trivial cases.
- With complex pull requests, it *may* make sense to keep them separate, but
they should be clearly marked as such. Reviewing commits is generally easier
with fixups squashed.
- Reviewers are encouraged to look at individual commits instead of github's
"changes from all commits" view (which just encourages bad git and review
practices).
Touching user-visible parts may require updating the mpv docs
-------------------------------------------------------------
@@ -222,7 +238,10 @@ General coding
Code of Conduct
---------------
We have one, but the document describing it got lost accidentally.
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.
The Contributor Code of Conduct can be found here:
https://www.contributor-covenant.org/version/2/0/code_of_conduct/
Rules for git push access
-------------------------
+122 -2
View File
@@ -146,7 +146,8 @@ The current implementation will
Another header part of this mechanism is ``no_clip``. This header is similar
to ``mp4_dash``, but does not include on-demand opening/closing of segments,
and does not support init segments. It also exists solely to support internal
ytdl requirements.
ytdl requirements. Using ``no_clip`` with segments is not recommended and
probably breaks. ``mp4_dash`` already implicitly does a variant of ``no_clip``.
The ``mp4_dash`` and ``no_clip`` headers are not part of the core EDL format.
They may be changed or removed at any time, depending on mpv's internal
@@ -182,6 +183,124 @@ this will use a unified cache for all streams.
The ``new_stream`` header is not part of the core EDL format. It may be changed
or removed at any time, depending on mpv's internal requirements.
If the first ``!new_stream`` is redundant, it is ignored. This is the same
example as above::
# mpv EDL v0
!new_stream
video.mkv
!new_stream
audio.mkv
Note that ``!new_stream`` must be the first header. Whether the parser accepts
(i.e. ignores) or rejects other headers before that is implementation specific.
Track metadata
==============
The special ``track_meta`` header can set some specific metadata fields of the
current ``!new_stream`` partition. The tags are applied to all tracks within
the partition. It is not possible to set the metadata for individual tracks (the
feature was needed only for single-track media).
It provides following parameters change track metadata:
``lang``
Set the language tag.
``title``
Set the title tag.
``byterate``
Number of bytes per second this stream uses. (Purely informational.)
``index``
The numeric index of the track this should map to (default: -1). This is
the 0-based index of the virtual stream as seen by the player, enumerating
all audio/video/subtitle streams. If nothing matches, this is silently
discarded. The special index -1 (the default) has two meanings: if there
was a previous meta data entry (either ``!track_meta`` or ``!delay_open``
element since the last ``!new_stream``), then this element manipulates
the previous meta data entry. If there was no previous entry, a new meta
data entry that matches all streams is created.
Example::
# mpv EDL v0
!track_meta,lang=bla,title=blabla
file.mkv
!new_stream
!track_meta,title=ducks
sub.srt
If ``file.mkv`` has an audio and a video stream, both will use ``blabla`` as
title. The subtitle stream will use ``ducks`` as title.
The ``track_meta`` header is not part of the core EDL format. It may be changed
or removed at any time, depending on mpv's internal requirements.
Delayed media opening
=====================
The special ``delay_open`` header can be used to open the media URL of the
stream only when the track is selected for the first time. This is supposed to
be an optimization to speed up opening of a remote stream if there are many
tracks for whatever reasons.
This has various tricky restrictions, and also will defer failure to open a
stream to "later". By design, it's supposed to be used for single-track streams.
Using multiple segments requires you to specify all offsets and durations (also
it was never tested whether it works at all). Interaction with ``mp4_dash`` may
be strange.
You can describe multiple sub-tracks by using multiple ``delay_open`` headers
before the same source URL. (If there are multiple sub-tracks of the same media
type, then the mapping to the real stream is probably rather arbitrary.) If the
source contains tracks not described, a warning is logged when the delayed
opening happens, and the track is hidden.
This has the following parameters:
``media_type``
Required. Must be set to ``video``, ``audio``, or ``sub``. (Other tracks in
the opened URL are ignored.)
``codec``
The mpv codec name that is expected. Although mpv tries to initialize a
decoder with it currently (and will fail track selection if it does not
initialize successfully), it is not used for decoding - decoding still uses
the information retrieved from opening the actual media information, and may
be a different codec (you should try to avoid this, of course). Defaults to
``null``.
Above also applies for similar fields such as ``w``. These fields are
mostly to help with user track pre-selection.
``flags``
A ``+`` separated list of boolean flags. Currently defined flags:
``default``
Set the default track flag.
``forced``
Set the forced track flag.
Other values are ignored after triggering a warning.
``w``, ``h``
For video codecs: expected video size. See ``codec`` for details.
``fps``
For video codecs: expected video framerate, as integer. (The rate is usually
only crudely reported, and it makes no sense to expect exact values.)
``samplerate``
For audio codecs: expected sample rate, as integer.
The ``delay_open`` header is not part of the core EDL format. It may be changed
or removed at any time, depending on mpv's internal requirements.
Timestamp format
================
@@ -189,7 +308,8 @@ Currently, time values are floating point values in seconds.
As an extension, you can set the ``timestamps=chapters`` option. If this option
is set, timestamps have to be integers, and refer to chapter numbers, starting
with 0.
with 0. The default value for this parameter is ``seconds``, which means the
time is as described in the previous paragraph.
Example::
+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
+67 -2
View File
@@ -17,13 +17,78 @@ a large part of the user interface and APIs.
Also see compatibility.rst.
This document lists changes to them. New changes are added to the top.
This document lists changes to them. New changes are added to the top. Usually,
only incompatible or important changes are mentioned. New options/commands/etc.
are not always listed.
Interface changes
=================
::
--- mpv 0.33.0 ---
- add `--d3d11-exclusive-fs` flag to enable D3D11 exclusive fullscreen mode
when the player enters fullscreen.
- directories in ~/.mpv/scripts/ (or equivalent) now have special semantics
(see mpv Lua scripting docs)
- names starting with "." in ~/.mpv/scripts/ (or equivalent) are now ignored
- js modules: ~~/scripts/modules.js/ is no longer used, global paths can be
set with custom init (see docs), dir-scripts first look at <dir>/modules/
- the OSX bundle now logs to "~/Library/Logs/mpv.log" by default
- deprecate the --cache-secs option (once removed, the cache cannot be
limited by time anymore)
- remove deprecated legacy hook API ("hook-add", "hook-ack"). Use either the
libmpv API (mpv_hook_add(), mpv_hook_continue()), or the Lua scripting
wrappers (mp.add_hook()).
- improve how property change notifications are delivered on events and on
hooks. In particular, a hook event is only returned to a client after all
changes initiated before the hook point were delivered to the same client.
In addition, it should no longer happen that events and property change
notifications were interleaved in bad ways (it could happen that a
property notification delivered after an event contained a value that was
valid only before the event happened).
- the playlist-pos and playlist-pos-1 properties now can return and accept
-1, and are never unavailable. Out of range indexes are now accepted, but
behave like writing -1.
- the playlist-pos and playlist-pos-1 properties deprecate the current
behavior when writing back the current value to the property: currently,
this restarts playback, but in the future, it will do nothing.
Using the "playlist-play-index" command is recommended instead.
- add "playlist-play-index" command
- add playlist-current-pos, playlist-playing-pos properties
- Lua end-file events set the "error" field; this is deprecated; use the
"file_error" instead for this specific event. Scripts relying on the
"error" field for end-file will silently break at some point in the
future.
- remove deprecated --input-file option, add --input-ipc-client, which is
vaguely a replacement of the removed option, but not the same
- change another detail for track selection options (see --aid manpage
entry)
- reading loop-file property as native property or mpv_node will now return
"inf" instead of boolean true (also affects loop option)
- remove some --vo-direct3d-... options (it got dumbed down; use --vo=gpu)
- remove video-params/plane-depth property (was too vaguely defined)
- remove --video-sync-adrop-size option (implementation was changed, no
replacement for what this option did)
- undeprecate --video-sync=display-adrop
- deprecate legacy auto profiles (profiles starting with "extension." and
"protocol."). Use conditional auto profiles instead.
- the "subprocess" command does not connect spawned processes' stdin to
mpv's stdin anymore. Instead, stdin is connected to /dev/null by default.
To get the old behavior, set the "passthrough_stdin" argument to true.
- key/value list options do not accept ":" as item separator anymore,
only ",". This means ":" is always considered part of the value.
- remove deprecated --vo-vdpau-deint option
- add `delete-watch-later-config` command to complement
`write-watch-later-config`
--- 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.
@@ -37,7 +102,7 @@ Interface changes
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)
but it will probably eventually go away <- that was a lie)
- 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
+29
View File
@@ -161,6 +161,28 @@ Available filters are:
Would play media at 1.2x normal speed, with audio at normal pitch.
Changing playback speed would change pitch, leaving audio tempo at
1.2x.
``scaletempo2[=option1:option2:...]``
Scales audio tempo without altering pitch.
The algorithm is ported from chromium and uses the
Waveform Similarity Overlap-and-add (WSOLA) method.
It seems to achieve a higher audio quality than scaletempo and rubberband.
By default, the ``search-interval`` and ``window-size`` parameters
have the same values as in chromium.
``min-speed=<speed>``
Mute audio if the playback speed is below ``<speed>``. (default: 0.25)
``max-speed=<speed>``
Mute audio if the playback speed is above ``<speed>``
and ``<speed> != 0``. (default: 4.0)
``search-interval=<amount>``
Length in milliseconds to search for best overlap position. (default: 30)
``window-size=<amount>``
Length in milliseconds of the overlap-and-add window. (default: 20)
``rubberband``
High quality pitch correction with librubberband. This can be used in place
@@ -220,3 +242,10 @@ Available filters are:
broken filters. In practice, these broken filters will either cause slow
A/V desync over time (with some files), or break playback completely if
you seek or start playback from the middle of a file.
``drop``
This filter drops or repeats audio frames to adapt to playback speed. It
always operates on full audio frames, because it was made to handle SPDIF
(compressed audio passthrough). This is used automatically if the
``--video-sync=display-adrop`` option is used. Do not use this filter (or
the given option); they are extremely low quality.
+2 -35
View File
@@ -14,8 +14,7 @@ in the list.
See ``--ao=help`` for a list of compiled-in audio output drivers. The
driver ``--ao=alsa`` is preferred. ``--ao=pulse`` is preferred on systems
where PulseAudio is used. On BSD systems, ``--ao=oss`` or ``--ao=sndio``
may work (the latter being experimental).
where PulseAudio is used.
Available audio output drivers are:
@@ -36,18 +35,6 @@ Available audio output drivers are:
with automatic upmixing with shared access, so playing stereo
and multichannel audio at the same time will work as expected.
``oss``
OSS audio output driver
The following global options are supported by this audio output:
``--oss-mixer-device``
Sets the audio mixer device (default: ``/dev/mixer``).
``--oss-mixer-channel``
Sets the audio mixer channel (default: ``pcm``). Other valid values
include **vol, pcm, line**. For a complete list of options look for
``SOUND_DEVICE_NAMES`` in ``/usr/include/linux/soundcard.h``.
``jack``
JACK (Jack Audio Connection Kit) audio output driver.
@@ -110,7 +97,7 @@ Available audio output drivers are:
exclusive mode (bypasses the sound server).
``openal``
OpenAL audio output driver
OpenAL audio output driver. This is broken and does not work.
``--openal-num-buffers=<2-128>``
Specify the number of audio buffers to use. Lower values are better for
@@ -173,10 +160,6 @@ Available audio output drivers are:
obtained exact buffer size. A value of 0 selects the sound system
default.
``--sdl-bufcnt=<count>``
Sets the number of extra audio buffers in mpv. Usually needs not be
changed.
``null``
Produces no audio output but maintains video playback speed. You can use
``--ao=null --ao-null-untimed`` for benchmarking.
@@ -233,21 +216,5 @@ Available audio output drivers are:
``no-waveheader`` option - with ``waveheader`` it's broken, because
it will write a WAVE header every time the file is opened.
``rsound``
Audio output to an RSound daemon. Use ``--audio-device=rsound/<hostname>``
to set the host name (with ``<hostname>`` replaced, without the ``< >``).
.. note:: Completely useless, unless you intend to run RSound. Not to be
confused with RoarAudio, which is something completely
different.
``sndio``
Audio output to the OpenBSD sndio sound system
.. note:: Experimental. There are known bugs and issues.
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
layouts.)
``wasapi``
Audio output to the Windows Audio Session API.
+6 -4
View File
@@ -8,10 +8,12 @@ There is no real changelog, but you can look at the following things:
https://github.com/mpv-player/mpv/releases
* The git log, which is the "real" changelog
* The files ``client-api-changes.rst`` and ``interface-changes.rst`` in the
``DOCS`` sub directoryon the git repository, which document API and user
interface changes (the latter usually documents breaking changes only, rather
than additions).
* The file https://github.com/mpv-player/mpv/blob/master/DOCS/interface-changes.rst
documents changes to the command and user interface, such as options and
properties. (It usually documents breaking changes only, additions and
enhancements are often not listed.)
* C API changes are listed in
https://github.com/mpv-player/mpv/blob/master/DOCS/client-api-changes.rst
* The file ``mplayer-changes.rst`` in the ``DOCS`` sub directory on the git
repository, which used to be in place of this section. It documents some
changes that happened since mplayer2 forked off MPlayer. (Not updated
+11 -5
View File
@@ -36,7 +36,7 @@ INSERT
Toggle insert mode.
Shift+INSERT
Paste text (uses the primary selection on X11.)
Paste text (uses the primary selection on X11).
TAB
Complete the command or property name at the cursor.
@@ -44,7 +44,7 @@ TAB
Ctrl+C
Clear current line.
Ctrl+K.
Ctrl+K
Delete text from the cursor to the end of the line.
Ctrl+L
@@ -54,7 +54,7 @@ Ctrl+U
Delete text from the cursor to the beginning of the line.
Ctrl+V
Paste text (uses the clipboard on X11.)
Paste text (uses the clipboard on X11).
Ctrl+W
Delete text from the cursor to the beginning of the current word.
@@ -62,8 +62,14 @@ Ctrl+W
Commands
--------
``script-message-to console type <text>``
Show the console and pre-fill it with the provided text.
``script-message-to console type <text> [<cursor_pos>]``
Show the console and pre-fill it with the provided text, optionally
specifying the initial cursor position as a positive integer starting from
1.
.. admonition:: Example for input.conf
``% script-message-to console type "seek absolute-percent" 6``
Known issues
------------
+9 -6
View File
@@ -17,8 +17,9 @@ You can encode files from one format/codec to another using this facility.
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.
@@ -42,8 +43,9 @@ You can encode files from one format/codec to another using this facility.
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,8 +76,9 @@ You can encode files from one format/codec to another using this facility.
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.
+731 -209
View File
File diff suppressed because it is too large. Load diff
+91 -3
View File
@@ -71,6 +71,9 @@ To be able to simultaneously read and write from the IPC pipe, like on Linux,
it's necessary to write an external program that uses overlapped file I/O (or
some wrapper like .NET's NamedPipeClientStream.)
You can open the pipe in PuTTY as "serial" device. This is not very
comfortable, but gives a way to test interactively without having to write code.
Protocol
--------
@@ -133,9 +136,6 @@ Would generate this response:
If you don't specify a ``request_id``, command replies will set it to 0.
Commands may run asynchronously in the future, instead of blocking the socket
until a reply is sent.
All commands, replies, and events are separated from each other with a line
break character (``\n``).
@@ -147,6 +147,72 @@ with ``#`` and empty lines are ignored.
Currently, embedded 0 bytes terminate the current line, but you should not
rely on this.
Data flow
---------
Currently, the mpv-side IPC implementation does not service the socket while a
command is executed and the reply is written. It is for example not possible
that other events, that happened during the execution of the command, are
written to the socket before the reply is written.
This might change in the future. The only guarantee is that replies to IPC
messages are sent in sequence.
Also, since socket I/O is inherently asynchronous, it is possible that you read
unrelated event messages from the socket, before you read the reply to the
previous command you sent. In this case, these events were queued by the mpv
side before it read and started processing your command message.
If the mpv-side IPC implementation switches away from blocking writes and
blocking command execution, it may attempt to send events at any time.
You can also use asynchronous commands, which can return in any order, and
which do not block IPC protocol interaction at all while the command is
executed in the background.
Asynchronous commands
---------------------
Command can be run asynchronously. This behaves exactly as with normal command
execution, except that execution is not blocking. Other commands can be sent
while it's executing, and command completion can be arbitrarily reordered.
The ``async`` field controls this. If present, it must be a boolean. If missing,
``false`` is assumed.
For example, this initiates an asynchronous command:
::
{ "command": ["screenshot"], "request_id": 123, "async": true }
And this is the completion:
::
{"request_id":123,"error":"success","data":null}
By design, you will not get a confirmation that the command was started. If a
command is long running, sending the message will lead to any reply until much
later when the command finishes.
Some commands execute synchronously, but these will behave like asynchronous
commands that finished execution immediately.
Cancellation of asynchronous commands is available in the libmpv API, but has
not yet been implemented in the IPC protocol.
Commands with named arguments
-----------------------------
If the ``command`` field is a JSON object, named arguments are expected. This
is described in the C API ``mpv_command_node()`` documentation (the
``MPV_FORMAT_NODE_MAP`` case). In some cases, this may make commands more
readable, while some obscure commands basically require using named arguments.
Currently, only "proper" commands (as listed by `List of Input Commands`_)
support named arguments.
Commands
--------
@@ -297,3 +363,25 @@ Is equivalent to:
::
{ "objkey": "value\n" }
Alternative ways of starting clients
------------------------------------
You can create an anonymous IPC connection without having to set
``--input-ipc-server``. This is achieved through a mpv pseudo scripting backend
that starts processes.
You can put ``.run`` file extension in the mpv scripts directory in its config
directory (see the `FILES`_ section for details), or load them through other
means (see `Script location`_). These scripts are simply executed with the OS
native mechanism (as if you ran them in the shell). They must have a proper
shebang and have the executable bit set.
When executed, a socket (the IPC connection) is passed to them through file
descriptor inheritance. The file descriptor is indicated as the special command
line argument ``--mpv-ipc-fd=N``, where ``N`` is the numeric file descriptor.
The rest is the same as with a normal ``--input-ipc-server`` IPC connection. mpv
does not attempt to observe or other interact with the started script process.
This does not work in Windows yet.
+26 -12
View File
@@ -139,6 +139,8 @@ success, ``fn`` is called always a-sync, ``error`` is empty string on success.
``mp.get_script_name()``
``mp.get_script_directory()``
``mp.osd_message(text [,duration])``
``mp.get_wakeup_pipe()``
@@ -187,9 +189,11 @@ success, ``fn`` is called always a-sync, ``error`` is empty string on success.
``mp.utils.subprocess_detached(t)``
``mp.utils.get_env_list()``
``mp.utils.getpid()`` (LE)
``mp.add_hook(type, priority, fn)``
``mp.add_hook(type, priority, fn(hook))``
``mp.options.read_options(obj [, identifier [, on_update]])`` (types:
string/boolean/number)
@@ -300,19 +304,20 @@ do work. In general, this is for mpv modules and not a node.js replacement.
A ``.js`` file extension is always added to ``id``, e.g. ``require("./foo")``
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).
An id which starts with ``./`` or ``../`` is relative to the script or module
which ``require`` it. 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 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.
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 according
to ``mp.module_paths`` in normal array order, e.g. ``require("x")`` tries to
load ``x.js`` at one of the array paths, and id ``foo/x`` tries to load ``x.js``
inside dir ``foo`` at one of the paths.
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.
The ``mp.module_paths`` array is empty by default except for scripts which are
loaded as a directory where it contains one item - ``<directory>/modules/`` .
The array may be updated from a script (or using custom init - see below) which
will affect future calls to ``require`` for 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``
@@ -320,6 +325,15 @@ as the global object, you could do ``this.global = this;`` before ``require``.
Functions and variables declared at a module don't pollute the global object.
Custom initialization
---------------------
After mpv initializes the JavaScript environment for a script but before it
loads the script - it tries to run the file ``.init.js`` at the root of the mpv
configuration directory. Code at this file can update the environment further
for all scripts. E.g. if it contains ``mp.module_paths.push("/foo")`` then
``require`` at all scripts will search global module id's also at ``/foo``.
The event loop
--------------
+98 -137
View File
@@ -1,12 +1,7 @@
LUA SCRIPTING
=============
mpv can load Lua scripts. Scripts passed to the ``--script`` option, or found in
the ``scripts`` subdirectory of the mpv configuration directory (usually
``~/.config/mpv/scripts/``) will be loaded on program start. mpv also appends the
``scripts`` subdirectory to the end of Lua's path so you can import scripts from
there too. Since it's added to the end, don't name scripts you want to import
the same as Lua libraries because they will be overshadowed by them.
mpv can load Lua scripts. (See `Script location`_.)
mpv provides the built-in module ``mp``, which contains functions to send
commands to the mpv core and to retrieve information about playback state, user
@@ -30,6 +25,49 @@ A script which leaves fullscreen mode when the player is paused:
mp.observe_property("pause", "bool", on_pause_change)
Script location
---------------
Scripts can be passed to the ``--script`` option, and are automatically loaded
from the ``scripts`` subdirectory of the mpv configuration directory (usually
``~/.config/mpv/scripts/``).
A script can be a single file. The file extension is used to select the
scripting backend to use for it. For Lua, it is ``.lua``. If the extension is
not recognized, an error is printed. (If an error happens, the extension is
either mistyped, or the backend was not compiled into your mpv binary.)
Entries with ``.disable`` extension are always ignored.
If a script is a directory (either if a directory is passed to ``--script``,
or any sub-directories in the script directory, such as for example
``~/.config/mpv/scripts/something/``), then the directory represents a single
script. The player will try to load a file named ``main.x``, where ``x`` is
replaced with the file extension. For example, if ``main.lua`` exists, it is
loaded with the Lua scripting backend.
You must not put any other files or directories that start with ``main.`` into
the script's top level directory. If the script directory contains for example
both ``main.lua`` and ``main.js``, only one of them will be loaded (and which
one depends on mpv internals that may change any time). Likewise, if there is
for example ``main.foo``, your script will break as soon as mpv adds a backend
that uses the ``.foo`` file extension.
mpv also appends the top level directory of the script to the start of Lua's
package path so you can import scripts from there too. Be aware that this will
shadow Lua libraries that use the same package path. (Single file scripts do not
include mpv specific directory the Lua package path. This was silently changed
in mpv 0.32.0.)
Using a script directory is the recommended way to package a script that
consists of multiple source files, or requires other files (you can use
``mp.get_script_directory()`` to get the location and e.g. load data files).
Making a script a git repository, basically a repository which contains a
``main.lua``` file in the root directory, makes scripts easily updateable
(without the dangers of auto-updates). Another suggestion is to use git
submodules to share common files or libraries.
Details on the script initialization and lifecycle
--------------------------------------------------
@@ -127,12 +165,19 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``mp.command_native_async(table [,fn])``
Like ``mp.command_native()``, but the command is ran asynchronously (as far
as possible), and upon completion, fn is called. fn has two arguments:
``fn(success, result, error)``. ``success`` is always a Boolean and is true
if the command was successful, otherwise false. The second parameter is
the result value (can be nil) in case of success, nil otherwise (as returned
by ``mp.command_native()``). The third parameter is the error string in case
of an error, nil otherwise.
as possible), and upon completion, fn is called. fn has three arguments:
``fn(success, result, error)``:
``success``
Always a Boolean and is true if the command was successful,
otherwise false.
``result``
The result value (can be nil) in case of success, nil otherwise (as
returned by ``mp.command_native()``).
``error``
The error string in case of an error, nil otherwise.
Returns a table with undefined contents, which can be used as argument for
``mp.abort_async_command``.
@@ -256,21 +301,22 @@ The ``mp`` module is preloaded, although it can be loaded manually with
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).
``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.
``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_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).
``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``.
@@ -460,6 +506,11 @@ The ``mp`` module is preloaded, although it can be loaded manually with
The script ``/path/to/fooscript.lua`` becomes ``fooscript``.
``mp.get_script_directory()``
Return the directory if this is a script packaged as directory (see
`Script location`_ for a description). Return nothing if this is a single
file script.
``mp.osd_message(text [,duration])``
Show an OSD message on the screen. ``duration`` is in seconds, and is
optional (uses ``--osd-duration`` by default).
@@ -548,6 +599,7 @@ are useful only in special situations.
``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.
Returns the result of the ``osd-overlay`` command itself.
``remove()``
Remove the overlay from the screen. A ``update()`` call will add it
@@ -732,7 +784,7 @@ strictly part of the guaranteed API.
``utils.join_path(p1, p2)``
Return the concatenation of the 2 paths. Tries to be clever. For example,
if ```p2`` is an absolute path, p2 is returned without change.
if ``p2`` is an absolute path, ``p2`` is returned without change.
``utils.subprocess(t)``
Runs an external process and waits until it exits. Returns process status
@@ -774,6 +826,10 @@ strictly part of the guaranteed API.
Returns the process ID of the running mpv process. This can be used to identify
the calling mpv when launching (detached) subprocesses.
``utils.get_env_list()``
Returns the C environment as a list of strings. (Do not confuse this with
the Lua "environment", which is an unrelated concept.)
``utils.parse_json(str [, trail])``
Parses the given string argument as JSON, and returns it as a Lua table. On
error, returns ``nil, error``. (Currently, ``error`` is just a string
@@ -819,116 +875,7 @@ Example:
mp.register_event("file-loaded", my_fn)
List of events
--------------
``start-file``
Happens right before a new file is loaded. When you receive this, the
player is loading the file (or possibly already done with it).
``end-file``
Happens after a file was unloaded. Typically, the player will load the
next file right away, or quit if this was the last file.
The event has the ``reason`` field, which takes one of these values:
``eof``
The file has ended. This can (but doesn't have to) include
incomplete files or broken network connections under
circumstances.
``stop``
Playback was ended by a command.
``quit``
Playback was ended by sending the quit command.
``error``
An error happened. In this case, an ``error`` field is present with
the error string.
``redirect``
Happens with playlists and similar. Details see
``MPV_END_FILE_REASON_REDIRECT`` in the C API.
``unknown``
Unknown. Normally doesn't happen, unless the Lua API is out of sync
with the C API. (Likewise, it could happen that your script gets
reason strings that did not exist yet at the time your script was
written.)
``file-loaded``
Happens after a file was loaded and begins playback.
``seek``
Happens on seeking. (This might include cases when the player seeks
internally, even without user interaction. This includes e.g. segment
changes when playing ordered chapters Matroska files.)
``playback-restart``
Start of playback after seek or after file was loaded.
``idle``
Idle mode is entered. This happens when playback ended, and the player was
started with ``--idle`` or ``--force-window``. This mode is implicitly ended
when the ``start-file`` or ``shutdown`` events happen.
``tick``
Called after a video frame was displayed. This is a hack, and you should
avoid using it. Use timers instead and maybe watch pausing/unpausing events
to avoid wasting CPU when the player is paused.
``shutdown``
Sent when the player quits, and the script should terminate. Normally
handled automatically. See `Details on the script initialization and lifecycle`_.
``log-message``
Receives messages enabled with ``mp.enable_messages``. The message data
is contained in the table passed as first parameter to the event handler.
The table contains, in addition to the default event fields, the following
fields:
``prefix``
The module prefix, identifies the sender of the message. This is what
the terminal player puts in front of the message text when using the
``--v`` option, and is also what is used for ``--msg-level``.
``level``
The log level as string. See ``msg.log`` for possible log level names.
Note that later versions of mpv might add new levels or remove
(undocumented) existing ones.
``text``
The log message. The text will end with a newline character. Sometimes
it can contain multiple lines.
Keep in mind that these messages are meant to be hints for humans. You
should not parse them, and prefix/level/text of messages might change
any time.
``get-property-reply``
Undocumented (not useful for Lua scripts).
``set-property-reply``
Undocumented (not useful for Lua scripts).
``command-reply``
Undocumented (not useful for Lua scripts).
``client-message``
Undocumented (used internally).
``video-reconfig``
Happens on video output or filter reconfig.
``audio-reconfig``
Happens on audio output or filter reconfig.
The following events also happen, but are deprecated: ``tracks-changed``,
``track-switched``, ``pause``, ``unpause``, ``metadata-update``,
``chapter-change``. Use ``mp.observe_property()`` instead.
For the existing event types, see `List of events`_.
Extras
------
@@ -942,8 +889,22 @@ guarantee a stable interface.
their result (normally, the Lua scripting interface is asynchronous from
the point of view of the player core). ``priority`` is an arbitrary integer
that allows ordering among hooks of the same kind. Using the value 50 is
recommended as neutral default value. ``fn`` is the function that will be
called during execution of the hook.
recommended as neutral default value.
``fn(hook)`` is the function that will be called during execution of the
hook. The parameter passed to it (``hook``) is a Lua object that can control
further aspects about the currently invoked hook. It provides the following
methods:
``defer()``
Returning from the hook function should not automatically continue
the hook. Instead, the API user wants to call ``hook:cont()`` on its
own at a later point in time (before or after the function has
returned).
``cont()``
Continue the hook. Doesn't need to be called unless ``defer()`` was
called.
See `Hooks`_ for currently existing hooks and what they do - only the hook
list is interesting; handling hook execution is done by the Lua script
+346 -33
View File
@@ -159,6 +159,9 @@ L
Ctrl + and Ctrl -
Adjust audio delay (A/V sync) by +/- 0.1 seconds.
Shift+g and Shift+f
Adjust subtitle font size by +/- 10%.
u
Switch between applying no style overrides to SSA/ASS subtitles, and
overriding them almost completely with the normal subtitle style. See
@@ -314,7 +317,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.
@@ -324,9 +327,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
--------------------------------------------
@@ -421,15 +430,20 @@ additionally wrapped in the fixed-length syntax, e.g. ``%n%string_of_length_n``
Some mpv options interpret paths starting with ``~``. Currently, the prefix
``~~/`` expands to the mpv configuration directory (usually ``~/.config/mpv/``).
``~/`` expands to the user's home directory. (The trailing ``/`` is always
required.) There are the following paths as well:
required.) The following paths are currently recognized:
================ ===============================================================
Name Meaning
================ ===============================================================
``~~/`` mpv config dir (for example ``~/.config/mpv/``)
``~/`` user home directory root (similar to shell, ``$HOME``)
``~~home/`` same as ``~~/``
``~~global/`` the global config path, if available (not on win32)
``~~osxbundle/`` the OSX bundle resource path (OSX only)
``~~desktop/`` the path to the desktop (win32, OSX)
``~~exe_dir`` win32 only: the path to the directory containing the exe (for
config file purposes; ``$MPV_HOME`` overrides it)
``~~old_home`` do not use
================ ===============================================================
@@ -531,6 +545,13 @@ Suffix Meaning
Keys are unique within the list. If an already present key is set, the existing
key is removed before the new value is appended.
If you want to pass a value without interpreting it for escapes or ``,``, it is
recommended to use the ``-add`` variant. When using libmpv, prefer using
``MPV_FORMAT_NODE_MAP``; when using a scripting backend or the JSON IPC, use an
appropriate structured data type.
Prior to mpv 0.33, ``:`` was also recognized as separator by ``-set``.
Filter options
~~~~~~~~~~~~~~
@@ -596,7 +617,7 @@ setting them to *no*. Even suboptions can be specified in this way.
# Use GPU-accelerated video output by default.
vo=gpu
# Use quotes for text that can contain spaces:
status-msg="Time: ${time-pos}"
term-status-msg="Time: ${time-pos}"
Escaping spaces and special characters
--------------------------------------
@@ -682,11 +703,209 @@ or at runtime with the ``apply-profile <name>`` command.
# you can also include other profiles
profile=big-cache
Runtime profiles
----------------
Auto profiles
-------------
Profiles can be set at runtime with ``apply-profile`` command. Since this
operation is "destructive" (every item in a profile is simply set as an
option, overwriting the previous value), you can't just enable and disable
profiles again.
Some profiles are loaded automatically. The following example demonstrates this:
As a partial remedy, there is a way to make profiles save old option values
before overwriting them with the profile values, and then restoring the old
values at a later point using ``apply-profile <profile-name> restore``.
This can be enabled with the ``profile-restore`` option, which takes one of
the following options:
``default``
Does nothing, and nothing can be restored (default).
``copy``
When applying a profile, copy the old values of all profile options to a
backup before setting them from the profile. These options are reset to
their old values using the backup when restoring.
Every profile has its own list of backed up values. If the backup
already exists (e.g. if ``apply-profile name`` was called more than
once in a row), the existing backup is no changed. The restore operation
will remove the backup.
It's important to know that restoring does not "undo" setting an option,
but simply copies the old option value. Consider for example ``vf-add``,
appends an entry to ``vf``. This mechanism will simply copy the entire
``vf`` list, and does _not_ execute the inverse of ``vf-add`` (that
would be ``vf-remove``) on restoring.
Note that if a profile contains recursive profiles (via the ``profile``
option), the options in these recursive profiles are treated as if they
were part of this profile. The referenced profile's backup list is not
used when creating or using the backup. Restoring a profile does not
restore referenced profiles, only the options of referenced profiles (as
if they were part of the main profile).
``copy-equal``
Similar to ``copy``, but restore an option only if it has the same value
as the value effectively set by the profile. This tries to deal with
the situation when the user does not want the option to be reset after
interactively changing it.
.. admonition:: Example
::
[something]
profile-restore=copy-equal
vf-add=rotate=90
Then running these commands will result in behavior as commented:
::
set vf vflip
apply-profile something
vf-add=hflip
apply-profile something
# vf == vflip,rotate=90,hflip,rotate=90
apply-profile something restore
# vf == vflip
Conditional auto profiles
-------------------------
Profiles which have the ``profile-cond`` option set are applied automatically
if the associated condition matches (unless auto profiles are disabled). The
option takes a string, which is interpreted as Lua condition. If evaluating the
expression returns true, the profile is applied, if it returns false, it is
ignored. This Lua code execution is not sandboxed.
Any variables in condition expressions can reference properties. If an
identifier is not already defined by Lua or mpv, it is interpreted as property.
For example, ``pause`` would return the current pause status. If the variable
name contains any ``_`` characters, they are turned into ``-``. For example,
``playback_time`` would return the property ``playback-time``.
A more robust way to access properties is using ``p.property_name`` or
``get("property-name", default_value)``. The automatic variable to property
magic will break if a new identifier with the same name is introduced (for
example, if a function named ``pause()`` were added, ``pause`` would return a
function value instead of the value of the ``pause`` property).
Note that if a property is not available, it will return ``nil``, which can
cause errors if used in expressions. These are logged in verbose mode, and the
expression is considered to be false.
Whenever a property referenced by a profile condition changes, the condition
is re-evaluated. If the return value of the condition changes from false or
error to true, the profile is applied.
This mechanism tries to "unapply" profiles once the condition changes from true
to false. If you want to use this, you need to set ``profile-restore`` for the
profile. Another possibility it to create another profile with an inverse
condition to undo the other profile.
Recursive profiles can be used. But it is discouraged to reference other
conditional profiles in a conditional profile, since this can lead to tricky
and unintuitive behavior.
.. admonition:: Example
Make only HD video look funny:
::
[something]
profile-desc=HD video sucks
profile-cond=width >= 1280
hue=-50
If you want the profile to be reverted if the condition goes to false again,
you can set ``profile-restore``:
::
[something]
profile-desc=Mess up video when entering fullscreen
profile-cond=fullscreen
profile-restore=copy
vf-add=rotate=90
This appends the ``rotate`` filter to the video filter chain when entering
fullscreen. When leaving fullscreen, the ``vf`` option is set to the value
it had before entering fullscreen. Note that this would also remove any
other filters that were added during fullscreen mode by the user. Avoiding
this is trickier, and could for example be solved by adding a second profile
with an inverse condition and operation:
::
[something]
profile-cond=fullscreen
vf-add=@rot:rotate=90
[something-inv]
profile-cond=not fullscreen
vf-remove=@rot
.. warning::
Every time an involved property changes, the condition is evaluated again.
If your condition uses ``p.playback_time`` for example, the condition is
re-evaluated approximately on every video frame. This is probably slow.
This feature is managed by an internal Lua script. Conditions are executed as
Lua code within this script. Its environment contains at least the following
things:
``(function environment table)``
Every Lua function has an environment table. This is used for identifier
access. There is no named Lua symbol for it; it is implicit.
The environment does "magic" accesses to mpv properties. If an identifier
is not already defined in ``_G``, it retrieves the mpv property of the same
name. Any occurrences of ``_`` in the name are replaced with ``-`` before
reading the property. The returned value is as retrieved by
``mp.get_property_native(name)``. Internally, a cache of property values,
updated by observing the property is used instead, so properties that are
not observable will be stuck at the initial value forever.
If you want to access properties, that actually contain ``_`` in the name,
use ``get()`` (which does not perform transliteration).
Internally, the environment table has a ``__index`` meta method set, which
performs the access logic.
``p``
A "magic" table similar to the environment table. Unlike the latter, this
does not prefer accessing variables defined in ``_G`` - it always accesses
properties.
``get(name [, def])``
Read a property and return its value. If the property value is ``nil`` (e.g.
if the property does not exist), ``def`` is returned.
This is superficially similar to ``mp.get_property_native(name)``. An
important difference is that this accesses the property cache, and enables
the change detection logic (which is essential to the dynamic runtime
behavior of auto profiles). Also, it does not return an error value as
second return value.
The "magic" tables mentioned above use this function as backend. It does not
perform the ``_`` transliteration.
In addition, the same environment as in a blank mpv Lua script is present. For
example, ``math`` is defined and gives access to the Lua standard math library.
.. warning::
This feature is subject to change indefinitely. You might be forced to
adjust your profiles on mpv updates.
Legacy auto profiles
--------------------
Some profiles are loaded automatically using a legacy mechanism. The following
example demonstrates this:
.. admonition:: Auto profile loading
@@ -694,14 +913,15 @@ Some profiles are loaded automatically. The following example demonstrates this:
[extension.mkv]
profile-desc="profile for .mkv files"
vf=flip
vf=vflip
The profile name follows the schema ``type.name``, where type can be
``protocol`` for the input/output protocol in use (see ``--list-protocols``),
and ``extension`` for the extension of the path of the currently played file
(*not* the file format).
This feature is very limited, and there are no other auto profiles.
This feature is very limited, and is considered soft-deprecated. Use conditional
auto profiles.
Using mpv from other programs or scripts
========================================
@@ -780,7 +1000,7 @@ listed.
- ``AV:`` or ``V:`` (video only) or ``A:`` (audio only)
- The current time position in ``HH:MM:SS`` format (``playback-time`` property)
- The total file duration (absent if unknown) (``length`` property)
- The total file duration (absent if unknown) (``duration`` property)
- Playback speed, e.g. `` x2.0``. Only visible if the speed is not normal. This
is the user-requested speed, and not the actual speed (usually they should
be the same, unless playback is too slow). (``speed`` property.)
@@ -806,11 +1026,11 @@ listed.
- Dropped frames, e.g. ``Dropped: 4``. Shows up only if the count is not 0. Can
grow if the video framerate is higher than that of the display, or if video
rendering is too slow. May also be incremented on "hiccups" and when the video
frame couldn't be displayed on time. (``vo-drop-frame-count`` property.)
frame couldn't be displayed on time. (``frame-drop-count`` property.)
If the decoder drops frames, the number of decoder-dropped frames is appended
to the display as well, e.g.: ``Dropped: 4/34``. This happens only if
decoder frame dropping is enabled with the ``--framedrop`` options.
(``drop-frame-count`` property.)
(``decoder-frame-drop-count`` property.)
- Cache state, e.g. ``Cache: 2s/134KB``. Visible if the stream cache is enabled.
The first value shows the amount of video buffered in the demuxer in seconds,
the second value shows the estimated size of the buffered amount in kilobytes.
@@ -889,7 +1109,7 @@ PROTOCOLS
``smb://PATH``
Play a path from Samba share.
Play a path from Samba share. (Requires FFmpeg support.)
``bd://[title][/device]`` ``--bluray-device=PATH``
@@ -984,6 +1204,34 @@ PROTOCOLS
Stitch together parts of multiple files and play them.
``slice://start[-end]@URL``
Read a slice of a stream.
``start`` and ``end`` represent a byte range and accept
suffixes such as ``KiB`` and ``MiB``. ``end`` is optional.
if ``end`` starts with ``+``, it is considered as offset from ``start``.
Only works with seekable streams.
Examples::
mpv slice://1g-2g@cap.ts
This starts reading from cap.ts after seeking 1 GiB, then
reads until reaching 2 GiB or end of file.
mpv slice://1g-+2g@cap.ts
This starts reading from cap.ts after seeking 1 GiB, then
reads until reaching 3 GiB or end of file.
mpv slice://100m@appending://cap.ts
This starts reading from cap.ts after seeking 100MiB, then
reads until end of file.
``null://``
Simulate an empty file. If opened for writing, it will discard all data.
@@ -1016,11 +1264,10 @@ Currently this happens only in the following cases:
- if you manually use ``--player-operation-mode=pseudo-gui`` on the command line
This mode applies options from the builtin profile ``builtin-pseudo-gui``, but
only if these haven't been set in the user's config file or on the command line.
Also, for compatibility with the old pseudo-gui behavior, the options in the
``pseudo-gui`` profile are applied unconditionally. In addition, the profile
makes sure to enable the pseudo-GUI mode, so that ``--profile=pseudo-gui``
works like in older mpv releases. The profiles are currently defined as follows:
only if these haven't been set in the user's config file or on the command line,
which is the main difference to using ``--profile=builtin-pseudo-gui``.
The profile is currently defined as follows:
::
@@ -1029,6 +1276,14 @@ works like in older mpv releases. The profiles are currently defined as follows:
force-window=yes
idle=once
screenshot-directory=~~desktop/
The ``pseudo-gui`` profile exists for compatibility. The options in the
``pseudo-gui`` profile are applied unconditionally. In addition, the profile
makes sure to enable the pseudo-GUI mode, so that ``--profile=pseudo-gui``
works like in older mpv releases:
::
[pseudo-gui]
player-operation-mode=pseudo-gui
@@ -1039,6 +1294,50 @@ works like in older mpv releases. The profiles are currently defined as follows:
change, and not apply your additional settings, and/or use a different
profile name.
Linux desktop issues
====================
This subsection describes common problems on the Linux desktop. None of these
problems exist on systems like Windows or OSX.
Disabling Screensaver
---------------------
By default, mpv tries to disable the OS screensaver during playback (only if
a VO using the OS GUI API is active). ``--stop-screensaver=no`` disables this.
A common problem is that Linux desktop environments ignore the standard
screensaver APIs on which mpv relies. In particular, mpv uses the Screen Saver
extension (XSS) on X11, and the idle-inhibit on Wayland.
GNOME is one of the worst offenders, and ignores even the now widely supported
idle-inhibit protocol. (This is either due to a combination of malice and
incompetence, but since implementing this protocol would only take a few lines
of code, it is most likely the former. You will also notice how GNOME advocates
react offended whenever their sabotage is pointed out, which indicates either
hypocrisy, or even worse ignorance.)
Such incompatible desktop environments (i.e. which ignore standards) typically
require using a DBus API. This is ridiculous in several ways. The immediate
practical problem is that it would require adding a quite unwieldy dependency
for a DBus library, somehow integrating its mainloop into mpv, and other
generally unacceptable things.
However, since mpv does not officially support GNOME, this is not much of a
problem. If you are one of those miserable users who want to use mpv on GNOME,
report a bug on the GNOME issue tracker:
https://gitlab.gnome.org/groups/GNOME/-/issues
Alternatively, you may be able to write a Lua script that calls the
``xdg-screensaver`` command line program. (By the way, this a command line
program is an utterly horrible kludge that tries to identify your DE, and then
tries to send the correct DBus command via a DBus CLI tool.) If you find the
idea of having to write a script just so your screensaver doesn't kick in
ridiculous, do not use GNOME, or use GNOME video software instead of mpv (good
luck).
Before mpv 0.33.0, the X11 backend ran ``xdg-screensaver reset`` in 10 second
intervals when not paused. This hack was removed in 0.33.0.
.. include:: options.rst
@@ -1083,10 +1382,6 @@ behavior of mpv.
``$HOME/.mpv`` is always added to the list of config search paths with a
lower priority.
``XDG_CONFIG_DIRS``
If set, XDG-style system configuration directories are used. Otherwise,
the UNIX convention (``PREFIX/etc/mpv/``) is used.
``MPV_HOME``
Directory where mpv looks for user settings. Overrides ``HOME``, and mpv
will try to load the config file as ``$MPV_HOME/mpv.conf``.
@@ -1211,6 +1506,28 @@ For Windows-specifics, see `FILES ON WINDOWS`_ section.
in default configuration will use ``/usr/local/etc/mpv/`` as config
directory, while most Linux distributions will set it to ``/etc/mpv/``).
``~/.config/mpv``
The standard configuration directory. This can be overridden by environment
variables, in ascending order:
:1: If ``$XDG_CONFIG_HOME`` is set, then the derived configuration directory
will be ``$XDG_CONFIG_HOME/mpv``.
:2: If ``$MPV_HOME`` is set, then the derived configuration directory will be
``$MPV_HOME``.
If this directory, nor the original configuration directory (see below) do
not exist, mpv tries to create this directory automatically.
``~/.mpv/``
The original (pre 0.5.0) configuration directory. It will continue to be
read if present.
If both this directory and the standard configuration directory are
present, configuration will be read from both with the standard
configuration directory content taking precedence. However, you should
fully migrate to the standard directory and a warning will be shown in
this situation.
``~/.config/mpv/mpv.conf``
mpv user settings (see `CONFIGURATION FILES`_ section)
@@ -1236,9 +1553,11 @@ 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.
The ``--load-scripts=no`` option disables loading these files.
See `Script location`_ for details.
``~/.config/mpv/watch_later/``
Contains temporary config files needed for resuming playback of files with
@@ -1260,12 +1579,6 @@ For Windows-specifics, see `FILES ON WINDOWS`_ section.
Other files in this directory are specific to the corresponding scripts
as well, and the mpv core doesn't touch them.
Note that the environment variables ``$XDG_CONFIG_HOME`` and ``$MPV_HOME`` can
override the standard directory ``~/.config/mpv/``.
Also, the old config location at ``~/.mpv/`` is still read, and if the XDG
variant does not exist, will still be preferred.
FILES ON WINDOWS
================
+637 -165
View File
File diff suppressed because it is too large. Load diff
+8 -6
View File
@@ -179,11 +179,12 @@ Configurable Options
``seekbarkeyframes``
Default: yes
Controls the mode used to seek when dragging the seekbar. By default,
keyframes are used. If set to false, exact seeking on mouse drags
will be used instead. Keyframes are preferred, but exact seeks may be
useful in cases where keyframes cannot be found. Note that using exact
seeks can potentially make mouse dragging much slower.
Controls the mode used to seek when dragging the seekbar (default: true). If
set to true, default seeking mode is used (usually keyframes, but player
defaults and heuristics can change it to exact). If set to false, exact
seeking on mouse drags will be used instead. Keyframes are preferred, but
exact seeks may be useful in cases where keyframes cannot be found. Note
that using exact seeks can potentially make mouse dragging much slower.
``seekrangestyle``
Default: inverted
@@ -328,7 +329,8 @@ Configurable Options
within the areas not covered by the osc (``yes``). If this option is set,
the osc may overwrite the ``--video-margin-ratio-*`` options, even if the
user has set them. (It will not overwrite them if all of them are set to
default values.)
default values.) Additionally, ``visibility`` must be set to ``always``.
Otherwise, this option does nothing.
Currently, this is supported for the ``bottombar`` and ``topbar`` layout
only. The other layouts do not change if this option is set. Separately,
+57 -1
View File
@@ -22,8 +22,16 @@ stats:
==== ==================
1 Show usual stats
2 Show frame timings
2 Show frame timings (scroll)
3 Input cache stats
4 Internal stuff (scroll)
==== ==================
On pages which support scroll, these key bindings are also active:
==== ==================
UP Scroll one line up
DOWN Scroll one line down
==== ==================
Font
@@ -56,9 +64,20 @@ Configurable Options
Default: 2
``key_page_3``
Default: 3
``key_page_4``
Default: 4
Key bindings for page switching while stats are displayed.
``key_scroll_up``
Default: UP
``key_scroll_down``
Default: DOWN
``scroll_lines``
Default: 1
Scroll key bindings and number of lines to scroll on pages which support it.
``duration``
Default: 4
@@ -163,3 +182,40 @@ Using ``input.conf``, it is also possible to directly display a certain page::
i script-binding stats/display-page-1
e script-binding stats/display-page-2
Internal stuff page
~~~~~~~~~~~~~~~~~~~
Most entries shown on this page have rather vague meaning. Likely none of this
is useful for you. Don't attempt to use it. Forget its existence.
Selecting this for the first time will start collecting some internal
performance data. That means performance will be slightly lower than normal for
the rest of the time the player is running (even if the stats page is closed).
Note that the stats page itself uses a lot of CPU and even GPU resources, and
may have a heavy impact on performance.
The displayed information is accumulated over the redraw delay (shown as
``poll-time`` field).
This adds entries for each Lua script. If there are too many scripts running,
parts of the list will simply be out of the screen, but it can be scrolled.
If the underlying platform does not support pthread per thread times, the
displayed times will be 0 or something random (I suspect that at time of this
writing, only Linux provides the correct via pthread APIs for per thread times).
Most entries are added lazily and only during data collection, which is why
entries may pop up randomly after some time. It's also why the memory usage
entries for scripts that have been inactive since the start of data collection
are missing.
Memory usage is approximate and does not reflect internal fragmentation.
JS scripts memory reporting is disabled by default because collecting the data
at the JS side has an overhead. It can be enabled by exporting the env var
``MPV_LEAK_REPORT=1`` before starting mpv, and will increase JS memory usage.
If entries have ``/time`` and ``/cpu`` variants, the former gives the real time
(monotonic clock), while the latter the thread CPU time (only if the
corresponding pthread API works and is supported).
+16
View File
@@ -321,6 +321,10 @@ Available mpv-only filters are:
Set the rotation the video is assumed to be encoded with in degrees.
The special value ``-1`` uses the input format.
``<w>``, ``<h>``
If not 0, perform conversion to the given size. Ignored if
``convert=yes`` is not set.
``<dw>``, ``<dh>``
Set the display size. Note that setting the display size such that
the video is scaled in both directions instead of just changing the
@@ -331,6 +335,18 @@ Available mpv-only filters are:
but values such as ``[16:9]`` can be passed too (``[...]`` for quoting
to prevent the option parser from interpreting the ``:`` character).
``<force-scaler=auto|zimg|sws>``
Force a specific scaler backend, if applicable. This is a debug option
and could go away any time.
``<alpha=auto|straight|premul>``
Set the kind of alpha the video uses. Undefined effect if the image
format has no alpha channel (could be ignored or cause an error,
depending on how mpv internals evolve). Setting this may or may not
cause downstream image processing to treat alpha differently, depending
on support. With ``convert`` and zimg used, this will convert the alpha.
libswscale and other FFmpeg components completely ignore this.
``lavfi=graph[:sws-flags[:o=opts]]``
Filter video using FFmpeg's libavfilter.
+104 -51
View File
@@ -99,29 +99,6 @@ Available video output drivers are:
Apply a noise reduction algorithm to the video (default: 0; no noise
reduction).
``--vo-vdpau-deint=<-4-4>``
(Deprecated. See note about ``vdpaupp``.)
Select deinterlacing mode (default: 0). In older versions (as well as
MPlayer/mplayer2) you could use this option to enable deinterlacing.
This doesn't work anymore, and deinterlacing is enabled with either
the ``d`` key (by default mapped to the command ``cycle deinterlace``),
or the ``--deinterlace`` option. Also, to select the default deint mode,
you should use something like ``--vf-defaults=vdpaupp:deint-mode=temporal``
instead of this sub-option.
0
Pick the ``vdpaupp`` video filter default, which corresponds to 3.
1
Show only first field.
2
Bob deinterlacing.
3
Motion-adaptive temporal deinterlacing. May lead to A/V desync
with slow video hardware and/or high resolution.
4
Motion-adaptive temporal deinterlacing with edge-guided spatial
interpolation. Needs fast video hardware.
``--vo-vdpau-chroma-deint``
(Deprecated. See note about ``vdpaupp``.)
@@ -204,33 +181,8 @@ Available video output drivers are:
.. note:: This driver is for compatibility with systems that don't provide
proper OpenGL drivers, and where ANGLE does not perform well.
.. note:: Before to 0.21.0, ``direct3d_shaders`` and ``direct3d`` were
different, with ``direct3d`` not using shader by default. Now
both use shaders by default, and ``direct3d_shaders`` is a
deprecated alias. Use the ``--vo-direct3d-prefer-stretchrect``
or the ``--vo-direct3d-disable-shaders`` options to get the old
behavior of ``direct3d``.
The following global options are supported by this video output:
``--vo-direct3d-prefer-stretchrect``
Use ``IDirect3DDevice9::StretchRect`` over other methods if possible.
``--vo-direct3d-disable-stretchrect``
Never render the video using ``IDirect3DDevice9::StretchRect``.
``--vo-direct3d-disable-textures``
Never render the video using D3D texture rendering. Rendering with
textures + shader will still be allowed. Add ``disable-shaders`` to
completely disable video rendering with textures.
``--vo-direct3d-disable-shaders``
Never use shaders when rendering video.
``--vo-direct3d-only-8bit``
Never render YUV video with more than 8 bits per component.
Using this flag will force software conversion to 8-bit.
``--vo-direct3d-disable-texture-align``
Normally texture sizes are always aligned to 16. With this option
enabled, the video texture will always have exactly the same size as
@@ -298,7 +250,7 @@ Available video output drivers are:
the hardware decoder APIs.
``gpu`` makes use of FBOs by default. Sometimes you can achieve better
quality or performance by changing the ``--gpu-fbo-format`` option to
quality or performance by changing the ``--fbo-format`` option to
``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include Mesa/Intel not
accepting ``rgb16``, Mesa sometimes not being compiled with float texture
support, and some OS X setups being very slow with ``rgb16`` but fast
@@ -383,12 +335,17 @@ Available video output drivers are:
``tct``
Color Unicode art video output driver that works on a text console.
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.
By default depends on support of true color by modern terminals to display
the images at full color range, but 256-colors outout is also supported (see
below). 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.
Note: the TCT image output is not synchronized with other terminal output
from mpv, which can lead to broken images. The options ``--no-terminal`` or
``--really-quiet`` can help with that.
``--vo-tct-algo=<algo>``
Select how to write the pixels to the terminal.
@@ -406,6 +363,102 @@ Available video output drivers are:
``--vo-tct-256=<yes|no>`` (default: no)
Use 256 colors - for terminals which don't support true color.
``sixel``
Graphical output for the terminal, using sixels. Tested with ``mlterm`` and
``xterm``.
Note: the Sixel image output is not synchronized with other terminal output
from mpv, which can lead to broken images. The option ``--really-quiet``
can help with that, and is recommended.
You may need to use ``--profile=sw-fast`` to get decent performance.
Note: at the time of writing, ``xterm`` does not enable sixel by default -
launching it as ``xterm -ti 340`` is one way to enable it. Also, ``xterm``
does not display images bigger than 1000x1000 pixels by default.
To render and align sixel images correctly, mpv needs to know the terminal
size both in cells and in pixels. By default it tries to use values which
the terminal reports, however, due to differences between terminals this is
an error-prone process which cannot be automated with certainty - some
terminals report the size in pixels including the padding - e.g. ``xterm``,
while others report the actual usable number of pixels - like ``mlterm``.
Additionally, they may behave differently when maximized or in fullscreen,
and mpv cannot detect this state using standard methods.
Sixel size and alignment options:
``--vo-sixel-cols=<columns>``, ``--vo-sixel-rows=<rows>`` (default: 0)
Specify the terminal size in character cells, otherwise (0) read it
from the terminal, or fall back to 80x25. Note that mpv doesn't use the
the last row with sixel because this seems to result in scrolling.
``--vo-sixel-width=<width>``, ``--vo-sixel-height=<height>`` (default: 0)
Specify the available size in pixels, otherwise (0) read it from the
terminal, or fall back to 320x240. Other than excluding the last line,
the height is also further rounded down to a multiple of 6 (sixel unit
height) to avoid overflowing below the designated size.
``--vo-sixel-left=<col>``, ``--vo-sixel-top=<row>`` (default: 0)
Specify the position in character cells where the image starts (1 is
the first column or row). If 0 (default) then try to automatically
determine it according to the other values and the image aspect ratio
and zoom.
``--vo-sixel-pad-x=<pad_x>``, ``--vo-sixel-pad-y=<pad_y>`` (default: -1)
Used only when mpv reads the size in pixels from the terminal.
Specify the number of padding pixels (on one side) which are included
at the size which the terminal reports. If -1 (default) then the number
of pixels is rounded down to a multiple of number of cells (per axis),
to take into account padding at the report - this only works correctly
when the overall padding per axis is smaller than the number of cells.
Sixel image quality options:
``--vo-sixel-dither=<algo>``
Selects the dither algorithm which libsixel should apply.
Can be one of the below list as per libsixel's documentation.
auto
Choose diffuse type automatically
none
Don't diffuse
atkinson
Diffuse with Bill Atkinson's method. (Default)
fs
Diffuse with Floyd-Steinberg method
jajuni
Diffuse with Jarvis, Judice & Ninke method
stucki
Diffuse with Stucki's method
burkes
Diffuse with Burkes' method
arithmetic
Positionally stable arithmetic dither
xor
Positionally stable arithmetic xor based dither
``--vo-sixel-fixedpalette=<yes|no>`` (default: yes)
Use libsixel's built-in static palette using the XTERM256 profile
for dither. Fixed palette uses 256 colors for dithering. Note that
using ``no`` (at the time of writing) will slow down ``xterm``.
``--vo-sixel-reqcolors=<colors>`` (default: 256)
Set up libsixel to use required number of colors for dynamic palette.
This value depends on the terminal emulator as well. Xterm supports
256 colors. Can set this to a lower value for faster performance.
This option has no effect if fixed palette is used.
``--vo-sixel-threshold=<threshold>`` (default: -1)
When using a dynamic palette, defines the threshold to change the
palette - as percentage of the number of colors, e.g. 20 will change
the palette when the number of colors changed by 20%. It's a simple
measure to reduce the number of palette changes, because it can be slow
in some terminals (``xterm``), however, it seems that in ``mlterm`` it
causes image corruption. The default (-1) will change the palette
on every frame and will have better quality, and no corruption in
``mlterm``.
``image``
Output each frame into an image file in the current directory. Each file
takes the frame number padded with leading zeros as name.
+1 -1
View File
@@ -113,7 +113,7 @@ options/options.h, options/options.c
link them to the option parser. For example, an entry like this may be
typical:
OPT_SUBSTRUCT("", demux_opts, demux_conf, 0),
{"", OPT_SUBSTRUCT(demux_opts, demux_conf)},
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
-1
View File
@@ -49,7 +49,6 @@ Releases can be found on the [release list][releases].
output methods can help (such as `--vo=xv` on Linux), but this use is not
recommended or supported.
## Downloads
+103 -52
View File
@@ -1,8 +1,12 @@
Release 0.31.0
Release 0.33.0
==============
This release requires FFmpeg 4.0 or newer.
For packagers: Note that mpv's build system is only supported on Python 3.
If you use the `bootstrap.py` script it will take care of this, otherwise you
need to explicitly invoke the build system using `python3 waf`.
Features
--------
@@ -10,32 +14,53 @@ Features
Added
~~~~~
- vo_gpu/d3d11: allow configurable swapchain color space for native HDR output
- player: add mechanisms for better logging as preperation for console.lua
- audio: add ao_audiotrack for Android
- input: introduce a pseudo key name that grabs all text input
- wayland: add grab zone for resizing window with mouse
- osc: implement pseudo client side decorations via OSC
- vf_gpu: add video filter using vo_gpu's renderer
- added console.lua: interactive REPL for input commands
- osc: display Santa hat for idle logo in December
- vd_lavc: add option to autoselect known good hwdec implementations
- mac: replace old event tap for media key support with MediaPlayer
- scripting: load scripts from directories
- mac: activate logging when started from the bundle
- ytdl_hook.lua: delay load subtitles
- sub: add an option to filter subtitles by regex
- scripting: add a way to run subprocesses as "scripts"
- command: implement asynchronous commands and support for named arguments
- player: add optional separate video decoding thread
- vo_gpu: d3d11: add support for exclusive fullscreen
- w32_common: Support HiDPI on Windows
- vo_x11: add 10 bit support
- vo_gpu: add BT.2390 tone-mapping
- client API: add software rendering API
- audio: add scaletempo2 filter based on chromium
- auto_profiles: add this script
- stream: Implement slice:// for reading slices of streams
- player: add automatic loading of external cover art files
- vo_sixel: implement terminal video output using sixel
Changed
~~~~~~~
- input: disable gamepad code by default
- vo_gpu: allow vdpau usage under EGL
- stream, demux: redo origin policy
- sws_utils: use zimg by default if available
- build: pick up Lua 5.2 by default (preferred over 5.1)
- build: disable RPI vendor blob auto-detection in favor of open-source stack
- build: make C11 atomics mandatory
- build: make libass non-optional
- player: stricter filename matching for external subtitle auto-loading
- lua: support Unicode paths in script loading and IO library
- vo_direct3d: rip out texture video rendering path and dumb down OSD rendering
- audio: rewrite internal audio handling and AO API
- build: disable GLX by default
Removed
~~~~~~~
- mac: remove Apple Remote support
- client API: deprecate tick event
- stream_libarchive: disable tar support due to bugs
- Remove remains of Libav compatibility
- stream_smb: remove due to lack of thread safety and the abundance
of alternatives, FFmpeg still includes SMB support
- command: remove legacy hook API (has been deprecated for a long time)
- client API: remove deprecated qthelper.hpp header
- removed audio outputs: sndio, rsound, oss
- x11: remove xdg-screensaver invocations that supported dbus based idle inhibit
- client API: deactivate the opengl_cb API
- build system: drop Python 2 compatbility
Options and Commands
@@ -44,64 +69,90 @@ Options and Commands
Added
~~~~~
- vo_gpu/d3d11: add --d3d11-output-csp for configuring swap chain color space
- command: add command-list property
- command, input: add input-bindings property
- command: add --window-maximized and make --window-minimized settable
- command: add property returning hidpi scale
- command, lua: add a way to share data between scripts
- client API, lua: add new API for setting OSD overlays
- demux: add option to disable cache "sharing" between back and forward buffers
- player: add ab-loop-count option/property
- ytdl_hook: add a way to use ytdl's default formats
- ytdl_hook: add all_formats option that loads all formats that were found
- demux_mkv: document probe-start-time option and enable it by default
- command: extend osd-overlay command with bounds reporting
- player: a number of new playlist contol commands/properties
- ipc: add --input-ipc-client option
- options: add option to control display-sync factor
- vo_gpu: add better gamut clipping option
- vo_gpu: vulkan: add ability to disable events
- x11: add option to make window appear on a specific workspace
- wayland: expose wayland-app-id as a user option
- player: add --subs-with-matching-audio option
- command: add read-only focused property
- screenshot: option to use software rendering for screenshots
- command: add delete-watch-later-config
- command: new property mouse-pos with current position and hover state
Changed
~~~~~~~
- add a builtin "sw-fast" profile, which restores performance settings
for software video conversion. These were switched to higher quality.
This affects video outputs like vo_x11 and vo_drm, and screenshots.
- options: make --show-profile without parameters list all profiles
- wayland: support for --hidpi-window-scale option
- stream_lavf: set --network-timeout to 60 seconds by default
- x11: scale window-scale by DPI
- options: remove deprecation warning for "-foo bar" syntax
- player: make audio hr-seek default
- ad_lavc: disable decoder downmix by default
- command: support save-position-on-quit for "stop" command too
- command: extend subprocess command
- options: do not accept ":" as separator anymore in key/value lists
Deprecated
~~~~~~~~~~
- deprecate --input-file
- deprecate --video-sync=display-adrop
- deprecate all input section commands
- deprecate --display-fps, replaced by --override-display-fps
- demux: deprecate --cache-secs
Removed
~~~~~~~
- remove deprecated --playlist-pos alias
- wayland: remove wayland-frame-wait-offset option
- input: remove deprecated --input-file option
- vo_vdpau: remove deprecated/inactive --vo-vdpau-deint option
Fixes and Minor Enhancements
----------------------------
- vo_drm, vo_x11: allow use of zimg
- vo_sdl: Support mouse wheel input, Improve mouse button input
- video: fix track switching work for external images
- vo_gpu: fix infinite scaler reinit spam
- f_output_chain: fix possible crash when changing filters
- vo_gpu: opengl: add hack for ancient Mesa/GLX
- demux_lavf: export demuxer_id for more formats which have it
- lua: make later key bindings always have higher priority
- drm_common: fix display FPS estimation for interlaced modes
- vo_drm: fix incorrect pixel format possibly being picked for 30-bit
- zsh completion: fix pcre usage to really be optional
- options: increase consistency between list options and document them
- osc: reduce unnecesary CPU usage by using property notifications
- options: stop hiding deprecated options from --help output
- lua, js: add mp.get_script_directory() function
- lua: fix security relevant loading order issue with scripts
- player: make screenshot each-frame mode more accurate
- bash completion: complete ao/af/vo/vf options
- zimg: add alpha support
- wayland: make resizing better
- edl: add mechanism for delay loading streams
- stream_file: fix caching-related performance regression on CIFS
- cocoa-cb: fix crashes and issues with UI updates
- sub, demux: improve behavior with negative subtitle delay/muxed subs
- demux: make seek ranges work for static images + audio
- cocoa-cb: support maximize/minimize on startup
- umpv: change from legacy FIFO to socket
- stats: move input speed to cache page, make it a graph
- stats: add fourth page with performance graphs
- command: print edition title to OSD when cycling
- zimg: add support for big endian input and output
- demux_mkv: add png intra support
- build: detect VT_GETMODE on FreeBSD and DragonFly
- win32: use windows 10 native virtual-terminal if available
- vo_gpu: enable frame caching for still frames
- command: add property to return text subtitles in ASS
- vo_gpu: ra_pl: add timers support
- build: allow vo_wlshm on more Wayland platforms (e.g. FreeBSD)
- zimg: add slice threading and use it by default
- command: add a way to access properties of a current track
- vo_gpu: EGL: fix transparency on X11/EGL/Mesa
- vd_lavc: add AV1 to the default allowed hwdec codec list
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.30.0..v0.31.0`
A complete changelog can be seen by running `git log v0.32.0..v0.33.0`
in the git repository or by visiting either
https://github.com/mpv-player/mpv/compare/v0.30.0...v0.31.0 or
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.30.0..v0.31.0
https://github.com/mpv-player/mpv/compare/v0.32.0...v0.33.0 or
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.32.0..v0.33.0
-1
View File
@@ -16,7 +16,6 @@ export PYTHON=/usr/bin/python3
--enable-jpeg \
--enable-lcms2 \
--enable-libarchive \
--enable-libass \
--enable-lua \
--enable-rubberband \
--enable-shaderc \
+4 -9
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Convert the contents of a file into a C string constant.
# Note that the compiler will implicitly add an extra 0 byte at the end
@@ -22,26 +22,21 @@
# License along with mpv. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import unicode_literals
import sys
# Indexing a byte string yields int on Python 3.x, and a str on Python 2.x
def pord(c):
return ord(c) if type(c) == str else c
def file2string(infilename, infile, outfile):
outfile.write("// Generated from %s\n\n" % infilename)
conv = ['\\' + ("%03o" % c) for c in range(256)]
conv = ["\\%03o" % c for c in range(256)]
safe_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" \
"0123456789!#%&'()*+,-./:;<=>?[]^_{|}~ "
"0123456789!#%&'()*+,-./:;<=>[]^_{|}~ "
for c in safe_chars:
conv[ord(c)] = c
for c, esc in ("\nn", "\tt", r"\\", '""'):
conv[ord(c)] = '\\' + esc
for line in infile:
outfile.write('"' + ''.join(conv[pord(c)] for c in line) + '"\n')
outfile.write('"' + ''.join(conv[c] for c in line) + '"\n')
if __name__ == "__main__":
with open(sys.argv[1], 'rb') as infile:
+303 -95
View File
@@ -1,114 +1,322 @@
-- This script uses the lavfi cropdetect filter to automatically
-- insert a crop filter with appropriate parameters for the currently
-- playing video.
--
-- It registers the key-binding "C" (shift+c), which when pressed,
-- inserts the filter vf=lavfi=cropdetect. After 1 second, it then
-- inserts the filter vf=crop=w:h:x:y, where w,h,x,y are determined
-- from the vf-metadata gathered by cropdetect. The cropdetect filter
-- is removed immediately after the crop filter is inserted as it is
-- no longer needed.
--
-- If the "C" key is pressed again, the crop filter is removed
-- restoring playback to its original state.
--
-- Since the crop parameters are determined from the 1 second of video
-- between inserting the cropdetect and crop filters, the "C" key
-- should be pressed at a position in the video where the crop region
-- is unambiguous (i.e., not a black frame, black background title
-- card, or dark scene).
--
-- The default delay between insertion of the cropdetect and
-- crop filters may be overridden by adding
--
-- --script-opts=autocrop.detect_seconds=<number of seconds>
--
-- to mpv's arguments. This may be desirable to allow cropdetect more
-- time to collect data.
--[[
This script uses the lavfi cropdetect filter to automatically
insert a crop filter with appropriate parameters for the
currently playing video.
It will automatically crop the video, when playback starts.
Also It registers the key-binding "C" (shift+c). You can manually
crop the video by pressing the "C" (shift+c) key.
If the "C" key is pressed again, the crop filter is removed
restoring playback to its original state.
The workflow is as follows: First, it inserts the filter
vf=lavfi=cropdetect. After <detect_seconds> (default is 1)
seconds, it then inserts the filter vf=crop=w:h:x:y, where
w,h,x,y are determined from the vf-metadata gathered by
cropdetect. The cropdetect filter is removed immediately after
the crop filter is inserted as it is no longer needed.
Since the crop parameters are determined from the 1 second of
video between inserting the cropdetect and crop filters, the "C"
key should be pressed at a position in the video where the crop
region is unambiguous (i.e., not a black frame, black background
title card, or dark scene).
The default options can be overridden by adding
script-opts-append=autocrop-<parameter>=<value> into mpv.conf
List of available parameters (For default values, see <options>):
auto: bool - Whether to automatically apply crop at the start of
playback. If you don't want to crop automatically, set it to
false or add "script-opts-append=autocrop-auto=no" into
mpv.conf.
auto_delay: seconds - Delay before starting crop in auto mode.
You can try to increase this value to avoid dark scene or
fade in at beginning. Automatic cropping will not occur if
the value is larger than the remaining playback time.
detect_limit: number[0-255] - Black threshold for cropdetect.
Smaller values will generally result in less cropping.
See limit of https://ffmpeg.org/ffmpeg-filters.html#cropdetect
detect_round: number[2^n] - The value which the width/height
should be divisible by. Smaller values ​​have better detection
accuracy. If you have problems with other filters,
you can try to set it to 4 or 16.
See round of https://ffmpeg.org/ffmpeg-filters.html#cropdetect
detect_min_ratio: number[0.0-1.0] - The ratio of the minimum clip
size to the original. If the picture is over cropped or under
cropped, try adjusting this value.
detect_seconds: seconds - How long to gather cropdetect data.
Increasing this may be desirable to allow cropdetect more
time to collect data.
--]]
require "mp.msg"
require 'mp.options'
script_name = mp.get_script_name()
cropdetect_label = string.format("%s-cropdetect", script_name)
crop_label = string.format("%s-crop", script_name)
-- number of seconds to gather cropdetect data
detect_seconds = tonumber(mp.get_opt(string.format("%s.detect_seconds", script_name)))
if not detect_seconds then
local options = {
auto = true,
auto_delay = 4,
detect_limit = "24/255",
detect_round = 2,
detect_min_ratio = 0.5,
detect_seconds = 1
end
}
read_options(options)
function del_filter_if_present(label)
-- necessary because mp.command('vf del @label:filter') raises an
-- error if the filter doesn't exist
local vfs = mp.get_property_native("vf")
for i,vf in pairs(vfs) do
if vf["label"] == label then
table.remove(vfs, i)
mp.set_property_native("vf", vfs)
local label_prefix = mp.get_script_name()
local labels = {
crop = string.format("%s-crop", label_prefix),
cropdetect = string.format("%s-cropdetect", label_prefix)
}
timers = {
auto_delay = nil,
detect_crop = nil
}
function is_filter_present(label)
local filters = mp.get_property_native("vf")
for index, filter in pairs(filters) do
if filter["label"] == label then
return true
end
end
return false
end
function autocrop_start()
-- exit if cropdetection is already in progress
if timer then
mp.msg.warn("already cropdetecting!")
return
end
function is_enough_time(seconds)
-- if there's a crop filter, remove it and exit
if del_filter_if_present(crop_label) then
return
end
-- Plus 1 second for deviation.
local time_needed = seconds + 1
local playtime_remaining = mp.get_property_native("playtime-remaining")
-- insert the cropdetect filter
ret=mp.command(
string.format(
'vf add @%s:cropdetect=limit=%f:round=2:reset=0',
cropdetect_label, 24/255
)
)
-- wait to gather data
timer=mp.add_timeout(detect_seconds, do_crop)
return playtime_remaining and time_needed < playtime_remaining
end
function do_crop()
-- get the metadata
local cropdetect_metadata = mp.get_property_native(
string.format("vf-metadata/%s", cropdetect_label)
)
function is_cropable()
local vid = mp.get_property_native("vid")
local is_album = vid and mp.get_property_native(
string.format("track-list/%d/albumart", vid)
) or false
-- use it to crop if its valid
if cropdetect_metadata then
if cropdetect_metadata["lavfi.cropdetect.w"]
and cropdetect_metadata["lavfi.cropdetect.h"]
and cropdetect_metadata["lavfi.cropdetect.x"]
and cropdetect_metadata["lavfi.cropdetect.y"]
then
mp.command(string.format("vf add @%s:lavfi-crop=w=%s:h=%s:x=%s:y=%s",
crop_label,
cropdetect_metadata["lavfi.cropdetect.w"],
cropdetect_metadata["lavfi.cropdetect.h"],
cropdetect_metadata["lavfi.cropdetect.x"],
cropdetect_metadata["lavfi.cropdetect.y"]))
else
mp.msg.error(
"Got empty crop data. You might need to increase detect_seconds."
)
return vid and not is_album
end
function remove_filter(label)
if is_filter_present(label) then
mp.command(string.format('vf remove @%s', label))
return true
end
return false
end
function cleanup()
-- Remove all existing filters.
for key, value in pairs(labels) do
remove_filter(value)
end
-- Kill all timers.
for index, timer in pairs(timers) do
if timer then
timer:kill()
timer = nil
end
else
mp.msg.error(
"No crop data. Was the cropdetect filter successfully inserted?"
)
mp.msg.error(
"Does your version of ffmpeg/libav support AVFrame metadata?"
)
end
-- remove the cropdetect filter
del_filter_if_present(cropdetect_label)
timer=nil
end
mp.add_key_binding("C", "auto_crop", autocrop_start)
function detect_crop()
-- If it's not cropable, exit.
if not is_cropable() then
mp.msg.warn("autocrop only works for videos.")
return
end
-- Verify if there is enough time to detect crop.
local time_needed = options.detect_seconds
if not is_enough_time(time_needed) then
mp.msg.warn("Not enough time to detect crop.")
return
end
-- Insert the cropdetect filter.
local limit = options.detect_limit
local round = options.detect_round
mp.command(
string.format(
'vf pre @%s:cropdetect=limit=%s:round=%d:reset=0',
labels.cropdetect, limit, round
)
)
-- Wait to gather data.
timers.detect_crop = mp.add_timeout(time_needed, detect_end)
end
function detect_end()
-- Get the metadata and remove the cropdetect filter.
local cropdetect_metadata =
mp.get_property_native(
string.format("vf-metadata/%s",
labels.cropdetect
)
)
remove_filter(labels.cropdetect)
-- Remove the timer of detect crop.
if timers.detect_crop then
timers.detect_crop:kill()
timers.detect_crop = nil
end
local meta = {}
-- Verify the existence of metadata.
if cropdetect_metadata then
meta = {
w = cropdetect_metadata["lavfi.cropdetect.w"],
h = cropdetect_metadata["lavfi.cropdetect.h"],
x = cropdetect_metadata["lavfi.cropdetect.x"],
y = cropdetect_metadata["lavfi.cropdetect.y"],
}
else
mp.msg.error("No crop data.")
mp.msg.info("Was the cropdetect filter successfully inserted?")
mp.msg.info("Does your version of ffmpeg/libav support AVFrame metadata?")
return
end
-- Verify that the metadata meets the requirements and convert it.
if meta.w and meta.h and meta.x and meta.y then
local width = mp.get_property_native("width")
local height = mp.get_property_native("height")
meta = {
w = tonumber(meta.w),
h = tonumber(meta.h),
x = tonumber(meta.x),
y = tonumber(meta.y),
min_w = width * options.detect_min_ratio,
min_h = height * options.detect_min_ratio,
max_w = width,
max_h = height
}
else
mp.msg.error("Got empty crop data.")
mp.msg.info("You might need to increase detect_seconds.")
return
end
apply_crop(meta)
end
function apply_crop(meta)
-- Verify if it is necessary to crop.
local is_effective = meta.x > 0 or meta.y > 0
or meta.w < meta.max_w or meta.h < meta.max_h
if not is_effective then
mp.msg.info("No area detected for cropping.")
return
end
-- Verify it is not over cropped.
local is_excessive = meta.w < meta.min_w and meta.h < meta.min_h
if is_excessive then
mp.msg.info("The area to be cropped is too large.")
mp.msg.info("You might need to decrease detect_min_ratio.")
return
end
-- Remove existing crop.
remove_filter(labels.crop)
-- Apply crop.
mp.command(
string.format("vf pre @%s:lavfi-crop=w=%s:h=%s:x=%s:y=%s",
labels.crop, meta.w, meta.h, meta.x, meta.y
)
)
end
function on_start()
-- Clean up at the beginning.
cleanup()
-- If auto is not true, exit.
if not options.auto then
return
end
-- If it is the beginning, wait for detect_crop
-- after auto_delay seconds, otherwise immediately.
local playback_time = mp.get_property_native("playback-time")
local is_delay_needed = playback_time
and options.auto_delay > playback_time
if is_delay_needed then
-- Verify if there is enough time for autocrop.
local time_needed = options.auto_delay + options.detect_seconds
if not is_enough_time(time_needed) then
mp.msg.warn("Not enough time for autocrop.")
return
end
timers.auto_delay = mp.add_timeout(time_needed,
function()
detect_crop()
-- Remove the timer of auto delay.
timers.auto_delay:kill()
timers.auto_delay = nil
end
)
else
detect_crop()
end
end
function on_toggle()
-- If it is during auto_delay, kill the timer.
if timers.auto_delay then
timers.auto_delay:kill()
timers.auto_delay = nil
end
-- Cropped => Remove it.
if remove_filter(labels.crop) then
return
end
-- Detecting => Leave it.
if timers.detect_crop then
mp.msg.warn("Already cropdetecting!")
return
end
-- Neither => Do delectcrop.
detect_crop()
end
mp.add_key_binding("C", "toggle_crop", on_toggle)
mp.register_event("end-file", cleanup)
mp.register_event("file-loaded", on_start)
+6 -6
View File
@@ -2,20 +2,20 @@
-- the currently played file. It does so by scanning the directory a file is
-- located in when starting playback. It sorts the directory entries
-- alphabetically, and adds entries before and after the current file to
-- the internal playlist. (It stops if the it would add an already existing
-- the internal playlist. (It stops if it would add an already existing
-- playlist entry at the same position - this makes it "stable".)
-- Add at most 5000 * 2 files when starting a file (before + after).
--[[
To configure this script use file autoload.conf in director script-opts (the "script-opts"
To configure this script use file autoload.conf in directory script-opts (the "script-opts"
directory must be in the mpv configuration directory, typically ~/.config/mpv/).
Example configuration would be:
disabled=false
images=false
videos=true
audio=true
disabled=no
images=no
videos=yes
audio=yes
--]]
+19
View File
@@ -76,6 +76,25 @@ mp.observe_property("vo-configured", "bool", function(_, v)
end)
mp.command_native_async({name = "subprocess", args = {"wc", "-c"},
stdin_data = "hello", capture_stdout = true},
function(res, val, err)
print("Should be '5': " .. val.stdout)
end)
-- blocking stdin by default
mp.command_native_async({name = "subprocess", args = {"cat"},
capture_stdout = true},
function(res, val, err)
print("Should be 0: " .. #val.stdout)
end)
-- stdin + detached
mp.command_native_async({name = "subprocess",
args = {"bash", "-c", "(sleep 5s ; cat)"},
stdin_data = "this should appear after 5s.\n",
detach = true},
function(res, val, err)
print("5s test: " .. val.status)
end)
-- This should get killed on script exit.
mp.command_native_async({name = "subprocess", playback_only = false,
+35
View File
@@ -0,0 +1,35 @@
local assdraw = require 'mp.assdraw'
local utils = require 'mp.utils'
things = {}
for i = 1, 2 do
things[i] = {
osd1 = mp.create_osd_overlay("ass-events"),
osd2 = mp.create_osd_overlay("ass-events")
}
end
things[1].text = "{\\an5}hello\\Nworld"
things[2].text = "{\\pos(400, 200)}something something"
mp.add_periodic_timer(2, function()
for i, thing in ipairs(things) do
thing.osd1.data = thing.text
thing.osd1.compute_bounds = true
--thing.osd1.hidden = true
local res = thing.osd1:update()
print("res " .. i .. ": " .. utils.to_string(res))
thing.osd2.hidden = true
if res ~= nil and res.x0 ~= nil then
local draw = assdraw.ass_new()
draw:append("{\\alpha&H80}")
draw:draw_start()
draw:pos(0, 0)
draw:rect_cw(res.x0, res.y0, res.x1, res.y1)
draw:draw_stop()
thing.osd2.hidden = false
thing.osd2.data = draw.text
end
thing.osd2:update()
end
end)
-1
View File
@@ -129,7 +129,6 @@ local function load_config()
setfenv(conf_fn, config)
end
else
msg.warn("Lua 5.2 was not tested, this might go wrong.")
conf_fn, err = loadfile(conf_file, "t", config)
end
else
+32
View File
@@ -0,0 +1,32 @@
local utils = require("mp.utils")
function hardsleep()
os.execute("sleep 1s")
end
local hooks = {"on_before_start_file", "on_load", "on_load_fail",
"on_preloaded", "on_unload", "on_after_end_file"}
for _, name in ipairs(hooks) do
mp.add_hook(name, 0, function()
print("--- hook: " .. name)
hardsleep()
print(" ... continue")
end)
end
local events = {"start-file", "end-file", "file-loaded", "seek",
"playback-restart", "idle", "shutdown"}
for _, name in ipairs(events) do
mp.register_event(name, function()
print("--- event: " .. name)
end)
end
local props = {"path", "metadata"}
for _, name in ipairs(props) do
mp.observe_property(name, "native", function(name, val)
print("property '" .. name .. "' changed to '" ..
utils.to_string(val) .. "'")
end)
end
+1 -1
View File
@@ -276,7 +276,7 @@ class MatroskaElement(object):
def add_subelements(self, subelements):
self.subelements = subelements
self.subids = set(x[0].elid for x in subelements)
self.subids = {x[0].elid for x in subelements}
elementd = {}
elementlist = []
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import shutil
import sys
@@ -37,7 +37,7 @@ def copy_binary(binary_name):
def apply_plist_template(plist_file, version):
for line in fileinput.input(plist_file, inplace=1):
print (line.rstrip().replace('${VERSION}', version))
print(line.rstrip().replace('${VERSION}', version))
def create_bundle_symlink(binary_name, symlink_name):
os.symlink(os.path.basename(binary_name),
@@ -217,6 +217,7 @@
<string>ftp</string>
<string>udp</string>
<string>smb</string>
<string>srt</string>
</array>
</dict>
<dict>
@@ -1 +1,2 @@
player-operation-mode=pseudo-gui
log-file=~/Library/Logs/mpv.log
+2 -2
View File
@@ -147,8 +147,8 @@ if hasval:
ax[1] = win.addPlot()
ax[1].setXLink(ax[0])
for cur in ax:
if cur is not None:
cur.addLegend(offset = (-1, 1))
if cur is not None:
cur.addLegend(offset = (-1, 1))
for e in G.sevents:
cur = ax[1 if e.type == "value" else 0]
if not cur in G.curveno:
+15 -24
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""
This script emulates "unique application" functionality on Linux. When starting
@@ -19,10 +19,6 @@ will typically just fill ~/.xsession-errors with garbage.
mpv will terminate if there are no more files to play, and running the umpv
script after that will start a new mpv instance.
Note that you can control the mpv instance by writing to the command fifo:
echo "cycle fullscreen" > ~/.umpv_fifo
Note: you can supply custom mpv path and options with the MPV environment
variable. The environment variable will be split on whitespace, and the
first item is used as path to mpv binary and the rest is passed as options
@@ -32,6 +28,7 @@ Note: you can supply custom mpv path and options with the MPV environment
import sys
import os
import socket
import errno
import subprocess
import fcntl
@@ -57,40 +54,34 @@ def make_abs(filename):
return filename
files = [make_abs(f) for f in files]
FIFO = os.path.join(os.getenv("HOME"), ".umpv_fifo")
SOCK = os.path.join(os.getenv("HOME"), ".umpv_socket")
fifo_fd = -1
sock = None
try:
fifo_fd = os.open(FIFO, os.O_NONBLOCK | os.O_WRONLY)
except OSError as e:
if e.errno == errno.ENXIO:
pass # pipe has no writer
sock = socket.socket(socket.AF_UNIX)
sock.connect(SOCK)
except socket.error as e:
if e.errno == errno.ECONNREFUSED:
sock = None
pass # abandoned socket
elif e.errno == errno.ENOENT:
sock = None
pass # doesn't exist
else:
raise e
if fifo_fd >= 0:
if sock:
# Unhandled race condition: what if mpv is terminating right now?
fcntl.fcntl(fifo_fd, fcntl.F_SETFL, 0) # set blocking mode
fifo = os.fdopen(fifo_fd, "w")
for f in files:
# escape: \ \n "
f = f.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n")
f = "\"" + f + "\""
fifo.write("raw loadfile " + f + " append\n")
sock.send(("raw loadfile " + f + " append\n").encode("utf-8"))
else:
# Recreate pipe if it doesn't already exist.
# Also makes sure it's safe, and no other user can create a bogus pipe
# that breaks security.
try:
os.unlink(FIFO)
except OSError as e:
pass
os.mkfifo(FIFO, 0o600)
# Let mpv recreate socket if it doesn't already exist.
opts = (os.getenv("MPV") or "mpv").split()
opts.extend(["--no-terminal", "--force-window", "--input-file=" + FIFO,
opts.extend(["--no-terminal", "--force-window", "--input-ipc-server=" + SOCK,
"--"])
opts.extend(files)
+1 -1
View File
@@ -1 +1 @@
0.31.0
0.33.0
+8
View File
@@ -15,6 +15,12 @@ shallow_clone: true
test: off
install:
# Work around age/brokenness of Appveyor's msys2 by adding the new
# maintainer's keyring.
- bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz"
- bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig"
- bash -lc "pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig"
- bash -lc "pacman -U --noconfirm msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz"
# Support for Ada and Objective-C was removed from MSYS2. GCC won't update if
# these packages are installed.
- >-
@@ -23,6 +29,8 @@ install:
mingw-w64-x86_64-gcc-objc
# Update core packages
- C:\msys64\usr\bin\pacman -Syyuu --noconfirm --noprogressbar --ask=20
# Explicitly kill any remaining msys2 processes after core update
- taskkill /f /fi "MODULES eq msys-2.0.dll"
# Update non-core packages
- C:\msys64\usr\bin\pacman -Suu --noconfirm --noprogressbar --ask=20
# Install required MSYS2 packages
+19 -8
View File
@@ -100,6 +100,19 @@ void mp_aframe_unref_data(struct mp_aframe *frame)
talloc_free(tmp);
}
// Allocate this much data. Returns false for failure (data already allocated,
// invalid sample count or format, allocation failures).
// Normally you're supposed to use a frame pool and mp_aframe_pool_allocate().
bool mp_aframe_alloc_data(struct mp_aframe *frame, int samples)
{
if (mp_aframe_is_allocated(frame))
return false;
struct mp_aframe_pool *p = mp_aframe_pool_create(NULL);
int r = mp_aframe_pool_allocate(p, frame, samples);
talloc_free(p);
return r >= 0;
}
// Return a new reference to the data in av_frame. av_frame itself is not
// touched. Returns NULL if not representable, or if input is NULL.
// Does not copy the timestamps.
@@ -121,11 +134,9 @@ struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame)
frame->format = format;
mp_chmap_from_lavc(&frame->chmap, frame->av_frame->channel_layout);
#if LIBAVUTIL_VERSION_MICRO >= 100
// FFmpeg being a stupid POS again
if (frame->chmap.num != frame->av_frame->channels)
mp_chmap_from_channels(&frame->chmap, av_frame->channels);
#endif
if (av_frame->opaque_ref) {
struct avframe_opaque *op = (void *)av_frame->opaque_ref->data;
@@ -194,10 +205,8 @@ void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src)
dst->av_frame->sample_rate = src->av_frame->sample_rate;
dst->av_frame->format = src->av_frame->format;
dst->av_frame->channel_layout = src->av_frame->channel_layout;
#if LIBAVUTIL_VERSION_MICRO >= 100
// FFmpeg being a stupid POS again
dst->av_frame->channels = src->av_frame->channels;
#endif
}
// Copy "soft" attributes from src to dst, excluding things which affect
@@ -311,10 +320,8 @@ bool mp_aframe_set_chmap(struct mp_aframe *frame, struct mp_chmap *in)
return false;
frame->chmap = *in;
frame->av_frame->channel_layout = lavc_layout;
#if LIBAVUTIL_VERSION_MICRO >= 100
// FFmpeg being a stupid POS again
frame->av_frame->channels = frame->chmap.num;
#endif
return true;
}
@@ -454,13 +461,13 @@ void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end)
double rate = mp_aframe_get_effective_rate(f);
if (f_end == MP_NOPTS_VALUE)
return;
if (af_fmt_is_spdif(mp_aframe_get_format(f)))
return;
if (end != MP_NOPTS_VALUE) {
if (f_end >= end) {
if (f->pts >= end) {
f->av_frame->nb_samples = 0;
} else {
if (af_fmt_is_spdif(mp_aframe_get_format(f)))
return;
int new = (end - f->pts) * rate;
f->av_frame->nb_samples = MPCLAMP(new, 0, f->av_frame->nb_samples);
}
@@ -472,6 +479,8 @@ void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end)
f->av_frame->nb_samples = 0;
f->pts = f_end;
} else {
if (af_fmt_is_spdif(mp_aframe_get_format(f)))
return;
int skip = (start - f->pts) * rate;
skip = MPCLAMP(skip, 0, f->av_frame->nb_samples);
mp_aframe_skip_samples(f, skip);
@@ -636,6 +645,8 @@ int mp_aframe_pool_allocate(struct mp_aframe_pool *pool, struct mp_aframe *frame
av_frame->linesize[0] = samples * sstride;
for (int n = 0; n < planes; n++)
av_frame->extended_data[n] = av_frame->buf[0]->data + n * plane_size;
for (int n = 0; n < MPMIN(planes, AV_NUM_DATA_POINTERS); n++)
av_frame->data[n] = av_frame->extended_data[n];
av_frame->nb_samples = samples;
return 0;
+1
View File
@@ -20,6 +20,7 @@ struct AVFrame *mp_aframe_to_avframe_and_unref(struct mp_aframe *frame);
struct AVFrame *mp_aframe_get_raw_avframe(struct mp_aframe *frame);
bool mp_aframe_is_allocated(struct mp_aframe *frame);
bool mp_aframe_alloc_data(struct mp_aframe *frame, int samples);
void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src);
bool mp_aframe_config_equals(struct mp_aframe *a, struct mp_aframe *b);
-160
View File
@@ -1,160 +0,0 @@
/*
* 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 <stddef.h>
#include <limits.h>
#include <assert.h>
#include "common/common.h"
#include "chmap.h"
#include "audio_buffer.h"
#include "format.h"
struct mp_audio_buffer {
int format;
struct mp_chmap channels;
int srate;
int sstride;
int num_planes;
uint8_t *data[MP_NUM_CHANNELS];
int allocated;
int num_samples;
};
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx)
{
return talloc_zero(talloc_ctx, struct mp_audio_buffer);
}
// Reinitialize the buffer, set a new format, drop old data.
// The audio data in fmt is not used, only the format.
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
const struct mp_chmap *channels, int srate)
{
for (int n = 0; n < MP_NUM_CHANNELS; n++)
TA_FREEP(&ab->data[n]);
ab->format = format;
ab->channels = *channels;
ab->srate = srate;
ab->allocated = 0;
ab->num_samples = 0;
ab->sstride = af_fmt_to_bytes(ab->format);
ab->num_planes = 1;
if (af_fmt_is_planar(ab->format)) {
ab->num_planes = ab->channels.num;
} else {
ab->sstride *= ab->channels.num;
}
}
// Make the total size of the internal buffer at least this number of samples.
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples)
{
if (samples > ab->allocated) {
for (int n = 0; n < ab->num_planes; n++) {
ab->data[n] = talloc_realloc(ab, ab->data[n], char,
ab->sstride * samples);
}
ab->allocated = samples;
}
}
// Get number of samples that can be written without forcing a resize of the
// internal buffer.
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab)
{
return ab->allocated - ab->num_samples;
}
// All integer parameters are in samples.
// dst and src can overlap.
static void copy_planes(struct mp_audio_buffer *ab,
uint8_t **dst, int dst_offset,
uint8_t **src, int src_offset, int length)
{
if (!length)
return;
for (int n = 0; n < ab->num_planes; n++) {
memmove((char *)dst[n] + dst_offset * ab->sstride,
(char *)src[n] + src_offset * ab->sstride,
length * ab->sstride);
}
}
// Append data to the end of the buffer.
// If the buffer is not large enough, it is transparently resized.
void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples)
{
mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
copy_planes(ab, ab->data, ab->num_samples, (uint8_t **)ptr, 0, samples);
ab->num_samples += samples;
}
// Prepend silence to the start of the buffer.
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples)
{
assert(samples >= 0);
mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
copy_planes(ab, ab->data, samples, ab->data, 0, ab->num_samples);
ab->num_samples += samples;
for (int n = 0; n < ab->num_planes; n++)
af_fill_silence(ab->data[n], samples * ab->sstride, ab->format);
}
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples)
{
assert(samples >= 0 && samples <= ab->num_samples);
mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
copy_planes(ab, ab->data, ab->num_samples,
ab->data, ab->num_samples - samples, samples);
ab->num_samples += samples;
}
// Get the start of the current readable buffer.
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr,
int *samples)
{
*ptr = ab->data;
*samples = ab->num_samples;
}
// Skip leading samples. (Used with mp_audio_buffer_peek() to read data.)
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples)
{
assert(samples >= 0 && samples <= ab->num_samples);
copy_planes(ab, ab->data, 0, ab->data, samples, ab->num_samples - samples);
ab->num_samples -= samples;
}
void mp_audio_buffer_clear(struct mp_audio_buffer *ab)
{
ab->num_samples = 0;
}
// Return number of buffered audio samples
int mp_audio_buffer_samples(struct mp_audio_buffer *ab)
{
return ab->num_samples;
}
// Return amount of buffered audio in seconds.
double mp_audio_buffer_seconds(struct mp_audio_buffer *ab)
{
return ab->num_samples / (double)ab->srate;
}
-39
View File
@@ -1,39 +0,0 @@
/*
* 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/>.
*/
#ifndef MP_AUDIO_BUFFER_H
#define MP_AUDIO_BUFFER_H
struct mp_audio_buffer;
struct mp_chmap;
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx);
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
const struct mp_chmap *channels, int srate);
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples);
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab);
void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples);
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr,
int *samples);
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_clear(struct mp_audio_buffer *ab);
int mp_audio_buffer_samples(struct mp_audio_buffer *ab);
double mp_audio_buffer_seconds(struct mp_audio_buffer *ab);
#endif
+5 -14
View File
@@ -63,16 +63,16 @@ struct ad_lavc_params {
const struct m_sub_options ad_lavc_conf = {
.opts = (const m_option_t[]) {
OPT_FLOATRANGE("ac3drc", ac3drc, 0, 0, 6),
OPT_FLAG("downmix", downmix, 0),
OPT_INTRANGE("threads", threads, 0, 0, 16),
OPT_KEYVALUELIST("o", avopts, 0),
{"ac3drc", OPT_FLOAT(ac3drc), M_RANGE(0, 6)},
{"downmix", OPT_FLAG(downmix)},
{"threads", OPT_INT(threads), M_RANGE(0, 16)},
{"o", OPT_KEYVALUELIST(avopts)},
{0}
},
.size = sizeof(struct ad_lavc_params),
.defaults = &(const struct ad_lavc_params){
.ac3drc = 0,
.downmix = 1,
.downmix = 0,
.threads = 1,
},
};
@@ -103,10 +103,7 @@ static bool init(struct mp_filter *da, struct mp_codec_params *codec,
ctx->avframe = av_frame_alloc();
lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
lavc_context->codec_id = lavc_codec->id;
#if LIBAVCODEC_VERSION_MICRO >= 100
lavc_context->pkt_timebase = ctx->codec_timebase;
#endif
if (opts->downmix && mpopts->audio_output_channels.num_chmaps == 1) {
lavc_context->request_channel_layout =
@@ -117,10 +114,8 @@ static bool init(struct mp_filter *da, struct mp_codec_params *codec,
av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc,
AV_OPT_SEARCH_CHILDREN);
#if LIBAVCODEC_VERSION_MICRO >= 100
// Let decoder add AV_FRAME_DATA_SKIP_SAMPLES.
av_opt_set(lavc_context, "flags2", "+skip_manual", AV_OPT_SEARCH_CHILDREN);
#endif
mp_set_avopts(da->log, lavc_context, opts->avopts);
@@ -199,10 +194,8 @@ static int receive_frame(struct mp_filter *da, struct mp_frame *out)
MP_ERR(da, "Error decoding audio.\n");
}
#if LIBAVCODEC_VERSION_MICRO >= 100
if (priv->avframe->flags & AV_FRAME_FLAG_DISCARD)
av_frame_unref(priv->avframe);
#endif
if (!priv->avframe->buf[0])
return ret;
@@ -224,7 +217,6 @@ static int receive_frame(struct mp_filter *da, struct mp_frame *out)
priv->next_pts = mp_aframe_end_pts(mpframe);
#if LIBAVCODEC_VERSION_MICRO >= 100
AVFrameSideData *sd =
av_frame_get_side_data(priv->avframe, AV_FRAME_DATA_SKIP_SAMPLES);
if (sd && sd->size >= 10) {
@@ -232,7 +224,6 @@ static int receive_frame(struct mp_filter *da, struct mp_frame *out)
priv->skip_samples += AV_RL32(d + 0);
priv->trim_samples += AV_RL32(d + 4);
}
#endif
if (!priv->preroll_done) {
// Skip only if this isn't already handled by AV_FRAME_DATA_SKIP_SAMPLES.
+1 -3
View File
@@ -176,10 +176,8 @@ static int init_filter(struct mp_filter *da, AVPacket *pkt)
goto fail;
}
// Request minimal buffering (not available on Libav)
#if LIBAVFORMAT_VERSION_MICRO >= 100
// Request minimal buffering
lavf_ctx->pb->direct = 1;
#endif
AVStream *stream = avformat_new_stream(lavf_ctx, 0);
if (!stream)
+114
View File
@@ -0,0 +1,114 @@
#include "audio/aframe.h"
#include "audio/format.h"
#include "common/common.h"
#include "filters/f_autoconvert.h"
#include "filters/filter_internal.h"
#include "filters/user_filters.h"
struct priv {
double speed;
double diff; // amount of too many additional samples in normal speed
struct mp_aframe *last; // for repeating
};
static void process(struct mp_filter *f)
{
struct priv *p = f->priv;
if (!mp_pin_in_needs_data(f->ppins[1]))
return;
struct mp_frame frame = {0};
double last_dur = p->last ? mp_aframe_duration(p->last) : 0;
if (p->last && p->diff < 0 && -p->diff > last_dur / 2) {
MP_VERBOSE(f, "repeat\n");
frame = MAKE_FRAME(MP_FRAME_AUDIO, p->last);
p->last = NULL;
} else {
frame = mp_pin_out_read(f->ppins[0]);
if (frame.type == MP_FRAME_AUDIO) {
last_dur = mp_aframe_duration(frame.data);
p->diff -= last_dur;
if (p->diff > last_dur / 2) {
MP_VERBOSE(f, "drop\n");
mp_frame_unref(&frame);
mp_filter_internal_mark_progress(f);
}
}
}
if (frame.type == MP_FRAME_AUDIO) {
struct mp_aframe *fr = frame.data;
talloc_free(p->last);
p->last = mp_aframe_new_ref(fr);
mp_aframe_mul_speed(fr, p->speed);
p->diff += mp_aframe_duration(fr);
mp_aframe_set_pts(p->last, mp_aframe_end_pts(fr));
} else if (frame.type == MP_FRAME_EOF) {
TA_FREEP(&p->last);
}
mp_pin_in_write(f->ppins[1], frame);
}
static bool command(struct mp_filter *f, struct mp_filter_command *cmd)
{
struct priv *p = f->priv;
switch (cmd->type) {
case MP_FILTER_COMMAND_SET_SPEED:
p->speed = cmd->speed;
return true;
}
return false;
}
static void reset(struct mp_filter *f)
{
struct priv *p = f->priv;
TA_FREEP(&p->last);
p->diff = 0;
}
static void destroy(struct mp_filter *f)
{
reset(f);
}
static const struct mp_filter_info af_drop_filter = {
.name = "drop",
.priv_size = sizeof(struct priv),
.process = process,
.command = command,
.reset = reset,
.destroy = destroy,
};
static struct mp_filter *af_drop_create(struct mp_filter *parent, void *options)
{
struct mp_filter *f = mp_filter_create(parent, &af_drop_filter);
if (!f) {
talloc_free(options);
return NULL;
}
mp_filter_add_pin(f, MP_PIN_IN, "in");
mp_filter_add_pin(f, MP_PIN_OUT, "out");
struct priv *p = f->priv;
p->speed = 1.0;
return f;
}
const struct mp_user_filter_entry af_drop = {
.desc = {
.description = "Change audio speed by dropping/repeating frames",
.name = "drop",
.priv_size = sizeof(struct priv),
},
.create = af_drop_create,
};
+8 -6
View File
@@ -128,12 +128,14 @@ const struct mp_user_filter_entry af_format = {
.description = "Force audio format",
.priv_size = sizeof(struct f_opts),
.options = (const struct m_option[]) {
OPT_AUDIOFORMAT("format", in_format, 0),
OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000),
OPT_CHANNELS("channels", in_channels, 0, .min = 1),
OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000),
OPT_CHANNELS("out-channels", out_channels, 0, .min = 1),
OPT_FLAG("fail", fail, 0),
{"format", OPT_AUDIOFORMAT(in_format)},
{"srate", OPT_INT(in_srate), M_RANGE(1000, 8*48000)},
{"channels", OPT_CHANNELS(in_channels),
.flags = M_OPT_CHANNELS_LIMITED},
{"out-srate", OPT_INT(out_srate), M_RANGE(1000, 8*48000)},
{"out-channels", OPT_CHANNELS(out_channels),
.flags = M_OPT_CHANNELS_LIMITED},
{"fail", OPT_FLAG(fail)},
{0}
},
},
+6 -6
View File
@@ -375,12 +375,12 @@ const struct mp_user_filter_entry af_lavcac3enc = {
.encoder = "ac3",
},
.options = (const struct m_option[]) {
OPT_FLAG("tospdif", add_iec61937_header, 0),
OPT_CHOICE_OR_INT("bitrate", bit_rate, 0, 32, 640,
({"auto", 0}, {"default", 0})),
OPT_INTRANGE("minch", min_channel_num, 0, 2, 6),
OPT_STRING("encoder", encoder, 0),
OPT_KEYVALUELIST("o", avopts, 0),
{"tospdif", OPT_FLAG(add_iec61937_header)},
{"bitrate", OPT_CHOICE(bit_rate,
{"auto", 0}, {"default", 0}), M_RANGE(32, 640)},
{"minch", OPT_INT(min_channel_num), M_RANGE(2, 6)},
{"encoder", OPT_STRING(encoder)},
{"o", OPT_KEYVALUELIST(avopts)},
{0}
},
},
+29 -29
View File
@@ -333,35 +333,35 @@ const struct mp_user_filter_entry af_rubberband = {
.channels = RubberBandOptionChannelsTogether,
},
.options = (const struct m_option[]) {
OPT_CHOICE("transients", transients, 0,
({"crisp", RubberBandOptionTransientsCrisp},
{"mixed", RubberBandOptionTransientsMixed},
{"smooth", RubberBandOptionTransientsSmooth})),
OPT_CHOICE("detector", detector, 0,
({"compound", RubberBandOptionDetectorCompound},
{"percussive", RubberBandOptionDetectorPercussive},
{"soft", RubberBandOptionDetectorSoft})),
OPT_CHOICE("phase", phase, 0,
({"laminar", RubberBandOptionPhaseLaminar},
{"independent", RubberBandOptionPhaseIndependent})),
OPT_CHOICE("window", window, 0,
({"standard", RubberBandOptionWindowStandard},
{"short", RubberBandOptionWindowShort},
{"long", RubberBandOptionWindowLong})),
OPT_CHOICE("smoothing", smoothing, 0,
({"off", RubberBandOptionSmoothingOff},
{"on", RubberBandOptionSmoothingOn})),
OPT_CHOICE("formant", formant, 0,
({"shifted", RubberBandOptionFormantShifted},
{"preserved", RubberBandOptionFormantPreserved})),
OPT_CHOICE("pitch", pitch, 0,
({"quality", RubberBandOptionPitchHighQuality},
{"speed", RubberBandOptionPitchHighSpeed},
{"consistency", RubberBandOptionPitchHighConsistency})),
OPT_CHOICE("channels", channels, 0,
({"apart", RubberBandOptionChannelsApart},
{"together", RubberBandOptionChannelsTogether})),
OPT_DOUBLE("pitch-scale", scale, M_OPT_RANGE, .min = 0.01, .max = 100),
{"transients", OPT_CHOICE(transients,
{"crisp", RubberBandOptionTransientsCrisp},
{"mixed", RubberBandOptionTransientsMixed},
{"smooth", RubberBandOptionTransientsSmooth})},
{"detector", OPT_CHOICE(detector,
{"compound", RubberBandOptionDetectorCompound},
{"percussive", RubberBandOptionDetectorPercussive},
{"soft", RubberBandOptionDetectorSoft})},
{"phase", OPT_CHOICE(phase,
{"laminar", RubberBandOptionPhaseLaminar},
{"independent", RubberBandOptionPhaseIndependent})},
{"window", OPT_CHOICE(window,
{"standard", RubberBandOptionWindowStandard},
{"short", RubberBandOptionWindowShort},
{"long", RubberBandOptionWindowLong})},
{"smoothing", OPT_CHOICE(smoothing,
{"off", RubberBandOptionSmoothingOff},
{"on", RubberBandOptionSmoothingOn})},
{"formant", OPT_CHOICE(formant,
{"shifted", RubberBandOptionFormantShifted},
{"preserved", RubberBandOptionFormantPreserved})},
{"pitch", OPT_CHOICE(pitch,
{"quality", RubberBandOptionPitchHighQuality},
{"speed", RubberBandOptionPitchHighSpeed},
{"consistency", RubberBandOptionPitchHighConsistency})},
{"channels", OPT_CHOICE(channels,
{"apart", RubberBandOptionChannelsApart},
{"together", RubberBandOptionChannelsTogether})},
{"pitch-scale", OPT_DOUBLE(scale), M_RANGE(0.01, 100)},
{0}
},
},
+16 -14
View File
@@ -30,6 +30,7 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <float.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
@@ -186,10 +187,10 @@ static int best_overlap_offset_s16(struct priv *s)
ps += s->samples_overlap - s->num_channels;
long i = -(s->samples_overlap - s->num_channels);
do {
corr += ppc[i + 0] * ps[i + 0];
corr += ppc[i + 1] * ps[i + 1];
corr += ppc[i + 2] * ps[i + 2];
corr += ppc[i + 3] * ps[i + 3];
corr += ppc[i + 0] * (int64_t)ps[i + 0];
corr += ppc[i + 1] * (int64_t)ps[i + 1];
corr += ppc[i + 2] * (int64_t)ps[i + 2];
corr += ppc[i + 3] * (int64_t)ps[i + 3];
i += 4;
} while (i < 0);
if (corr > best_corr) {
@@ -537,7 +538,8 @@ static void reset(struct mp_filter *f)
s->bytes_queued = 0;
s->bytes_to_slide = 0;
s->frames_stride_error = 0;
memset(s->buf_overlap, 0, s->bytes_overlap);
if (s->buf_overlap && s->bytes_overlap)
memset(s->buf_overlap, 0, s->bytes_overlap);
TA_FREEP(&s->in);
}
@@ -608,15 +610,15 @@ const struct mp_user_filter_entry af_scaletempo = {
.scale_nominal = 1.0,
},
.options = (const struct m_option[]) {
OPT_FLOAT("scale", scale_nominal, M_OPT_MIN, .min = 0.01),
OPT_FLOAT("stride", ms_stride, M_OPT_MIN, .min = 0.01),
OPT_FLOAT("overlap", percent_overlap, M_OPT_RANGE, .min = 0, .max = 1),
OPT_FLOAT("search", ms_search, M_OPT_MIN, .min = 0),
OPT_CHOICE("speed", speed_opt, 0,
({"pitch", SCALE_PITCH},
{"tempo", SCALE_TEMPO},
{"none", 0},
{"both", SCALE_TEMPO | SCALE_PITCH})),
{"scale", OPT_FLOAT(scale_nominal), M_RANGE(0.01, DBL_MAX)},
{"stride", OPT_FLOAT(ms_stride), M_RANGE(0.01, DBL_MAX)},
{"overlap", OPT_FLOAT(percent_overlap), M_RANGE(0, 1)},
{"search", OPT_FLOAT(ms_search), M_RANGE(0, DBL_MAX)},
{"speed", OPT_CHOICE(speed_opt,
{"pitch", SCALE_PITCH},
{"tempo", SCALE_TEMPO},
{"none", 0},
{"both", SCALE_TEMPO | SCALE_PITCH})},
{0}
},
},
+245
View File
@@ -0,0 +1,245 @@
#include "audio/aframe.h"
#include "audio/filter/af_scaletempo2_internals.h"
#include "audio/format.h"
#include "common/common.h"
#include "filters/f_autoconvert.h"
#include "filters/filter_internal.h"
#include "filters/user_filters.h"
#include "options/m_option.h"
struct priv {
struct mp_scaletempo2 data;
struct mp_pin *in_pin;
struct mp_aframe *cur_format;
struct mp_aframe_pool *out_pool;
bool sent_final;
struct mp_aframe *pending;
bool initialized;
double frame_delay;
float speed;
};
static bool init_scaletempo2(struct mp_filter *f);
static void reset(struct mp_filter *f);
static void process(struct mp_filter *f)
{
struct priv *p = f->priv;
if (!mp_pin_in_needs_data(f->ppins[1]))
return;
while (!p->initialized || !p->pending ||
!mp_scaletempo2_frames_available(&p->data))
{
bool eof = false;
if (!p->pending || !mp_aframe_get_size(p->pending)) {
struct mp_frame frame = mp_pin_out_read(p->in_pin);
if (frame.type == MP_FRAME_AUDIO) {
TA_FREEP(&p->pending);
p->pending = frame.data;
} else if (frame.type == MP_FRAME_EOF) {
eof = true;
} else if (frame.type) {
MP_ERR(f, "unexpected frame type\n");
goto error;
} else {
return; // no new data yet
}
}
assert(p->pending || eof);
if (!p->initialized) {
if (!p->pending) {
mp_pin_in_write(f->ppins[1], MP_EOF_FRAME);
return;
}
if (!init_scaletempo2(f))
goto error;
}
bool format_change =
p->pending && !mp_aframe_config_equals(p->pending, p->cur_format);
bool final = format_change || eof;
if (p->pending && !format_change && !p->sent_final) {
int frame_size = mp_aframe_get_size(p->pending);
uint8_t **planes = mp_aframe_get_data_ro(p->pending);
int read = mp_scaletempo2_fill_input_buffer(&p->data,
planes, frame_size, final);
p->frame_delay += read;
mp_aframe_skip_samples(p->pending, read);
}
p->sent_final |= final;
if (mp_scaletempo2_frames_available(&p->data)) {
if (eof) {
mp_pin_out_repeat_eof(p->in_pin); // drain more next time
}
} else if (final) {
p->initialized = false;
p->sent_final = false;
if (eof) {
mp_pin_in_write(f->ppins[1], MP_EOF_FRAME);
return;
} else if (format_change) {
// go on with proper reinit on the next iteration
p->initialized = false;
p->sent_final = false;
}
}
}
assert(p->pending);
if (mp_scaletempo2_frames_available(&p->data)) {
struct mp_aframe *out = mp_aframe_new_ref(p->cur_format);
int out_samples = p->data.ola_hop_size;
if (mp_aframe_pool_allocate(p->out_pool, out, out_samples) < 0) {
talloc_free(out);
goto error;
}
mp_aframe_copy_attributes(out, p->pending);
uint8_t **planes = mp_aframe_get_data_rw(out);
assert(planes);
assert(mp_aframe_get_planes(out) == p->data.channels);
out_samples = mp_scaletempo2_fill_buffer(&p->data,
(float**)planes, out_samples, p->speed);
double pts = mp_aframe_get_pts(p->pending);
p->frame_delay -= out_samples * p->speed;
if (pts != MP_NOPTS_VALUE) {
double delay = p->frame_delay / mp_aframe_get_effective_rate(out);
mp_aframe_set_pts(out, pts - delay);
}
mp_aframe_set_size(out, out_samples);
mp_aframe_mul_speed(out, p->speed);
mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_AUDIO, out));
}
return;
error:
mp_filter_internal_mark_failed(f);
}
static bool init_scaletempo2(struct mp_filter *f)
{
struct priv *p = f->priv;
assert(p->pending);
if (mp_aframe_get_format(p->pending) != AF_FORMAT_FLOATP)
return false;
mp_aframe_reset(p->cur_format);
p->initialized = true;
p->sent_final = false;
p->frame_delay = 0;
mp_aframe_config_copy(p->cur_format, p->pending);
mp_scaletempo2_init(&p->data, mp_aframe_get_channels(p->pending),
mp_aframe_get_rate(p->pending));
return true;
}
static bool command(struct mp_filter *f, struct mp_filter_command *cmd)
{
struct priv *p = f->priv;
switch (cmd->type) {
case MP_FILTER_COMMAND_SET_SPEED:
p->speed = cmd->speed;
return true;
}
return false;
}
static void reset(struct mp_filter *f)
{
struct priv *p = f->priv;
mp_scaletempo2_reset(&p->data);
p->frame_delay = 0;
p->initialized = false;
TA_FREEP(&p->pending);
}
static void destroy(struct mp_filter *f)
{
struct priv *p = f->priv;
mp_scaletempo2_destroy(&p->data);
talloc_free(p->pending);
}
static const struct mp_filter_info af_scaletempo2_filter = {
.name = "scaletempo2",
.priv_size = sizeof(struct priv),
.process = process,
.command = command,
.reset = reset,
.destroy = destroy,
};
static struct mp_filter *af_scaletempo2_create(
struct mp_filter *parent, void *options)
{
struct mp_filter *f = mp_filter_create(parent, &af_scaletempo2_filter);
if (!f) {
talloc_free(options);
return NULL;
}
mp_filter_add_pin(f, MP_PIN_IN, "in");
mp_filter_add_pin(f, MP_PIN_OUT, "out");
struct priv *p = f->priv;
p->data.opts = talloc_steal(p, options);
p->speed = 1.0;
p->cur_format = talloc_steal(p, mp_aframe_create());
p->out_pool = mp_aframe_pool_create(p);
p->pending = NULL;
p->initialized = false;
struct mp_autoconvert *conv = mp_autoconvert_create(f);
if (!conv)
abort();
mp_autoconvert_add_afmt(conv, AF_FORMAT_FLOATP);
mp_pin_connect(conv->f->pins[0], f->ppins[0]);
p->in_pin = conv->f->pins[1];
return f;
}
#define OPT_BASE_STRUCT struct mp_scaletempo2_opts
const struct mp_user_filter_entry af_scaletempo2 = {
.desc = {
.description = "Scale audio tempo while maintaining pitch"
" (filter ported from chromium)",
.name = "scaletempo2",
.priv_size = sizeof(OPT_BASE_STRUCT),
.priv_defaults = &(const OPT_BASE_STRUCT) {
.min_playback_rate = 0.25,
.max_playback_rate = 4.0,
.ola_window_size_ms = 20,
.wsola_search_interval_ms = 30,
},
.options = (const struct m_option[]) {
{"search-interval",
OPT_FLOAT(wsola_search_interval_ms), M_RANGE(1, 1000)},
{"window-size",
OPT_FLOAT(ola_window_size_ms), M_RANGE(1, 1000)},
{"min-speed",
OPT_FLOAT(min_playback_rate), M_RANGE(0, FLT_MAX)},
{"max-speed",
OPT_FLOAT(max_playback_rate), M_RANGE(0, FLT_MAX)},
{0}
}
},
.create = af_scaletempo2_create,
};
+724
View File
@@ -0,0 +1,724 @@
#include <float.h>
#include <math.h>
#include "audio/chmap.h"
#include "audio/filter/af_scaletempo2_internals.h"
// Algorithm overview (from chromium):
// Waveform Similarity Overlap-and-add (WSOLA).
//
// One WSOLA iteration
//
// 1) Extract |target_block| as input frames at indices
// [|target_block_index|, |target_block_index| + |ola_window_size|).
// Note that |target_block| is the "natural" continuation of the output.
//
// 2) Extract |search_block| as input frames at indices
// [|search_block_index|,
// |search_block_index| + |num_candidate_blocks| + |ola_window_size|).
//
// 3) Find a block within the |search_block| that is most similar
// to |target_block|. Let |optimal_index| be the index of such block and
// write it to |optimal_block|.
//
// 4) Update:
// |optimal_block| = |transition_window| * |target_block| +
// (1 - |transition_window|) * |optimal_block|.
//
// 5) Overlap-and-add |optimal_block| to the |wsola_output|.
//
// 6) Update:write
struct interval {
int lo;
int hi;
};
static bool in_interval(int n, struct interval q)
{
return n >= q.lo && n <= q.hi;
}
static float **realloc_2d(float **p, int x, int y)
{
float **array = realloc(p, sizeof(float*) * x + sizeof(float) * x * y);
float* data = (float*) (array + x);
for (int i = 0; i < x; ++i) {
array[i] = data + i * y;
}
return array;
}
static void zero_2d(float **a, int x, int y)
{
memset(a + x, 0, sizeof(float) * x * y);
}
static void zero_2d_partial(float **a, int x, int y)
{
for (int i = 0; i < x; ++i) {
memset(a[i], 0, sizeof(float) * y);
}
}
// Energies of sliding windows of channels are interleaved.
// The number windows is |input_frames| - (|frames_per_window| - 1), hence,
// the method assumes |energy| must be, at least, of size
// (|input_frames| - (|frames_per_window| - 1)) * |channels|.
static void multi_channel_moving_block_energies(
float **input, int input_frames, int channels,
int frames_per_block, float *energy)
{
int num_blocks = input_frames - (frames_per_block - 1);
for (int k = 0; k < channels; ++k) {
const float* input_channel = input[k];
energy[k] = 0;
// First block of channel |k|.
for (int m = 0; m < frames_per_block; ++m) {
energy[k] += input_channel[m] * input_channel[m];
}
const float* slide_out = input_channel;
const float* slide_in = input_channel + frames_per_block;
for (int n = 1; n < num_blocks; ++n, ++slide_in, ++slide_out) {
energy[k + n * channels] = energy[k + (n - 1) * channels]
- *slide_out * *slide_out + *slide_in * *slide_in;
}
}
}
static float multi_channel_similarity_measure(
const float* dot_prod_a_b,
const float* energy_a, const float* energy_b,
int channels)
{
const float epsilon = 1e-12f;
float similarity_measure = 0.0f;
for (int n = 0; n < channels; ++n) {
similarity_measure += dot_prod_a_b[n]
/ sqrtf(energy_a[n] * energy_b[n] + epsilon);
}
return similarity_measure;
}
// Dot-product of channels of two AudioBus. For each AudioBus an offset is
// given. |dot_product[k]| is the dot-product of channel |k|. The caller should
// allocate sufficient space for |dot_product|.
static void multi_channel_dot_product(
float **a, int frame_offset_a,
float **b, int frame_offset_b,
int channels,
int num_frames, float *dot_product)
{
assert(frame_offset_a >= 0);
assert(frame_offset_b >= 0);
memset(dot_product, 0, sizeof(*dot_product) * channels);
for (int k = 0; k < channels; ++k) {
const float* ch_a = a[k] + frame_offset_a;
const float* ch_b = b[k] + frame_offset_b;
for (int n = 0; n < num_frames; ++n) {
dot_product[k] += *ch_a++ * *ch_b++;
}
}
}
// Fit the curve f(x) = a * x^2 + b * x + c such that
// f(-1) = y[0]
// f(0) = y[1]
// f(1) = y[2]
// and return the maximum, assuming that y[0] <= y[1] >= y[2].
static void quadratic_interpolation(
const float* y_values, float* extremum, float* extremum_value)
{
float a = 0.5f * (y_values[2] + y_values[0]) - y_values[1];
float b = 0.5f * (y_values[2] - y_values[0]);
float c = y_values[1];
if (a == 0.f) {
// The coordinates are colinear (within floating-point error).
*extremum = 0;
*extremum_value = y_values[1];
} else {
*extremum = -b / (2.f * a);
*extremum_value = a * (*extremum) * (*extremum) + b * (*extremum) + c;
}
}
// Search a subset of all candid blocks. The search is performed every
// |decimation| frames. This reduces complexity by a factor of about
// 1 / |decimation|. A cubic interpolation is used to have a better estimate of
// the best match.
static int decimated_search(
int decimation, struct interval exclude_interval,
float **target_block, int target_block_frames,
float **search_segment, int search_segment_frames,
int channels,
const float *energy_target_block, const float *energy_candidate_blocks)
{
int num_candidate_blocks = search_segment_frames - (target_block_frames - 1);
float dot_prod [MP_NUM_CHANNELS];
float similarity[3]; // Three elements for cubic interpolation.
int n = 0;
multi_channel_dot_product(
target_block, 0,
search_segment, n,
channels,
target_block_frames, dot_prod);
similarity[0] = multi_channel_similarity_measure(
dot_prod, energy_target_block,
&energy_candidate_blocks[n * channels], channels);
// Set the starting point as optimal point.
float best_similarity = similarity[0];
int optimal_index = 0;
n += decimation;
if (n >= num_candidate_blocks) {
return 0;
}
multi_channel_dot_product(
target_block, 0,
search_segment, n,
channels,
target_block_frames, dot_prod);
similarity[1] = multi_channel_similarity_measure(
dot_prod, energy_target_block,
&energy_candidate_blocks[n * channels], channels);
n += decimation;
if (n >= num_candidate_blocks) {
// We cannot do any more sampling. Compare these two values and return the
// optimal index.
return similarity[1] > similarity[0] ? decimation : 0;
}
for (; n < num_candidate_blocks; n += decimation) {
multi_channel_dot_product(
target_block, 0,
search_segment, n,
channels,
target_block_frames, dot_prod);
similarity[2] = multi_channel_similarity_measure(
dot_prod, energy_target_block,
&energy_candidate_blocks[n * channels], channels);
if ((similarity[1] > similarity[0] && similarity[1] >= similarity[2]) ||
(similarity[1] >= similarity[0] && similarity[1] > similarity[2]))
{
// A local maximum is found. Do a cubic interpolation for a better
// estimate of candidate maximum.
float normalized_candidate_index;
float candidate_similarity;
quadratic_interpolation(similarity, &normalized_candidate_index,
&candidate_similarity);
int candidate_index = n - decimation
+ (int)(normalized_candidate_index * decimation + 0.5f);
if (candidate_similarity > best_similarity
&& !in_interval(candidate_index, exclude_interval)) {
optimal_index = candidate_index;
best_similarity = candidate_similarity;
}
} else if (n + decimation >= num_candidate_blocks &&
similarity[2] > best_similarity &&
!in_interval(n, exclude_interval))
{
// If this is the end-point and has a better similarity-measure than
// optimal, then we accept it as optimal point.
optimal_index = n;
best_similarity = similarity[2];
}
memmove(similarity, &similarity[1], 2 * sizeof(*similarity));
}
return optimal_index;
}
// Search [|low_limit|, |high_limit|] of |search_segment| to find a block that
// is most similar to |target_block|. |energy_target_block| is the energy of the
// |target_block|. |energy_candidate_blocks| is the energy of all blocks within
// |search_block|.
static int full_search(
int low_limit, int high_limit,
struct interval exclude_interval,
float **target_block, int target_block_frames,
float **search_block, int search_block_frames,
int channels,
const float* energy_target_block,
const float* energy_candidate_blocks)
{
// int block_size = target_block->frames;
float dot_prod [sizeof(float) * MP_NUM_CHANNELS];
float best_similarity = -FLT_MAX;//FLT_MIN;
int optimal_index = 0;
for (int n = low_limit; n <= high_limit; ++n) {
if (in_interval(n, exclude_interval)) {
continue;
}
multi_channel_dot_product(target_block, 0, search_block, n, channels,
target_block_frames, dot_prod);
float similarity = multi_channel_similarity_measure(
dot_prod, energy_target_block,
&energy_candidate_blocks[n * channels], channels);
if (similarity > best_similarity) {
best_similarity = similarity;
optimal_index = n;
}
}
return optimal_index;
}
// Find the index of the block, within |search_block|, that is most similar
// to |target_block|. Obviously, the returned index is w.r.t. |search_block|.
// |exclude_interval| is an interval that is excluded from the search.
static int compute_optimal_index(
float **search_block, int search_block_frames,
float **target_block, int target_block_frames,
float *energy_candidate_blocks,
int channels,
struct interval exclude_interval)
{
int num_candidate_blocks = search_block_frames - (target_block_frames - 1);
// This is a compromise between complexity reduction and search accuracy. I
// don't have a proof that down sample of order 5 is optimal.
// One can compute a decimation factor that minimizes complexity given
// the size of |search_block| and |target_block|. However, my experiments
// show the rate of missing the optimal index is significant.
// This value is chosen heuristically based on experiments.
const int search_decimation = 5;
float energy_target_block [MP_NUM_CHANNELS];
// energy_candidate_blocks must have at least size
// sizeof(float) * channels * num_candidate_blocks
// Energy of all candid frames.
multi_channel_moving_block_energies(
search_block,
search_block_frames,
channels,
target_block_frames,
energy_candidate_blocks);
// Energy of target frame.
multi_channel_dot_product(
target_block, 0,
target_block, 0,
channels,
target_block_frames, energy_target_block);
int optimal_index = decimated_search(
search_decimation, exclude_interval,
target_block, target_block_frames,
search_block, search_block_frames,
channels,
energy_target_block,
energy_candidate_blocks);
int lim_low = MPMAX(0, optimal_index - search_decimation);
int lim_high = MPMIN(num_candidate_blocks - 1,
optimal_index + search_decimation);
return full_search(
lim_low, lim_high, exclude_interval,
target_block, target_block_frames,
search_block, search_block_frames,
channels,
energy_target_block, energy_candidate_blocks);
}
static void peek_buffer(struct mp_scaletempo2 *p,
int frames, int read_offset, int write_offset, float **dest)
{
assert(p->input_buffer_frames >= frames);
for (int i = 0; i < p->channels; ++i) {
memcpy(dest[i] + write_offset,
p->input_buffer[i] + read_offset,
frames * sizeof(float));
}
}
static void seek_buffer(struct mp_scaletempo2 *p, int frames)
{
assert(p->input_buffer_frames >= frames);
p->input_buffer_frames -= frames;
for (int i = 0; i < p->channels; ++i) {
memmove(p->input_buffer[i], p->input_buffer[i] + frames,
p->input_buffer_frames * sizeof(float));
}
}
static void read_buffer(struct mp_scaletempo2 *p, int frames, float **dest)
{
peek_buffer(p, frames, 0, 0, dest);
seek_buffer(p, frames);
}
static int write_completed_frames_to(struct mp_scaletempo2 *p,
int requested_frames, int dest_offset, float **dest)
{
int rendered_frames = MPMIN(p->num_complete_frames, requested_frames);
if (rendered_frames == 0)
return 0; // There is nothing to read from |wsola_output|, return.
for (int i = 0; i < p->channels; ++i) {
memcpy(dest[i] + dest_offset, p->wsola_output[i],
rendered_frames * sizeof(float));
}
// Remove the frames which are read.
int frames_to_move = p->wsola_output_size - rendered_frames;
for (int k = 0; k < p->channels; ++k) {
float *ch = p->wsola_output[k];
memmove(ch, &ch[rendered_frames], sizeof(*ch) * frames_to_move);
}
p->num_complete_frames -= rendered_frames;
return rendered_frames;
}
static bool can_perform_wsola(struct mp_scaletempo2 *p)
{
const int search_block_size = p->num_candidate_blocks
+ (p->ola_window_size - 1);
return p->target_block_index + p->ola_window_size <= p->input_buffer_frames
&& p->search_block_index + search_block_size <= p->input_buffer_frames;
}
// number of frames needed until a wsola iteration can be performed
static int frames_needed(struct mp_scaletempo2 *p)
{
return MPMAX(0, MPMAX(
p->target_block_index + p->ola_window_size - p->input_buffer_frames,
p->search_block_index + p->search_block_size - p->input_buffer_frames));
}
int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p,
uint8_t **planes, int frame_size, bool final)
{
int needed = frames_needed(p);
int read = MPMIN(needed, frame_size);
int total_fill = final ? needed : read;
if (total_fill == 0) return 0;
assert(total_fill + p->input_buffer_frames <= p->input_buffer_size);
for (int i = 0; i < p->channels; ++i) {
memcpy(p->input_buffer[i] + p->input_buffer_frames,
planes[i], read * sizeof(float));
for (int j = read; j < total_fill; ++j) {
p->input_buffer[p->input_buffer_frames + j] = 0;
}
}
p->input_buffer_frames += total_fill;
return read;
}
static bool target_is_within_search_region(struct mp_scaletempo2 *p)
{
const int search_block_size = p->num_candidate_blocks + (p->ola_window_size - 1);
return p->target_block_index >= p->search_block_index
&& p->target_block_index + p->ola_window_size
<= p->search_block_index + search_block_size;
}
static void peek_audio_with_zero_prepend(struct mp_scaletempo2 *p,
int read_offset_frames, float **dest, int dest_frames)
{
assert(read_offset_frames + dest_frames <= p->input_buffer_frames);
int write_offset = 0;
int num_frames_to_read = dest_frames;
if (read_offset_frames < 0) {
int num_zero_frames_appended = MPMIN(
-read_offset_frames, num_frames_to_read);
read_offset_frames = 0;
num_frames_to_read -= num_zero_frames_appended;
write_offset = num_zero_frames_appended;
zero_2d_partial(dest, p->channels, num_zero_frames_appended);
}
peek_buffer(p, num_frames_to_read, read_offset_frames, write_offset, dest);
}
static void get_optimal_block(struct mp_scaletempo2 *p)
{
int optimal_index = 0;
// An interval around last optimal block which is excluded from the search.
// This is to reduce the buzzy sound. The number 160 is rather arbitrary and
// derived heuristically.
const int exclude_interval_length_frames = 160;
if (target_is_within_search_region(p)) {
optimal_index = p->target_block_index;
peek_audio_with_zero_prepend(p,
optimal_index, p->optimal_block, p->ola_window_size);
} else {
peek_audio_with_zero_prepend(p,
p->target_block_index, p->target_block, p->ola_window_size);
peek_audio_with_zero_prepend(p,
p->search_block_index, p->search_block, p->search_block_size);
int last_optimal = p->target_block_index
- p->ola_hop_size - p->search_block_index;
struct interval exclude_iterval = {
.lo = last_optimal - exclude_interval_length_frames / 2,
.hi = last_optimal + exclude_interval_length_frames / 2
};
// |optimal_index| is in frames and it is relative to the beginning of the
// |search_block|.
optimal_index = compute_optimal_index(
p->search_block, p->search_block_size,
p->target_block, p->ola_window_size,
p->energy_candidate_blocks,
p->channels,
exclude_iterval);
// Translate |index| w.r.t. the beginning of |audio_buffer| and extract the
// optimal block.
optimal_index += p->search_block_index;
peek_audio_with_zero_prepend(p,
optimal_index, p->optimal_block, p->ola_window_size);
// Make a transition from target block to the optimal block if different.
// Target block has the best continuation to the current output.
// Optimal block is the most similar block to the target, however, it might
// introduce some discontinuity when over-lap-added. Therefore, we combine
// them for a smoother transition. The length of transition window is twice
// as that of the optimal-block which makes it like a weighting function
// where target-block has higher weight close to zero (weight of 1 at index
// 0) and lower weight close the end.
for (int k = 0; k < p->channels; ++k) {
float* ch_opt = p->optimal_block[k];
float* ch_target = p->target_block[k];
for (int n = 0; n < p->ola_window_size; ++n) {
ch_opt[n] = ch_opt[n] * p->transition_window[n]
+ ch_target[n] * p->transition_window[p->ola_window_size + n];
}
}
}
// Next target is one hop ahead of the current optimal.
p->target_block_index = optimal_index + p->ola_hop_size;
}
static void update_output_time(struct mp_scaletempo2 *p,
float playback_rate, double time_change)
{
p->output_time += time_change;
// Center of the search region, in frames.
int search_block_center_index = (int)(p->output_time * playback_rate + 0.5);
p->search_block_index = search_block_center_index
- p->search_block_center_offset;
}
static void remove_old_input_frames(struct mp_scaletempo2 *p, float playback_rate)
{
const int earliest_used_index = MPMIN(
p->target_block_index, p->search_block_index);
if (earliest_used_index <= 0)
return; // Nothing to remove.
// Remove frames from input and adjust indices accordingly.
seek_buffer(p, earliest_used_index);
p->target_block_index -= earliest_used_index;
// Adjust output index.
double output_time_change = ((double) earliest_used_index) / playback_rate;
assert(p->output_time >= output_time_change);
update_output_time(p, playback_rate, -output_time_change);
}
static bool run_one_wsola_iteration(struct mp_scaletempo2 *p, float playback_rate)
{
if (!can_perform_wsola(p)){
return false;
}
get_optimal_block(p);
// Overlap-and-add.
for (int k = 0; k < p->channels; ++k) {
float* ch_opt_frame = p->optimal_block[k];
float* ch_output = p->wsola_output[k] + p->num_complete_frames;
for (int n = 0; n < p->ola_hop_size; ++n) {
ch_output[n] = ch_output[n] * p->ola_window[p->ola_hop_size + n] +
ch_opt_frame[n] * p->ola_window[n];
}
// Copy the second half to the output.
memcpy(&ch_output[p->ola_hop_size], &ch_opt_frame[p->ola_hop_size],
sizeof(*ch_opt_frame) * p->ola_hop_size);
}
p->num_complete_frames += p->ola_hop_size;
update_output_time(p, playback_rate, p->ola_hop_size);
remove_old_input_frames(p, playback_rate);
return true;
}
int mp_scaletempo2_fill_buffer(struct mp_scaletempo2 *p,
float **dest, int dest_size, float playback_rate)
{
if (playback_rate == 0) return 0;
// Optimize the muted case to issue a single clear instead of performing
// the full crossfade and clearing each crossfaded frame.
if (playback_rate < p->opts->min_playback_rate
|| (playback_rate > p->opts->max_playback_rate
&& p->opts->max_playback_rate > 0))
{
int frames_to_render = MPMIN(dest_size,
(int) (p->input_buffer_frames / playback_rate));
// Compute accurate number of frames to actually skip in the source data.
// Includes the leftover partial frame from last request. However, we can
// only skip over complete frames, so a partial frame may remain for next
// time.
p->muted_partial_frame += frames_to_render * playback_rate;
int seek_frames = (int) (p->muted_partial_frame);
zero_2d_partial(dest, p->channels, frames_to_render);
seek_buffer(p, seek_frames);
// Determine the partial frame that remains to be skipped for next call. If
// the user switches back to playing, it may be off time by this partial
// frame, which would be undetectable. If they subsequently switch to
// another playback rate that mutes, the code will attempt to line up the
// frames again.
p->muted_partial_frame -= seek_frames;
return frames_to_render;
}
int slower_step = (int) ceilf(p->ola_window_size * playback_rate);
int faster_step = (int) ceilf(p->ola_window_size / playback_rate);
// Optimize the most common |playback_rate| ~= 1 case to use a single copy
// instead of copying frame by frame.
if (p->ola_window_size <= faster_step && slower_step >= p->ola_window_size) {
int frames_to_copy = MPMIN(dest_size, p->input_buffer_frames);
read_buffer(p, frames_to_copy, dest);
return frames_to_copy;
}
int rendered_frames = 0;
do {
rendered_frames += write_completed_frames_to(p,
dest_size - rendered_frames, rendered_frames, dest);
} while (rendered_frames < dest_size
&& run_one_wsola_iteration(p, playback_rate));
return rendered_frames;
}
bool mp_scaletempo2_frames_available(struct mp_scaletempo2 *p)
{
return can_perform_wsola(p) || p->num_complete_frames > 0;
}
void mp_scaletempo2_destroy(struct mp_scaletempo2 *p)
{
free(p->ola_window);
free(p->transition_window);
free(p->wsola_output);
free(p->optimal_block);
free(p->search_block);
free(p->target_block);
free(p->input_buffer);
free(p->energy_candidate_blocks);
}
void mp_scaletempo2_reset(struct mp_scaletempo2 *p)
{
p->input_buffer_frames = 0;
p->output_time = 0.0;
p->search_block_index = 0;
p->target_block_index = 0;
// Clear the queue of decoded packets.
zero_2d(p->wsola_output, p->channels, p->wsola_output_size);
p->num_complete_frames = 0;
}
// Return a "periodic" Hann window. This is the first L samples of an L+1
// Hann window. It is perfect reconstruction for overlap-and-add.
static void get_symmetric_hanning_window(int window_length, float* window)
{
const float scale = 2.0f * M_PI / window_length;
for (int n = 0; n < window_length; ++n)
window[n] = 0.5f * (1.0f - cosf(n * scale));
}
void mp_scaletempo2_init(struct mp_scaletempo2 *p, int channels, int rate)
{
p->muted_partial_frame = 0;
p->output_time = 0;
p->search_block_center_offset = 0;
p->search_block_index = 0;
p->num_complete_frames = 0;
p->channels = channels;
p->samples_per_second = rate;
p->num_candidate_blocks = (int)(p->opts->wsola_search_interval_ms
* p->samples_per_second / 1000);
p->ola_window_size = (int)(p->opts->ola_window_size_ms
* p->samples_per_second / 1000);
// Make sure window size in an even number.
p->ola_window_size += p->ola_window_size & 1;
p->ola_hop_size = p->ola_window_size / 2;
// |num_candidate_blocks| / 2 is the offset of the center of the search
// block to the center of the first (left most) candidate block. The offset
// of the center of a candidate block to its left most point is
// |ola_window_size| / 2 - 1. Note that |ola_window_size| is even and in
// our convention the center belongs to the left half, so we need to subtract
// one frame to get the correct offset.
//
// Search Block
// <------------------------------------------->
//
// |ola_window_size| / 2 - 1
// <----
//
// |num_candidate_blocks| / 2
// <----------------
// center
// X----X----------------X---------------X-----X
// <----------> <---------->
// Candidate ... Candidate
// 1, ... |num_candidate_blocks|
p->search_block_center_offset = p->num_candidate_blocks / 2
+ (p->ola_window_size / 2 - 1);
p->ola_window = realloc(p->ola_window, sizeof(float) * p->ola_window_size);
get_symmetric_hanning_window(p->ola_window_size, p->ola_window);
p->transition_window = realloc(p->transition_window,
sizeof(float) * p->ola_window_size * 2);
get_symmetric_hanning_window(2 * p->ola_window_size, p->transition_window);
p->wsola_output_size = p->ola_window_size + p->ola_hop_size;
p->wsola_output = realloc_2d(p->wsola_output, p->channels, p->wsola_output_size);
// Initialize for overlap-and-add of the first block.
zero_2d(p->wsola_output, p->channels, p->wsola_output_size);
// Auxiliary containers.
p->optimal_block = realloc_2d(p->optimal_block, p->channels, p->ola_window_size);
p->search_block_size = p->num_candidate_blocks + (p->ola_window_size - 1);
p->search_block = realloc_2d(p->search_block, p->channels, p->search_block_size);
p->target_block = realloc_2d(p->target_block, p->channels, p->ola_window_size);
p->input_buffer_size = 4 * MPMAX(p->ola_window_size, p->search_block_size);
p->input_buffer = realloc_2d(p->input_buffer, p->channels, p->input_buffer_size);
p->input_buffer_frames = 0;
p->energy_candidate_blocks = realloc(p->energy_candidate_blocks,
sizeof(float) * p->channels * p->num_candidate_blocks);
}
+121
View File
@@ -0,0 +1,121 @@
// This filter was ported from Chromium
// (https://chromium.googlesource.com/chromium/chromium/+/51ed77e3f37a9a9b80d6d0a8259e84a8ca635259/media/filters/audio_renderer_algorithm.cc)
//
// Copyright 2015 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "common/common.h"
struct mp_scaletempo2_opts {
// Max/min supported playback rates for fast/slow audio. Audio outside of these
// ranges are muted.
// Audio at these speeds would sound better under a frequency domain algorithm.
float min_playback_rate;
float max_playback_rate;
// Overlap-and-add window size in milliseconds.
float ola_window_size_ms;
// Size of search interval in milliseconds. The search interval is
// [-delta delta] around |output_index| * |playback_rate|. So the search
// interval is 2 * delta.
float wsola_search_interval_ms;
};
struct mp_scaletempo2 {
struct mp_scaletempo2_opts *opts;
// Number of channels in audio stream.
int channels;
// Sample rate of audio stream.
int samples_per_second;
// If muted, keep track of partial frames that should have been skipped over.
double muted_partial_frame;
// Book keeping of the current time of generated audio, in frames. This
// should be appropriately updated when out samples are generated, regardless
// of whether we push samples out when fill_buffer() is called or we store
// audio in |wsola_output| for the subsequent calls to fill_buffer().
// Furthermore, if samples from |audio_buffer| are evicted then this
// member variable should be updated based on |playback_rate|.
// Note that this member should be updated ONLY by calling update_output_time(),
// so that |search_block_index| is update accordingly.
double output_time;
// The offset of the center frame of |search_block| w.r.t. its first frame.
int search_block_center_offset;
// Index of the beginning of the |search_block|, in frames.
int search_block_index;
// Number of Blocks to search to find the most similar one to the target
// frame.
int num_candidate_blocks;
// Index of the beginning of the target block, counted in frames.
int target_block_index;
// Overlap-and-add window size in frames.
int ola_window_size;
// The hop size of overlap-and-add in frames. This implementation assumes 50%
// overlap-and-add.
int ola_hop_size;
// Number of frames in |wsola_output| that overlap-and-add is completed for
// them and can be copied to output if fill_buffer() is called. It also
// specifies the index where the next WSOLA window has to overlap-and-add.
int num_complete_frames;
// Overlap-and-add window.
float *ola_window;
// Transition window, used to update |optimal_block| by a weighted sum of
// |optimal_block| and |target_block|.
float *transition_window;
// This stores a part of the output that is created but couldn't be rendered.
// Output is generated frame-by-frame which at some point might exceed the
// number of requested samples. Furthermore, due to overlap-and-add,
// the last half-window of the output is incomplete, which is stored in this
// buffer.
float **wsola_output;
int wsola_output_size;
// Auxiliary variables to avoid allocation in every iteration.
// Stores the optimal block in every iteration. This is the most
// similar block to |target_block| within |search_block| and it is
// overlap-and-added to |wsola_output|.
float **optimal_block;
// A block of data that search is performed over to find the |optimal_block|.
float **search_block;
int search_block_size;
// Stores the target block, denoted as |target| above. |search_block| is
// searched for a block (|optimal_block|) that is most similar to
// |target_block|.
float **target_block;
// Buffered audio data.
float **input_buffer;
int input_buffer_size;
int input_buffer_frames;
float *energy_candidate_blocks;
};
void mp_scaletempo2_destroy(struct mp_scaletempo2 *p);
void mp_scaletempo2_reset(struct mp_scaletempo2 *p);
void mp_scaletempo2_init(struct mp_scaletempo2 *p, int channels, int rate);
int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p,
uint8_t **planes, int frame_size, bool final);
int mp_scaletempo2_fill_buffer(struct mp_scaletempo2 *p,
float **dest, int dest_size, float playback_rate);
bool mp_scaletempo2_frames_available(struct mp_scaletempo2 *p);
+23 -129
View File
@@ -29,19 +29,17 @@
#include "audio/format.h"
#include "options/options.h"
#include "options/m_config.h"
#include "options/m_config_frontend.h"
#include "osdep/endian.h"
#include "common/msg.h"
#include "common/common.h"
#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;
extern const struct ao_driver audio_out_rsound;
extern const struct ao_driver audio_out_sndio;
extern const struct ao_driver audio_out_pulse;
extern const struct ao_driver audio_out_jack;
extern const struct ao_driver audio_out_openal;
@@ -72,9 +70,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
#endif
#if HAVE_WASAPI
&audio_out_wasapi,
#endif
#if HAVE_OSS_AUDIO
&audio_out_oss,
#endif
// wrappers:
#if HAVE_JACK
@@ -88,9 +83,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
#endif
#if HAVE_SDL2_AUDIO
&audio_out_sdl,
#endif
#if HAVE_SNDIO
&audio_out_sndio,
#endif
&audio_out_null,
#if HAVE_COREAUDIO
@@ -98,9 +90,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
#endif
&audio_out_pcm,
&audio_out_lavc,
#if HAVE_RSOUND
&audio_out_rsound,
#endif
NULL
};
@@ -136,11 +125,12 @@ 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, 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,
UPDATE_AUDIO | M_OPT_MIN | M_OPT_MAX, .min = 0, .max = 10),
{"ao", OPT_SETTINGSLIST(audio_driver_list, &ao_obj_list),
.flags = UPDATE_AUDIO},
{"audio-device", OPT_STRING(audio_device), .flags = UPDATE_AUDIO},
{"audio-client-name", OPT_STRING(audio_client_name), .flags = UPDATE_AUDIO},
{"audio-buffer", OPT_DOUBLE(audio_buffer),
.flags = UPDATE_AUDIO, M_RANGE(0, 10)},
{0}
},
.size = sizeof(OPT_BASE_STRUCT),
@@ -210,14 +200,9 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
af_fmt_to_str(ao->format));
ao->device = talloc_strdup(ao, dev);
ao->api = ao->driver->play ? &ao_api_push : &ao_api_pull;
ao->api_priv = talloc_zero_size(ao, ao->api->priv_size);
assert(!ao->api->priv_defaults && !ao->api->options);
ao->stream_silence = flags & AO_INIT_STREAM_SILENCE;
ao->period_size = 1;
init_buffer_pre(ao);
int r = ao->driver->init(ao);
if (r < 0) {
@@ -226,18 +211,14 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
char redirect[80], rdevice[80];
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : "");
talloc_free(ao);
ao_uninit(ao);
return ao_init(probing, global, wakeup_cb, wakeup_ctx,
encode_lavc_ctx, flags, samplerate, format, channels,
rdevice, redirect);
}
goto fail;
}
if (ao->period_size < 1) {
MP_ERR(ao, "Invalid period size set.\n");
goto fail;
}
ao->driver_initialized = true;
ao->sstride = af_fmt_to_bytes(ao->format);
ao->num_planes = 1;
@@ -248,8 +229,10 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
}
ao->bps = ao->samplerate * ao->sstride;
if (!ao->device_buffer && ao->driver->get_space)
ao->device_buffer = ao->driver->get_space(ao);
if (ao->device_buffer <= 0 && ao->driver->write) {
MP_ERR(ao, "Device buffer size not set.\n");
goto fail;
}
if (ao->device_buffer)
MP_VERBOSE(ao, "device buffer: %d samples.\n", ao->device_buffer);
ao->buffer = MPMAX(ao->device_buffer, ao->def_buffer * ao->samplerate);
@@ -259,12 +242,12 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
ao->buffer = (ao->buffer + align - 1) / align * align;
MP_VERBOSE(ao, "using soft-buffer of %d samples.\n", ao->buffer);
if (ao->api->init(ao) < 0)
if (!init_buffer_post(ao))
goto fail;
return ao;
fail:
talloc_free(ao);
ao_uninit(ao);
return NULL;
}
@@ -358,96 +341,20 @@ struct ao *ao_init_best(struct mpv_global *global,
return ao;
}
// Uninitialize and destroy the AO. Remaining audio must be dropped.
void ao_uninit(struct ao *ao)
{
if (ao)
ao->api->uninit(ao);
talloc_free(ao);
}
// Queue the given audio data. Start playback if it hasn't started yet. Return
// the number of samples that was accepted (the core will try to queue the rest
// again later). Should never block.
// data: start pointer for each plane. If the audio data is packed, only
// data[0] is valid, otherwise there is a plane for each channel.
// samples: size of the audio data (see ao->sstride)
// flags: currently AOPLAY_FINAL_CHUNK can be set
int ao_play(struct ao *ao, void **data, int samples, int flags)
{
return ao->api->play(ao, data, samples, flags);
}
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg)
{
return ao->api->control ? ao->api->control(ao, cmd, arg) : CONTROL_UNKNOWN;
}
// Return size of the buffered data in seconds. Can include the device latency.
// Basically, this returns how much data there is still to play, and how long
// it takes until the last sample in the buffer reaches the speakers. This is
// used for audio/video synchronization, so it's very important to implement
// this correctly.
double ao_get_delay(struct ao *ao)
{
return ao->api->get_delay(ao);
}
// Return free size of the internal audio buffer. This controls how much audio
// the core should decode and try to queue with ao_play().
int ao_get_space(struct ao *ao)
{
return ao->api->get_space(ao);
}
// Stop playback and empty buffers. Essentially go back to the state after
// ao->init().
void ao_reset(struct ao *ao)
{
if (ao->api->reset)
ao->api->reset(ao);
atomic_fetch_and(&ao->events_, ~(unsigned int)AO_EVENT_UNDERRUN);
}
// Pause playback. Keep the current buffer. ao_get_delay() must return the
// same value as before pausing.
void ao_pause(struct ao *ao)
{
if (ao->api->pause)
ao->api->pause(ao);
}
// Resume playback. Play the remaining buffer. If the driver doesn't support
// pausing, it has to work around this and e.g. use ao_play_silence() to fill
// the lost audio.
void ao_resume(struct ao *ao)
{
if (ao->api->resume)
ao->api->resume(ao);
}
// Block until the current audio buffer has played completely.
void ao_drain(struct ao *ao)
{
if (ao->api->drain)
ao->api->drain(ao);
}
bool ao_eof_reached(struct ao *ao)
{
return ao->api->get_eof ? ao->api->get_eof(ao) : true;
}
// Query the AO_EVENT_*s as requested by the events parameter, and return them.
int ao_query_and_reset_events(struct ao *ao, int events)
{
return atomic_fetch_and(&ao->events_, ~(unsigned)events) & events;
}
void ao_add_events(struct ao *ao, int events)
// Returns events that were set by this calls.
int ao_add_events(struct ao *ao, int events)
{
atomic_fetch_or(&ao->events_, events);
ao->wakeup_cb(ao->wakeup_ctx);
unsigned prev_events = atomic_fetch_or(&ao->events_, events);
unsigned new = events & ~prev_events;
if (new)
ao->wakeup_cb(ao->wakeup_ctx);
return new;
}
// Request that the player core destroys and recreates the AO. Fully thread-safe.
@@ -462,14 +369,6 @@ void ao_hotplug_event(struct ao *ao)
ao_add_events(ao, AO_EVENT_HOTPLUG);
}
void ao_underrun_event(struct ao *ao)
{
// Racy check, but it's just for the message.
if (!(atomic_load(&ao->events_) & AO_EVENT_UNDERRUN))
MP_WARN(ao, "Device underrun detected.\n");
ao_add_events(ao, AO_EVENT_UNDERRUN);
}
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map)
{
@@ -530,11 +429,6 @@ const char *ao_get_description(struct ao *ao)
return ao->driver->description;
}
bool ao_get_reports_underruns(struct ao *ao)
{
return ao->driver->reports_underruns;
}
bool ao_untimed(struct ao *ao)
{
return ao->untimed;
+7 -9
View File
@@ -39,13 +39,12 @@ enum aocontrol {
// If set, then the queued audio data is the last. Note that after a while, new
// data might be written again, instead of closing the AO.
#define AOPLAY_FINAL_CHUNK 1
#define PLAYER_FINAL_CHUNK 1
enum {
AO_EVENT_RELOAD = 1,
AO_EVENT_HOTPLUG = 2,
AO_EVENT_INITIAL_UNBLOCK = 4,
AO_EVENT_UNDERRUN = 8,
};
enum {
@@ -97,20 +96,19 @@ void ao_get_format(struct ao *ao,
int *samplerate, int *format, struct mp_chmap *channels);
const char *ao_get_name(struct ao *ao);
const char *ao_get_description(struct ao *ao);
bool ao_get_reports_underruns(struct ao *ao);
bool ao_untimed(struct ao *ao);
int ao_play(struct ao *ao, void **data, int samples, int flags);
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg);
void ao_set_gain(struct ao *ao, float gain);
double ao_get_delay(struct ao *ao);
int ao_get_space(struct ao *ao);
void ao_reset(struct ao *ao);
void ao_pause(struct ao *ao);
void ao_resume(struct ao *ao);
void ao_start(struct ao *ao);
void ao_set_paused(struct ao *ao, bool paused);
void ao_drain(struct ao *ao);
bool ao_eof_reached(struct ao *ao);
bool ao_is_playing(struct ao *ao);
struct mp_async_queue;
struct mp_async_queue *ao_get_queue(struct ao *ao);
int ao_query_and_reset_events(struct ao *ao, int events);
void ao_add_events(struct ao *ao, int events);
int ao_add_events(struct ao *ao, int events);
void ao_unblock(struct ao *ao);
void ao_request_reload(struct ao *ao);
void ao_hotplug_event(struct ao *ao);
+163 -269
View File
@@ -67,14 +67,14 @@ struct ao_alsa_opts {
#define OPT_BASE_STRUCT struct ao_alsa_opts
static const struct m_sub_options ao_alsa_conf = {
.opts = (const struct m_option[]) {
OPT_FLAG("alsa-resample", resample, 0),
OPT_STRING("alsa-mixer-device", mixer_device, 0),
OPT_STRING("alsa-mixer-name", mixer_name, 0),
OPT_INTRANGE("alsa-mixer-index", mixer_index, 0, 0, 99),
OPT_FLAG("alsa-non-interleaved", ni, 0),
OPT_FLAG("alsa-ignore-chmap", ignore_chmap, 0),
OPT_INTRANGE("alsa-buffer-time", buffer_time, 0, 0, INT_MAX),
OPT_INTRANGE("alsa-periods", frags, 0, 0, INT_MAX),
{"alsa-resample", OPT_FLAG(resample)},
{"alsa-mixer-device", OPT_STRING(mixer_device)},
{"alsa-mixer-name", OPT_STRING(mixer_name)},
{"alsa-mixer-index", OPT_INT(mixer_index), M_RANGE(0, 99)},
{"alsa-non-interleaved", OPT_FLAG(ni)},
{"alsa-ignore-chmap", OPT_FLAG(ignore_chmap)},
{"alsa-buffer-time", OPT_INT(buffer_time), M_RANGE(0, INT_MAX)},
{"alsa-periods", OPT_INT(frags), M_RANGE(0, INT_MAX)},
{0}
},
.defaults = &(const struct ao_alsa_opts) {
@@ -93,10 +93,6 @@ struct priv {
bool device_lost;
snd_pcm_format_t alsa_fmt;
bool can_pause;
bool paused;
bool final_chunk_written;
snd_pcm_sframes_t prepause_frames;
double delay_before_pause;
snd_pcm_uframes_t buffersize;
snd_pcm_uframes_t outburst;
@@ -121,34 +117,6 @@ struct priv {
MP_WARN(ao, "%s: %s\n", (message), snd_strerror(err)); \
} while (0)
// Common code for handling ENODEV, which happens if a device gets "lost", and
// can't be used anymore. Returns true if alsa_err is not ENODEV.
static bool check_device_present(struct ao *ao, int alsa_err)
{
struct priv *p = ao->priv;
if (alsa_err != -ENODEV)
return true;
if (!p->device_lost) {
MP_WARN(ao, "Device lost, trying to recover...\n");
ao_request_reload(ao);
p->device_lost = true;
}
return false;
}
static void handle_underrun(struct ao *ao)
{
struct priv *p = ao->priv;
if (!p->final_chunk_written) {
ao_underrun_event(ao);
int err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
alsa_error: ;
}
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
@@ -865,9 +833,8 @@ static int init_device(struct ao *ao, int mode)
err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary);
CHECK_ALSA_ERROR("Unable to get boundary");
/* start playing when one period has been written */
err = snd_pcm_sw_params_set_start_threshold
(p->alsa, alsa_swparams, p->outburst);
// Manual trigger; INT_MAX as suggested by ALSA doxygen (they call it MAXINT).
err = snd_pcm_sw_params_set_start_threshold(p->alsa, alsa_swparams, INT_MAX);
CHECK_ALSA_ERROR("Unable to set start threshold");
/* play silence when there is an underrun */
@@ -883,10 +850,12 @@ static int init_device(struct ao *ao, int mode)
MP_VERBOSE(ao, "period size: %d samples\n", (int)p->outburst);
ao->device_buffer = p->buffersize;
ao->period_size = p->outburst;
p->convert.channels = ao->channels.num;
err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
return 0;
alsa_error:
@@ -944,264 +913,194 @@ static int init(struct ao *ao)
return r;
}
static void drain(struct ao *ao)
// Function for dealing with playback state. This attempts to recover the ALSA
// state (bring it into SND_PCM_STATE_{PREPARED,RUNNING,PAUSED,UNDERRUN}). If
// state!=NULL, fill it after recovery is attempted.
// Returns true if PCM is in one the expected states.
static bool recover_and_get_state(struct ao *ao, struct mp_pcm_state *state)
{
struct priv *p = ao->priv;
snd_pcm_drain(p->alsa);
}
int err;
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
snd_pcm_status_t *st;
snd_pcm_status_alloca(&st);
// in case of pausing or the device still being configured,
// just return our buffer size.
if (p->paused || snd_pcm_state(p->alsa) == SND_PCM_STATE_SETUP)
return p->buffersize;
bool state_ok = false;
snd_pcm_state_t pcmst = SND_PCM_STATE_DISCONNECTED;
snd_pcm_sframes_t space = snd_pcm_avail(p->alsa);
if (space < 0 && space != -EPIPE) {
MP_ERR(ao, "Error received from snd_pcm_avail "
"(%ld, %s with ALSA state %s)!\n",
space, snd_strerror(space),
snd_pcm_state_name(snd_pcm_state(p->alsa)));
// Give it a number of chances to recover. This tries to deal with the fact
// that the API is asynchronous, and to account for some past cargo-cult
// (where things were retried in a loop).
for (int n = 0; n < 10; n++) {
err = snd_pcm_status(p->alsa, st);
if (err == -EPIPE) {
// ALSA APIs can return -EPIPE when an XRUN happens,
// we skip right to handling it by setting pcmst
// manually.
pcmst = SND_PCM_STATE_XRUN;
} else {
// Otherwise do error checking and query the PCM state properly.
CHECK_ALSA_ERROR("snd_pcm_status");
// request a reload of the AO if device is not present,
// then error out.
check_device_present(ao, space);
goto alsa_error;
pcmst = snd_pcm_status_get_state(st);
}
if (pcmst == SND_PCM_STATE_PREPARED ||
pcmst == SND_PCM_STATE_RUNNING ||
pcmst == SND_PCM_STATE_PAUSED)
{
state_ok = true;
break;
}
MP_VERBOSE(ao, "attempt %d to recover from state '%s'...\n",
n + 1, snd_pcm_state_name(pcmst));
switch (pcmst) {
// Underrun; recover. (We never use draining.)
case SND_PCM_STATE_XRUN:
case SND_PCM_STATE_DRAINING:
err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
continue;
// Hardware suspend.
case SND_PCM_STATE_SUSPENDED:
MP_INFO(ao, "PCM in suspend mode, trying to resume.\n");
err = snd_pcm_resume(p->alsa);
if (err == -EAGAIN) {
// Cargo-cult from decades ago, with a cargo cult timeout.
MP_INFO(ao, "PCM resume EAGAIN - retrying.\n");
sleep(1);
continue;
}
if (err == -ENOSYS) {
// As suggested by ALSA doxygen.
MP_VERBOSE(ao, "ENOSYS, retrying with snd_pcm_prepare().\n");
err = snd_pcm_prepare(p->alsa);
}
if (err < 0)
MP_ERR(ao, "resuming from SUSPENDED: %s\n", snd_strerror(err));
continue;
// Device lost. OPEN/SETUP are states we never enter after init, so
// treat them like DISCONNECTED.
case SND_PCM_STATE_DISCONNECTED:
case SND_PCM_STATE_OPEN:
case SND_PCM_STATE_SETUP:
default:
if (!p->device_lost) {
MP_WARN(ao, "Device lost, trying to recover...\n");
ao_request_reload(ao);
p->device_lost = true;
}
goto alsa_error;
}
}
if (space == -EPIPE)
handle_underrun(ao);
if (space > p->buffersize || space < 0) // Buffer underrun?
space = p->buffersize;
return space / p->outburst * p->outburst;
if (!state_ok) {
MP_ERR(ao, "could not recover\n");
}
alsa_error:
return 0;
if (state) {
snd_pcm_sframes_t del = state_ok ? snd_pcm_status_get_delay(st) : 0;
state->delay = MPMAX(del, 0) / (double)ao->samplerate;
state->free_samples = state_ok ? snd_pcm_status_get_avail(st) : 0;
state->free_samples = MPCLAMP(state->free_samples, 0, ao->device_buffer);
// Align to period size.
state->free_samples = state->free_samples / p->outburst * p->outburst;
state->queued_samples = ao->device_buffer - state->free_samples;
state->playing = pcmst == SND_PCM_STATE_RUNNING ||
pcmst == SND_PCM_STATE_PAUSED;
}
return state_ok;
}
/* delay in seconds between first and last sample in buffer */
static double get_delay(struct ao *ao)
static void audio_get_state(struct ao *ao, struct mp_pcm_state *state)
{
struct priv *p = ao->priv;
snd_pcm_sframes_t delay;
if (p->paused)
return p->delay_before_pause;
int err = snd_pcm_delay(p->alsa, &delay);
if (err < 0) {
if (err == -EPIPE)
handle_underrun(ao);
return 0;
}
if (delay < 0) {
/* underrun - move the application pointer forward to catch up */
snd_pcm_forward(p->alsa, -delay);
delay = 0;
}
return delay / (double)ao->samplerate;
recover_and_get_state(ao, state);
}
// For stream-silence mode: replace remaining buffer with silence.
// Tries to cause an instant buffer underrun.
static void soft_reset(struct ao *ao)
{
struct priv *p = ao->priv;
snd_pcm_sframes_t frames = snd_pcm_rewindable(p->alsa);
if (frames > 0 && snd_pcm_state(p->alsa) == SND_PCM_STATE_RUNNING) {
frames = snd_pcm_rewind(p->alsa, frames);
if (frames < 0) {
int err = frames;
CHECK_ALSA_WARN("pcm rewind error");
}
}
}
static void audio_pause(struct ao *ao)
static void audio_start(struct ao *ao)
{
struct priv *p = ao->priv;
int err;
if (p->paused)
return;
recover_and_get_state(ao, NULL);
p->delay_before_pause = get_delay(ao);
p->prepause_frames = p->delay_before_pause * ao->samplerate;
if (ao->stream_silence) {
soft_reset(ao);
} else if (p->can_pause) {
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_RUNNING) {
err = snd_pcm_pause(p->alsa, 1);
CHECK_ALSA_ERROR("pcm pause error");
p->prepause_frames = 0;
}
} else {
err = snd_pcm_drop(p->alsa);
CHECK_ALSA_ERROR("pcm drop error");
}
p->paused = true;
err = snd_pcm_start(p->alsa);
CHECK_ALSA_ERROR("pcm start error");
alsa_error: ;
}
static void resume_device(struct ao *ao)
static void audio_reset(struct ao *ao)
{
struct priv *p = ao->priv;
int err;
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_SUSPENDED) {
MP_INFO(ao, "PCM in suspend mode, trying to resume.\n");
err = snd_pcm_drop(p->alsa);
CHECK_ALSA_ERROR("pcm drop error");
err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
while ((err = snd_pcm_resume(p->alsa)) == -EAGAIN)
sleep(1);
}
}
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
int err;
if (!p->paused)
return;
resume_device(ao);
if (ao->stream_silence) {
p->paused = false;
get_delay(ao); // recovers from underrun (as a side-effect)
} else if (p->can_pause) {
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_PAUSED) {
err = snd_pcm_pause(p->alsa, 0);
CHECK_ALSA_ERROR("pcm resume error");
}
} else {
MP_VERBOSE(ao, "resume not supported by hardware\n");
err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
}
if (p->prepause_frames)
ao_play_silence(ao, p->prepause_frames);
alsa_error: ;
p->paused = false;
}
static void reset(struct ao *ao)
{
struct priv *p = ao->priv;
int err;
p->paused = false;
p->prepause_frames = 0;
p->delay_before_pause = 0;
p->final_chunk_written = false;
if (ao->stream_silence) {
soft_reset(ao);
} else {
err = snd_pcm_drop(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
}
recover_and_get_state(ao, NULL);
alsa_error: ;
}
static int play(struct ao *ao, void **data, int samples, int flags)
static bool audio_set_paused(struct ao *ao, bool paused)
{
struct priv *p = ao->priv;
snd_pcm_sframes_t res = 0;
bool final_chunk = flags & AOPLAY_FINAL_CHUNK;
int err;
if (!final_chunk)
samples = samples / p->outburst * p->outburst;
recover_and_get_state(ao, NULL);
if (!p->can_pause)
return false;
snd_pcm_state_t pcmst = snd_pcm_state(p->alsa);
if (pcmst == SND_PCM_STATE_RUNNING && paused) {
err = snd_pcm_pause(p->alsa, 1);
CHECK_ALSA_ERROR("pcm pause error");
} else if (pcmst == SND_PCM_STATE_PAUSED && !paused) {
err = snd_pcm_pause(p->alsa, 0);
CHECK_ALSA_ERROR("pcm resume error");
}
return true;
alsa_error:
return false;
}
static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *p = ao->priv;
if (samples == 0)
goto done;
ao_convert_inplace(&p->convert, data, samples);
do {
if (af_fmt_is_planar(ao->format)) {
res = snd_pcm_writen(p->alsa, data, samples);
} else {
res = snd_pcm_writei(p->alsa, data[0], samples);
}
if (!recover_and_get_state(ao, NULL))
return false;
if (res == -EINTR || res == -EAGAIN) { /* retry */
res = 0;
} else if (!check_device_present(ao, res)) {
goto alsa_error;
} else if (res < 0) {
if (res == -ESTRPIPE) { /* suspend */
resume_device(ao);
} else if (res == -EPIPE) {
handle_underrun(ao);
} else {
MP_ERR(ao, "Write error: %s\n", snd_strerror(res));
}
int err = snd_pcm_prepare(p->alsa);
CHECK_ALSA_ERROR("pcm prepare error");
res = 0;
}
} while (res == 0);
p->paused = false;
done:
p->final_chunk_written = res == samples && final_chunk;
return res < 0 ? -1 : res;
alsa_error:
return -1;
}
#define MAX_POLL_FDS 20
static int audio_wait(struct ao *ao, pthread_mutex_t *lock)
{
struct priv *p = ao->priv;
int err;
int num_fds = snd_pcm_poll_descriptors_count(p->alsa);
if (num_fds <= 0 || num_fds >= MAX_POLL_FDS)
goto alsa_error;
struct pollfd fds[MAX_POLL_FDS];
err = snd_pcm_poll_descriptors(p->alsa, fds, num_fds);
CHECK_ALSA_ERROR("cannot get pollfds");
while (1) {
int r = ao_wait_poll(ao, fds, num_fds, lock);
if (r)
return r;
unsigned short revents;
err = snd_pcm_poll_descriptors_revents(p->alsa, fds, num_fds, &revents);
CHECK_ALSA_ERROR("cannot read poll events");
if (revents & POLLERR) {
snd_pcm_status_t *status;
snd_pcm_status_alloca(&status);
err = snd_pcm_status(p->alsa, status);
check_device_present(ao, err);
return -1;
}
if (revents & POLLOUT)
return 0;
snd_pcm_sframes_t err = 0;
if (af_fmt_is_planar(ao->format)) {
err = snd_pcm_writen(p->alsa, data, samples);
} else {
err = snd_pcm_writei(p->alsa, data[0], samples);
}
return 0;
CHECK_ALSA_ERROR("pcm write error");
if (err >= 0 && err != samples) {
MP_ERR(ao, "unexpected partial write (%d of %d frames), dropping audio\n",
(int)err, samples);
}
return true;
alsa_error:
return -1;
return false;
}
static bool is_useless_device(char *name)
@@ -1254,17 +1153,12 @@ const struct ao_driver audio_out_alsa = {
.init = init,
.uninit = uninit,
.control = control,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
.drain = drain,
.wait = audio_wait,
.wakeup = ao_wakeup_poll,
.get_state = audio_get_state,
.write = audio_write,
.start = audio_start,
.set_pause = audio_set_paused,
.reset = audio_reset,
.list_devs = list_devs,
.reports_underruns = true,
.priv_size = sizeof(struct priv),
.global_opts = &ao_alsa_conf,
};
+3 -3
View File
@@ -706,11 +706,11 @@ const struct ao_driver audio_out_audiotrack = {
.init = init,
.uninit = uninit,
.reset = stop,
.resume = start,
.start = 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),
{"pcm-float", OPT_FLAG(cfg_pcm_float)},
{"session-id", OPT_INT(cfg_session_id)},
{0}
},
.options_prefix = "audiotrack",
+1 -2
View File
@@ -21,7 +21,6 @@
#include "audio/format.h"
#include "osdep/timer.h"
#include "options/m_option.h"
#include "misc/ring.h"
#include "common/msg.h"
#include "ao_coreaudio_utils.h"
#include "ao_coreaudio_chmap.h"
@@ -193,6 +192,6 @@ const struct ao_driver audio_out_audiounit = {
.uninit = uninit,
.init = init,
.reset = stop,
.resume = start,
.start = start,
.priv_size = sizeof(struct priv),
};
+2 -3
View File
@@ -23,7 +23,6 @@
#include "audio/format.h"
#include "osdep/timer.h"
#include "options/m_option.h"
#include "misc/ring.h"
#include "common/msg.h"
#include "ao_coreaudio_chmap.h"
#include "ao_coreaudio_properties.h"
@@ -417,13 +416,13 @@ const struct ao_driver audio_out_coreaudio = {
.init = init,
.control = control,
.reset = stop,
.resume = start,
.start = start,
.hotplug_init = hotplug_init,
.hotplug_uninit = hotplug_uninit,
.list_devs = ca_get_device_list,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]){
OPT_FLAG("change-physical-format", change_physical_format, 0),
{"change-physical-format", OPT_FLAG(change_physical_format)},
{0}
},
.options_prefix = "coreaudio",
+2 -2
View File
@@ -455,7 +455,7 @@ const struct ao_driver audio_out_coreaudio_exclusive = {
.uninit = uninit,
.init = init,
.reset = audio_pause,
.resume = audio_resume,
.start = audio_resume,
.list_devs = ca_get_device_list,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv){
@@ -465,7 +465,7 @@ const struct ao_driver audio_out_coreaudio_exclusive = {
.changed_mixing = false,
},
.options = (const struct m_option[]){
OPT_FLAG("spdif-hack", spdif_hack, 0),
{"spdif-hack", OPT_FLAG(spdif_hack)},
{0}
},
.options_prefix = "coreaudio",
+8 -8
View File
@@ -55,12 +55,12 @@ struct jack_opts {
#define OPT_BASE_STRUCT struct jack_opts
static const struct m_sub_options ao_jack_conf = {
.opts = (const struct m_option[]){
OPT_STRING("jack-port", port, 0),
OPT_STRING("jack-name", client_name, 0),
OPT_FLAG("jack-autostart", autostart, 0),
OPT_FLAG("jack-connect", connect, 0),
OPT_CHOICE("jack-std-channel-layout", stdlayout, 0,
({"waveext", 0}, {"any", 1})),
{"jack-port", OPT_STRING(port)},
{"jack-name", OPT_STRING(client_name)},
{"jack-autostart", OPT_FLAG(autostart)},
{"jack-connect", OPT_FLAG(connect)},
{"jack-std-channel-layout", OPT_CHOICE(stdlayout,
{"waveext", 0}, {"any", 1})},
{0}
},
.defaults = &(const struct jack_opts) {
@@ -194,7 +194,7 @@ err_port_register:
return -1;
}
static void resume(struct ao *ao)
static void start(struct ao *ao)
{
struct priv *p = ao->priv;
if (!p->activated) {
@@ -276,7 +276,7 @@ const struct ao_driver audio_out_jack = {
.name = "jack",
.init = init,
.uninit = uninit,
.resume = resume,
.start = start,
.priv_size = sizeof(struct priv),
.global_opts = &ao_jack_conf,
};
+102 -118
View File
@@ -30,8 +30,11 @@
#include "config.h"
#include "options/options.h"
#include "common/common.h"
#include "audio/aframe.h"
#include "audio/format.h"
#include "audio/fmt-conversion.h"
#include "filters/filter_internal.h"
#include "filters/f_utils.h"
#include "mpv_talloc.h"
#include "ao.h"
#include "internal.h"
@@ -44,20 +47,19 @@ struct priv {
int pcmhack;
int aframesize;
int aframecount;
int64_t savepts;
int framecount;
int64_t lastpts;
int sample_size;
const void *sample_padding;
double expected_next_pts;
struct mp_filter *filter_root;
struct mp_filter *fix_frame_size;
AVRational worst_time_base;
bool shutdown;
};
static void encode(struct ao *ao, double apts, void **data);
static bool write_frame(struct ao *ao, struct mp_frame frame);
static bool supports_format(const AVCodec *codec, int format)
{
@@ -87,6 +89,9 @@ static void select_format(struct ao *ao, const AVCodec *codec)
static void on_ready(void *ptr)
{
struct ao *ao = ptr;
struct priv *ac = ao->priv;
ac->worst_time_base = encoder_get_mux_timebase_unlocked(ac->enc);
ao_add_events(ao, AO_EVENT_INITIAL_UNBLOCK);
}
@@ -148,15 +153,16 @@ static int init(struct ao *ao)
// but at least one!
ac->framecount = MPMAX(ac->framecount, 1);
ac->savepts = AV_NOPTS_VALUE;
ac->lastpts = AV_NOPTS_VALUE;
ao->untimed = true;
ao->period_size = ac->aframesize * ac->framecount;
ao->device_buffer = ac->aframesize * ac->framecount;
if (ao->channels.num > AV_NUM_DATA_POINTERS)
goto fail;
ac->filter_root = mp_filter_create_root(ao->global);
ac->fix_frame_size = mp_fixed_aframe_size_create(ac->filter_root,
ac->aframesize, true);
MP_HANDLE_OOM(ac->fix_frame_size);
return 0;
@@ -181,106 +187,88 @@ static void uninit(struct ao *ao)
pthread_mutex_unlock(&ectx->lock);
outpts += encoder_get_offset(ac->enc);
encode(ao, outpts, NULL);
if (!write_frame(ao, MP_EOF_FRAME))
MP_WARN(ao, "could not flush last frame\n");
encoder_encode(ac->enc, NULL);
}
}
// return: how many samples can be played without blocking
static int get_space(struct ao *ao)
{
struct priv *ac = ao->priv;
return ac->aframesize * ac->framecount;
talloc_free(ac->filter_root);
}
// must get exactly ac->aframesize amount of data
static void encode(struct ao *ao, double apts, void **data)
static void encode(struct ao *ao, struct mp_aframe *af)
{
struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
AVCodecContext *encoder = ac->enc->encoder;
double realapts = ac->aframecount * (double) ac->aframesize /
ao->samplerate;
double outpts = mp_aframe_get_pts(af);
ac->aframecount++;
AVFrame *frame = mp_aframe_to_avframe(af);
if (!frame)
abort();
pthread_mutex_lock(&ectx->lock);
if (data)
ectx->audio_pts_offset = realapts - apts;
pthread_mutex_unlock(&ectx->lock);
frame->pts = rint(outpts * av_q2d(av_inv_q(encoder->time_base)));
if(data) {
AVFrame *frame = av_frame_alloc();
frame->format = af_to_avformat(ao->format);
frame->nb_samples = ac->aframesize;
size_t num_planes = af_fmt_is_planar(ao->format) ? ao->channels.num : 1;
assert(num_planes <= AV_NUM_DATA_POINTERS);
for (int n = 0; n < num_planes; n++)
frame->extended_data[n] = data[n];
frame->linesize[0] = frame->nb_samples * ao->sstride;
frame->pts = rint(apts * av_q2d(av_inv_q(encoder->time_base)));
int64_t frame_pts = av_rescale_q(frame->pts, encoder->time_base,
ac->worst_time_base);
if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) {
// this indicates broken video
// (video pts failing to increase fast enough to match audio)
MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n",
(int)frame->pts, (int)ac->lastpts);
frame_pts = ac->lastpts + 1;
frame->pts = av_rescale_q(frame_pts, ac->worst_time_base,
encoder->time_base);
}
int64_t frame_pts = av_rescale_q(frame->pts, encoder->time_base,
ac->worst_time_base);
if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) {
// whatever the fuck this code does?
MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n",
(int)frame->pts, (int)ac->lastpts);
frame_pts = ac->lastpts + 1;
ac->lastpts = frame_pts;
frame->quality = encoder->global_quality;
encoder_encode(ac->enc, frame);
av_frame_free(&frame);
} else {
encoder_encode(ac->enc, NULL);
frame->pts = av_rescale_q(frame_pts, ac->worst_time_base,
encoder->time_base);
frame_pts = av_rescale_q(frame->pts, encoder->time_base,
ac->worst_time_base);
}
ac->lastpts = frame_pts;
frame->quality = encoder->global_quality;
encoder_encode(ac->enc, frame);
av_frame_free(&frame);
}
// this should round samples down to frame sizes
// return: number of samples played
static int play(struct ao *ao, void **data, int samples, int flags)
static bool write_frame(struct ao *ao, struct mp_frame frame)
{
struct priv *ac = ao->priv;
// Can't push in frame if it doesn't want it output one.
mp_pin_out_request_data(ac->fix_frame_size->pins[1]);
if (!mp_pin_in_write(ac->fix_frame_size->pins[0], frame))
return false; // shouldn't happen™
while (1) {
struct mp_frame fr = mp_pin_out_read(ac->fix_frame_size->pins[1]);
if (!fr.type)
break;
if (fr.type != MP_FRAME_AUDIO)
continue;
struct mp_aframe *af = fr.data;
encode(ao, af);
mp_frame_unref(&fr);
}
return true;
}
static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *ac = ao->priv;
struct encoder_context *enc = ac->enc;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
int bufpos = 0;
// See ao_driver.write_frames.
struct mp_aframe *af = mp_aframe_new_ref(*(struct mp_aframe **)data);
double nextpts;
int orig_samples = samples;
double pts = mp_aframe_get_pts(af);
double outpts = pts;
// for ectx PTS fields
pthread_mutex_lock(&ectx->lock);
double pts = ectx->last_audio_in_pts;
pts += ectx->samples_since_last_pts / (double)ao->samplerate;
size_t num_planes = af_fmt_is_planar(ao->format) ? ao->channels.num : 1;
void *tempdata = NULL;
void *padded[MP_NUM_CHANNELS];
if ((flags & AOPLAY_FINAL_CHUNK) && (samples % ac->aframesize)) {
tempdata = talloc_new(NULL);
size_t bytelen = samples * ao->sstride;
size_t extralen = (ac->aframesize - 1) * ao->sstride;
for (int n = 0; n < num_planes; n++) {
padded[n] = talloc_size(tempdata, bytelen + extralen);
memcpy(padded[n], data[n], bytelen);
af_fill_silence((char *)padded[n] + bytelen, extralen, ao->format);
}
data = padded;
samples = (bytelen + extralen) / ao->sstride;
}
double outpts = pts;
if (!enc->options->rawts) {
if (!ectx->options->rawts) {
// Fix and apply the discontinuity pts offset.
nextpts = pts;
if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
@@ -297,52 +285,45 @@ static int play(struct ao *ao, void **data, int samples, int flags)
outpts = pts + ectx->discontinuity_pts_offset;
}
pthread_mutex_unlock(&ectx->lock);
// Shift pts by the pts offset first.
outpts += encoder_get_offset(enc);
while (samples - bufpos >= ac->aframesize) {
void *start[MP_NUM_CHANNELS] = {0};
for (int n = 0; n < num_planes; n++)
start[n] = (char *)data[n] + bufpos * ao->sstride;
encode(ao, outpts + bufpos / (double) ao->samplerate, start);
bufpos += ac->aframesize;
}
outpts += encoder_get_offset(ac->enc);
// Calculate expected pts of next audio frame (input side).
ac->expected_next_pts = pts + bufpos / (double) ao->samplerate;
pthread_mutex_lock(&ectx->lock);
ac->expected_next_pts = pts + mp_aframe_get_size(af) / (double) ao->samplerate;
// Set next allowed input pts value (input side).
if (!enc->options->rawts) {
if (!ectx->options->rawts) {
nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset;
if (nextpts > ectx->next_in_pts)
ectx->next_in_pts = nextpts;
}
talloc_free(tempdata);
int taken = MPMIN(bufpos, orig_samples);
ectx->samples_since_last_pts += taken;
pthread_mutex_unlock(&ectx->lock);
if (flags & AOPLAY_FINAL_CHUNK) {
if (bufpos < orig_samples)
MP_ERR(ao, "did not write enough data at the end\n");
} else {
if (bufpos > orig_samples)
MP_ERR(ao, "audio buffer overflow (should never happen)\n");
}
mp_aframe_set_pts(af, outpts);
return taken;
return write_frame(ao, MAKE_FRAME(MP_FRAME_AUDIO, af));
}
static void drain(struct ao *ao)
static void get_state(struct ao *ao, struct mp_pcm_state *state)
{
state->free_samples = 1;
state->queued_samples = 0;
state->delay = 0;
}
static bool set_pause(struct ao *ao, bool paused)
{
return true; // signal support so common code doesn't write silence
}
static void start(struct ao *ao)
{
// we use data immediately
}
static void reset(struct ao *ao)
{
// pretend we support it, so generic code doesn't force a wait
}
const struct ao_driver audio_out_lavc = {
@@ -350,12 +331,15 @@ const struct ao_driver audio_out_lavc = {
.description = "audio encoding using libavcodec",
.name = "lavc",
.initially_blocked = true,
.write_frames = true,
.priv_size = sizeof(struct priv),
.init = init,
.uninit = uninit,
.get_space = get_space,
.play = play,
.drain = drain,
.get_state = get_state,
.set_pause = set_pause,
.write = audio_write,
.start = start,
.reset = reset,
};
// vim: sw=4 ts=4 et tw=80
+49 -70
View File
@@ -40,9 +40,9 @@
struct priv {
bool paused;
double last_time;
bool playing_final;
float buffered; // samples
int buffersize; // samples
bool playing;
int untimed;
float bufferlen; // seconds
@@ -76,11 +76,8 @@ static void drain(struct ao *ao)
double now = mp_time_sec();
if (priv->buffered > 0) {
priv->buffered -= (now - priv->last_time) * ao->samplerate * priv->speed;
if (priv->buffered < 0) {
if (!priv->playing_final)
MP_ERR(ao, "buffer underrun\n");
if (priv->buffered < 0)
priv->buffered = 0;
}
}
priv->last_time = now;
}
@@ -108,12 +105,10 @@ static int init(struct ao *ao)
// A "buffer" for this many seconds of audio
int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst;
priv->buffersize = priv->outburst * bursts + priv->latency;
ao->device_buffer = priv->outburst * bursts + priv->latency;
priv->last_time = mp_time_sec();
ao->period_size = priv->outburst;
return 0;
}
@@ -122,98 +117,84 @@ static void uninit(struct ao *ao)
{
}
static void wait_drain(struct ao *ao)
{
struct priv *priv = ao->priv;
drain(ao);
if (!priv->paused)
mp_sleep_us(1000000.0 * priv->buffered / ao->samplerate / priv->speed);
}
// stop playing and empty buffers (for seeking/pause)
static void reset(struct ao *ao)
{
struct priv *priv = ao->priv;
priv->buffered = 0;
priv->playing_final = false;
priv->playing = false;
}
// stop playing, keep buffers (for pause)
static void pause(struct ao *ao)
static void start(struct ao *ao)
{
struct priv *priv = ao->priv;
drain(ao);
priv->paused = true;
}
// resume playing, after pause()
static void resume(struct ao *ao)
{
struct priv *priv = ao->priv;
if (priv->paused)
MP_ERR(ao, "illegal state: start() while paused\n");
drain(ao);
priv->paused = false;
priv->last_time = mp_time_sec();
priv->playing = true;
}
static int get_space(struct ao *ao)
static bool set_pause(struct ao *ao, bool paused)
{
struct priv *priv = ao->priv;
drain(ao);
int samples = priv->buffersize - priv->latency - priv->buffered;
return samples / priv->outburst * priv->outburst;
if (!priv->playing)
MP_ERR(ao, "illegal state: set_pause() while not playing\n");
if (priv->paused != paused) {
drain(ao);
priv->paused = paused;
if (!priv->paused)
priv->last_time = mp_time_sec();
}
return true;
}
static int play(struct ao *ao, void **data, int samples, int flags)
static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *priv = ao->priv;
int accepted;
resume(ao);
if (priv->buffered <= 0)
priv->buffered = priv->latency; // emulate fixed latency
priv->playing_final = flags & AOPLAY_FINAL_CHUNK;
if (priv->playing_final) {
// Last audio chunk - don't round to outburst.
accepted = MPMIN(priv->buffersize - priv->buffered, samples);
} else {
int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst;
int playbursts = samples / priv->outburst;
int bursts = playbursts > maxbursts ? maxbursts : playbursts;
accepted = bursts * priv->outburst;
}
priv->buffered += accepted;
return accepted;
priv->buffered += samples;
return true;
}
static double get_delay(struct ao *ao)
static void get_state(struct ao *ao, struct mp_pcm_state *state)
{
struct priv *priv = ao->priv;
drain(ao);
// Note how get_delay returns the delay in audio device time (instead of
state->free_samples = ao->device_buffer - priv->latency - priv->buffered;
state->free_samples = state->free_samples / priv->outburst * priv->outburst;
state->queued_samples = priv->buffered;
// Note how get_state returns the delay in audio device time (instead of
// adjusting for speed), since most AOs seem to also do that.
double delay = priv->buffered;
state->delay = priv->buffered;
// Drivers with broken EOF handling usually always report the same device-
// level delay that is additional to the buffer time.
if (priv->broken_eof && priv->buffered < priv->latency)
delay = priv->latency;
state->delay = priv->latency;
delay /= ao->samplerate;
state->delay /= ao->samplerate;
if (priv->broken_delay) { // Report only multiples of outburst
double q = priv->outburst / (double)ao->samplerate;
if (delay > 0)
delay = (int)(delay / q) * q;
if (state->delay > 0)
state->delay = (int)(state->delay / q) * q;
}
return delay;
state->playing = priv->playing && priv->buffered > 0;
}
#define OPT_BASE_STRUCT struct priv
@@ -224,12 +205,10 @@ const struct ao_driver audio_out_null = {
.init = init,
.uninit = uninit,
.reset = reset,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = pause,
.resume = resume,
.drain = wait_drain,
.get_state = get_state,
.set_pause = set_pause,
.write = audio_write,
.start = start,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.bufferlen = 0.2,
@@ -237,15 +216,15 @@ const struct ao_driver audio_out_null = {
.speed = 1,
},
.options = (const struct m_option[]) {
OPT_FLAG("untimed", untimed, 0),
OPT_FLOATRANGE("buffer", bufferlen, 0, 0, 100),
OPT_INTRANGE("outburst", outburst, 0, 1, 100000),
OPT_FLOATRANGE("speed", speed, 0, 0, 10000),
OPT_FLOATRANGE("latency", latency_sec, 0, 0, 100),
OPT_FLAG("broken-eof", broken_eof, 0),
OPT_FLAG("broken-delay", broken_delay, 0),
OPT_CHANNELS("channel-layouts", channel_layouts, 0),
OPT_AUDIOFORMAT("format", format, 0),
{"untimed", OPT_FLAG(untimed)},
{"buffer", OPT_FLOAT(bufferlen), M_RANGE(0, 100)},
{"outburst", OPT_INT(outburst), M_RANGE(1, 100000)},
{"speed", OPT_FLOAT(speed), M_RANGE(0, 10000)},
{"latency", OPT_FLOAT(latency_sec), M_RANGE(0, 100)},
{"broken-eof", OPT_FLAG(broken_eof)},
{"broken-delay", OPT_FLAG(broken_delay)},
{"channel-layouts", OPT_CHANNELS(channel_layouts)},
{"format", OPT_AUDIOFORMAT(format)},
{0}
},
.options_prefix = "ao-null",
+42 -82
View File
@@ -61,8 +61,6 @@ struct priv {
int direct_channels;
};
static void reset(struct ao *ao);
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
switch (cmd) {
@@ -266,7 +264,7 @@ static int init(struct ao *ao)
goto err_out;
}
ao->period_size = p->num_samples;
ao->device_buffer = p->num_buffers * p->num_samples;
return 0;
err_out:
@@ -274,16 +272,6 @@ err_out:
return -1;
}
static void drain(struct ao *ao)
{
ALint state;
alGetSourcei(source, AL_SOURCE_STATE, &state);
while (state == AL_PLAYING) {
mp_sleep_us(10000);
alGetSourcei(source, AL_SOURCE_STATE, &state);
}
}
static void unqueue_buffers(struct ao *ao)
{
struct priv *q = ao->priv;
@@ -301,67 +289,32 @@ static void unqueue_buffers(struct ao *ao)
}
}
/**
* \brief stop playing and empty buffers (for seeking/pause)
*/
static void reset(struct ao *ao)
{
alSourceStop(source);
unqueue_buffers(ao);
}
/**
* \brief stop playing, keep buffers (for pause)
*/
static void audio_pause(struct ao *ao)
static bool audio_set_pause(struct ao *ao, bool pause)
{
alSourcePause(source);
}
/**
* \brief resume playing, after audio_pause()
*/
static void audio_resume(struct ao *ao)
{
alSourcePlay(source);
}
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
ALint queued;
unqueue_buffers(ao);
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
queued = p->num_buffers - queued;
if (queued < 0)
return 0;
return p->num_samples * queued;
}
/**
* \brief write data into buffer and reset underrun flag
*/
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
int buffered_samples = 0;
int num = 0;
if (flags & AOPLAY_FINAL_CHUNK) {
num = 1;
buffered_samples = samples;
if (pause) {
alSourcePause(source);
} else {
num = samples / p->num_samples;
buffered_samples = num * p->num_samples;
alSourcePlay(source);
}
return true;
}
static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *p = ao->priv;
int num = (samples + p->num_samples - 1) / p->num_samples;
for (int i = 0; i < num; i++) {
char *d = *data;
if (flags & AOPLAY_FINAL_CHUNK) {
buffer_size[cur_buf] = samples;
} else {
buffer_size[cur_buf] = p->num_samples;
}
buffer_size[cur_buf] =
MPMIN(samples - i * p->num_samples, p->num_samples);
d += i * buffer_size[cur_buf] * ao->sstride;
alBufferData(buffers[cur_buf], p->al_format, d,
buffer_size[cur_buf] * ao->sstride, ao->samplerate);
@@ -369,33 +322,34 @@ static int play(struct ao *ao, void **data, int samples, int flags)
cur_buf = (cur_buf + 1) % p->num_buffers;
}
ALint state;
alGetSourcei(source, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING) // checked here in case of an underrun
alSourcePlay(source);
return buffered_samples;
return true;
}
static double get_delay(struct ao *ao)
static void audio_start(struct ao *ao)
{
alSourcePlay(source);
}
static void get_state(struct ao *ao, struct mp_pcm_state *state)
{
struct priv *p = ao->priv;
ALint queued;
unqueue_buffers(ao);
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
double soft_source_latency = 0;
double source_offset = 0;
if(alIsExtensionPresent("AL_SOFT_source_latency")) {
ALdouble offsets[2];
LPALGETSOURCEDVSOFT alGetSourcedvSOFT = alGetProcAddress("alGetSourcedvSOFT");
alGetSourcedvSOFT(source, AL_SEC_OFFSET_LATENCY_SOFT, offsets);
// Additional latency to the play buffer, the remaining seconds to be
// played minus the offset (seconds already played)
soft_source_latency = offsets[1] - offsets[0];
source_offset = offsets[1] - offsets[0];
} else {
float offset = 0;
alGetSourcef(source, AL_SEC_OFFSET, &offset);
soft_source_latency = -offset;
source_offset = -offset;
}
int queued_samples = 0;
@@ -403,7 +357,15 @@ static double get_delay(struct ao *ao)
queued_samples += buffer_size[index];
index = (index + 1) % p->num_buffers;
}
return (queued_samples / (double)ao->samplerate) + soft_source_latency;
state->delay = queued_samples / (double)ao->samplerate + source_offset;
state->queued_samples = queued_samples;
state->free_samples = MPMAX(p->num_buffers - queued, 0) * p->num_samples;
ALint source_state = 0;
alGetSourcei(source, AL_SOURCE_STATE, &source_state);
state->playing = source_state == AL_PLAYING;
}
#define OPT_BASE_STRUCT struct priv
@@ -414,13 +376,11 @@ const struct ao_driver audio_out_openal = {
.init = init,
.uninit = uninit,
.control = control,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = audio_pause,
.resume = audio_resume,
.get_state = get_state,
.write = audio_write,
.start = audio_start,
.set_pause = audio_set_pause,
.reset = reset,
.drain = drain,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.num_buffers = 4,
@@ -428,9 +388,9 @@ const struct ao_driver audio_out_openal = {
.direct_channels = 0,
},
.options = (const struct m_option[]) {
OPT_INTRANGE("num-buffers", num_buffers, 0, 2, MAX_BUF),
OPT_INTRANGE("num-samples", num_samples, 0, 256, MAX_SAMPLES),
OPT_FLAG("direct-channels", direct_channels, 0),
{"num-buffers", OPT_INT(num_buffers), M_RANGE(2, MAX_BUF)},
{"num-samples", OPT_INT(num_samples), M_RANGE(256, MAX_SAMPLES)},
{"direct-channels", OPT_FLAG(direct_channels)},
{0}
},
.options_prefix = "openal",
+5 -3
View File
@@ -247,15 +247,17 @@ const struct ao_driver audio_out_opensles = {
.init = init,
.uninit = uninit,
.reset = reset,
.resume = resume,
.start = resume,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.buffer_size_in_ms = 250,
},
.options = (const struct m_option[]) {
OPT_INTRANGE("frames-per-enqueue", frames_per_enqueue, 0, 1, 96000),
OPT_INTRANGE("buffer-size-in-ms", buffer_size_in_ms, 0, 0, 500),
{"frames-per-enqueue", OPT_INT(frames_per_enqueue),
M_RANGE(1, 96000)},
{"buffer-size-in-ms", OPT_INT(buffer_size_in_ms),
M_RANGE(0, 500)},
{0}
},
.options_prefix = "opensles",
-657
View File
@@ -1,657 +0,0 @@
/*
* OSS audio output driver
*
* Original author: A'rpi
* Support for >2 output channels added 2001-11-25
* - Steve Davies <steve@daviesfam.org>
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include "config.h"
#include "options/options.h"
#include "common/common.h"
#include "common/msg.h"
#include "osdep/timer.h"
#include "osdep/endian.h"
#include <sys/soundcard.h>
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
#if !HAVE_GPL
#error GPL only
#endif
// Define to 0 if the device must be reopened to reset it (stop all playback,
// clear the buffer), and the device should be closed when unused.
// Define to 1 if SNDCTL_DSP_RESET should be used to reset without close.
#if defined(SNDCTL_DSP_RESET) && !defined(__NetBSD__)
#define KEEP_DEVICE 1
#else
#define KEEP_DEVICE 0
#endif
#define PATH_DEV_DSP "/dev/dsp"
#define PATH_DEV_MIXER "/dev/mixer"
struct priv {
int audio_fd;
int prepause_samples;
int oss_mixer_channel;
int audio_delay_method;
int buffersize;
int outburst;
bool device_failed;
double audio_end;
char *oss_mixer_device;
char *cfg_oss_mixer_channel;
};
static const char *const mixer_channels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
/* like alsa except for 6.1 and 7.1, from pcm/matrix_map.h */
static const struct mp_chmap oss_layouts[MP_NUM_CHANNELS + 1] = {
{0}, // empty
MP_CHMAP_INIT_MONO, // mono
MP_CHMAP2(FL, FR), // stereo
MP_CHMAP3(FL, FR, LFE), // 2.1
MP_CHMAP4(FL, FR, BL, BR), // 4.0
MP_CHMAP5(FL, FR, BL, BR, FC), // 5.0
MP_CHMAP6(FL, FR, BL, BR, FC, LFE), // 5.1
MP_CHMAP7(FL, FR, BL, BR, FC, LFE, BC), // 6.1
MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), // 7.1
};
#if !defined(AFMT_S16_NE) && defined(AFMT_S16_LE) && defined(AFMT_S16_BE)
#define AFMT_S16_NE MP_SELECT_LE_BE(AFMT_S16_LE, AFMT_S16_BE)
#endif
#if !defined(AFMT_S32_NE) && defined(AFMT_S32_LE) && defined(AFMT_S32_BE)
#define AFMT_S32_NE AFMT_S32MP_SELECT_LE_BE(AFMT_S32_LE, AFMT_S32_BE)
#endif
static const int format_table[][2] = {
{AFMT_U8, AF_FORMAT_U8},
{AFMT_S16_NE, AF_FORMAT_S16},
#ifdef AFMT_S32_NE
{AFMT_S32_NE, AF_FORMAT_S32},
#endif
#ifdef AFMT_FLOAT
{AFMT_FLOAT, AF_FORMAT_FLOAT},
#endif
#ifdef AFMT_MPEG
{AFMT_MPEG, AF_FORMAT_S_MP3},
#endif
{-1, -1}
};
#ifndef AFMT_AC3
#define AFMT_AC3 -1
#endif
static int format2oss(int format)
{
for (int n = 0; format_table[n][0] != -1; n++) {
if (format_table[n][1] == format)
return format_table[n][0];
}
return -1;
}
static int oss2format(int format)
{
for (int n = 0; format_table[n][0] != -1; n++) {
if (format_table[n][0] == format)
return format_table[n][1];
}
return 0;
}
#ifdef SNDCTL_DSP_GETPLAYVOL
static int volume_oss4(struct ao *ao, ao_control_vol_t *vol, int cmd)
{
struct priv *p = ao->priv;
int v;
if (p->audio_fd < 0)
return CONTROL_ERROR;
if (cmd == AOCONTROL_GET_VOLUME) {
if (ioctl(p->audio_fd, SNDCTL_DSP_GETPLAYVOL, &v) == -1)
return CONTROL_ERROR;
vol->right = (v & 0xff00) >> 8;
vol->left = v & 0x00ff;
return CONTROL_OK;
} else if (cmd == AOCONTROL_SET_VOLUME) {
v = ((int) vol->right << 8) | (int) vol->left;
if (ioctl(p->audio_fd, SNDCTL_DSP_SETPLAYVOL, &v) == -1)
return CONTROL_ERROR;
return CONTROL_OK;
} else
return CONTROL_UNKNOWN;
}
#endif
// to set/get/query special features/parameters
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
switch (cmd) {
case AOCONTROL_GET_VOLUME:
case AOCONTROL_SET_VOLUME: {
ao_control_vol_t *vol = (ao_control_vol_t *)arg;
int fd, v, devs;
#ifdef SNDCTL_DSP_GETPLAYVOL
// Try OSS4 first
if (volume_oss4(ao, vol, cmd) == CONTROL_OK)
return CONTROL_OK;
#endif
if (!af_fmt_is_pcm(ao->format))
return CONTROL_TRUE;
if ((fd = open(p->oss_mixer_device, O_RDONLY)) != -1) {
ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs);
if (devs & (1 << p->oss_mixer_channel)) {
if (cmd == AOCONTROL_GET_VOLUME) {
ioctl(fd, MIXER_READ(p->oss_mixer_channel), &v);
vol->right = (v & 0xFF00) >> 8;
vol->left = v & 0x00FF;
} else {
v = ((int)vol->right << 8) | (int)vol->left;
ioctl(fd, MIXER_WRITE(p->oss_mixer_channel), &v);
}
} else {
close(fd);
return CONTROL_ERROR;
}
close(fd);
return CONTROL_OK;
}
return CONTROL_ERROR;
}
}
return CONTROL_UNKNOWN;
}
// 1: ok, 0: not writable, -1: error
static int device_writable(struct ao *ao)
{
struct priv *p = ao->priv;
struct pollfd fd = {.fd = p->audio_fd, .events = POLLOUT};
return poll(&fd, 1, 0);
}
static void close_device(struct ao *ao)
{
struct priv *p = ao->priv;
p->device_failed = false;
if (p->audio_fd == -1)
return;
#if defined(SNDCTL_DSP_RESET)
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#endif
close(p->audio_fd);
p->audio_fd = -1;
}
// close audio device
static void uninit(struct ao *ao)
{
close_device(ao);
}
static bool try_format(struct ao *ao, int *format)
{
struct priv *p = ao->priv;
int oss_format = format2oss(*format);
if (oss_format == -1 && af_fmt_is_spdif(*format))
oss_format = AFMT_AC3;
if (oss_format == -1) {
MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n",
af_fmt_to_str(*format));
*format = 0;
return false;
}
int actual_format = oss_format;
if (ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &actual_format) < 0)
actual_format = -1;
if (actual_format == oss_format)
return true;
MP_WARN(ao, "Can't set audio device to %s output.\n", af_fmt_to_str(*format));
*format = oss2format(actual_format);
if (actual_format != -1 && !*format)
MP_ERR(ao, "Unknown/Unsupported OSS format: 0x%x.\n", actual_format);
return false;
}
static int reopen_device(struct ao *ao, bool allow_format_changes)
{
struct priv *p = ao->priv;
int samplerate = ao->samplerate;
int format = ao->format;
struct mp_chmap channels = ao->channels;
const char *device = PATH_DEV_DSP;
if (ao->device)
device = ao->device;
MP_VERBOSE(ao, "using '%s' dsp device\n", device);
#ifdef __linux__
p->audio_fd = open(device, O_WRONLY | O_NONBLOCK);
#else
p->audio_fd = open(device, O_WRONLY);
#endif
if (p->audio_fd < 0) {
MP_ERR(ao, "Can't open audio device %s: %s\n",
device, mp_strerror(errno));
goto fail;
}
#ifdef __linux__
/* Remove the non-blocking flag */
if (fcntl(p->audio_fd, F_SETFL, 0) < 0) {
MP_ERR(ao, "Can't make file descriptor blocking: %s\n",
mp_strerror(errno));
goto fail;
}
#endif
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
if (af_fmt_is_spdif(format)) {
if (ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate) == -1)
goto fail;
// Probably could be fixed by setting number of channels; needs testing.
if (channels.num != 2) {
MP_ERR(ao, "Format %s not implemented.\n", af_fmt_to_str(format));
goto fail;
}
}
int try_formats[AF_FORMAT_COUNT + 1];
af_get_best_sample_formats(format, try_formats);
for (int n = 0; try_formats[n]; n++) {
format = try_formats[n];
if (try_format(ao, &format))
break;
}
if (!format) {
MP_ERR(ao, "Can't set sample format.\n");
goto fail;
}
MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(format));
if (!af_fmt_is_spdif(format)) {
struct mp_chmap_sel sel = {0};
for (int n = 0; n < MP_NUM_CHANNELS + 1; n++)
mp_chmap_sel_add_map(&sel, &oss_layouts[n]);
if (!ao_chmap_sel_adjust(ao, &sel, &channels))
goto fail;
int c, nchannels, reqchannels;
nchannels = reqchannels = channels.num;
// We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
if (reqchannels > 2) {
if (ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1) {
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
goto fail;
}
if (nchannels != reqchannels) {
// Fallback to stereo
nchannels = 2;
goto stereo;
}
} else {
stereo:
c = nchannels - 1;
if (ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
goto fail;
}
if (!ao_chmap_sel_get_def(ao, &sel, &channels, c + 1))
goto fail;
}
MP_VERBOSE(ao, "using %d channels (requested: %d)\n",
channels.num, reqchannels);
// set rate
if (ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate) == -1)
goto fail;
MP_VERBOSE(ao, "using %d Hz samplerate\n", samplerate);
}
audio_buf_info zz = {0};
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &zz) == -1) {
int r = 0;
MP_WARN(ao, "driver doesn't support SNDCTL_DSP_GETOSPACE\n");
if (ioctl(p->audio_fd, SNDCTL_DSP_GETBLKSIZE, &r) == -1)
MP_VERBOSE(ao, "%d bytes/frag (config.h)\n", p->outburst);
else {
p->outburst = r;
MP_VERBOSE(ao, "%d bytes/frag (GETBLKSIZE)\n", p->outburst);
}
} else {
MP_VERBOSE(ao, "frags: %3d/%d (%d bytes/frag) free: %6d\n",
zz.fragments, zz.fragstotal, zz.fragsize, zz.bytes);
p->buffersize = zz.bytes;
p->outburst = zz.fragsize;
}
if (allow_format_changes) {
ao->format = format;
ao->samplerate = samplerate;
ao->channels = channels;
} else {
if (format != ao->format || samplerate != ao->samplerate ||
!mp_chmap_equals(&channels, &ao->channels))
{
MP_ERR(ao, "Could not reselect previous audio format.\n");
goto fail;
}
}
int sstride = channels.num * af_fmt_to_bytes(format);
p->outburst -= p->outburst % sstride; // round down
ao->period_size = p->outburst / sstride;
return 0;
fail:
close_device(ao);
return -1;
}
// open & setup audio device
// return: 0=success -1=fail
static int init(struct ao *ao)
{
struct priv *p = ao->priv;
const char *mchan = NULL;
if (p->cfg_oss_mixer_channel && p->cfg_oss_mixer_channel[0])
mchan = p->cfg_oss_mixer_channel;
if (mchan) {
int fd, devs, i;
if ((fd = open(p->oss_mixer_device, O_RDONLY)) == -1) {
MP_ERR(ao, "Can't open mixer device %s: %s\n",
p->oss_mixer_device, mp_strerror(errno));
} else {
ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs);
close(fd);
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
if (!strcasecmp(mixer_channels[i], mchan)) {
if (!(devs & (1 << i))) {
MP_ERR(ao, "Audio card mixer does not have "
"channel '%s', using default.\n", mchan);
i = SOUND_MIXER_NRDEVICES + 1;
break;
}
p->oss_mixer_channel = i;
break;
}
}
if (i == SOUND_MIXER_NRDEVICES) {
MP_ERR(ao, "Audio card mixer does not have "
"channel '%s', using default.\n", mchan);
}
}
} else {
p->oss_mixer_channel = SOUND_MIXER_PCM;
}
MP_VERBOSE(ao, "using '%s' mixer device\n", p->oss_mixer_device);
MP_VERBOSE(ao, "using '%s' mixer channel\n", mixer_channels[p->oss_mixer_channel]);
ao->format = af_fmt_from_planar(ao->format);
if (reopen_device(ao, true) < 0)
goto fail;
if (p->buffersize == -1) {
// Measuring buffer size:
void *data = malloc(p->outburst);
if (!data) {
MP_ERR(ao, "Out of memory, or broken outburst size.\n");
goto fail;
}
p->buffersize = 0;
memset(data, 0, p->outburst);
while (p->buffersize < 0x40000 && device_writable(ao) > 0) {
(void)write(p->audio_fd, data, p->outburst);
p->buffersize += p->outburst;
}
free(data);
if (p->buffersize == 0) {
MP_ERR(ao, "Your OSS audio driver DOES NOT support poll().\n");
goto fail;
}
}
return 0;
fail:
uninit(ao);
return -1;
}
static void drain(struct ao *ao)
{
#ifdef SNDCTL_DSP_SYNC
struct priv *p = ao->priv;
// to get the buffer played
if (p->audio_fd != -1)
ioctl(p->audio_fd, SNDCTL_DSP_SYNC, NULL);
#endif
}
// stop playing and empty buffers (for seeking/pause)
static void reset(struct ao *ao)
{
#if KEEP_DEVICE
struct priv *p = ao->priv;
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
#endif
}
// plays 'len' samples of 'data'
// it should round it down to outburst*n
// return: number of samples played
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
int len = samples * ao->sstride;
if (len == 0)
return len;
if (p->audio_fd < 0 && !p->device_failed && reopen_device(ao, false) < 0)
MP_ERR(ao, "Fatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n");
if (p->audio_fd < 0) {
// Let playback continue normally, even with a closed device.
p->device_failed = true;
double now = mp_time_sec();
if (p->audio_end < now)
p->audio_end = now;
p->audio_end += samples / (double)ao->samplerate;
return samples;
}
if (len > p->outburst || !(flags & AOPLAY_FINAL_CHUNK)) {
len /= p->outburst;
len *= p->outburst;
}
len = write(p->audio_fd, data[0], len);
return len / ao->sstride;
}
// return: delay in seconds between first and last sample in buffer
static double get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->audio_fd < 0) {
double rest = p->audio_end - mp_time_sec();
if (rest > 0)
return rest;
return 0;
}
/* Calculate how many bytes/second is sent out */
if (p->audio_delay_method == 2) {
#ifdef SNDCTL_DSP_GETODELAY
int r = 0;
if (ioctl(p->audio_fd, SNDCTL_DSP_GETODELAY, &r) != -1)
return r / (double)ao->bps;
#endif
p->audio_delay_method = 1; // fallback if not supported
}
if (p->audio_delay_method == 1) {
audio_buf_info zz = {0};
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &zz) != -1) {
return (p->buffersize - zz.bytes) / (double)ao->bps;
}
p->audio_delay_method = 0; // fallback if not supported
}
return p->buffersize / (double)ao->bps;
}
// return: how many samples can be played without blocking
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
audio_buf_info zz = {0};
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &zz) != -1) {
// calculate exact buffer space:
return zz.fragments * zz.fragsize / ao->sstride;
}
if (p->audio_fd < 0 && p->device_failed && get_delay(ao) > 0.2)
return 0;
if (p->audio_fd < 0 || device_writable(ao) > 0)
return p->outburst / ao->sstride;
return 0;
}
// stop playing, keep buffers (for pause)
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
p->prepause_samples = get_delay(ao) * ao->samplerate;
#if KEEP_DEVICE
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
#endif
}
// resume playing, after audio_pause()
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
p->audio_end = 0;
if (p->prepause_samples > 0)
ao_play_silence(ao, p->prepause_samples);
}
static int audio_wait(struct ao *ao, pthread_mutex_t *lock)
{
struct priv *p = ao->priv;
struct pollfd fd = {.fd = p->audio_fd, .events = POLLOUT};
int r = ao_wait_poll(ao, &fd, 1, lock);
if (fd.revents & (POLLERR | POLLNVAL))
return -1;
return r;
}
static void list_devs(struct ao *ao, struct ao_device_list *list)
{
if (stat(PATH_DEV_DSP, &(struct stat){0}) == 0)
ao_device_list_add(list, ao, &(struct ao_device_desc){"", "Default"});
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_oss = {
.description = "OSS/ioctl audio output",
.name = "oss",
.init = init,
.uninit = uninit,
.control = control,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
.drain = drain,
.wait = audio_wait,
.wakeup = ao_wakeup_poll,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.audio_fd = -1,
.audio_delay_method = 2,
.buffersize = -1,
.outburst = 512,
.oss_mixer_channel = SOUND_MIXER_PCM,
.oss_mixer_device = PATH_DEV_MIXER,
},
.options = (const struct m_option[]) {
OPT_STRING("mixer-device", oss_mixer_device, M_OPT_FILE),
OPT_STRING("mixer-channel", cfg_oss_mixer_channel, 0),
{0}
},
.options_prefix = "oss",
};
+41 -18
View File
@@ -111,9 +111,11 @@ static int init(struct ao *ao)
{
struct priv *priv = ao->priv;
if (!priv->outputfilename)
priv->outputfilename =
talloc_strdup(priv, priv->waveheader ? "audiodump.wav" : "audiodump.pcm");
char *outputfilename = priv->outputfilename;
if (!outputfilename) {
outputfilename = talloc_strdup(priv, priv->waveheader ? "audiodump.wav"
: "audiodump.pcm");
}
ao->format = af_fmt_from_planar(ao->format);
@@ -148,18 +150,19 @@ static int init(struct ao *ao)
ao->bps = ao->channels.num * ao->samplerate * af_fmt_to_bytes(ao->format);
MP_INFO(ao, "File: %s (%s)\nPCM: Samplerate: %d Hz Channels: %d Format: %s\n",
priv->outputfilename,
outputfilename,
priv->waveheader ? "WAVE" : "RAW PCM", ao->samplerate,
ao->channels.num, af_fmt_to_str(ao->format));
priv->fp = fopen(priv->outputfilename, priv->append ? "ab" : "wb");
priv->fp = fopen(outputfilename, priv->append ? "ab" : "wb");
if (!priv->fp) {
MP_ERR(ao, "Failed to open %s for writing!\n", priv->outputfilename);
MP_ERR(ao, "Failed to open %s for writing!\n", outputfilename);
return -1;
}
if (priv->waveheader) // Reserve space for wave header
write_wave_header(ao, priv->fp, 0x7ffff000);
ao->untimed = true;
ao->device_buffer = 1 << 16;
return 0;
}
@@ -191,19 +194,36 @@ static void uninit(struct ao *ao)
fclose(priv->fp);
}
static int get_space(struct ao *ao)
{
return 65536;
}
static int play(struct ao *ao, void **data, int samples, int flags)
static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *priv = ao->priv;
int len = samples * ao->sstride;
fwrite(data[0], len, 1, priv->fp);
priv->data_length += len;
return samples;
return true;
}
static void get_state(struct ao *ao, struct mp_pcm_state *state)
{
state->free_samples = ao->device_buffer;
state->queued_samples = 0;
state->delay = 0;
}
static bool set_pause(struct ao *ao, bool paused)
{
return true; // signal support so common code doesn't write silence
}
static void start(struct ao *ao)
{
// we use data immediately
}
static void reset(struct ao *ao)
{
}
#define OPT_BASE_STRUCT struct priv
@@ -213,14 +233,17 @@ const struct ao_driver audio_out_pcm = {
.name = "pcm",
.init = init,
.uninit = uninit,
.get_space = get_space,
.play = play,
.get_state = get_state,
.set_pause = set_pause,
.write = audio_write,
.start = start,
.reset = reset,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) { .waveheader = 1 },
.options = (const struct m_option[]) {
OPT_STRING("file", outputfilename, M_OPT_FILE),
OPT_FLAG("waveheader", waveheader, 0),
OPT_FLAG("append", append, 0),
{"file", OPT_STRING(outputfilename), .flags = M_OPT_FILE},
{"waveheader", OPT_FLAG(waveheader)},
{"append", OPT_FLAG(append)},
{0}
},
.options_prefix = "ao-pcm",
+96 -113
View File
@@ -52,11 +52,8 @@ struct priv {
struct pa_sink_input_info pi;
int retval;
// for wakeup handling
pthread_mutex_t wakeup_lock;
pthread_cond_t wakeup;
int wakeup_status;
bool playing;
bool underrun_signalled;
char *cfg_host;
int cfg_buffer;
@@ -119,38 +116,14 @@ static void stream_state_cb(pa_stream *s, void *userdata)
}
}
static void wakeup(struct ao *ao)
{
struct priv *priv = ao->priv;
pthread_mutex_lock(&priv->wakeup_lock);
priv->wakeup_status = 1;
pthread_cond_signal(&priv->wakeup);
pthread_mutex_unlock(&priv->wakeup_lock);
}
static void stream_request_cb(pa_stream *s, size_t length, void *userdata)
{
struct ao *ao = userdata;
struct priv *priv = ao->priv;
wakeup(ao);
ao_wakeup_playthread(ao);
pa_threaded_mainloop_signal(priv->mainloop, 0);
}
static int wait_audio(struct ao *ao, pthread_mutex_t *lock)
{
struct priv *priv = ao->priv;
// We don't use this mutex, because pulse like to call stream_request_cb
// while we have the central mutex held.
pthread_mutex_unlock(lock);
pthread_mutex_lock(&priv->wakeup_lock);
while (!priv->wakeup_status)
pthread_cond_wait(&priv->wakeup, &priv->wakeup_lock);
priv->wakeup_status = 0;
pthread_mutex_unlock(&priv->wakeup_lock);
pthread_mutex_lock(lock);
return 0;
}
static void stream_latency_update_cb(pa_stream *s, void *userdata)
{
struct ao *ao = userdata;
@@ -158,6 +131,16 @@ static void stream_latency_update_cb(pa_stream *s, void *userdata)
pa_threaded_mainloop_signal(priv->mainloop, 0);
}
static void underflow_cb(pa_stream *s, void *userdata)
{
struct ao *ao = userdata;
struct priv *priv = ao->priv;
priv->playing = false;
priv->underrun_signalled = true;
ao_wakeup_playthread(ao);
pa_threaded_mainloop_signal(priv->mainloop, 0);
}
static void success_cb(pa_stream *s, int success, void *userdata)
{
struct ao *ao = userdata;
@@ -166,28 +149,33 @@ static void success_cb(pa_stream *s, int success, void *userdata)
pa_threaded_mainloop_signal(priv->mainloop, 0);
}
/**
* \brief waits for a pulseaudio operation to finish, frees it and
* unlocks the mainloop
* \param op operation to wait for
* \return 1 if operation has finished normally (DONE state), 0 otherwise
*/
static int waitop(struct priv *priv, pa_operation *op)
// Like waitop(), but keep the lock (even if it may unlock temporarily).
static bool waitop_no_unlock(struct priv *priv, pa_operation *op)
{
if (!op) {
pa_threaded_mainloop_unlock(priv->mainloop);
return 0;
}
if (!op)
return false;
pa_operation_state_t state = pa_operation_get_state(op);
while (state == PA_OPERATION_RUNNING) {
pa_threaded_mainloop_wait(priv->mainloop);
state = pa_operation_get_state(op);
}
pa_operation_unref(op);
pa_threaded_mainloop_unlock(priv->mainloop);
return state == PA_OPERATION_DONE;
}
/**
* \brief waits for a pulseaudio operation to finish, frees it and
* unlocks the mainloop
* \param op operation to wait for
* \return 1 if operation has finished normally (DONE state), 0 otherwise
*/
static bool waitop(struct priv *priv, pa_operation *op)
{
bool r = waitop_no_unlock(priv, op);
pa_threaded_mainloop_unlock(priv->mainloop);
return r;
}
static const struct format_map {
int mp_format;
pa_sample_format_t pa_format;
@@ -278,15 +266,6 @@ static bool select_chmap(struct ao *ao, pa_channel_map *dst)
chmap_pa_from_mp(dst, &ao->channels);
}
static void drain(struct ao *ao)
{
struct priv *priv = ao->priv;
if (priv->stream) {
pa_threaded_mainloop_lock(priv->mainloop);
waitop(priv, pa_stream_drain(priv->stream, success_cb, ao));
}
}
static void uninit(struct ao *ao)
{
struct priv *priv = ao->priv;
@@ -310,9 +289,6 @@ static void uninit(struct ao *ao)
pa_threaded_mainloop_free(priv->mainloop);
priv->mainloop = NULL;
}
pthread_cond_destroy(&priv->wakeup);
pthread_mutex_destroy(&priv->wakeup_lock);
}
static int pa_init_boilerplate(struct ao *ao)
@@ -321,9 +297,6 @@ static int pa_init_boilerplate(struct ao *ao)
char *host = priv->cfg_host && priv->cfg_host[0] ? priv->cfg_host : NULL;
bool locked = false;
pthread_mutex_init(&priv->wakeup_lock, NULL);
pthread_cond_init(&priv->wakeup, NULL);
if (!(priv->mainloop = pa_threaded_mainloop_new())) {
MP_ERR(ao, "Failed to allocate main loop\n");
goto fail;
@@ -460,17 +433,18 @@ static int init(struct ao *ao)
pa_stream_set_write_callback(priv->stream, stream_request_cb, ao);
pa_stream_set_latency_update_callback(priv->stream,
stream_latency_update_cb, ao);
pa_stream_set_underflow_callback(priv->stream, underflow_cb, ao);
uint32_t buf_size = ao->samplerate * (priv->cfg_buffer / 1000.0) *
af_fmt_to_bytes(ao->format) * ao->channels.num;
pa_buffer_attr bufattr = {
.maxlength = -1,
.tlength = buf_size > 0 ? buf_size : -1,
.prebuf = -1,
.prebuf = 0,
.minreq = -1,
.fragsize = -1,
};
int flags = PA_STREAM_NOT_MONOTONIC;
int flags = PA_STREAM_NOT_MONOTONIC | PA_STREAM_START_CORKED;
if (!priv->cfg_latency_hacks)
flags |= PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE;
@@ -493,6 +467,14 @@ static int init(struct ao *ao)
goto unlock_and_fail;
}
const pa_buffer_attr* final_bufattr = pa_stream_get_buffer_attr(priv->stream);
if(!final_bufattr) {
MP_ERR(ao, "PulseAudio didn't tell us what buffer sizes it set. Bailing out.\n");
goto unlock_and_fail;
}
ao->device_buffer = final_bufattr->tlength /
af_fmt_to_bytes(ao->format) / ao->channels.num;
pa_threaded_mainloop_unlock(priv->mainloop);
return 0;
@@ -514,28 +496,36 @@ static void cork(struct ao *ao, bool pause)
struct priv *priv = ao->priv;
pa_threaded_mainloop_lock(priv->mainloop);
priv->retval = 0;
if (!waitop(priv, pa_stream_cork(priv->stream, pause, success_cb, ao)) ||
!priv->retval)
if (waitop_no_unlock(priv, pa_stream_cork(priv->stream, pause, success_cb, ao))
&& priv->retval)
{
if (!pause)
priv->playing = true;
} else {
GENERIC_ERR_MSG("pa_stream_cork() failed");
priv->playing = false;
}
pa_threaded_mainloop_unlock(priv->mainloop);
}
// Play the specified data to the pulseaudio server
static int play(struct ao *ao, void **data, int samples, int flags)
static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *priv = ao->priv;
bool res = true;
pa_threaded_mainloop_lock(priv->mainloop);
if (pa_stream_write(priv->stream, data[0], samples * ao->sstride, NULL, 0,
PA_SEEK_RELATIVE) < 0) {
GENERIC_ERR_MSG("pa_stream_write() failed");
samples = -1;
}
if (flags & AOPLAY_FINAL_CHUNK) {
// Force start in case the stream was too short for prebuf
pa_operation *op = pa_stream_trigger(priv->stream, NULL, NULL);
pa_operation_unref(op);
res = false;
}
pa_threaded_mainloop_unlock(priv->mainloop);
return samples;
return res;
}
static void start(struct ao *ao)
{
cork(ao, false);
}
// Reset the audio stream, i.e. flush the playback buffer on the server side
@@ -549,29 +539,12 @@ static void reset(struct ao *ao)
if (!waitop(priv, pa_stream_flush(priv->stream, success_cb, ao)) ||
!priv->retval)
GENERIC_ERR_MSG("pa_stream_flush() failed");
cork(ao, false);
}
// Pause the audio stream by corking it on the server
static void pause(struct ao *ao)
static bool set_pause(struct ao *ao, bool paused)
{
cork(ao, true);
}
// Resume the audio stream by uncorking it on the server
static void resume(struct ao *ao)
{
cork(ao, false);
}
// Return number of samples that may be written to the server without blocking
static int get_space(struct ao *ao)
{
struct priv *priv = ao->priv;
pa_threaded_mainloop_lock(priv->mainloop);
size_t space = pa_stream_writable_size(priv->stream);
pa_threaded_mainloop_unlock(priv->mainloop);
return space / ao->sstride;
cork(ao, paused);
return true;
}
static double get_delay_hackfixed(struct ao *ao)
@@ -590,21 +563,19 @@ static double get_delay_hackfixed(struct ao *ao)
* this should be enough to fix the normal local playback case.
*/
struct priv *priv = ao->priv;
pa_threaded_mainloop_lock(priv->mainloop);
if (!waitop(priv, pa_stream_update_timing_info(priv->stream, NULL, NULL))) {
if (!waitop_no_unlock(priv, pa_stream_update_timing_info(priv->stream,
NULL, NULL)))
{
GENERIC_ERR_MSG("pa_stream_update_timing_info() failed");
return 0;
}
pa_threaded_mainloop_lock(priv->mainloop);
const pa_timing_info *ti = pa_stream_get_timing_info(priv->stream);
if (!ti) {
pa_threaded_mainloop_unlock(priv->mainloop);
GENERIC_ERR_MSG("pa_stream_get_timing_info() failed");
return 0;
}
const struct pa_sample_spec *ss = pa_stream_get_sample_spec(priv->stream);
if (!ss) {
pa_threaded_mainloop_unlock(priv->mainloop);
GENERIC_ERR_MSG("pa_stream_get_sample_spec() failed");
return 0;
}
@@ -625,7 +596,6 @@ static double get_delay_hackfixed(struct ao *ao)
latency += sink_latency;
if (latency < 0)
latency = 0;
pa_threaded_mainloop_unlock(priv->mainloop);
return latency / 1e6;
}
@@ -633,7 +603,6 @@ static double get_delay_pulse(struct ao *ao)
{
struct priv *priv = ao->priv;
pa_usec_t latency = (pa_usec_t) -1;
pa_threaded_mainloop_lock(priv->mainloop);
while (pa_stream_get_latency(priv->stream, &latency, NULL) < 0) {
if (pa_context_errno(priv->context) != PA_ERR_NODATA) {
GENERIC_ERR_MSG("pa_stream_get_latency() failed");
@@ -642,18 +611,35 @@ static double get_delay_pulse(struct ao *ao)
/* Wait until latency data is available again */
pa_threaded_mainloop_wait(priv->mainloop);
}
pa_threaded_mainloop_unlock(priv->mainloop);
return latency == (pa_usec_t) -1 ? 0 : latency / 1000000.0;
}
// Return the current latency in seconds
static double get_delay(struct ao *ao)
static void audio_get_state(struct ao *ao, struct mp_pcm_state *state)
{
struct priv *priv = ao->priv;
pa_threaded_mainloop_lock(priv->mainloop);
size_t space = pa_stream_writable_size(priv->stream);
state->free_samples = space == (size_t)-1 ? 0 : space / ao->sstride;
state->queued_samples = ao->device_buffer - state->free_samples; // dunno
if (priv->cfg_latency_hacks) {
return get_delay_hackfixed(ao);
state->delay = get_delay_hackfixed(ao);
} else {
return get_delay_pulse(ao);
state->delay = get_delay_pulse(ao);
}
state->playing = priv->playing;
pa_threaded_mainloop_unlock(priv->mainloop);
// Otherwise, PA will keep hammering us for underruns (which it does instead
// of stopping the stream automatically).
if (!state->playing && priv->underrun_signalled) {
reset(ao);
priv->underrun_signalled = false;
}
}
@@ -821,14 +807,10 @@ const struct ao_driver audio_out_pulse = {
.init = init,
.uninit = uninit,
.reset = reset,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = pause,
.resume = resume,
.drain = drain,
.wait = wait_audio,
.wakeup = wakeup,
.get_state = audio_get_state,
.write = audio_write,
.start = start,
.set_pause = set_pause,
.hotplug_init = hotplug_init,
.hotplug_uninit = hotplug_uninit,
.list_devs = list_devs,
@@ -837,10 +819,11 @@ const struct ao_driver audio_out_pulse = {
.cfg_buffer = 100,
},
.options = (const struct m_option[]) {
OPT_STRING("host", cfg_host, 0),
OPT_CHOICE_OR_INT("buffer", cfg_buffer, 0, 1, 2000, ({"native", 0})),
OPT_FLAG("latency-hacks", cfg_latency_hacks, 0),
OPT_FLAG("allow-suspended", cfg_allow_suspended, 0),
{"host", OPT_STRING(cfg_host)},
{"buffer", OPT_CHOICE(cfg_buffer, {"native", 0}),
M_RANGE(1, 2000)},
{"latency-hacks", OPT_FLAG(cfg_latency_hacks)},
{"allow-suspended", OPT_FLAG(cfg_allow_suspended)},
{0}
},
.options_prefix = "pulse",
-154
View File
@@ -1,154 +0,0 @@
/*
* RSound audio output driver
*
* Copyright (C) 2011 Hans-Kristian Arntzen
*
* 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 "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <rsound.h>
#include "mpv_talloc.h"
#include "options/m_option.h"
#include "osdep/timer.h"
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
struct priv {
rsound_t *rd;
};
static int set_format(struct ao *ao)
{
int rsd_format;
switch (ao->format) {
case AF_FORMAT_U8:
rsd_format = RSD_U8;
break;
case AF_FORMAT_S32:
rsd_format = RSD_S32_NE;
break;
default:
rsd_format = RSD_S16_NE;
ao->format = AF_FORMAT_S16;
}
return rsd_format;
}
static int init(struct ao *ao)
{
struct priv *priv = ao->priv;
if (rsd_init(&priv->rd) < 0)
return -1;
if (ao->device)
rsd_set_param(priv->rd, RSD_HOST, ao->device);
// Actual channel layout unknown.
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext_def(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) {
rsd_free(priv->rd);
return -1;
}
rsd_set_param(priv->rd, RSD_SAMPLERATE, (int[]) { ao->samplerate });
rsd_set_param(priv->rd, RSD_CHANNELS, (int[]) { ao->channels.num });
ao->format = af_fmt_from_planar(ao->format);
int rsd_format = set_format(ao);
rsd_set_param(priv->rd, RSD_FORMAT, &rsd_format);
if (rsd_start(priv->rd) < 0) {
rsd_free(priv->rd);
return -1;
}
return 0;
}
static void uninit(struct ao *ao)
{
struct priv *priv = ao->priv;
rsd_stop(priv->rd);
rsd_free(priv->rd);
}
static void reset(struct ao *ao)
{
struct priv *priv = ao->priv;
rsd_stop(priv->rd);
rsd_start(priv->rd);
}
static void audio_pause(struct ao *ao)
{
struct priv *priv = ao->priv;
rsd_pause(priv->rd, 1);
}
static void audio_resume(struct ao *ao)
{
struct priv *priv = ao->priv;
rsd_pause(priv->rd, 0);
}
static int get_space(struct ao *ao)
{
struct priv *priv = ao->priv;
return rsd_get_avail(priv->rd) / ao->sstride;
}
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *priv = ao->priv;
return rsd_write(priv->rd, data[0], samples * ao->sstride) / ao->sstride;
}
static double get_delay(struct ao *ao)
{
struct priv *priv = ao->priv;
return rsd_delay_ms(priv->rd) / 1000.0;
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_rsound = {
.description = "RSound output driver",
.name = "rsound",
.init = init,
.uninit = uninit,
.reset = reset,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = audio_pause,
.resume = audio_resume,
.priv_size = sizeof(struct priv),
};
+3 -4
View File
@@ -188,7 +188,7 @@ static void reset(struct ao *ao)
priv->paused = 1;
}
static void resume(struct ao *ao)
static void start(struct ao *ao)
{
struct priv *priv = ao->priv;
if (priv->paused)
@@ -204,14 +204,13 @@ const struct ao_driver audio_out_sdl = {
.init = init,
.uninit = uninit,
.reset = reset,
.resume = resume,
.reports_underruns = true,
.start = start,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.buflen = 0, // use SDL default
},
.options = (const struct m_option[]) {
OPT_FLOAT("buflen", buflen, 0),
{"buflen", OPT_FLOAT(buflen)},
{0}
},
.options_prefix = "sdl",
-319
View File
@@ -1,319 +0,0 @@
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
* Copyright (c) 2013 Christian Neukirchen <chneukirchen@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#include <sys/types.h>
#include <poll.h>
#include <errno.h>
#include <sndio.h>
#include "options/m_option.h"
#include "common/msg.h"
#include "audio/format.h"
#include "ao.h"
#include "internal.h"
struct priv {
struct sio_hdl *hdl;
struct sio_par par;
int delay;
bool playing;
int vol;
int havevol;
#define SILENCE_NMAX 0x1000
char silence[SILENCE_NMAX];
struct pollfd *pfd;
char *dev;
};
/*
* misc parameters (volume, etc...)
*/
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
ao_control_vol_t *vol = arg;
switch (cmd) {
case AOCONTROL_GET_VOLUME:
if (!p->havevol)
return CONTROL_FALSE;
vol->left = vol->right = p->vol * 100 / SIO_MAXVOL;
break;
case AOCONTROL_SET_VOLUME:
if (!p->havevol)
return CONTROL_FALSE;
sio_setvol(p->hdl, vol->left * SIO_MAXVOL / 100);
break;
default:
return CONTROL_UNKNOWN;
}
return CONTROL_OK;
}
/*
* call-back invoked to notify of the hardware position
*/
static void movecb(void *addr, int delta)
{
struct priv *p = addr;
p->delay -= delta;
}
/*
* call-back invoked to notify about volume changes
*/
static void volcb(void *addr, unsigned newvol)
{
struct priv *p = addr;
p->vol = newvol;
}
static const struct mp_chmap sndio_layouts[MP_NUM_CHANNELS + 1] = {
{0}, // empty
{1, {MP_SPEAKER_ID_FL}}, // mono
MP_CHMAP2(FL, FR), // stereo
{0}, // 2.1
MP_CHMAP4(FL, FR, BL, BR), // 4.0
{0}, // 5.0
MP_CHMAP6(FL, FR, BL, BR, FC, LFE), // 5.1
{0}, // 6.1
MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), // 7.1
/* above is the fixed channel assignment for sndio, since we need to fill
all channels and cannot insert silence, not all layouts are supported.
NOTE: MP_SPEAKER_ID_NA could be used to add padding channels. */
};
/*
* open device and setup parameters
* return: 0=success -1=fail
*/
static int init(struct ao *ao)
{
struct priv *p = ao->priv;
struct af_to_par {
int format, bits, sig;
};
static const struct af_to_par af_to_par[] = {
{AF_FORMAT_U8, 8, 0},
{AF_FORMAT_S16, 16, 1},
{AF_FORMAT_S32, 32, 1},
};
const struct af_to_par *ap;
int i;
p->hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0);
if (p->hdl == NULL) {
MP_ERR(ao, "can't open sndio %s\n", SIO_DEVANY);
goto error;
}
ao->format = af_fmt_from_planar(ao->format);
sio_initpar(&p->par);
for (i = 0, ap = af_to_par;; i++, ap++) {
if (i == sizeof(af_to_par) / sizeof(struct af_to_par)) {
MP_VERBOSE(ao, "unsupported format\n");
p->par.bits = 16;
p->par.sig = 1;
p->par.le = SIO_LE_NATIVE;
break;
}
if (ap->format == ao->format) {
p->par.bits = ap->bits;
p->par.sig = ap->sig;
if (ap->bits > 8)
p->par.le = SIO_LE_NATIVE;
if (ap->bits != SIO_BPS(ap->bits))
p->par.bps = ap->bits / 8;
break;
}
}
p->par.rate = ao->samplerate;
struct mp_chmap_sel sel = {0};
for (int n = 0; n < MP_NUM_CHANNELS+1; n++)
mp_chmap_sel_add_map(&sel, &sndio_layouts[n]);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
goto error;
p->par.pchan = ao->channels.num;
p->par.appbufsz = p->par.rate * 250 / 1000; /* 250ms buffer */
p->par.round = p->par.rate * 10 / 1000; /* 10ms block size */
if (!sio_setpar(p->hdl, &p->par)) {
MP_ERR(ao, "couldn't set params\n");
goto error;
}
if (!sio_getpar(p->hdl, &p->par)) {
MP_ERR(ao, "couldn't get params\n");
goto error;
}
if (p->par.bps > 1 && p->par.le != SIO_LE_NATIVE) {
MP_ERR(ao, "swapped endian output not supported\n");
goto error;
}
if (p->par.bits == 8 && p->par.bps == 1 && !p->par.sig) {
ao->format = AF_FORMAT_U8;
} else if (p->par.bits == 16 && p->par.bps == 2 && p->par.sig) {
ao->format = AF_FORMAT_S16;
} else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4 && p->par.sig) {
ao->format = AF_FORMAT_S32;
} else {
MP_ERR(ao, "couldn't set format\n");
goto error;
}
p->havevol = sio_onvol(p->hdl, volcb, p);
sio_onmove(p->hdl, movecb, p);
if (!sio_start(p->hdl))
MP_ERR(ao, "init: couldn't start\n");
p->pfd = calloc (sio_nfds(p->hdl), sizeof (struct pollfd));
if (!p->pfd)
goto error;
ao->period_size = p->par.round;
return 0;
error:
if (p->hdl)
sio_close(p->hdl);
return -1;
}
/*
* close device
*/
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->hdl)
sio_close(p->hdl);
free(p->pfd);
}
/*
* stop playing and empty buffers (for seeking/pause)
*/
static void reset(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->playing) {
MP_WARN(ao, "Blocking until remaining audio is played... (sndio design bug).\n");
p->playing = false;
if (!sio_stop(p->hdl))
MP_ERR(ao, "reset: couldn't stop\n");
p->delay = 0;
if (!sio_start(p->hdl))
MP_ERR(ao, "reset: couldn't start\n");
}
}
/*
* play given number of samples until sio_write() blocks
*/
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
int n;
n = sio_write(p->hdl, data[0], samples * ao->sstride) / ao->sstride;
p->delay += n;
p->playing = true;
/* on AOPLAY_FINAL_CHUNK, just let it underrun */
return n;
}
/*
* make libsndio call movecb()
*/
static void update(struct ao *ao)
{
struct priv *p = ao->priv;
int n = sio_pollfd(p->hdl, p->pfd, POLLOUT);
while (poll(p->pfd, n, 0) < 0 && errno == EINTR) {}
sio_revents(p->hdl, p->pfd);
}
/*
* how many samples can be played without blocking
*/
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
update(ao);
int samples = p->par.bufsz - p->delay;
return samples / p->par.round * p->par.round;
}
/*
* return: delay in seconds between first and last sample in buffer
*/
static double get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
update(ao);
return p->delay / (double)p->par.rate;
}
/*
* stop playing, keep buffers (for pause)
*/
static void audio_pause(struct ao *ao)
{
reset(ao);
}
/*
* resume playing, after audio_pause()
*/
static void audio_resume(struct ao *ao)
{
return;
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_sndio = {
.description = "sndio audio output",
.name = "sndio",
.init = init,
.uninit = uninit,
.control = control,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
.priv_size = sizeof(struct priv),
};
+1 -1
View File
@@ -493,7 +493,7 @@ const struct ao_driver audio_out_wasapi = {
.uninit = uninit,
.control = control,
.reset = audio_reset,
.resume = audio_resume,
.start = audio_resume,
.list_devs = wasapi_list_devs,
.hotplug_init = hotplug_init,
.hotplug_uninit = hotplug_uninit,
+40 -15
View File
@@ -299,8 +299,9 @@ static bool set_ao_format(struct ao *ao, WAVEFORMATEX *wf,
}
#define mp_format_res_str(hres) \
(SUCCEEDED(hres) ? "ok" : ((hres) == AUDCLNT_E_UNSUPPORTED_FORMAT) \
? "unsupported" : mp_HRESULT_to_str(hres))
(SUCCEEDED(hres) ? ((hres) == S_OK) ? "ok" : "close" \
: ((hres) == AUDCLNT_E_UNSUPPORTED_FORMAT) \
? "unsupported" : mp_HRESULT_to_str(hres))
static bool try_format_exclusive(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat)
{
@@ -426,32 +427,57 @@ static bool find_formats_shared(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat)
{
struct wasapi_state *state = ao->priv;
WAVEFORMATEX *closestMatch;
HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient,
AUDCLNT_SHAREMODE_SHARED,
&wformat->Format,
&closestMatch);
struct mp_chmap channels;
if (!chmap_from_waveformat(&channels, &wformat->Format)) {
MP_ERR(ao, "Error converting channel map\n");
return false;
}
HRESULT hr;
WAVEFORMATEX *mix_format;
hr = IAudioClient_GetMixFormat(state->pAudioClient, &mix_format);
EXIT_ON_ERROR(hr);
// WASAPI doesn't do any sample rate conversion on its own and
// will typically only accept the mix format samplerate. Although
// it will accept any PCM sample format, everything gets converted
// to the mix format anyway (pretty much always float32), so just
// use that.
WAVEFORMATEXTENSIBLE try_format;
waveformat_copy(&try_format, mix_format);
CoTaskMemFree(mix_format);
// WASAPI may accept channel maps other than the mix format
// if a surround emulator is enabled.
change_waveformat_channels(&try_format, &channels);
hr = IAudioClient_IsFormatSupported(state->pAudioClient,
AUDCLNT_SHAREMODE_SHARED,
&try_format.Format,
&mix_format);
MP_VERBOSE(ao, "Trying %s (shared) -> %s\n",
waveformat_to_str(&wformat->Format), mp_format_res_str(hr));
waveformat_to_str(&try_format.Format), mp_format_res_str(hr));
if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
EXIT_ON_ERROR(hr);
switch (hr) {
case S_OK:
waveformat_copy(wformat, &try_format.Format);
break;
case S_FALSE:
waveformat_copy(wformat, closestMatch);
CoTaskMemFree(closestMatch);
waveformat_copy(wformat, mix_format);
CoTaskMemFree(mix_format);
MP_VERBOSE(ao, "Closest match is %s\n",
waveformat_to_str(&wformat->Format));
break;
default:
hr = IAudioClient_GetMixFormat(state->pAudioClient, &closestMatch);
hr = IAudioClient_GetMixFormat(state->pAudioClient, &mix_format);
EXIT_ON_ERROR(hr);
waveformat_copy(wformat, closestMatch);
waveformat_copy(wformat, mix_format);
CoTaskMemFree(mix_format);
MP_VERBOSE(ao, "Fallback to mix format %s\n",
waveformat_to_str(&wformat->Format));
CoTaskMemFree(closestMatch);
}
return true;
@@ -525,9 +551,8 @@ static void init_session_display(struct wasapi_state *state) {
(void **)&state->pSessionControl);
EXIT_ON_ERROR(hr);
wchar_t path[MAX_PATH+12] = {0};
wchar_t path[MAX_PATH] = {0};
GetModuleFileNameW(NULL, path, MAX_PATH);
wcscat(path, L",-IDI_ICON1");
hr = IAudioSessionControl_SetIconPath(state->pSessionControl, path, NULL);
if (FAILED(hr)) {
// don't goto exit_label here since SetDisplayName might still work
+699
View File
@@ -0,0 +1,699 @@
/*
* 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 <stddef.h>
#include <pthread.h>
#include <inttypes.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include "ao.h"
#include "internal.h"
#include "audio/aframe.h"
#include "audio/format.h"
#include "common/msg.h"
#include "common/common.h"
#include "filters/f_async_queue.h"
#include "filters/filter_internal.h"
#include "osdep/timer.h"
#include "osdep/threads.h"
struct buffer_state {
// Buffer and AO
pthread_mutex_t lock;
pthread_cond_t wakeup;
// Playthread sleep
pthread_mutex_t pt_lock;
pthread_cond_t pt_wakeup;
// Access from AO driver's thread only.
char *convert_buffer;
// Immutable.
struct mp_async_queue *queue;
// --- protected by lock
struct mp_filter *filter_root;
struct mp_filter *input; // connected to queue
struct mp_aframe *pending; // last, not fully consumed output
bool streaming; // AO streaming active
bool playing; // logically playing audio from buffer
bool paused; // logically paused
int64_t end_time_us; // absolute output time of last played sample
bool initial_unblocked;
// "Push" AOs only (AOs with driver->write).
bool hw_paused; // driver->set_pause() was used successfully
bool recover_pause; // non-hw_paused: needs to recover delay
struct mp_pcm_state prepause_state;
pthread_t thread; // thread shoveling data to AO
bool thread_valid; // thread is running
struct mp_aframe *temp_buf;
// --- protected by pt_lock
bool need_wakeup;
bool terminate; // exit thread
};
static void *playthread(void *arg);
void ao_wakeup_playthread(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
pthread_mutex_lock(&p->pt_lock);
p->need_wakeup = true;
pthread_cond_broadcast(&p->pt_wakeup);
pthread_mutex_unlock(&p->pt_lock);
}
// called locked
static void get_dev_state(struct ao *ao, struct mp_pcm_state *state)
{
struct buffer_state *p = ao->buffer_state;
if (p->paused && p->playing && !ao->stream_silence) {
*state = p->prepause_state;
return;
}
*state = (struct mp_pcm_state){
.free_samples = -1,
.queued_samples = -1,
.delay = -1,
};
ao->driver->get_state(ao, state);
}
struct mp_async_queue *ao_get_queue(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
return p->queue;
}
// Special behavior with data==NULL: caller uses p->pending.
static int read_buffer(struct ao *ao, void **data, int samples, bool *eof)
{
struct buffer_state *p = ao->buffer_state;
int pos = 0;
*eof = false;
while (p->playing && !p->paused && pos < samples) {
if (!p->pending || !mp_aframe_get_size(p->pending)) {
TA_FREEP(&p->pending);
struct mp_frame frame = mp_pin_out_read(p->input->pins[0]);
if (!frame.type)
break; // we can't/don't want to block
if (frame.type != MP_FRAME_AUDIO) {
if (frame.type == MP_FRAME_EOF)
*eof = true;
mp_frame_unref(&frame);
continue;
}
p->pending = frame.data;
}
if (!data)
break;
int copy = mp_aframe_get_size(p->pending);
uint8_t **fdata = mp_aframe_get_data_ro(p->pending);
copy = MPMIN(copy, samples - pos);
for (int n = 0; n < ao->num_planes; n++) {
memcpy((char *)data[n] + pos * ao->sstride,
fdata[n], copy * ao->sstride);
}
mp_aframe_skip_samples(p->pending, copy);
pos += copy;
*eof = false;
}
if (!data) {
if (!p->pending)
return 0;
void **pd = (void *)mp_aframe_get_data_rw(p->pending);
if (pd)
ao_post_process_data(ao, pd, mp_aframe_get_size(p->pending));
return 1;
}
// pad with silence (underflow/paused/eof)
for (int n = 0; n < ao->num_planes; n++) {
af_fill_silence((char *)data[n] + pos, (samples - pos) * ao->sstride,
ao->format);
}
ao_post_process_data(ao, data, pos);
return pos;
}
// Read the given amount of samples in the user-provided data buffer. Returns
// the number of samples copied. If there is not enough data (buffer underrun
// or EOF), return the number of samples that could be copied, and fill the
// rest of the user-provided buffer with silence.
// This basically assumes that the audio device doesn't care about underruns.
// If this is called in paused mode, it will always return 0.
// The caller should set out_time_us to the expected delay until the last sample
// reaches the speakers, in microseconds, using mp_time_us() as reference.
int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us)
{
struct buffer_state *p = ao->buffer_state;
assert(!ao->driver->write);
pthread_mutex_lock(&p->lock);
int pos = read_buffer(ao, data, samples, &(bool){0});
if (pos > 0)
p->end_time_us = out_time_us;
if (pos < samples && p->playing && !p->paused) {
p->playing = false;
// For ao_drain().
pthread_cond_broadcast(&p->wakeup);
}
pthread_mutex_unlock(&p->lock);
return pos;
}
// Same as ao_read_data(), but convert data according to *fmt.
// fmt->src_fmt and fmt->channels must be the same as the AO parameters.
int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt,
void **data, int samples, int64_t out_time_us)
{
struct buffer_state *p = ao->buffer_state;
void *ndata[MP_NUM_CHANNELS] = {0};
if (!ao_need_conversion(fmt))
return ao_read_data(ao, data, samples, out_time_us);
assert(ao->format == fmt->src_fmt);
assert(ao->channels.num == fmt->channels);
bool planar = af_fmt_is_planar(fmt->src_fmt);
int planes = planar ? fmt->channels : 1;
int plane_samples = samples * (planar ? 1: fmt->channels);
int src_plane_size = plane_samples * af_fmt_to_bytes(fmt->src_fmt);
int dst_plane_size = plane_samples * fmt->dst_bits / 8;
int needed = src_plane_size * planes;
if (needed > talloc_get_size(p->convert_buffer) || !p->convert_buffer) {
talloc_free(p->convert_buffer);
p->convert_buffer = talloc_size(NULL, needed);
}
for (int n = 0; n < planes; n++)
ndata[n] = p->convert_buffer + n * src_plane_size;
int res = ao_read_data(ao, ndata, samples, out_time_us);
ao_convert_inplace(fmt, ndata, samples);
for (int n = 0; n < planes; n++)
memcpy(data[n], ndata[n], dst_plane_size);
return res;
}
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct buffer_state *p = ao->buffer_state;
int r = CONTROL_UNKNOWN;
if (ao->driver->control) {
// Only need to lock in push mode.
if (ao->driver->write)
pthread_mutex_lock(&p->lock);
r = ao->driver->control(ao, cmd, arg);
if (ao->driver->write)
pthread_mutex_unlock(&p->lock);
}
return r;
}
double ao_get_delay(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
pthread_mutex_lock(&p->lock);
double driver_delay;
if (ao->driver->write) {
struct mp_pcm_state state;
get_dev_state(ao, &state);
driver_delay = state.delay;
} else {
int64_t end = p->end_time_us;
int64_t now = mp_time_us();
driver_delay = MPMAX(0, (end - now) / (1000.0 * 1000.0));
}
int pending = mp_async_queue_get_samples(p->queue);
if (p->pending)
pending += mp_aframe_get_size(p->pending);
pthread_mutex_unlock(&p->lock);
return driver_delay + pending / (double)ao->samplerate;
}
// Fully stop playback; clear buffers, including queue.
void ao_reset(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
bool wakeup = false;
bool do_reset = false;
pthread_mutex_lock(&p->lock);
TA_FREEP(&p->pending);
mp_async_queue_reset(p->queue);
mp_filter_reset(p->filter_root);
mp_async_queue_resume_reading(p->queue);
if (!ao->stream_silence && ao->driver->reset) {
if (ao->driver->write) {
ao->driver->reset(ao);
} else {
// Pull AOs may wait for ao_read_data() to return.
// That would deadlock if called from within the lock.
do_reset = true;
}
p->streaming = false;
}
wakeup = p->playing;
p->playing = false;
p->recover_pause = false;
p->hw_paused = false;
p->end_time_us = 0;
pthread_mutex_unlock(&p->lock);
if (do_reset)
ao->driver->reset(ao);
if (wakeup)
ao_wakeup_playthread(ao);
}
// Initiate playback. This moves from the stop/underrun state to actually
// playing (orthogonally taking the paused state into account). Plays all
// data in the queue, and goes into underrun state if no more data available.
// No-op if already running.
void ao_start(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
bool do_start = false;
pthread_mutex_lock(&p->lock);
p->playing = true;
if (!ao->driver->write && !p->paused && !p->streaming) {
p->streaming = true;
do_start = true;
}
pthread_mutex_unlock(&p->lock);
// Pull AOs might call ao_read_data() so do this outside the lock.
if (do_start)
ao->driver->start(ao);
ao_wakeup_playthread(ao);
}
void ao_set_paused(struct ao *ao, bool paused)
{
struct buffer_state *p = ao->buffer_state;
bool wakeup = false;
bool do_reset = false, do_start = false;
pthread_mutex_lock(&p->lock);
if (p->playing && !p->paused && paused) {
if (p->streaming && !ao->stream_silence) {
if (ao->driver->write) {
if (!p->recover_pause)
get_dev_state(ao, &p->prepause_state);
if (ao->driver->set_pause && ao->driver->set_pause(ao, true)) {
p->hw_paused = true;
} else {
ao->driver->reset(ao);
p->streaming = false;
p->recover_pause = !ao->untimed;
}
} else if (ao->driver->reset) {
// See ao_reset() why this is done outside of the lock.
do_reset = true;
p->streaming = false;
}
}
wakeup = true;
} else if (p->playing && p->paused && !paused) {
if (ao->driver->write) {
if (p->hw_paused)
ao->driver->set_pause(ao, false);
p->hw_paused = false;
} else {
if (!p->streaming)
do_start = true;
p->streaming = true;
}
wakeup = true;
}
p->paused = paused;
pthread_mutex_unlock(&p->lock);
if (do_reset)
ao->driver->reset(ao);
if (do_start)
ao->driver->start(ao);
if (wakeup)
ao_wakeup_playthread(ao);
}
// Whether audio is playing. This means that there is still data in the buffers,
// and ao_start() was called. This returns true even if playback was logically
// paused. On false, EOF was reached, or an underrun happened, or ao_reset()
// was called.
bool ao_is_playing(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
pthread_mutex_lock(&p->lock);
bool playing = p->playing;
pthread_mutex_unlock(&p->lock);
return playing;
}
// Block until the current audio buffer has played completely.
void ao_drain(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
pthread_mutex_lock(&p->lock);
while (!p->paused && p->playing) {
pthread_mutex_unlock(&p->lock);
double delay = ao_get_delay(ao);
pthread_mutex_lock(&p->lock);
// Limit to buffer + arbitrary ~250ms max. waiting for robustness.
delay += mp_async_queue_get_samples(p->queue) / (double)ao->samplerate;
struct timespec ts = mp_rel_time_to_timespec(MPMAX(delay, 0) + 0.25);
// Wait for EOF signal from AO.
if (pthread_cond_timedwait(&p->wakeup, &p->lock, &ts)) {
MP_VERBOSE(ao, "drain timeout\n");
break;
}
if (!p->playing && mp_async_queue_get_samples(p->queue)) {
MP_WARN(ao, "underrun during draining\n");
pthread_mutex_unlock(&p->lock);
ao_start(ao);
pthread_mutex_lock(&p->lock);
}
}
pthread_mutex_unlock(&p->lock);
ao_reset(ao);
}
static void wakeup_filters(void *ctx)
{
struct ao *ao = ctx;
ao_wakeup_playthread(ao);
}
void ao_uninit(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
if (p->thread_valid) {
pthread_mutex_lock(&p->pt_lock);
p->terminate = true;
pthread_cond_broadcast(&p->pt_wakeup);
pthread_mutex_unlock(&p->pt_lock);
pthread_join(p->thread, NULL);
p->thread_valid = false;
}
if (ao->driver_initialized)
ao->driver->uninit(ao);
talloc_free(p->filter_root);
talloc_free(p->queue);
talloc_free(p->pending);
talloc_free(p->convert_buffer);
talloc_free(p->temp_buf);
pthread_cond_destroy(&p->wakeup);
pthread_mutex_destroy(&p->lock);
pthread_cond_destroy(&p->pt_wakeup);
pthread_mutex_destroy(&p->pt_lock);
talloc_free(ao);
}
void init_buffer_pre(struct ao *ao)
{
ao->buffer_state = talloc_zero(ao, struct buffer_state);
}
bool init_buffer_post(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
assert(ao->driver->start);
if (ao->driver->write) {
assert(ao->driver->reset);
assert(ao->driver->get_state);
}
pthread_mutex_init(&p->lock, NULL);
pthread_cond_init(&p->wakeup, NULL);
pthread_mutex_init(&p->pt_lock, NULL);
pthread_cond_init(&p->pt_wakeup, NULL);
p->queue = mp_async_queue_create();
p->filter_root = mp_filter_create_root(ao->global);
p->input = mp_async_queue_create_filter(p->filter_root, MP_PIN_OUT, p->queue);
mp_async_queue_resume_reading(p->queue);
struct mp_async_queue_config cfg = {
.sample_unit = AQUEUE_UNIT_SAMPLES,
.max_samples = ao->buffer,
.max_bytes = INT64_MAX,
};
mp_async_queue_set_config(p->queue, cfg);
if (ao->driver->write) {
mp_filter_graph_set_wakeup_cb(p->filter_root, wakeup_filters, ao);
p->thread_valid = true;
if (pthread_create(&p->thread, NULL, playthread, ao)) {
p->thread_valid = false;
return false;
}
} else {
if (ao->stream_silence) {
ao->driver->start(ao);
p->streaming = true;
}
}
if (ao->stream_silence) {
MP_WARN(ao, "The --audio-stream-silence option is set. This will break "
"certain player behavior.\n");
}
return true;
}
static bool realloc_buf(struct ao *ao, int samples)
{
struct buffer_state *p = ao->buffer_state;
samples = MPMAX(1, samples);
if (!p->temp_buf || samples > mp_aframe_get_size(p->temp_buf)) {
TA_FREEP(&p->temp_buf);
p->temp_buf = mp_aframe_create();
if (!mp_aframe_set_format(p->temp_buf, ao->format) ||
!mp_aframe_set_chmap(p->temp_buf, &ao->channels) ||
!mp_aframe_set_rate(p->temp_buf, ao->samplerate) ||
!mp_aframe_alloc_data(p->temp_buf, samples))
{
TA_FREEP(&p->temp_buf);
return false;
}
}
return true;
}
// called locked
static bool ao_play_data(struct ao *ao)
{
struct buffer_state *p = ao->buffer_state;
if ((!p->playing || p->paused) && !ao->stream_silence)
return false;
struct mp_pcm_state state;
get_dev_state(ao, &state);
if (p->streaming && !state.playing && !ao->untimed)
goto eof;
void **planes = NULL;
int space = state.free_samples;
if (!space)
return false;
assert(space >= 0);
int samples = 0;
bool got_eof = false;
if (ao->driver->write_frames) {
TA_FREEP(&p->pending);
samples = read_buffer(ao, NULL, 1, &got_eof);
planes = (void **)&p->pending;
} else {
if (!realloc_buf(ao, space)) {
MP_ERR(ao, "Failed to allocate buffer.\n");
return false;
}
planes = (void **)mp_aframe_get_data_rw(p->temp_buf);
assert(planes);
if (p->recover_pause) {
samples = MPCLAMP(p->prepause_state.delay * ao->samplerate, 0, space);
p->recover_pause = false;
mp_aframe_set_silence(p->temp_buf, 0, space);
}
if (!samples) {
samples = read_buffer(ao, planes, space, &got_eof);
if (p->paused || (ao->stream_silence && !p->playing))
samples = space; // read_buffer() sets remainder to silent
}
}
if (samples) {
MP_STATS(ao, "start ao fill");
if (!ao->driver->write(ao, planes, samples))
MP_ERR(ao, "Error writing audio to device.\n");
MP_STATS(ao, "end ao fill");
if (!p->streaming) {
MP_VERBOSE(ao, "starting AO\n");
ao->driver->start(ao);
p->streaming = true;
state.playing = true;
}
}
MP_TRACE(ao, "in=%d space=%d(%d) pl=%d, eof=%d\n",
samples, space, state.free_samples, p->playing, got_eof);
if (got_eof)
goto eof;
return samples > 0 && (samples < space || ao->untimed);
eof:
MP_VERBOSE(ao, "audio end or underrun\n");
// Normal AOs signal EOF on underrun, untimed AOs never signal underruns.
if (ao->untimed || !state.playing || ao->stream_silence) {
p->streaming = state.playing && !ao->untimed;
p->playing = false;
}
ao->wakeup_cb(ao->wakeup_ctx);
// For ao_drain().
pthread_cond_broadcast(&p->wakeup);
return true;
}
static void *playthread(void *arg)
{
struct ao *ao = arg;
struct buffer_state *p = ao->buffer_state;
mpthread_set_name("ao");
while (1) {
pthread_mutex_lock(&p->lock);
bool retry = false;
if (!ao->driver->initially_blocked || p->initial_unblocked)
retry = ao_play_data(ao);
// Wait until the device wants us to write more data to it.
// Fallback to guessing.
double timeout = INFINITY;
if (p->streaming && !retry && (!p->paused || ao->stream_silence)) {
// Wake up again if half of the audio buffer has been played.
// Since audio could play at a faster or slower pace, wake up twice
// as often as ideally needed.
timeout = ao->device_buffer / (double)ao->samplerate * 0.25;
}
pthread_mutex_unlock(&p->lock);
pthread_mutex_lock(&p->pt_lock);
if (p->terminate) {
pthread_mutex_unlock(&p->pt_lock);
break;
}
if (!p->need_wakeup && !retry) {
MP_STATS(ao, "start audio wait");
struct timespec ts = mp_rel_time_to_timespec(timeout);
pthread_cond_timedwait(&p->pt_wakeup, &p->pt_lock, &ts);
MP_STATS(ao, "end audio wait");
}
p->need_wakeup = false;
pthread_mutex_unlock(&p->pt_lock);
}
return NULL;
}
void ao_unblock(struct ao *ao)
{
if (ao->driver->write) {
struct buffer_state *p = ao->buffer_state;
pthread_mutex_lock(&p->lock);
p->initial_unblocked = true;
pthread_mutex_unlock(&p->lock);
ao_wakeup_playthread(ao);
}
}
+68 -77
View File
@@ -37,8 +37,8 @@ struct ao {
bool untimed; // don't assume realtime playback
int device_buffer; // device buffer in samples (guessed by
// common init code if not set by driver)
const struct ao_driver *api; // entrypoints to the wrapper (push.c/pull.c)
const struct ao_driver *driver;
bool driver_initialized;
void *priv;
struct mpv_global *global;
struct encode_lavc_context *encode_lavc_ctx;
@@ -48,14 +48,6 @@ struct ao {
int init_flags; // AO_INIT_* flags
bool stream_silence; // if audio inactive, just play silence
// Set by the driver on init. This is typically the period size, and the
// smallest unit the driver will accept in one piece (although if
// AOPLAY_FINAL_CHUNK is set, the driver must accept everything).
// This value is in complete samples (i.e. 1 for stereo means 1 sample
// for both channels each).
// Used for push based API only.
int period_size;
// The device as selected by the user, usually using ao_device_desc.name
// from an entry from the list returned by driver->list_devices. If the
// default device should be used, this is set to NULL.
@@ -75,12 +67,30 @@ struct ao {
int buffer;
double def_buffer;
void *api_priv;
struct buffer_state *buffer_state;
};
extern const struct ao_driver ao_api_push;
extern const struct ao_driver ao_api_pull;
void init_buffer_pre(struct ao *ao);
bool init_buffer_post(struct ao *ao);
struct mp_pcm_state {
// Note: free_samples+queued_samples <= ao->device_buffer; the sum may be
// less if the audio API can report partial periods played, while
// free_samples should be period-size aligned. If free_samples is not
// period-size aligned, the AO thread might get into a situation where
// it writes a very small number of samples in each iteration, leading
// to extremely inefficient behavior.
// Keep in mind that write() may write less than free_samples (or your
// period size alignment) anyway.
int free_samples; // number of free space in ring buffer
int queued_samples; // number of samples to play in ring buffer
double delay; // total latency in seconds (includes queued_samples)
bool playing; // set if underlying API is actually playing audio;
// the AO must unset it on underrun (accidental
// underrun and EOF are indistinguishable; the upper
// layers decide what it was)
// real pausing may assume playing=true
};
/* Note:
*
@@ -89,39 +99,32 @@ extern const struct ao_driver ao_api_pull;
* b) pull callback based (the audio API calls a callback to get audio)
*
* The ao.c code can handle both. It basically implements two audio paths
* and provides a uniform API for them. If ao_driver->play is NULL, it assumes
* and provides a uniform API for them. If ao_driver->write is NULL, it assumes
* that the driver uses a callback based audio API, otherwise push based.
*
* Requirements:
* a) ->play is called to queue audio. push.c creates a thread to regularly
* refill audio device buffers with ->play, but all driver functions are
* always called under an exclusive lock.
* Mandatory:
* a+b) Mandatory for both types:
* init
* uninit
* reset
* get_space
* play
* get_delay
* pause
* resume
* Optional:
* start
* Optional for both types:
* control
* drain
* wait
* wakeup
* b) ->play must be NULL. ->resume must be provided, and should make the
* a) ->write is called to queue audio. push.c creates a thread to regularly
* refill audio device buffers with ->write, but all driver functions are
* always called under an exclusive lock.
* Mandatory:
* reset
* write
* get_state
* Optional:
* set_pause
* b) ->write must be NULL. ->start must be provided, and should make the
* audio API start calling the audio callback. Your audio callback should
* in turn call ao_read_data() to get audio data. Most functions are
* optional and will be emulated if missing (e.g. pausing is emulated as
* silence). ->get_delay and ->get_space are never called.
* Mandatory:
* init
* uninit
* resume (starts the audio callback)
* silence).
* Also, the following optional callbacks can be provided:
* reset (stops the audio callback, resume() restarts it)
* control
* reset (stops the audio callback, start() restarts it)
*/
struct ao_driver {
// If true, use with encoding only.
@@ -131,14 +134,12 @@ struct ao_driver {
// Description shown with --ao=help.
const char *description;
// This requires waiting for a AO_EVENT_INITIAL_UNBLOCK event before the
// first play() call is done. Encode mode uses this, and push mode
// first write() call is done. Encode mode uses this, and push mode
// respects it automatically (don't use with pull mode).
bool initially_blocked;
// Whether underruns are strictly _always_ reported via ao_underrun_event().
// Do not set this to true if underruns may be missed in some way. If the
// AO can't guarantee to play silence after underruns, it may be better not
// to set this.
bool reports_underruns;
// If true, write units of entire frames. The write() call is modified to
// use data==mp_aframe. Useful for encoding AO only.
bool write_frames;
// Init the device using ao->format/ao->channels/ao->samplerate. If the
// device doesn't accept these parameters, you can attempt to negotiate
// fallback parameters, and set the ao format fields accordingly.
@@ -146,38 +147,32 @@ struct ao_driver {
// Optional. See ao_control() etc. in ao.c
int (*control)(struct ao *ao, enum aocontrol cmd, void *arg);
void (*uninit)(struct ao *ao);
// push based: see ao_reset()
// pull based: stop the audio callback
// Stop all audio playback, clear buffers, back to state after init().
// Optional for pull AOs.
void (*reset)(struct ao *ao);
// push based: see ao_pause()
void (*pause)(struct ao *ao);
// push based: see ao_resume()
// push based: set pause state. Only called after start() and before reset().
// returns success (this is intended for paused=true; if it
// returns false, playback continues, and the core emulates via
// reset(); unpausing always works)
// The pausing state is also cleared by reset().
bool (*set_pause)(struct ao *ao, bool paused);
// pull based: start the audio callback
void (*resume)(struct ao *ao);
// push based: see ao_play()
int (*get_space)(struct ao *ao);
// push based: see ao_play()
int (*play)(struct ao *ao, void **data, int samples, int flags);
// push based: see ao_get_delay()
double (*get_delay)(struct ao *ao);
// push based: block until all queued audio is played (optional)
void (*drain)(struct ao *ao);
// Optional. Return true if audio has stopped in any way.
bool (*get_eof)(struct ao *ao);
// Wait until the audio buffer needs to be refilled. The lock is the
// internal mutex usually protecting the internal AO state (and used to
// protect driver calls), and must be temporarily unlocked while waiting.
// ->wakeup will be called (with lock held) if the wait should be canceled.
// Returns 0 on success, -1 on error.
// Optional; if this is not provided, generic code using audio timing is
// used to estimate when the AO needs to be refilled.
// Warning: it's only called if the feed thread truly needs to know when
// the audio thread takes data again. Often, it will just copy
// the complete soft-buffer to the AO, and then wait for the
// decoder instead. Don't do necessary work in this callback.
int (*wait)(struct ao *ao, pthread_mutex_t *lock);
// In combination with wait(). Lock may or may not be held.
void (*wakeup)(struct ao *ao);
// push based: start playing queued data
// AO should call ao_wakeup_playthread() if a period boundary
// is crossed, or playback stops due to external reasons
// (including underruns or device removal)
// must set mp_pcm_state.playing; unset on error/underrun/end
void (*start)(struct ao *ao);
// push based: queue new data. This won't try to write more data than the
// reported free space (samples <= mp_pcm_state.free_samples).
// This must NOT start playback. start() does that, and write() may be
// called multiple times before start() is called. It may also happen that
// reset() is called to discard the buffer. start() without write() will
// immediately reported an underrun.
// Return false on failure.
bool (*write)(struct ao *ao, void **data, int samples);
// push based: return mandatory stream information
void (*get_state)(struct ao *ao, struct mp_pcm_state *state);
// Return the list of devices currently available in the system. Use
// ao_device_list_add() to add entries. The selected device will be set as
@@ -205,13 +200,7 @@ struct ao_driver {
// These functions can be called by AOs.
int ao_play_silence(struct ao *ao, int samples);
int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us);
struct pollfd;
int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds,
pthread_mutex_t *lock);
void ao_wakeup_poll(struct ao *ao);
void ao_underrun_event(struct ao *ao);
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map);
@@ -239,6 +228,8 @@ bool ao_can_convert_inplace(struct ao_convert_fmt *fmt);
bool ao_need_conversion(struct ao_convert_fmt *fmt);
void ao_convert_inplace(struct ao_convert_fmt *fmt, void **data, int num_samples);
void ao_wakeup_playthread(struct ao *ao);
int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt,
void **data, int samples, int64_t out_time_us);
-342
View File
@@ -1,342 +0,0 @@
/*
* 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 <stddef.h>
#include <inttypes.h>
#include <assert.h>
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
#include "common/msg.h"
#include "common/common.h"
#include "input/input.h"
#include "osdep/timer.h"
#include "osdep/threads.h"
#include "osdep/atomic.h"
#include "misc/ring.h"
/*
* Note: there is some stupid stuff in this file in order to avoid mutexes.
* This requirement is dictated by several audio APIs, at least jackaudio.
*/
enum {
AO_STATE_NONE, // idle (e.g. before playback started, or after playback
// finished, but device is open)
AO_STATE_WAIT, // wait for callback to go into AO_STATE_NONE state
AO_STATE_PLAY, // play the buffer
AO_STATE_BUSY, // like AO_STATE_PLAY, but ao_read_data() is being called
};
#define IS_PLAYING(st) ((st) == AO_STATE_PLAY || (st) == AO_STATE_BUSY)
struct ao_pull_state {
// Be very careful with the order when accessing planes.
struct mp_ring *buffers[MP_NUM_CHANNELS];
// AO_STATE_*
atomic_int state;
// Set when the buffer is intentionally not fed anymore in PLAY state.
atomic_bool draining;
// Set by the audio thread when an underflow was detected.
// It adds the number of samples.
atomic_int underflow;
// Device delay of the last written sample, in realtime.
atomic_llong end_time_us;
char *convert_buffer;
};
static void set_state(struct ao *ao, int new_state)
{
struct ao_pull_state *p = ao->api_priv;
while (1) {
int old = atomic_load(&p->state);
if (old == AO_STATE_BUSY) {
// A spinlock, because some audio APIs don't want us to use mutexes.
mp_sleep_us(1);
continue;
}
if (atomic_compare_exchange_strong(&p->state, &old, new_state))
break;
}
}
static int get_space(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
// Since the reader will read the last plane last, its free space is the
// minimum free space across all planes.
return mp_ring_available(p->buffers[ao->num_planes - 1]) / ao->sstride;
}
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct ao_pull_state *p = ao->api_priv;
int write_samples = get_space(ao);
write_samples = MPMIN(write_samples, samples);
// Write starting from the last plane - this way, the first plane will
// always contain the minimum amount of data readable across all planes
// (assumes the reader starts with the first plane).
int write_bytes = write_samples * ao->sstride;
for (int n = ao->num_planes - 1; n >= 0; n--) {
int r = mp_ring_write(p->buffers[n], data[n], write_bytes);
assert(r == write_bytes);
}
int state = atomic_load(&p->state);
if (!IS_PLAYING(state)) {
atomic_store(&p->draining, false);
atomic_store(&p->underflow, 0);
set_state(ao, AO_STATE_PLAY);
if (!ao->stream_silence)
ao->driver->resume(ao);
}
bool draining = write_samples == samples && (flags & AOPLAY_FINAL_CHUNK);
atomic_store(&p->draining, draining);
int underflow = atomic_fetch_and(&p->underflow, 0);
if (underflow)
MP_WARN(ao, "Audio underflow by %d samples.\n", underflow);
return write_samples;
}
// Read the given amount of samples in the user-provided data buffer. Returns
// the number of samples copied. If there is not enough data (buffer underrun
// or EOF), return the number of samples that could be copied, and fill the
// rest of the user-provided buffer with silence.
// This basically assumes that the audio device doesn't care about underruns.
// If this is called in paused mode, it will always return 0.
// The caller should set out_time_us to the expected delay until the last sample
// reaches the speakers, in microseconds, using mp_time_us() as reference.
int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us)
{
assert(ao->api == &ao_api_pull);
struct ao_pull_state *p = ao->api_priv;
int full_bytes = samples * ao->sstride;
bool need_wakeup = false;
int bytes = 0;
// Play silence in states other than AO_STATE_PLAY.
if (!atomic_compare_exchange_strong(&p->state, &(int){AO_STATE_PLAY},
AO_STATE_BUSY))
goto end;
// Since the writer will write the first plane last, its buffered amount
// of data is the minimum amount across all planes.
int buffered_bytes = mp_ring_buffered(p->buffers[0]);
bytes = MPMIN(buffered_bytes, full_bytes);
if (full_bytes > bytes && !atomic_load(&p->draining)) {
if (ao->driver->reports_underruns) {
ao_underrun_event(ao);
} else {
atomic_fetch_add(&p->underflow, (full_bytes - bytes) / ao->sstride);
}
}
if (bytes > 0)
atomic_store(&p->end_time_us, out_time_us);
for (int n = 0; n < ao->num_planes; n++) {
int r = mp_ring_read(p->buffers[n], data[n], bytes);
bytes = MPMIN(bytes, r);
}
// Half of the buffer played -> request more.
need_wakeup = buffered_bytes - bytes <= mp_ring_size(p->buffers[0]) / 2;
// Should never fail.
atomic_compare_exchange_strong(&p->state, &(int){AO_STATE_BUSY}, AO_STATE_PLAY);
end:
if (need_wakeup)
ao->wakeup_cb(ao->wakeup_ctx);
// pad with silence (underflow/paused/eof)
for (int n = 0; n < ao->num_planes; n++)
af_fill_silence((char *)data[n] + bytes, full_bytes - bytes, ao->format);
ao_post_process_data(ao, data, samples);
return bytes / ao->sstride;
}
// Same as ao_read_data(), but convert data according to *fmt.
// fmt->src_fmt and fmt->channels must be the same as the AO parameters.
int ao_read_data_converted(struct ao *ao, struct ao_convert_fmt *fmt,
void **data, int samples, int64_t out_time_us)
{
assert(ao->api == &ao_api_pull);
struct ao_pull_state *p = ao->api_priv;
void *ndata[MP_NUM_CHANNELS] = {0};
if (!ao_need_conversion(fmt))
return ao_read_data(ao, data, samples, out_time_us);
assert(ao->format == fmt->src_fmt);
assert(ao->channels.num == fmt->channels);
bool planar = af_fmt_is_planar(fmt->src_fmt);
int planes = planar ? fmt->channels : 1;
int plane_samples = samples * (planar ? 1: fmt->channels);
int src_plane_size = plane_samples * af_fmt_to_bytes(fmt->src_fmt);
int dst_plane_size = plane_samples * fmt->dst_bits / 8;
int needed = src_plane_size * planes;
if (needed > talloc_get_size(p->convert_buffer) || !p->convert_buffer) {
talloc_free(p->convert_buffer);
p->convert_buffer = talloc_size(NULL, needed);
}
for (int n = 0; n < planes; n++)
ndata[n] = p->convert_buffer + n * src_plane_size;
int res = ao_read_data(ao, ndata, samples, out_time_us);
ao_convert_inplace(fmt, ndata, samples);
for (int n = 0; n < planes; n++)
memcpy(data[n], ndata[n], dst_plane_size);
return res;
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
if (ao->driver->control)
return ao->driver->control(ao, cmd, arg);
return CONTROL_UNKNOWN;
}
// Return size of the buffered data in seconds. Can include the device latency.
// Basically, this returns how much data there is still to play, and how long
// it takes until the last sample in the buffer reaches the speakers. This is
// used for audio/video synchronization, so it's very important to implement
// this correctly.
static double get_delay(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
int64_t end = atomic_load(&p->end_time_us);
int64_t now = mp_time_us();
double driver_delay = MPMAX(0, (end - now) / (1000.0 * 1000.0));
return mp_ring_buffered(p->buffers[0]) / (double)ao->bps + driver_delay;
}
static void reset(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
if (!ao->stream_silence && ao->driver->reset)
ao->driver->reset(ao); // assumes the audio callback thread is stopped
set_state(ao, AO_STATE_NONE);
for (int n = 0; n < ao->num_planes; n++)
mp_ring_reset(p->buffers[n]);
atomic_store(&p->end_time_us, 0);
}
static void pause(struct ao *ao)
{
if (!ao->stream_silence && ao->driver->reset)
ao->driver->reset(ao);
set_state(ao, AO_STATE_NONE);
}
static void resume(struct ao *ao)
{
set_state(ao, AO_STATE_PLAY);
if (!ao->stream_silence)
ao->driver->resume(ao);
}
static bool get_eof(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
// For simplicity, ignore the latency. Otherwise, we would have to run an
// extra thread to time it.
return mp_ring_buffered(p->buffers[0]) == 0;
}
static void drain(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
int state = atomic_load(&p->state);
if (IS_PLAYING(state)) {
atomic_store(&p->draining, true);
// Wait for lower bound.
mp_sleep_us(mp_ring_buffered(p->buffers[0]) / (double)ao->bps * 1e6);
// And then poll for actual end. (Unfortunately, this code considers
// audio APIs which do not want you to use mutexes in the audio
// callback, and an extra semaphore would require slightly more effort.)
// Limit to arbitrary ~250ms max. waiting for robustness.
int64_t max = mp_time_us() + 250000;
while (mp_time_us() < max && !get_eof(ao))
mp_sleep_us(1);
}
reset(ao);
}
static void uninit(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
ao->driver->uninit(ao);
talloc_free(p->convert_buffer);
}
static int init(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
for (int n = 0; n < ao->num_planes; n++)
p->buffers[n] = mp_ring_new(ao, ao->buffer * ao->sstride);
atomic_store(&p->state, AO_STATE_NONE);
assert(ao->driver->resume);
if (ao->stream_silence)
ao->driver->resume(ao);
return 0;
}
const struct ao_driver ao_api_pull = {
.init = init,
.control = control,
.uninit = uninit,
.drain = drain,
.reset = reset,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.get_eof = get_eof,
.pause = pause,
.resume = resume,
.priv_size = sizeof(struct ao_pull_state),
};
-570
View File
@@ -1,570 +0,0 @@
/*
* 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 <stddef.h>
#include <pthread.h>
#include <inttypes.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include "osdep/io.h"
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
#include "common/msg.h"
#include "common/common.h"
#include "input/input.h"
#include "osdep/threads.h"
#include "osdep/timer.h"
#include "osdep/atomic.h"
#include "audio/audio_buffer.h"
struct ao_push_state {
pthread_t thread;
pthread_mutex_t lock;
pthread_cond_t wakeup;
// --- protected by lock
struct mp_audio_buffer *buffer;
uint8_t *silence[MP_NUM_CHANNELS];
int silence_samples;
bool terminate;
bool wait_on_ao;
bool still_playing;
bool need_wakeup;
bool paused;
bool initial_unblocked;
// Whether the current buffer contains the complete audio.
bool final_chunk;
double expected_end_time;
int wakeup_pipe[2];
};
// lock must be held
static void wakeup_playthread(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
if (ao->driver->wakeup)
ao->driver->wakeup(ao);
p->need_wakeup = true;
pthread_cond_signal(&p->wakeup);
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
int r = CONTROL_UNKNOWN;
if (ao->driver->control) {
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
r = ao->driver->control(ao, cmd, arg);
pthread_mutex_unlock(&p->lock);
}
return r;
}
static double unlocked_get_delay(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
double driver_delay = 0;
if (ao->driver->get_delay)
driver_delay = ao->driver->get_delay(ao);
return driver_delay + mp_audio_buffer_seconds(p->buffer);
}
static double get_delay(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
double delay = unlocked_get_delay(ao);
pthread_mutex_unlock(&p->lock);
return delay;
}
static void reset(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
if (ao->driver->reset)
ao->driver->reset(ao);
mp_audio_buffer_clear(p->buffer);
p->paused = false;
if (p->still_playing)
wakeup_playthread(ao);
p->still_playing = false;
pthread_mutex_unlock(&p->lock);
}
static void audio_pause(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
if (ao->driver->pause)
ao->driver->pause(ao);
p->paused = true;
wakeup_playthread(ao);
pthread_mutex_unlock(&p->lock);
}
static void resume(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
if (ao->driver->resume)
ao->driver->resume(ao);
p->paused = false;
p->expected_end_time = 0;
wakeup_playthread(ao);
pthread_mutex_unlock(&p->lock);
}
static void drain(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
double maxbuffer = ao->buffer / (double)ao->samplerate + 1;
MP_VERBOSE(ao, "draining...\n");
pthread_mutex_lock(&p->lock);
if (p->paused)
goto done;
p->final_chunk = true;
wakeup_playthread(ao);
// Wait until everything is done. Since the audio API (especially ALSA)
// can't be trusted to do this right, and we're hard-blocking here, apply
// an upper bound timeout.
struct timespec until = mp_rel_time_to_timespec(maxbuffer);
while (p->still_playing && mp_audio_buffer_samples(p->buffer) > 0) {
if (pthread_cond_timedwait(&p->wakeup, &p->lock, &until)) {
MP_WARN(ao, "Draining is taking too long, aborting.\n");
goto done;
}
}
if (ao->driver->drain) {
ao->driver->drain(ao);
} else {
double time = unlocked_get_delay(ao);
mp_sleep_us(MPMIN(time, maxbuffer) * 1e6);
}
done:
pthread_mutex_unlock(&p->lock);
reset(ao);
}
static int unlocked_get_space(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
int space = mp_audio_buffer_get_write_available(p->buffer);
if (ao->driver->get_space) {
int align = af_format_sample_alignment(ao->format);
// The following code attempts to keep the total buffered audio to
// ao->buffer in order to improve latency.
int device_space = ao->driver->get_space(ao);
int device_buffered = ao->device_buffer - device_space;
int soft_buffered = mp_audio_buffer_samples(p->buffer);
// The extra margin helps avoiding too many wakeups if the AO is fully
// byte based and doesn't do proper chunked processing.
int min_buffer = ao->buffer + 64;
int missing = min_buffer - device_buffered - soft_buffered;
missing = (missing + align - 1) / align * align;
// But always keep the device's buffer filled as much as we can.
int device_missing = device_space - soft_buffered;
missing = MPMAX(missing, device_missing);
space = MPMIN(space, missing);
space = MPMAX(0, space);
}
return space;
}
static int get_space(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
int space = unlocked_get_space(ao);
pthread_mutex_unlock(&p->lock);
return space;
}
static bool get_eof(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
bool eof = !p->still_playing;
pthread_mutex_unlock(&p->lock);
return eof;
}
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
int write_samples = mp_audio_buffer_get_write_available(p->buffer);
write_samples = MPMIN(write_samples, samples);
MP_TRACE(ao, "samples=%d flags=%d r=%d\n", samples, flags, write_samples);
if (write_samples < samples)
flags = flags & ~AOPLAY_FINAL_CHUNK;
bool is_final = flags & AOPLAY_FINAL_CHUNK;
mp_audio_buffer_append(p->buffer, data, samples);
bool got_data = write_samples > 0 || p->paused || p->final_chunk != is_final;
p->final_chunk = is_final;
p->paused = false;
if (got_data) {
p->still_playing = true;
p->expected_end_time = 0;
// If we don't have new data, the decoder thread basically promises it
// will send new data as soon as it's available.
wakeup_playthread(ao);
}
pthread_mutex_unlock(&p->lock);
return write_samples;
}
static bool realloc_silence(struct ao *ao, int samples)
{
struct ao_push_state *p = ao->api_priv;
if (samples <= 0 || !af_fmt_is_pcm(ao->format))
return false;
if (samples > p->silence_samples) {
talloc_free(p->silence[0]);
int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num;
p->silence[0] = talloc_size(p, bytes);
for (int n = 1; n < MP_NUM_CHANNELS; n++)
p->silence[n] = p->silence[0];
p->silence_samples = samples;
af_fill_silence(p->silence[0], bytes, ao->format);
}
return true;
}
// called locked
static void ao_play_data(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
int space = ao->driver->get_space(ao);
bool play_silence = p->paused || (ao->stream_silence && !p->still_playing);
space = MPMAX(space, 0);
if (space % ao->period_size)
MP_ERR(ao, "Audio device reports unaligned available buffer size.\n");
uint8_t **planes;
int samples;
if (play_silence) {
planes = p->silence;
samples = realloc_silence(ao, space) ? space : 0;
} else {
mp_audio_buffer_peek(p->buffer, &planes, &samples);
}
int max = samples;
if (samples > space)
samples = space;
int flags = 0;
if (p->final_chunk && samples == max) {
flags |= AOPLAY_FINAL_CHUNK;
} else {
samples = samples / ao->period_size * ao->period_size;
}
MP_STATS(ao, "start ao fill");
ao_post_process_data(ao, (void **)planes, samples);
int r = 0;
if (samples)
r = ao->driver->play(ao, (void **)planes, samples, flags);
MP_STATS(ao, "end ao fill");
if (r > samples) {
MP_ERR(ao, "Audio device returned nonsense value.\n");
r = samples;
} else if (r < 0) {
MP_ERR(ao, "Error writing audio to device.\n");
} else if (r != samples) {
MP_ERR(ao, "Audio device returned broken buffer state (sent %d samples, "
"got %d samples, %d period%s)!\n", samples, r,
ao->period_size, flags & AOPLAY_FINAL_CHUNK ? " final" : "");
}
r = MPMAX(r, 0);
// Probably can't copy the rest of the buffer due to period alignment.
bool stuck_eof = r <= 0 && space >= max && samples > 0;
if ((flags & AOPLAY_FINAL_CHUNK) && stuck_eof) {
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
r = max;
}
if (!play_silence)
mp_audio_buffer_skip(p->buffer, r);
if (r > 0)
p->expected_end_time = 0;
// Nothing written, but more input data than space - this must mean the
// AO's get_space() doesn't do period alignment correctly.
bool stuck = r == 0 && max >= space && space > 0;
if (stuck)
MP_ERR(ao, "Audio output is reporting incorrect buffer status.\n");
// Wait until space becomes available. Also wait if we actually wrote data,
// so the AO wakes us up properly if it needs more data.
p->wait_on_ao = space == 0 || r > 0 || stuck;
p->still_playing |= r > 0 && !play_silence;
// If we just filled the AO completely (r == space), don't refill for a
// while. Prevents wakeup feedback with byte-granular AOs.
int needed = unlocked_get_space(ao);
bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck &&
!(flags & AOPLAY_FINAL_CHUNK);
if (more)
ao->wakeup_cb(ao->wakeup_ctx); // request more data
MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n",
max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more);
}
static void *playthread(void *arg)
{
struct ao *ao = arg;
struct ao_push_state *p = ao->api_priv;
mpthread_set_name("ao");
pthread_mutex_lock(&p->lock);
while (!p->terminate) {
bool blocked = ao->driver->initially_blocked && !p->initial_unblocked;
bool playing = (!p->paused || ao->stream_silence) && !blocked;
if (playing)
ao_play_data(ao);
if (!p->need_wakeup) {
MP_STATS(ao, "start audio wait");
if (!p->wait_on_ao || !playing) {
// Avoid busy waiting, because the audio API will still report
// that it needs new data, even if we're not ready yet, or if
// get_space() decides that the amount of audio buffered in the
// device is enough, and p->buffer can be empty.
// The most important part is that the decoder is woken up, so
// that the decoder will wake up us in turn.
MP_TRACE(ao, "buffer inactive.\n");
bool was_playing = p->still_playing;
double timeout = -1;
if (p->still_playing && !p->paused && p->final_chunk &&
!mp_audio_buffer_samples(p->buffer))
{
double now = mp_time_sec();
if (!p->expected_end_time)
p->expected_end_time = now + unlocked_get_delay(ao);
if (p->expected_end_time < now) {
p->still_playing = false;
} else {
timeout = p->expected_end_time - now;
}
}
if (was_playing && !p->still_playing)
ao->wakeup_cb(ao->wakeup_ctx);
pthread_cond_signal(&p->wakeup); // for draining
if (p->still_playing && timeout > 0) {
struct timespec ts = mp_rel_time_to_timespec(timeout);
pthread_cond_timedwait(&p->wakeup, &p->lock, &ts);
} else {
pthread_cond_wait(&p->wakeup, &p->lock);
}
} else {
// Wait until the device wants us to write more data to it.
if (!ao->driver->wait || ao->driver->wait(ao, &p->lock) < 0) {
// Fallback to guessing.
double timeout = 0;
if (ao->driver->get_delay)
timeout = ao->driver->get_delay(ao);
timeout *= 0.25; // wake up if 25% played
if (!p->need_wakeup) {
struct timespec ts = mp_rel_time_to_timespec(timeout);
pthread_cond_timedwait(&p->wakeup, &p->lock, &ts);
}
}
}
MP_STATS(ao, "end audio wait");
}
p->need_wakeup = false;
}
pthread_mutex_unlock(&p->lock);
return NULL;
}
static void destroy_no_thread(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
ao->driver->uninit(ao);
for (int n = 0; n < 2; n++) {
int h = p->wakeup_pipe[n];
if (h >= 0)
close(h);
}
pthread_cond_destroy(&p->wakeup);
pthread_mutex_destroy(&p->lock);
}
static void uninit(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
p->terminate = true;
wakeup_playthread(ao);
pthread_mutex_unlock(&p->lock);
pthread_join(p->thread, NULL);
destroy_no_thread(ao);
}
static int init(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_init(&p->lock, NULL);
pthread_cond_init(&p->wakeup, NULL);
mp_make_wakeup_pipe(p->wakeup_pipe);
if (ao->device_buffer <= 0) {
MP_FATAL(ao, "Couldn't probe device buffer size.\n");
goto err;
}
p->buffer = mp_audio_buffer_create(ao);
mp_audio_buffer_reinit_fmt(p->buffer, ao->format,
&ao->channels, ao->samplerate);
mp_audio_buffer_preallocate_min(p->buffer, ao->buffer);
if (pthread_create(&p->thread, NULL, playthread, ao))
goto err;
return 0;
err:
destroy_no_thread(ao);
return -1;
}
const struct ao_driver ao_api_push = {
.init = init,
.control = control,
.uninit = uninit,
.reset = reset,
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.pause = audio_pause,
.resume = resume,
.drain = drain,
.get_eof = get_eof,
.priv_size = sizeof(struct ao_push_state),
};
// Must be called locked.
int ao_play_silence(struct ao *ao, int samples)
{
assert(ao->api == &ao_api_push);
struct ao_push_state *p = ao->api_priv;
if (!realloc_silence(ao, samples) || !ao->driver->play)
return 0;
return ao->driver->play(ao, (void **)p->silence, samples, 0);
}
void ao_unblock(struct ao *ao)
{
if (ao->api == &ao_api_push) {
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
p->need_wakeup = true;
p->initial_unblocked = true;
wakeup_playthread(ao);
pthread_cond_signal(&p->wakeup);
pthread_mutex_unlock(&p->lock);
}
}
#ifndef __MINGW32__
#include <poll.h>
#define MAX_POLL_FDS 20
// Call poll() for the given fds. This will extend the given fds with the
// wakeup pipe, so ao_wakeup_poll() will basically interrupt this function.
// Unlocks the lock temporarily.
// Returns <0 on error, 0 on success, 1 if the caller should return immediately.
int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds,
pthread_mutex_t *lock)
{
struct ao_push_state *p = ao->api_priv;
assert(ao->api == &ao_api_push);
assert(&p->lock == lock);
if (num_fds >= MAX_POLL_FDS || p->wakeup_pipe[0] < 0)
return -1;
struct pollfd p_fds[MAX_POLL_FDS];
memcpy(p_fds, fds, num_fds * sizeof(p_fds[0]));
p_fds[num_fds] = (struct pollfd){
.fd = p->wakeup_pipe[0],
.events = POLLIN,
};
pthread_mutex_unlock(&p->lock);
int r = poll(p_fds, num_fds + 1, -1);
r = r < 0 ? -errno : 0;
pthread_mutex_lock(&p->lock);
memcpy(fds, p_fds, num_fds * sizeof(fds[0]));
bool wakeup = false;
if (p_fds[num_fds].revents & POLLIN) {
wakeup = true;
// might "drown" some wakeups, but that's ok for our use-case
mp_flush_wakeup_pipe(p->wakeup_pipe[0]);
}
return (r >= 0 || r == -EINTR) ? wakeup : -1;
}
void ao_wakeup_poll(struct ao *ao)
{
assert(ao->api == &ao_api_push);
struct ao_push_state *p = ao->api_priv;
(void)write(p->wakeup_pipe[1], &(char){0}, 1);
}
#endif
+8 -2
View File
@@ -5,10 +5,10 @@
from __future__ import print_function
import os, sys, stat, hashlib, subprocess
WAFRELEASE = "waf-2.0.9"
WAFRELEASE = "waf-2.0.20"
WAFURLS = ["https://waf.io/" + WAFRELEASE,
"http://www.freehackers.org/~tnagy/release/" + WAFRELEASE]
SHA256HASH = "2a8e0816f023995e557f79ea8940d322bec18f286917c8f9a6fa2dc3875dfa48"
SHA256HASH = "bf971e98edc2414968a262c6aa6b88541a26c3cd248689c89f4c57370955ee7f"
if os.path.exists("waf"):
wafver = subprocess.check_output([sys.executable, './waf', '--version']).decode()
@@ -41,6 +41,12 @@ if not waf:
sys.exit(1)
if SHA256HASH == hashlib.sha256(waf).hexdigest():
# Upstream waf is not changing the default interpreter during
# 2.0.x line due to compatibility reasons apparently. So manually
# convert it to use python3 (the script works with both).
expected = b"#!/usr/bin/env python\n"
assert waf.startswith(expected)
waf = b"#!/usr/bin/env python3\n" + waf[len(expected):]
with open("waf", "wb") as wf:
wf.write(waf)
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
set -e
export CFLAGS="$CFLAGS -isystem/usr/local/include"
export CXXFLAGS="$CXXFLAGS -isystem/usr/local/include"
export LDFLAGS="$LDFLAGS -L/usr/local/lib"
if [ ! -e "./waf" ] ; then
python3 ./bootstrap.py
fi
python3 ./waf configure \
--enable-libmpv-shared \
--enable-lua \
--enable-egl-drm \
--enable-openal \
--enable-sdl2 \
--enable-vaapi-wayland \
--enable-vdpau \
--enable-vulkan \
$(pkg info -q v4l_compat && echo --enable-dvbin) \
$(pkg info -q libdvdnav && echo --enable-dvdnav) \
$(pkg info -q libcdio-paranoia && echo --enable-cdda) \
$NULL
python3 ./waf build
+3 -2
View File
@@ -18,8 +18,9 @@ PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" pytho
./waf configure \
--variant="${MPV_VARIANT}" \
--prefix="${MPV_INSTALL_PREFIX}" \
--enable-{gl,iconv,lcms2,libass,libass-osd,libmpv-shared,lua,jpeg,plain-gl,zlib} \
--enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl}
--enable-{gl,iconv,lcms2,libmpv-shared,lua,jpeg,plain-gl,zlib} \
--enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl} \
--swift-flags="${CI_SWIFT_FLAGS}"
python3 ./waf build --variant="${MPV_VARIANT}" -j4
+154 -25
View File
@@ -1,33 +1,162 @@
#!/bin/sh
set -e
#!/bin/bash -e
_mingw_sysroot=/usr/$TARGET/sysroot
_mingw_prefix=$_mingw_sysroot/mingw
_mingw_exec_prefix=$_mingw_prefix
_mingw_libdir=$_mingw_exec_prefix/lib
_mingw_datadir=$_mingw_prefix/share
prefix_dir=$PWD/mingw_prefix
mkdir -p "$prefix_dir"
ln -snf . "$prefix_dir/usr"
ln -snf . "$prefix_dir/local"
export PKG_CONFIG_PATH="$_mingw_libdir/pkgconfig:$_mingw_datadir/pkgconfig";
export CC=$TARGET-gcc
export CXX=$TARGET-g++
wget="wget -nc --progress=bar:force"
gitclone="git clone --depth=10"
commonflags="--disable-static --enable-shared"
export PKG_CONFIG_SYSROOT_DIR="$prefix_dir"
export PKG_CONFIG_LIBDIR="$PKG_CONFIG_SYSROOT_DIR/lib/pkgconfig"
# -posix is Ubuntu's variant with pthreads support
export CC=$TARGET-gcc-posix
export CXX=$TARGET-g++-posix
export AR=$TARGET-ar
export NM=$TARGET-nm
export RANLIB=$TARGET-ranlib
export CFLAGS="-O2 -mtune=intel -g -ggdb -pipe -Wall --param=ssp-buffer-size=4 -mms-bitfields -fmessage-length=0 -D_FORTIFY_SOURCE=2 -fexceptions -fasynchronous-unwind-tables -fstack-protector-strong -fno-ident"
export LDFLAGS="-Wl,--no-keep-memory -fstack-protector-strong"
export CFLAGS="-O2 -pipe -Wall -D_FORTIFY_SOURCE=2"
export LDFLAGS="-fstack-protector-strong"
function builddir () {
[ -d "$1/builddir" ] && rm -rf "$1/builddir"
mkdir -p "$1/builddir"
pushd "$1/builddir"
}
function makeplusinstall () {
make -j$(nproc)
make DESTDIR="$prefix_dir" install
}
function gettar () {
name="${1##*/}"
[ -d "${name%%.*}" ] && return 0
$wget "$1"
tar -xaf "$name"
}
## iconv
if [ ! -e "$prefix_dir/lib/libiconv.dll.a" ]; then
ver=1.16
gettar "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ver}.tar.gz"
builddir libiconv-${ver}
../configure --host=$TARGET $commonflags
makeplusinstall
popd
fi
## zlib
if [ ! -e "$prefix_dir/lib/libz.dll.a" ]; then
ver=1.2.11
gettar "https://zlib.net/zlib-${ver}.tar.gz"
pushd zlib-${ver}
make -fwin32/Makefile.gcc PREFIX=$TARGET- SHARED_MODE=1 \
DESTDIR="$prefix_dir" install \
BINARY_PATH=/bin INCLUDE_PATH=/include LIBRARY_PATH=/lib
popd
fi
## ffmpeg
if [ ! -e "$prefix_dir/lib/libavcodec.dll.a" ]; then
[ -d ffmpeg ] || $gitclone https://github.com/FFmpeg/FFmpeg.git ffmpeg
builddir ffmpeg
../configure --pkg-config=pkg-config --target-os=mingw32 \
--enable-cross-compile --cross-prefix=$TARGET- --arch=${TARGET%%-*} \
$commonflags \
--disable-{stripping,doc,programs,muxers,encoders,devices}
makeplusinstall
popd
fi
## shaderc
if [ ! -e "$prefix_dir/lib/libshaderc_shared.dll.a" ]; then
if [ ! -d shaderc ]; then
$gitclone https://github.com/google/shaderc.git
(cd shaderc && ./utils/git-sync-deps)
fi
builddir shaderc
cmake .. -DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \
-DSHADERC_SKIP_TESTS=ON -DCMAKE_INSTALL_PREFIX=/
makeplusinstall
popd
fi
## spirv-cross
if [ ! -e "$prefix_dir/lib/libspirv-cross-c-shared.dll.a" ]; then
[ -d SPIRV-Cross ] || $gitclone https://github.com/KhronosGroup/SPIRV-Cross
builddir SPIRV-Cross
cmake .. -DCMAKE_SYSTEM_NAME=Windows \
-DSPIRV_CROSS_SHARED=ON -DSPIRV_CROSS_{CLI,STATIC}=OFF
makeplusinstall
popd
fi
## freetype2
if [ ! -e "$prefix_dir/lib/libfreetype.dll.a" ]; then
ver=2.10.2
gettar "https://download.savannah.gnu.org/releases/freetype/freetype-${ver}.tar.gz"
builddir freetype-${ver}
ZLIB_LIBS="-L'$prefix_dir/lib' -lz" \
../configure --host=$TARGET $commonflags --with-png=no
makeplusinstall
popd
fi
[ -f "$prefix_dir/lib/libfreetype.dll.a" ] || { echo "libtool fuckup"; exit 1; }
## fribidi
if [ ! -e "$prefix_dir/lib/libfribidi.dll.a" ]; then
ver=1.0.9
gettar "https://github.com/fribidi/fribidi/releases/download/v${ver}/fribidi-${ver}.tar.xz"
builddir fribidi-${ver}
../configure --host=$TARGET $commonflags
makeplusinstall
popd
fi
## harfbuzz
if [ ! -e "$prefix_dir/lib/libharfbuzz.dll.a" ]; then
ver=2.7.2
gettar "https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.tar.xz"
builddir harfbuzz-${ver}
../configure --host=$TARGET $commonflags --with-icu=no
makeplusinstall
popd
rm "$prefix_dir"/lib/*.la # fuck off
fi
## libass
if [ ! -e "$prefix_dir/lib/libass.dll.a" ]; then
[ -d libass ] || $gitclone https://github.com/libass/libass.git
builddir libass
[ -f ../configure ] || (cd .. && ./autogen.sh)
../configure --host=$TARGET $commonflags
makeplusinstall
popd
fi
## luajit
if [ ! -e "$prefix_dir/lib/libluajit-5.1.a" ]; then
ver=2.0.5
gettar "http://luajit.org/download/LuaJIT-${ver}.tar.gz"
pushd LuaJIT-${ver}
hostcc=gcc
[[ "$TARGET" == "i686-"* ]] && hostcc="$hostcc -m32"
make HOST_CC="$hostcc" CROSS=$TARGET- TARGET_SYS=Windows \
BUILDMODE=static amalg
make DESTDIR="$prefix_dir" INSTALL_DEP= FILE_T=luajit.exe install
popd
fi
## mpv
PKG_CONFIG=pkg-config CFLAGS="-I'$prefix_dir/include'" LDFLAGS="-L'$prefix_dir/lib'" \
python3 ./waf configure \
--enable-static-build \
--enable-libmpv-shared \
--enable-lua \
--enable-javascript \
--enable-libarchive \
--enable-libass \
--enable-libbluray \
--enable-dvdnav \
--enable-uchardet \
--enable-vulkan \
--enable-shaderc \
--enable-rubberband \
--enable-lcms2
--enable-libmpv-shared --lua=luajit \
--enable-{shaderc,spirv-cross,d3d11}
python3 ./waf build --verbose
-1
View File
@@ -7,7 +7,6 @@ python3 ./waf configure \
--enable-dvdnav \
--enable-libarchive \
--enable-libmpv-shared \
--enable-libsmbclient \
--enable-manpage-build \
--enable-shaderc \
--enable-vulkan
-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
+13 -27
View File
@@ -35,6 +35,7 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
#include <libavfilter/avfilter.h>
@@ -42,18 +43,6 @@
#include <libavdevice/avdevice.h>
#endif
#if HAVE_LIBAV
#include <libavresample/avresample.h>
#else
#include <libswresample/swresample.h>
#endif
#if LIBAVCODEC_VERSION_MICRO >= 100
#define LIB_PREFIX "ffmpeg"
#else
#define LIB_PREFIX "libav"
#endif
// Needed because the av_log callback does not provide a library-safe message
// callback.
static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -151,7 +140,7 @@ void init_libav(struct mpv_global *global)
pthread_mutex_lock(&log_lock);
if (!log_mpv_instance) {
log_mpv_instance = global;
log_root = mp_log_new(NULL, global->log, LIB_PREFIX);
log_root = mp_log_new(NULL, global->log, "ffmpeg");
log_decaudio = mp_log_new(log_root, log_root, "audio");
log_decvideo = mp_log_new(log_root, log_root, "video");
log_demuxer = mp_log_new(log_root, log_root, "demuxer");
@@ -187,7 +176,7 @@ struct lib {
unsigned runv;
};
bool print_libav_versions(struct mp_log *log, int v)
void check_library_versions(struct mp_log *log, int v)
{
const struct lib libs[] = {
{"libavutil", LIBAVUTIL_VERSION_INT, avutil_version()},
@@ -195,30 +184,27 @@ bool print_libav_versions(struct mp_log *log, int v)
{"libavformat", LIBAVFORMAT_VERSION_INT, avformat_version()},
{"libswscale", LIBSWSCALE_VERSION_INT, swscale_version()},
{"libavfilter", LIBAVFILTER_VERSION_INT, avfilter_version()},
#if HAVE_LIBAV
{"libavresample", LIBAVRESAMPLE_VERSION_INT, avresample_version()},
#else
{"libswresample", LIBSWRESAMPLE_VERSION_INT, swresample_version()},
#endif
};
mp_msg(log, v, "%s library versions:\n", LIB_PREFIX);
mp_msg(log, v, "FFmpeg library versions:\n");
bool mismatch = false;
for (int n = 0; n < MP_ARRAY_SIZE(libs); n++) {
const struct lib *l = &libs[n];
mp_msg(log, v, " %-15s %d.%d.%d", l->name, V(l->buildv));
if (l->buildv != l->runv) {
if (l->buildv != l->runv)
mp_msg(log, v, " (runtime %d.%d.%d)", V(l->runv));
mismatch = l->buildv > l->runv ||
AV_VERSION_MAJOR(l->buildv) != AV_VERSION_MAJOR(l->runv);
}
mp_msg(log, v, "\n");
if (l->buildv > l->runv ||
AV_VERSION_MAJOR(l->buildv) != AV_VERSION_MAJOR(l->runv))
{
fprintf(stderr, "%s: %d.%d.%d -> %d.%d.%d\n",
l->name, V(l->buildv), V(l->runv));
abort();
}
}
mp_msg(log, v, "%s version: %s\n", LIB_PREFIX, av_version_info());
return !mismatch;
mp_msg(log, v, "FFmpeg version: %s\n", av_version_info());
}
#undef V
+1 -1
View File
@@ -7,5 +7,5 @@ struct mpv_global;
struct mp_log;
void init_libav(struct mpv_global *global);
void uninit_libav(struct mpv_global *global);
bool print_libav_versions(struct mp_log *log, int v);
void check_library_versions(struct mp_log *log, int v);
#endif
+28 -5
View File
@@ -126,6 +126,28 @@ bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2)
rc1->x1 == rc2->x1 && rc1->y1 == rc2->y1;
}
// Compute rc1-rc2, put result in res_array, return number of rectangles in
// res_array. In the worst case, there are 4 rectangles, so res_array must
// provide that much storage space.
int mp_rect_subtract(const struct mp_rect *rc1, const struct mp_rect *rc2,
struct mp_rect res[4])
{
struct mp_rect rc = *rc1;
if (!mp_rect_intersection(&rc, rc2))
return 0;
int cnt = 0;
if (rc1->y0 < rc.y0)
res[cnt++] = (struct mp_rect){rc1->x0, rc1->y0, rc1->x1, rc.y0};
if (rc1->x0 < rc.x0)
res[cnt++] = (struct mp_rect){rc1->x0, rc.y0, rc.x0, rc.y1};
if (rc1->x1 > rc.x1)
res[cnt++] = (struct mp_rect){rc.x1, rc.y0, rc1->x1, rc.y1};
if (rc1->y1 > rc.y1)
res[cnt++] = (struct mp_rect){rc1->x0, rc.y1, rc1->x1, rc1->y1};
return cnt;
}
// This works like snprintf(), except that it starts writing the first output
// character to str[strlen(str)]. This returns the number of characters the
// string would have *appended* assuming a large enough buffer, will make sure
@@ -344,9 +366,10 @@ unsigned int mp_log2(uint32_t v)
// 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;
if (!v)
return 1;
if (!(v & (v - 1)))
return v;
int l = mp_log2(v) + 1;
return l == 32 ? 0 : (uint32_t)1 << l;
}
+2
View File
@@ -87,6 +87,8 @@ void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src);
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);
int mp_rect_subtract(const struct mp_rect *rc1, const struct mp_rect *rc2,
struct mp_rect res_array[4]);
unsigned int mp_log2(uint32_t v);
uint32_t mp_round_next_power_of_2(uint32_t v);
Loaded 100 of 412 files, more files were not shown because too many files have changed in this diff. Show more