Compare commits

...
1429 Commits
Author SHA1 Message Date
Alessandro Ghedini 1783e8cade Release 0.7.2 2014-12-20 12:00:13 +01:00
wm4 c7d6b21789 options: enable --ytdl by default
Let's see who complains...
2014-12-19 19:23:28 +01:00
ChrisK2 8d4e6498c3 ytdl: bump requrired youtube-dl version to 2014.11.26 2014-12-19 19:23:22 +01:00
ChrisK2 9984f4fffd ytdl: Try to handle multi-arc videos
this currently uses a sketchy but apparently working workaround,
which will be removed once the neccessary changes in youtube-dl
are implemented

Fixes #1277
2014-12-19 19:23:15 +01:00
ChrisK2 75a62c7a64 ytdl: When using DASH, print actual duration
prints the actual duration as reported by youtube-dl to the
terminal when available
2014-12-19 19:23:11 +01:00
wm4 73eaadf6c3 vo_opengl: clamp filters to their size
This gives better results with fancy-downscaling. The issue here is that
fancy-downscalign "extends" the filter radius by some amount, which
requires using a larger filter size and shader. Then most of the filter
is "unused", but some filters still return non-0 coefficients, which
create heavy artifacts. Just clamp them off.

I'm not sure if this is the right solution, but at least it's better
than before.
2014-12-19 19:23:07 +01:00
Stefano Pigozzi 292f6f1904 cocoa: don't change app activation policy in libmpv
/cc @mpv-player/stable
2014-12-17 20:15:38 +01:00
Stefano Pigozzi 5a2947c9d0 cocoa: remove urlencoding for url open events
This fixes using the mpv:// custom protocol on Yosemite were apparently
we receive an url which is automatically urlencoded by the system.

/cc mpv-player/stable
2014-12-17 20:15:07 +01:00
Stefano Pigozzi fdea35a71b ao_coreaudio: add missing goto for error path 2014-12-17 20:13:23 +01:00
wm4 8f6eb196cd build: require alsa libs not older than 6 years
Some IEC958 flags we use have been introduced in 2008, which makes
compilation fail on older systems.
2014-12-17 20:12:44 +01:00
wm4 3b6e063599 vo_x11: don't attempt to resize when unconfigured
Fixes #1347.

The previous commit actually fixes the crash.
2014-12-17 20:12:06 +01:00
wm4 015218f8c8 vo_x11: check allocation errors
Avoids a crash if allocation fails.
2014-12-17 20:11:41 +01:00
wm4 00d1d6d807 build: add checks for some compiler warning flags 2014-12-17 20:11:30 +01:00
wm4 49c3cbfb4e vd_lavc: fix error handling path
The ctx->pic check must uninitialize the decoder.
2014-12-17 20:11:12 +01:00
wm4 925becfb15 mp_image: check for malloc failure
Or rather, the only reason av_buffer_create() can fail is a malloc
failure.
2014-12-17 20:11:03 +01:00
wm4 2cebc52065 stream_cdda: don't return number of tracks as number of titles
Apparently, we treat different tracks as titles, so returning the number
of titles (which is user-visible as "disc-titles" property) is
completely misguided.
2014-12-17 20:10:54 +01:00
wm4 34e504bf93 Check some mallocs
Fixes #1337.
2014-12-17 20:09:24 +01:00
James Ross-Gowan f0649ce841 pipe-win32: possible fix for Windows XP deadlock
This fixes a hang with the VirtualBox OpenGL drivers. It might help
with #1325 as well.
2014-12-17 20:09:05 +01:00
wm4 65af6a55b7 manpage: fix mistake in --video-zoom mention
Fixes #1331.
2014-12-17 20:08:48 +01:00
wm4 1326d3f0b8 command: fix crash with some forms of script_binding
"script_binding name ..." just crashed it. Oops.
2014-12-17 20:08:15 +01:00
wm4 b062b54626 vo_opengl: fix linkage type
Can happen on Windows, I suppose.
2014-12-17 20:06:05 +01:00
wm4 9bee56cc67 vo_opengl: don't crash if framebuffers are not available
In theory, vo_opengl supports operation without framebuffers. But this
has been broken for a while now (commit cc00b3ff is a contender). It
crashed because it unconditionally called gl->BindFramebuffer() (which
is NULL if framebuffers are missing).

Since this function is actually only called to set the default
framebuffer, the simplest way to deal with this is to provide a dummy
function, insteas of uglifying the code with additional if branches.
2014-12-17 20:05:46 +01:00
James Ross-Gowan 9fb0180eb2 w32_common: fix GUID linking in Cygwin 2014-12-17 20:05:07 +01:00
wm4 4f8af1a518 player: restore ab-loop settings with playback resume
Fixes #1324.
2014-12-17 20:05:01 +01:00
wm4 62b6048468 build: fix --disable-libass
Still supported, but obviously untested.

You shouldn't use this option anyway.
2014-12-17 20:04:02 +01:00
ChrisK2 b6363c8100 DOCS: Improve documentation of --ytdl-format option
As suggested in #1321
2014-12-08 00:06:41 +01:00
wm4 db4cec8a6c sub: remove assertion
This should clearly be impossible, but it seems to happen with ordered
chapters for a user.

Since I can't tell what the actual bug is and it seems impossible to
know the details without downloading possibly huge files, this is
probably the best we can do.

Should at least partially fix #1319.
2014-12-08 00:06:17 +01:00
reimar 4de6f4f616 af_hrtf: Fix out-of-range read.
Based on patch by Yuriy Kaminskiy [yumkam gmail].

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@37330 b3059339-0415-0410-9bf9-f77b7e298cf2
Signed-off-by: wm4 <wm4@nowhere>
2014-12-08 00:04:42 +01:00
wm4 7c53bb4bb1 demux_mkv: reject 0 TimecodeScale
Also reject anything over INT_MAX; no particular reason for this upper
bound.

Fixes #1317.
2014-12-08 00:04:27 +01:00
Stefano Pigozzi 115709e3c1 cocoa: save screenshots to desktop when using app bundle
Fixes #947
2014-12-08 00:03:39 +01:00
Stefano Pigozzi 1e8dbf8212 cocoa: don't create Dock icon for audio only files
fixes #635
2014-12-08 00:03:34 +01:00
wm4 1bfaab13ca ao_alsa: hackfix mono playback
ALSA returns "FL" as channel layout when trying to play mono. mpv and
libavresample don't like this; in particular, using libavresample to
convert stereo to "FL" fails.
2014-12-08 00:02:45 +01:00
wm4 083235d91f osc, dvd, bd: fix mouse state when changing menu modes
The flags weren't correctly set, and the mouse cursor remained visible
after leaving menu mode.

This was apparently broken in 0.7.0 too.

Fixes #1316.
2014-12-08 00:02:24 +01:00
wm4 bc4e115b30 discnav: remove redundant call
This was made the default a while ago.
2014-12-08 00:02:16 +01:00
Stefano Pigozzi 807763c85e coreaudio: don't output too many channel descriptions
for #1279 and #1249
2014-12-07 23:59:33 +01:00
Stefano Pigozzi 69fa6c4b73 coreaudio: add missing \n in log line 2014-12-07 23:59:23 +01:00
Stefano Pigozzi 3141381c2e coreaudio: don't print layout a second time
For #1279
2014-12-07 23:59:16 +01:00
Stefano Pigozzi 8f847437a9 cocoa: don't async redraw when waiting for VO redraw
This fixes the very annoying glitch where the black bars disappear for
a single frame when going fullscreen.
2014-12-07 23:59:02 +01:00
wm4 487fcea6f4 ao_alsa: try to fallback to "default" device if device is busy
ALSA is crap. It's impossible to make multichannel playback just do the
right thing. dmix (the default on most distros) can do stereo only, and
will refuse to play multichannel. On the other hand, if you try like mpv
(and mplayer) to open a multichannel device (like "surround51" etc.),
this will actually open a hardware device, which will either fail if
dmix is active, or block out dmix if opening succeeds.

This commit falls back to "default" (i.e. dmix) if opening a
multichannel device fails, which is a tiny step towards the right
behavior. (Although fixing it fully is impossible.)
2014-12-07 23:57:34 +01:00
wm4 63a31db0a3 input: add a hack to fix keyboard navigation with dvd/bd menu
If the user has LEFT/RIGHT/etc. bound in his input.conf, then these were
overriding the menu keys in dvdnav mode.

This hack works because the dvdnav crap happens to be the only user of
MP_INPUT_ON_TOP. If it finds a default key binding in the dvdnav menu
section, it will use that, instead of continuing search and possibly
finding the user key bindings meant for normal playback.
2014-12-07 23:56:25 +01:00
Stefano Pigozzi 575edecccb coreaudio: reject descriptions with too many channels
This is a fix attempt for #1279 and #1249.
2014-12-07 23:55:28 +01:00
Stefano Pigozzi 14adda8f6b coreaudio: fix more layout prints 2014-12-07 23:55:08 +01:00
Stefano Pigozzi 7cacff6d61 coreaudio: fix prints of uint32_t in log_layout 2014-12-07 23:54:22 +01:00
wm4 4ced125239 dvd, bd, osc: disable OSC while a menu is active
They interfere.

It turns out that commit b6ca4a48 actually broke this in weird ways, but
this solution is better anyway.
2014-12-07 23:54:12 +01:00
wm4 ac94c81134 input, lua: make removing key bindings work
This just kept adding bindings to the input section, rather than
defining it. One bad effect was that mp.remove_key_binding() in Lua
didn't work.
2014-12-07 23:52:33 +01:00
wm4 9501050ddc osc: always force mouse_move binding
So the OSC will still appear when using --no-input-default-bindings. It
also means it may override a user's mouse_move binding, but I guess
users who don't want the OSC should just use the --no-osc option.
2014-12-07 23:50:41 +01:00
wm4 c688880f9e lua: fix broken error message
luaL_error() doesn't support %.*s, because it uses Lua's own format
string mechanism that just looks like the C one. Just drop this part.
2014-12-07 23:50:13 +01:00
wm4 47ec404a52 player: don't signal an error if --stream-dump is used
The player thinks an error happened because no audio or video was played
after finishing the file, but this obviously makes no sense with stream
dumping. (error_playing follows the client API convention that negative
values are errors.)
2014-12-07 23:49:55 +01:00
Alessandro Ghedini 18b15a436f Release 0.7.1 2014-12-02 18:24:30 +01:00
Stefano Pigozzi 6583ad6970 cocoa: fix opening reference URLs (.file/id=)
Fixes #1202

/cc @mpv-player/stable
2014-12-01 21:38:51 +01:00
Niklas Haas 863701391c vo_opengl: Linearize non-RGB sRGB files correctly (eg. JPEG)
Signed-off-by: wm4 <wm4@nowhere>
2014-12-01 21:07:26 +01:00
Niklas Haas 3803c14279 vo_opengl: Reword comment in shader
I didn't quite understand this comment after looking at the code again
months later, so I reworded it for better clarity.
2014-12-01 21:07:12 +01:00
wm4 39126c3828 vo_opengl: make operator precedence explicit
More readable.
2014-12-01 21:07:06 +01:00
Stefano Pigozzi b9cfc3622c ao_coreaudio: initialize fetched properties to zeros
Should hopefully fix #1249 and #1279
2014-12-01 21:06:07 +01:00
wm4 1b0bf6507e options: fix channel map options sometimes failing
Channel amp otpions were not copied correctly: it copied the size of a
pointer to struct chmap, not the struct itself. Since mp_chmap is
currently 9 bytes, this meant the last channel entry was not copied
correctly on 64 bit systems, leading to very strange failures. It could
be triggered especially when using the client API, because the client
API always copies options on access (mpv command line options tend to
work directly on options).
2014-12-01 21:06:00 +01:00
wm4 7ca6aa4ad0 options: fix swapped deprecated/replacement in warning
This was relevant for --af and --vo (both use this option type, and have
deprecated aliases).
2014-12-01 21:05:56 +01:00
wm4 b82a98722a player: simplify and fix ordered chapter EOF handling
Ordered chapter EOF was handled as special-case of ending the last
segment. This broke --kee-open, because it set AT_END_OF_FILE in an
"inconvenient" place (after checking for --keep-open, and before the
code that exits playback if EOF is reached).

We don't actually need to handle the last segment specially. Instead, we
remain in the same segment if it ends. The normal playback logic will
recognize EOF, because the end of the segment "cuts off" the file.

Now timeline_set_from_time() never "fails", and we can remove the old
segment EOF handling code in mp_seek().
2014-12-01 21:05:53 +01:00
wm4 3d6d7012ff command: sub_add with "auto" should not always select a subtitle track
Running "sub_add file.srt auto" during hook execution automatically
selected the first added track. This happened because all tracks added
with sub_add are marked as "external", and external subtitles are always
selected by default.

Fix this by negating the "external" flag when autoselecting subtitles
during loading. The no_default flag exists for this purpose; it was
probably added for libquvi originally, where we had the same issue.
2014-12-01 21:05:49 +01:00
wm4 3051ff9f25 mixer: don't show softvol neutral marker on OSD if not using softvol
Also fix the comment on the softvol field.
2014-12-01 21:05:45 +01:00
wm4 9bf66294f8 vo_opengl: fix srgb with certain inputs
Sampling from the source texture and scaling must always be done
separately in this mode.

Fix suggested by haasn.

Still looks a bit wrong, though.
2014-12-01 21:05:20 +01:00
wm4 577378b827 vo_opengl: something
Insert explanation here.

Fixes #1023.
2014-12-01 21:05:15 +01:00
wm4 1679222e18 audio: fix one of the previous commits
Fixes commit 52c51149. It broke multichannel (or possibly everything)
for ao_alsa, ao_oss, ao_sndio.
2014-12-01 18:31:49 +01:00
wm4 74270cd1db audio: allow more than 20 channel map entries
This could trigger an assertion when using ao_alsa or ao_coreaudio. The
code was simply assuming the number of channel maps was bounded
statically (which was true at first in both AOs).

Fix by using dynamic memory allocation. It needs to be explicitly
enabled by the AOs by setting a temp context, because otherwise the
memory couldn't be freed. (Or at least this seems to be the most elegant
solution.)

Fixes #1306.
2014-12-01 15:41:26 +01:00
wm4 718bf3b39e vd_lavc: don't crash if codec could not be opened
Fixes #1307.
2014-12-01 15:41:17 +01:00
wm4 5ecb381d78 demux_playlist: don't ignore last line in m3u
If EOF is reached after reading a line, the EOF flag is set. This was a
problem for the m3u code, which checked for EOF _after_ reading a line,
which will discard the last line read.

Also fix a typo in an unrelated part of the file.
2014-12-01 15:40:57 +01:00
wm4 17f1332955 win32: add screen offset when handling overlarge windows
MS Windows doesn't allow windows larger than the screen, so we include
a hack to make the window smaller. This hack recenters the window (what
else would it do?).

It didn't account for the virtual offset of the current screen, and it
was reported that it forces the window to the first screen.

Should fix #1292.
2014-12-01 15:38:28 +01:00
Stefano Pigozzi f4a1dfdffb build: fix typos
thanks to @Nikoli
2014-11-28 15:51:43 +01:00
James Ross-Gowan d3972125a1 subprocess-win: remove a Vista-only flag
PIPE_REJECT_REMOTE_CLIENTS isn't supported on XP. It's not really
needed, so remove it. Also fix error checking for CreateNamedPipe.
2014-11-28 15:51:39 +01:00
wm4 71f504a43d demux_mkv: fix a possible out of bounds access
The if branch has a weak check to test whether the codec_id is the short
ID, and handles the long IDs in the else branch. The long IDs are all
longer than 12 bytes long, so hardcoding the string offset to get the
trailing part of the name makes sense. But the if condition checks for
another thing, which could get the else branch run even if the codec_id
is short.

Fix the bogus control flow and check if the codec_id is long enough. One
of these checks could be considered redundant, but include them both for
defensive coding.
2014-11-28 15:51:32 +01:00
wm4 bc1370041d audio: alternative fix for previous commit
This is a somewhat obscure situation, and happens only if audio starts
again after it has ended (in particular can happens with files where
audio starts later). It doesn't matter much whether audio starts
immediately or some milliseconds later, so simplify it.
2014-11-28 15:51:03 +01:00
wm4 4f74869cd8 audio: fix busy loop when seeking while paused
When playing paused, the amount of decoded audio is limited to a small
amount (1 sample), because we don't write any audio to the AO when
paused. The small amount could trigger the case of the wanted audio
being too far in the future in the PTS sync code, which set the audio
status to STATUS_DRAINING, which in turn triggered the EOF code in the
next iteration. This was ok, but unfortunately, this triggered another
retry in order to check resuming from EOF by setting the status to
STATUS_SYNCING, which in turn lead to the busy loop by alternating
between the 2 states. So don't try resyncing while paused.

Since the PTS syncing code also calls ao_reset(), this could cause the
pulseaudio daemon to consume some CPU time as well.

This was caused by commit 33b57f55. Before that, the playloop was merely
run more often, but didn't cause any problems.

Fixes #1288.
2014-11-28 15:50:58 +01:00
Alessandro Ghedini 8d8b36df1b manpage: lua: fix typo paramater -> parameter 2014-11-28 15:49:52 +01:00
Alessandro Ghedini 2da6c95208 Release 0.7.0 2014-11-25 20:18:53 +01:00
wm4 9479daa13e demux_lavf: set PTS of first packet for formats with no timestamps
Makes time display work for some raw audio formats (*.shn).
2014-11-25 19:08:23 +01:00
wm4 5b69b76609 ao_alsa: fix channel map in pre-channel map API case
Forgotten in commit 5d5f5b09.
2014-11-25 18:34:24 +01:00
wm4 e1ae936e6b ao_alsa: always enable "plug" plugin for non-default device
This seems safer: otherwise, opening the AO could randomly fail if the
audio formats happens to be not float.

Unfortunately, this only works if the user does not select a device.
Since ALSA devices are arbitrary strings, including plugins with complex
parameters, it's not trivial or maybe even impossible to edit the string
in a way the "plug" plugin is added.

With --audio-device, it would be safe for users to select either
"default" or one of the "plughw" devices. Everything else seems
questionable.
2014-11-25 18:15:45 +01:00
wm4 5d5f5b094b ao_alsa: select and set channel maps via channel map API
Use the ALSA channel map API for querying and selecting supported
channel maps.

Since we (probably?) want to be compatible with ALSA versions before the
change, we still try to select the device name by channel map, and open
that device. There's no way to negotiate a channel map before opening,
so we're stuck with this approach. Fortunately, it seems these devices
allow selecting and setting any other supported channel layout, so maybe
this is not an issue at all. In particular, this avoids selecting the
default (dmix) device, which can only do stereo.

Most code is based on Martin Herkt <lachs0r@srsfckn.biz>'s alsa_ng
branch, with heavy modifications.
2014-11-25 18:09:36 +01:00
wm4 5fb54fa756 ao_alsa: minor fixes
Don't crash if no fallback channel layout could be found (caller can't
handle NULL return from select_chmap()). Apparently this could never
actually happen, though.

Don't treat snd_pcm_hw_params_set_periods_near() failure as fatal error.
Same deal as with snd_pcm_hw_params_set_buffer_time_near().

Actually free channel maps returned by snd_pcm_get_chmap().

Adjust some messages.
2014-11-25 17:27:19 +01:00
wm4 78f59df6ed client API: make sure youtube-dl is not used by default
Currently, --ytdl is off by default, but even if this is changed, never
enable it by default for the client API. It would be inappropriate to
start an intrusive external subprocess behind the host application's
back.
2014-11-25 17:27:19 +01:00
Stefano Pigozzi 4590c198e6 cocoa: don’t hand over view memory ownership to libmpv clients 2014-11-25 14:45:13 +01:00
wm4 7d6e58471f audio: make mp_audio_config_to_str return a stack-allocated string
Simpler overall.
2014-11-25 11:11:31 +01:00
wm4 8a7b686597 ao_alsa: cleanups
No functional changes.

ALSA_PCM_NEW_HW_PARAMS_API was a pre-ALSA 1.0.0 thing and does nothing
with modern ALSA. It stopped being necessary about 10 years ago.

3 functions are moved to avoid forward references.
2014-11-25 11:10:44 +01:00
wm4 26190dbe57 player: add option not to use OSD/fontconfig
Makeshift-solution for working around certain fontconfig issues.

With --use-text-osd=no, libass and fontconfig won't be initialized, and
fontconfig won't block everything with scanning for fonts.
2014-11-25 11:08:25 +01:00
wm4 28b6ce39d3 audio: make mp_chmap_to_str() return a stack-allocated string
Simplifies memory management.
2014-11-24 19:56:01 +01:00
wm4 2228d47373 ao_alsa: try to use the channel map reported by ALSA
If ALSA reports a channel map, and it looks like it makes sense (i.e.
could be converted to mpv channel map, and the channel count matches),
then use that instead of the channel map we are assuming.

This is based on code written by lachs0r (alsa_ng branch).
2014-11-24 19:44:26 +01:00
wm4 7561adb14d travis: restrict build matrix further
We don't actually want to test all possible combinations; we just want
to make sure that each thing (e.g. linux/osx, ffmpeg/libav) is tested
once.

Exclude Linux + ffmpeg-stable, because ffmpeg-stable is already tested
on OSX.

Exclude clang on Linux, because OSX needs clang, but Coverity (running
on Linux) needs gcc - so we use gcc only on Linux.

I also wanted to reduce the matrix to a single configuration when
running Coverity, but apparently this is not possible.
(See travis-ci/travis-ci#1975.)
2014-11-24 18:42:27 +01:00
wm4 8178f842bf travis: add gcc to the build matrix
For the purpose of running Coverity correctly.

Although I'm not sure how well this works. gcc won't work on OSX, and
also I'm not sure if Coverity will act up if the build matrix has more
than 1 configuration (will it submit multiple scans?).
2014-11-24 16:56:48 +01:00
wm4 d33ae93b89 input: simplify 2014-11-24 16:48:34 +01:00
wm4 0c5fd5a047 lua: remove redundant call 2014-11-24 16:47:13 +01:00
wm4 89c1525585 lua: always handle key repeat on the script side
Simpler, and leaves the decision to repeat or not fully to the script
(instead of requiring the user to care about it when remapping a script
binding).
2014-11-24 16:47:03 +01:00
wm4 2a017734a5 lua, ipc: remove leftovers
MPV_EVENT_SCRIPT_INPUT_DISPATCH is now unused/deprecated.

Also remove a debug-print from defaults.lua.
2014-11-24 10:33:55 +01:00
wm4 5bbd734fff command: don't queue framesteps
If repeated framestep commands are sent, just unpause the player, instead
of playing N frames for N repeated commands.
2014-11-23 15:31:32 +01:00
wm4 17ee2ca524 player: don't crash when using sub_seek without subtitles
Recent regression. It turns out the assertion was completely unneeded.

Fixes #1285.
2014-11-23 15:13:35 +01:00
wm4 ae5df9be98 input, lua: redo input handling
Much of it is the same, but now there's the possibility to distinguish
key down/up events in the Lua API.
2014-11-23 15:13:35 +01:00
wm4 7b47f12f8f client API: restrict client names
Use a fixed size array for the client name, which also limits the client
name in size. Sanitize the client name string, and replace characters
that are not in [A-Za-z0-9] with '_'.
2014-11-23 15:13:34 +01:00
wm4 9d91776d0d x11: fix crash
Broken by previous commit. Oops.
2014-11-23 13:58:03 +01:00
wm4 c9fdf4308c x11: fix crash with --wid=0 and vo_xv/vo_x11
But seriously, don't use --wid=0, don't use vo_xv, and _especially_
don't use vo_x11.

Fixes #1284.
2014-11-23 10:54:34 +01:00
wm4 4cdd346246 input: set mouse area by default for all input
Otherwise, mouse button bindings added by mp.add_key_binding() would be
ignored.

It's possible that this "breaks" some older scripts using undocumented
Lua script functions, but it should be safe otherwise.

Fixes #1283.
2014-11-23 09:10:51 +01:00
wm4 1eeca36d5f subprocess: minor cosmetic cleanup
Don't recursively include the whole stream.h header; only include what's
minimally needed, and handle the rest with forward declarations.
2014-11-22 14:38:58 +01:00
wm4 8097cee4c8 README: cleanup contact section
I spotted to the grammatically incorrect "it's", and ended up redoing
parts of the section.
2014-11-22 14:37:57 +01:00
James Ross-Gowan ef0d1cddb6 lua: subprocess: move to osdep/subprocess-{win,posix}.c
The subprocess code was already split into fairly general functions,
separate from the Lua code. It's getting pretty big though, especially
the Windows-specific parts, so move it into its own files.
2014-11-22 18:15:13 +11:00
James Ross-Gowan b2d0484404 manpage: update utils.subprocess() for Windows 2014-11-22 18:15:12 +11:00
James Ross-Gowan 060bf43d02 lua: subprocess: use macros for SetHandleInformation
Apparently both parameters refer to the same set of flags (the first is
a mask for which flags to set.)
2014-11-22 18:15:11 +11:00
James Ross-Gowan d2848daebb lua: subprocess: fix handle inheritance race condition
Normally, when creating a process with inherited handles on Windows, the
process inherits all inheritable handles from the parent, including ones
that were created on other threads. This can cause a race condition,
where unintended handles are copied into the new process, preventing
them from being closed correctly while the process is running. The only
way to prevent this on Windows XP was to serialise the creation of all
inheritable handles, which is clearly unacceptable for libmpv.

Windows Vista solves this problem by allowing programs to specify
exactly which handles are inherited, so do that on Vista and up.

See http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx
2014-11-22 18:15:10 +11:00
James Ross-Gowan 6a1746b4e3 lua: subprocess: fix Ctrl+C handling on Windows
The CREATE_NO_WINDOW flag is used to prevent the subprocess from
creating an empty console window when mpv is not running in a console.
When mpv is running in a console, it causes the subprocess to detach
itself, and prevents it from seeing Ctrl+C events, so it hangs around in
the background after mpv is killed.

Fix this by only specifying CREATE_NO_WINDOW when mpv is not attached to
a console. When it is attached to a console, subprocesses will
automatically inherit the console and correctly receive Ctrl+C events.
2014-11-22 18:15:09 +11:00
James Ross-Gowan f2b94a3b49 lua: subprocess: cancel pending I/O before return
I'm not sure if this is necessary, but it can't hurt, and it's what
you're supposed to do before leaving the stack frame that contains the
OVERLAPPED object and the buffer. If there is no pending I/O, CancelIo
will do nothing and GetOverlappedResult will silently fail.
2014-11-22 18:15:08 +11:00
Rudolf Polzer 92316eb740 TOOLS/idet.sh: Adjust for changes in FFmpeg.
Compatibility to older idet is preserved.
2014-11-22 08:13:26 +01:00
wm4 863a050258 parse_configfile: check quote termination properly
This is some terrible code; I blame MPlayer legacy.

Found by Coverity.
2014-11-21 10:09:45 +01:00
wm4 75f38dcc9a m_property: fix a typo
The wrong value was checked for an error. Oops.

Found by Coverity.
2014-11-21 10:09:38 +01:00
wm4 df43e2d22a ao_pcm: simplify
Also shuts up Coverity.
2014-11-21 10:09:38 +01:00
wm4 9d2aef048d ao_oss: check whether setting samplerate succeeds
Independent from whether the samplerate was accepted or adjusted, errors
returned by the ioctl are fatal errors.

Found by Coverity.
2014-11-21 10:09:26 +01:00
wm4 c6c46f5aa7 ao_lavc: fix setting up AVFrame pointers
The caller set up the "start" pointer array using the number of planes,
the encode() function used the number of channels. This copied
uninitialized values for packed formats, which makes Coverity warn.
2014-11-21 10:09:25 +01:00
wm4 c01a62efbc af_scaletempo: use float division for rate
From what I understand the division is to align the dimension of the
value from seconds to milliseconds. Hard to tell whether the "rounding"
was intentional or not; I'm tipping on "not".

Found by Coverity.
2014-11-21 10:09:15 +01:00
wm4 86b521f7df Silence some Coverity warnings
None of this really matters.
2014-11-21 09:59:58 +01:00
wm4 e082c2c3df Remove some unneeded NULL checks
Found by Coverity; also see commit 85fb2af3.
2014-11-21 09:58:09 +01:00
wm4 38f4ec69d1 README: add Coverity status
Because it looks nice.
2014-11-21 06:01:20 +01:00
wm4 9a724f62ce draw_bmp: make code more obvious, remove assertion
Silences a Coverity warning.

Also, drop the assert(); although it should be pretty much guaranteed
that things happen this way, it's still a bit fuzzy.
2014-11-21 05:56:55 +01:00
wm4 9df4e7c70e stream: fix endian swapping
In addition to the messed-up expression, the endianness was also
inverted. The code reads big endian by default.

It "worked" by coincidence, but for little endian, codepoints outside of
latin1 were broken.

The broken expression was found by Coverity.
2014-11-21 05:18:16 +01:00
wm4 9c456ab58f bstr: don't call memcpy(..., NULL, 0)
This is clearly not allowed, although it's not a problem on most libcs.

Found by Coverity.
2014-11-21 05:18:11 +01:00
wm4 85fb2af369 Remove some superfluous NULL checks
In all of these situations, NULL is logically not allowed, making the
checks redundant.

Coverity complained about accessing the pointers before checking them
for NULL later.
2014-11-21 05:18:09 +01:00
wm4 4704fab82c ipc: fix confusion of write() return value and errno
Found by Coverity.
2014-11-21 05:18:05 +01:00
wm4 3938349cd5 demux_mkv: fix scary sign extension issues
Expressions involving uint16_t are promoted to int, which then can
overflow if the uint16_t values are large enough.

Found by Coverity.
2014-11-21 05:18:01 +01:00
wm4 550c16fe9d demux_mkv: fix possible real-audio out of bounds accesses
Could index static arrays from arbitrary input data without checking for
bounds.

Found by Coverity.
2014-11-21 05:17:52 +01:00
wm4 3df8e64ec0 demux_mkv: fix uninitialized variable
Found by Coverity.
2014-11-21 03:50:57 +01:00
wm4 524aa99401 audio/out/push: fix off-by-one error
Needs 1 additional free entry.

Found by Coverity.
2014-11-21 03:50:57 +01:00
wm4 459f3aa4f9 ao_lavc: fix dangling pointers
Found by Coverity.
2014-11-21 03:50:52 +01:00
wm4 78fe4f1bd4 travis: another attempt (2)
They said YAML is "simple"...
2014-11-21 02:34:01 +01:00
wm4 cd42d72a7f travis: another attempt
I guess it didn't like the duplicate env section.
2014-11-21 02:28:59 +01:00
wm4 cfa9724a79 build: don't build win32 mpv.com wrapper with --disable-cplayer
It'll be useless.
2014-11-21 01:47:30 +01:00
wm4 e627168233 travis: attempt to add Coverity integration
Not sure if this will work. Probably not, because it seems Coverity will
be missing some required dependencies.
2014-11-21 01:46:25 +01:00
wm4 00626817c8 lua: add a way to add repeatable key bindings
For these, autorepeat is enabled.
2014-11-21 00:01:59 +01:00
wm4 0a78a61d89 input: add a prefix to make any binding act on key repeat
The fact that it's a generic command prefix that is parsed even when
using the client API is a bit unclean (because this flag makes sense
for actual key-bindings only), but it's less code this way.
2014-11-20 23:41:01 +01:00
wm4 a1811211a2 command: dvd: better audio/video recovery on angle switching
Does the same thing as the drop_buffers command. When implementing that
command, it turned out that resetting the higher level playback state
was more effective for achieving smooth recovery.

Untested; I don't even have any DVDs or DVD images with multiple angles.
2014-11-20 22:45:02 +01:00
wm4 2d039e691f command: add drop_buffers
This command was actually requested on IRC ages ago, but I forgot about
it.

The main purpose is that the decoding state can be reset without issuing
a seek, in particular in situations where you can't seek.

This restarts decoding from the middle of the packet stream; since it
discards the packet buffer intentionally, and the decoder will typically
not output "incomplete" frames until it has recovered, it can skip a
large amount of data.

It doesn't clear the byte stream cache - I'm not sure if it should.
2014-11-20 22:41:50 +01:00
wm4 7df909e9fc demux_mkv: haali hack: add last frame duration to video length too
From what I can see, only the blockduration of the packet needs to be
added, never the "default duration".
2014-11-20 22:27:27 +01:00
wm4 f93ce21d45 Catch SIGPIPE
Avoids a crash if OpenSSL tries to write to a broken connection with
write().

Obviously OpenSSL really should use send() with MSG_NOSIGNAL, but for
some reason it doesn't. This should probably be considered an OpenSSL
bug, but since in this case we "own" the process, there is no harm in
ignoring the signal.

This is not done with libmpv, because as a library we don't want to mess
with global state. It's also not done if terminal handling is disabled -
this is a bit arbitrary, but I don't care much.
2014-11-20 21:45:12 +01:00
wm4 8a1d5e91ad vd_lavc: flush frames before uninitializing hw decoder
This way, no surfaces are in use when uninitializing the hw decoders,
which might help with -copy hw decoders (normal hw decoding is not
affected).
2014-11-20 16:48:03 +01:00
Jaime Marquínez Ferrándiz cf8efe3235 options: add --ytdl-format option for youtube-dl format
It's passed with the '--format' option to youtube-dl.

If it isn't set, we don't pass '--format best' so that youtube-dl can
use the options from its configuration file.

Signed-off-by: wm4 <wm4@nowhere>
2014-11-20 00:17:13 +01:00
wm4 bf2eb51d68 manpage: changes.rst: add youtube-dl script 2014-11-19 23:05:08 +01:00
wm4 de47b34112 input.conf: add some additional bindings 2014-11-19 23:03:42 +01:00
wm4 079ecd7f01 player: integrate ytdl_hook.lua 2014-11-19 18:59:38 +01:00
ChrisK2 0f7df89468 lua: add youtube-dl hook script
This merely adds the file without using it, for the sake of retaining
authorship information.

Signed-off-by: wm4 <wm4@nowhere>
2014-11-19 18:37:39 +01:00
wm4 9b8a62c0b2 manpage: fix typo 2014-11-19 18:27:53 +01:00
wm4 d51a032fd7 demux_mkv: add an option for compatibility with Haali
This was requested on IRC.
2014-11-18 23:07:20 +01:00
wm4 cc84f73a95 manpage: document vo_cmdline command 2014-11-18 21:40:30 +01:00
wm4 534b08e6ba command: add an ab_loop command
As suggested in #1241; to make using the feature easier.

Also add better OSD-formatting for the ab-loop-a/b properties.
2014-11-18 21:34:57 +01:00
wm4 5d1a3fb406 command: improve A-B loop behavior
If the B point is set, then loop back to A.

Also, update the OSD bar if necessary.
2014-11-18 20:28:54 +01:00
Kevin Mitchell 71095be5b0 ao/wasapi: actually only retry once (not twice)
oops
2014-11-18 07:54:26 -08:00
Kevin Mitchell f2dda72dbc ao/wasapi: only retry resizing the buffer once
like the MSDN example:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd370875%28v=vs.85%29.aspx
2014-11-18 07:50:51 -08:00
wm4 b8ac594af0 vo_direct3d: fix texture-memory sub-option, extend it
This sub-option was turned into a flag when the sub-option parser was
changed to the generic one (probably accidentally). Turn it into a
proper choice-option.

Also, adjust what the options do. Though none of this probably makes
much sense; the default should work, and if it doesn't, the GPU/driver
is probably beyond help.
2014-11-18 16:30:32 +01:00
Kevin Mitchell caf2fbf688 ao/wasapi: only retry resizing the buffer once
like the MSDN example:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd370875%28v=vs.85%29.aspx
2014-11-18 07:26:11 -08:00
Kevin Mitchell da03334a73 ao/wasapi: keep bufferPeriod in sync on retry
Without this, the retry will fail if they are not equal or
bufferPeriod is zero.
2014-11-18 06:59:26 -08:00
Kevin Mitchell 94ea4435a9 ao/wasapi: refix printf warning for both cygwin and msys
a cast to (unsigned) should do "the right thing".
2014-11-18 05:03:33 -08:00
Kevin Mitchell 19e9c9d1be ao/wasapi: periodicity in shared mode must be zero
IAudioClient::Initialize hnsPeriodicity argument is nonzero only for exclusive mode

http://msdn.microsoft.com/en-us/library/windows/desktop/dd370805%28v=vs.85%29.aspx
2014-11-18 05:03:33 -08:00
Kevin Mitchell c545c406fa ao/wasapi: increase buffer size to 50 ms
Before it was the default device period, which was too small
causing glitches on on entering/exiting fullscreen.
2014-11-18 05:03:33 -08:00
wm4 1507ef05c2 stream: reduce ifdeffery for win32 somewhat
Remove the ones which are not strictly needed.
2014-11-18 13:40:34 +01:00
James Ross-Gowan c644178098 lua: subprocess: support cancellation on Windows 2014-11-18 13:34:00 +01:00
James Ross-Gowan 9e77ba8003 stream: signal a Windows event object on cancel
This will be used in the following commit to cancel subprocesses started
by Lua.
2014-11-18 13:34:00 +01:00
James Ross-Gowan 67132750a6 lua: subprocess: use overlapped I/O on Windows
Instead of threads, use overlapped (asynchronous) I/O to read from both
stdout and stderr. Like in d0643fa, stdout and stderr could be closed at
different times, so a sparse_wait function is added to wrap
WaitForMultipleObjects and skip NULL handles.
2014-11-18 13:34:00 +01:00
wm4 c862955bac command: initialize a-b loop options correctly
It was initialized as 0/0, which basically cleared the chapter marks by
default.
2014-11-18 12:51:43 +01:00
wm4 d96bd0eaa8 audio/out: always log retrieved audio device size 2014-11-18 12:51:43 +01:00
Jonathan Yong 7697d300d2 ao/wasapi: fix leaked marshaled interface streams
Signed-off-by: Kevin Mitchell <kevmitch@gmail.com>
2014-11-18 02:12:28 -08:00
Kevin Mitchell 22bf0a78df ao/wasapi: Don't free stuff the thread may still be using on timeout
In the unlikely event of a timeout waiting for the audio thread to return,
don't free stuff that it may still be using.
2014-11-17 23:46:38 -08:00
Kevin Mitchell 20d42b3475 ao/wasapi: also free the threadLoop handle on uninit
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx
2014-11-17 23:43:51 -08:00
Kevin Mitchell 23f52fd41b ao/wasapi: fix leaked event handles 2014-11-17 23:32:28 -08:00
Kevin Mitchell ebd161b256 ao/wasapi: fix race condition in uninit on failure.
When the audio thread fails to properly init, it signals failure
to the main thread, AND THEN starts to clean up. For this to work,
ao_init callback must not return until the thread's cleanup is finished.
This is correctly handled in the ao_uninit callback by waiting for
the thread to exit, so just call that to clean up the main thread.
I have no idea why I didn't do this in the first place.
2014-11-17 23:32:13 -08:00
James Ross-Gowan d9bac96a9d ao/wasapi: silence format string warnings 2014-11-18 12:19:36 +11:00
wm4 4bd6c91d9b command: implement A-B loops
Probably needs to be polished a bit more. Also, might require a key
binding that can set/clear the loop points in a more intuitive way.

For now, something like this can be put into input.conf to use it:

ctrl+y set ab-loop-a ${time-pos}    # set A
ctrl+x set ab-loop-b ${time-pos}    # set B
ctrl+c set ab-loop-a no             # clear (mostly)

Fixes #1241.
2014-11-18 01:36:35 +01:00
wm4 ed59234378 wscript: move down some less important checks 2014-11-17 23:50:32 +01:00
wm4 41fd7fa021 build: check for mingw-w64 explicitly
And fail building if not any of MingW-w64 or POSIX are found. Obviously,
mpv needs one of those 2.
2014-11-17 23:47:30 +01:00
wm4 469eb321e8 command: adjust previous commit
Due to the current code structure, the "current" entry and the entry
which is playing can be different. This is probably silly, but still
try to mark the entries correctly.

Refs #1260.
2014-11-17 22:48:38 +01:00
wm4 ebd41bdf6c command: playlist property: return if an entry is currently playing
This actually doesn't even write/return the new sub-property, because
I dislike the idea of dumping that field for every single playlist
entry, even though it's "needed" only for one.

Fixes #1260.
2014-11-17 22:16:52 +01:00
wm4 fb86750a67 ao_alsa: check for EAGAIN too
Simply retry on EAGAIN.

I've seen this in several other projects; it might be just cargo-culting
though.
2014-11-17 20:07:59 +01:00
wm4 8b2798cb3e audio/out: switch back to wasapi as default on win32
dsound was set as default, because there were some hard to fix problems
with wasapi. These problems were probably fixed now, so let's try with
wasapi as default again.
2014-11-17 14:07:11 +01:00
Kevin Mitchell 313f1954c5 Merge branch 'wasapi_fix2' 2014-11-17 05:02:18 -08:00
Kevin Mitchell 4c8b841fc4 ao/wasapi: request ao reload on thread_feed failures
Even with change notifications, there are still (rare) cases when the
feed thread gets AUDCLIENT_DEVICE_INVALIDATED. So handle failures in
thread_feed by requesting ao_reload.
2014-11-17 04:31:22 -08:00
Kevin Mitchell 9371990bd1 ao/wasapi: add retry loop on AUDCLNT_E_DEVICE_IN_USE
this works around reinitializing too fast on device property changes
2014-11-17 04:31:22 -08:00
Kevin Mitchell 6c512892d4 ao/wasapi: request reset on appropriate events
on changes to PKEY_AudioEngine_DeviceFormat, device status, and default device.
call ao_reload directly in the change_notify "methods".

this requires keeping a device enumerator around for the duration of
execution, rather than just for initially querying devices
2014-11-17 04:31:20 -08:00
Kevin Mitchell e647f202ed ao/wasapi: add convenience functions for change notifiy 2014-11-17 04:30:53 -08:00
Jonathan Yong f29f16663a ao/wasapi: new wasapi device monitoring interface
Implement skeleton IMMNotificationClient to watch for changes in the
sound device.  This will make recovery possible from changes shared
mode sample rate, bit depth, "enhancements"/effects and even graceful
device removal.

http://msdn.microsoft.com/en-us/library/windows/desktop/dd371417%28v=vs.85%29.aspx

Signed-off-by: Kevin Mitchell <kevmitch@gmail.com>
2014-11-17 04:30:53 -08:00
Kevin Mitchell 497df443c0 ao/wasapi: look for "multimedia" default device instead of "console"
console is more for system notifications / voice command, mpv is most certainly multimedia

http://msdn.microsoft.com/en-us/library/windows/desktop/dd370842%28v=vs.85%29.aspx
2014-11-17 04:30:53 -08:00
Kevin Mitchell e8dbdf1eb9 ao/wasapi: put loading of default device in it's own function 2014-11-17 04:30:47 -08:00
Kevin Mitchell f7c26230eb ao/wasapi: fix possible null dereference of pDevice
IMMDeviceEnumerator::GetDefaultAudioEndpoint may set pDevice to null on failure.

http://msdn.microsoft.com/en-us/library/windows/desktop/dd371401%28v=vs.85%29.aspx
2014-11-17 04:13:52 -08:00
Kevin Mitchell 3da6f723c6 ao/wasapi: tidy up better on failure
Before, failures, particularly in the thread loop init, could lead to a
bad state for the duration of mpvs execution. Make sure that
everything that was initialized gets properly and safely
uninitialized.
2014-11-17 04:13:52 -08:00
Kevin Mitchell e28102f1a8 ao/wasapi: improve error messages and add more debug statements
also enforce more consistency in the exit codes and error handling

thanks to Jonathan Yong <10walls@gmail.com>
2014-11-17 04:13:49 -08:00
Kevin Mitchell d4393be0f9 ao/wasapi: make calling of thread_init consistent with thread_uninit 2014-11-17 03:37:07 -08:00
Kevin Mitchell 6eb5c6d186 ao/wasapi: reenable the reset function
the race condition that necessitated disabling
this was fixed in
e440352313
2014-11-17 03:37:07 -08:00
Jonathan Yong 227f0e3f39 ao/wasapi: fix leaked deviceID 2014-11-17 03:36:54 -08:00
wm4 f4804b0c45 lua: subprocess: remove minor code duplication
Now that the code for stderr and stdout does exactly the same things,
and the specialization is in the callbacks, this is blatantly
duplicated.

Also, define a typedef for those callbacks to reduce the verbosity.
2014-11-16 19:18:23 +01:00
wm4 4cf1843664 demux_mkv: check file type without actually reading data
Do a minimal check on data read with stream_peek(). This could help with
probing from unseekable streams in some situations. (We could check the
entire EBML and Matroska headers, but probably not worth the trouble. We
could also seek back to the start, which demux.c doesn't do, but which
would work usually - also not worth the trouble.)
2014-11-16 18:51:56 +01:00
wm4 78cbbb4c49 demux_cue: use stream_peek()
This could cause probing failures with unseekable streams. (Although I'm
not perfectly sure why; seeking back should work in this particular
case.)
2014-11-16 18:13:41 +01:00
wm4 613ee8f450 restore-old-bindings.conf: add recently changed binding 2014-11-16 18:09:40 +01:00
James Ross-Gowan ebccfc4351 lua: subprocess: add Windows implementation
Doesn't handle mp_cancel yet.
2014-11-16 18:08:02 +01:00
ChrisK2 c372856c11 input.conf: Don't make ENTER exit the player
Apparently this is confusing.
2014-11-15 23:10:28 +01:00
ahoka b4a147bbe2 man: document osc seekbarstyle option 2014-11-15 20:20:54 +01:00
ahoka e7b45b1efa osc: add validation for string user options 2014-11-15 20:20:52 +01:00
ahoka 6de303c339 osc: add seekbarstyle option 2014-11-15 20:20:50 +01:00
Ben Boeckel 07c4d67565 umpv: update comment for the new FIFO location 2014-11-15 20:20:06 +01:00
wm4 2125e49422 sub: workaround braindead libass API
libass won't use embedded fonts, unless ass_set_fonts() (called by
mp_ass_configure_fonts()) is called. However, we call this function when
the ASS_Renderer is initialized, which is long before the .ass file is
actually loaded. (I'm not sure why it tries to keep 1 ASS_Renderer, but
it always did this.)

Fix by calling mp_ass_configure_fonts() after loading them. This also
means this function will be called multiple times - hopefully this is
harmless (it will reinit fontconfig every time, though).

While we're at it, also initialize the ASS_Renderer lazily.

Fixes #1244.
2014-11-15 19:43:43 +01:00
wm4 a6694d2788 demux_mkv: adjust subtitle preroll again (2)
Make the changes started in commit c827ae5f more eloborate, and provide
an option to control the amount of data read before the seek-target. To
achieve this, rewrite the loop that finds the lowest still acceptable
target cluster. It is now searched by time instead of file position. The
behavior (both with and without preroll option) may be different from
before this change, although it shouldn't be worse.

The change demux_mkv_read_cues() fixes a bug: when seeking after playing
normally, the code would erroneously assume that durations are set. This
doesn't happen if the first operation after loading was a seek instead
of playback.
2014-11-15 00:55:30 +01:00
wm4 d484cb3f32 vo_opengl: allow setting different filters for downscaling 2014-11-14 15:22:37 +01:00
wm4 508d236c9a command: list filters/VOs/AOs with option-info
Another special-case, but pretty simple after all.
2014-11-14 14:52:51 +01:00
wm4 5d12a2696e command: export some option metadata
This might be interesting for GUIs and such.

It's probably still a little bit insufficient. For example, the filter
and audio/video output lists are not available through this.
2014-11-13 18:01:27 +01:00
wm4 71168e740e command: rename "option-flags" property to "option-info" 2014-11-13 17:27:31 +01:00
wm4 13033ce2c4 command: make sub-properties more flexible
This makes it work with all kind of types, instead of just some simple
ones.
2014-11-13 17:26:22 +01:00
wm4 dbf59abe05 command: fix weird stuff
Happens to fix some aspects of some properties (especially reading
"option-flags/x" as native value).
2014-11-13 17:25:04 +01:00
wm4 23e0682dd4 command: export mpv configure arguments as property
It seems strange that a client API user can't get this string, other
than analyzing the mpv log output.
2014-11-13 16:18:40 +01:00
Rudolf Polzer 0f30803172 terminal-unix: Add some comments about FD use. 2014-11-13 12:25:43 +01:00
Rudolf Polzer a09f7a371e terminal-unix: Fix initial terminal state.
When mpv is backgrounded initially (via & in the shell), do no longer
change terminal settings on startup. This fixes broken local echo after
launching a backgrounded mpv.
2014-11-13 12:25:43 +01:00
wm4 09e08bfe2e demux: update cache state when paused
This was removed in commit 480f82fa. This caused the cache display not
to update while paused, because the update_cache() function is never
called in the thread (now I remember why the extra call was "needed").

The old implementation intentionally run update_cache() only before
waiting on a mutex, with no further checks for the condition variable.
In theory, this is strictly not sane, but since it was just for the
retrieval of the very fuzzy cache status, it was ok. Now we want to call
update_cache() outside of the mutex though - which means that in order
to avoid missed wakeups, a proper condition has to be used.
2014-11-12 21:47:41 +01:00
wm4 be9eb08389 af: remove redundant function 2014-11-12 20:19:21 +01:00
wm4 a669a1d0dd af: check audio params for validity
Normally, these should be valid anyway, so this is just being cautious.
2014-11-12 20:03:04 +01:00
wm4 e9792326e3 mp_image: slightly better image params verbose info 2014-11-12 19:30:59 +01:00
wm4 4136531343 video: move formatting of image parameters to separate function 2014-11-12 19:30:59 +01:00
wm4 509997ec12 vf: minor simplification
Remove the extra vf_chain.output field - there's absolutely no need for
it, because there is always a last filter which will buffer the output.

For some reason, vf_chain.last was never set, which we now need to fix
too.
2014-11-12 19:30:59 +01:00
wm4 b244d5d817 manpage: adjust --hwdec docs 2014-11-12 19:30:58 +01:00
wm4 a9ece6371f player: simplify audio uninit on segment switches
The purpose of temporarily setting stop_play was to make the audio
uninit code to explicitly drain audio if needed. This was the only way
to do it before ao_drain() was made a separate function; now we can just
do it explicitly instead.
2014-11-12 19:30:58 +01:00
wm4 f0efd0b100 audio: fix some issues when reloading the AO
We absolutely need to clear the AO reference in the mixer.

The audio_status must be changed to a state where no code assumes that
the AO is available. (It's allowed to do this blindly.)
2014-11-12 14:19:16 +01:00
Rudolf Polzer 4f63a812de ao_lavc, vo_lavc: Fix crashes in case of multiple init attempts.
When initialization failed, vo_lavc may cause an irrecoverable state in
the ffmpeg-related structs. Therefore, we reject additional
initialization attempts at least until we know a better way to clean up
the mess.

ao_lavc currently cannot be initialized more than once, yet it's good to
do consistent changes there as well.

Also, clean up uninit-after-failure handling to be less spammy.
2014-11-12 12:16:07 +01:00
wm4 88762cd6a7 player: make the osd-msg prefix work for playlist_next/prev
If input.conf e.g. contains "n osd-msg playlist_next", then pressing the
n key will switch to the next file, and display the filename on OSD.
2014-11-11 22:07:16 +01:00
wm4 d4cc41bbcd audio: make sure AVFrame is actually refcounted
The mp_audio_from_avframe() function requires the AVFrame to be
refcounted, and merely increases its refcount while referencing the same
data. For non-refcounted frames, it simply did nothing and potentially
would make the caller pass around a frame with dangling pointers.

(libavcodec should always return refcounted frames, but it's not clear
what other code does; and also the function should simply work, instead
of having weird requirements on its arguments.)
2014-11-11 21:20:21 +01:00
wm4 475226c783 audio: refuse to allocate frames in invalid format 2014-11-11 21:10:53 +01:00
wm4 c827ae5f36 demux_mkv: adjust subtitle preroll again
Revert commit 24e52f66; even though the old beheavior doesn't make sense
(as the commit message assured), it turns out that this works better:
typically, it means preroll will start from the previous video key frame
(the video CUE index will contain clusters with video key frames only),
which often coincides with subtitle changes. Thus the old behavior is
actually better.

Change the code that uses CueDuration elements. Instead of merely
checking whether preroll should be done, find the first cluster that
needs to be read to get all subtitle packets. (The intention is to
compensate for the enlarged preroll cluster-range due to reverting
commit 24e52f66.)
2014-11-11 19:36:03 +01:00
wm4 481ab94c4e vf_sub: fix previous commit
The previous fix breaks another obscure case: if the second vf_sub adds
margins, the image is accidentally not extended, which would return in
an assertion failure when returning the bogus image.
2014-11-11 19:26:43 +01:00
wm4 599a4a8769 vf_sub: don't crash if no subtitle context is available
Happens with --vf=sub,sub (only the first one gets the context).
2014-11-11 18:47:21 +01:00
wm4 67e0230905 encode: don't segfault when bailing out due to resolution change
Somehow this code expects lastimg is always set.
2014-11-11 17:59:49 +01:00
wm4 d8cd768ed0 vo_opengl: don't reset user-set gamma when using vo_cmdline 2014-11-11 10:48:54 +01:00
wm4 5fd8a1e04c audio: make decoders output refcounted frames
This rewrites the audio decode loop to some degree. Audio filters don't
do refcounted frames yet, so af.c contains a hacky "emulation".

Remove some of the weird heuristic-heavy code in dec_audio.c. Instead of
estimating how much audio we need to filter, we always filter full
frames. Maybe this should be adjusted later: in case filtering increases
the volume of the audio data, we should try not to buffer too much
filter output by reducing the input that is fed at once.

For ad_spdif.c and ad_mpg123.c, we don't avoid extra copying yet - it
doesn't seem worth the trouble.
2014-11-10 22:02:05 +01:00
wm4 46d6fb9dc1 audio: add mp_audio_make_writeable() 2014-11-10 22:02:05 +01:00
wm4 c1b034f2aa audio: clear buffer array too with mp_audio_set_null_data() 2014-11-10 22:02:05 +01:00
wm4 e094e9cb75 audio: change how filters are inserted on playback speed changes
Use a pseudo-filter when changing speed with resampling, instead of
somehow changing a samplerate somewhere. This uses the same underlying
mechanism, but is a bit more structured and cleaner. It also makes some
of the following changes easier.

Since we now always use filters to change audio speed, move most of the
work set_playback_speed() does to recreate_audio_filters().
2014-11-10 22:02:05 +01:00
wm4 995a6af787 af_format: remove redundant message prefixes 2014-11-10 22:02:04 +01:00
wm4 0b26d8c666 audio: add function to convert AVFrame to mp_audio references
This is somewhat duplicated from ad_lavc.c and af_lavfi.c, but will
eventually be used by both.
2014-11-10 22:02:04 +01:00
wm4 5d46e44160 audio: add mp_audio_pool
A helper to allocate refcounted audio frames from a pool. This will
replace the static buffer many audio filters use (af->data), because
such static buffers are incompatible with refcounting.
2014-11-10 18:15:22 +01:00
wm4 c3d446ee2e player: don't try to use duration 0 2014-11-10 18:11:33 +01:00
wm4 cb13d7fadb dvd, bluray: reload demuxer on title changes
Causes the player to reload the demuxer and to relist the found
streams. Probably slightly dangerous/broken, because the demuxer
thread and possibly even the decoders will keep reading data from
the new title before the new demuxer takes over.

Fixes #1250.
2014-11-10 10:50:55 +01:00
wm4 9388f69f67 audio: use AVBufferRef to allocate audio frames
A first step towards refcounted audio frames.

Amazingly, the API just does what we want, and the code becomes
simpler. We will need to NIH allocation from a pool, though.
2014-11-10 10:43:15 +01:00
Alessandro Ghedini 5f175b0bdc command: send property-change event on playlist change 2014-11-09 15:31:48 +01:00
wm4 e440352313 audio/out/pull: avoid deadlock if audio callback stops
If the audio callback suddenly stops, and the AO provides no "reset"
callback, then reset() could deadlock by waiting on the audio callback
forever.

The waiting was needed to enter a consistent state, where the audio
callback guarantees it won't access the ringbuffer. This in turn is
needed because mp_ring_reset() is not concurrency-safe.

This active waiting is unavoidable. But the way it was implemented, the
audio callback had to call ao_read_data() at least once when reset() is
called. Fix this by making ao_read_data() set a flag upon entering and
leaving, which basically turns p->state into some sort of spinlock.

The audio callback actually never needs to spin, because there are only
2 states: playing audio, or playing silence. This might be a bit
surprising, because usually atomic_compare_exchange_strong() requires a
retry-loop idiom for correct operation.

This commit is needed because ao_wasapi can (or will in the future)
randomly stop the audio callback in certain corner cases. Then the
player would hang forever in reset().
2014-11-09 15:23:40 +01:00
wm4 0025f0042f atomics: add atomic_compare_exchange_strong()
As usual, we use C11 semantics, and emulate it if <stdatomic.h> is not
available.

It's a bit messy with __sync_val_compare_and_swap(). We assume it has
"strong" semantics (it can't fail sporadically), but I'm not sure if
this is really the case. On the other hand, weak semantics don't seem to
be possible, since the builtin can't distinguish between the two failure
cases that could occur. Also, to match the C11 interface, use of gcc
builtins is unavoidable. Add a check to the build system to make sure
the compiler supports them (although I don't think there's any compiler
which supports __sync_*, but not these extensions).

Needed for the following commit.
2014-11-09 15:12:54 +01:00
wm4 5db0fbd95e audio/out: consistently use double return type for get_delay
ao_get_delay() returns double, but the get_delay callback still
returned float.
2014-11-09 11:45:04 +01:00
wm4 3d7d1f3f26 video/out: minor simplification to event query function
The "clear" parameter is confusing and useless.
2014-11-09 10:01:16 +01:00
wm4 b021d038c2 audio/out: make ao_request_reload() idempotent
This is what you would expect. Before this commit, each
ao_request_reload() call would just queue a reload command, and then
recreate the AO for the number of times the function was called.

Instead of sending a command, introduce some sort of event retrieval
mechanism. At least for the reload case, use atomics, because we're too
lazy to setup an extra mutex.
2014-11-09 09:58:44 +01:00
wm4 7ee4e53369 audio: handle reinit after AO reload slightly cleaner
Don't print bogus messages about packets read in verbose mode.
2014-11-09 09:54:39 +01:00
wm4 4235aab897 mp_image: check memory allocation 2014-11-08 16:10:04 +01:00
wm4 33b57f5557 player: improve audio time display
This commit fixes a "cosmetic" user interface issue. Instead of
displaying the interpolated seek time on OSD, show the actual audio
time.

This is rather silly: when seeking in audio-only mode, it takes some
iterations until audio is "ready", but on the other hand, the audio
state machine is rather fickle, and fixing this cosmetic issue would be
intrusive. So just add a hack that paints over the ugly behavior as
perceived by the user. Probably the lesser evil.

It doesn't happen if video is enabled, because that mode sets the
current time immediately to video PTS. (Audio has to be synced to video,
so the code is a bit more complex.)

Fixes #1233.
2014-11-08 16:09:42 +01:00
James Ross-Gowan 68ecbdf920 w32_common: open window menu on Alt+Space
Since mpv doesn't call TranslateMessage, this must be done manually.

Should fix #1254
2014-11-08 12:16:14 +01:00
wm4 249e8f6a54 Revert "w32_common: don't override alt+space"
This reverts commit d859549424.

Going to apply the alternative fix through PR #1256, which came just
some seconds after pushing the reverted commit. The reverted commit
was reported as not actually working.
2014-11-08 12:14:29 +01:00
wm4 d859549424 w32_common: don't override alt+space
Apparently, stealing this from the WM is bad form, just like with F10.

Fixes #1254.
2014-11-08 12:06:44 +01:00
James Ross-Gowan cee0d7f2ad win32: silence some warnings
Signed-off-by: wm4 <wm4@nowhere>
2014-11-08 10:24:49 +01:00
wm4 9f239464da command: silence a warning on win32
Same goal as a change in the #1255 PR, but IMO slightly less
ifdefferish.
2014-11-08 10:24:26 +01:00
wm4 2a5c77df73 demux_mkv: fix undefined shifts
Found by clang sanitizer. Casting unsigned integers to signed integers
with same size has implementation defined behavior (it's even allowed to
crash), but it seems reasonable to expect that reasonable
implementations do a complement of 2 "conversion".
2014-11-08 10:21:12 +01:00
wm4 64f6e88c45 command: fix option-flags property
The sub-path wasn't adjusted, and it worked only in some situations.
2014-11-08 10:19:17 +01:00
wm4 f5c2e3d6e2 client API: deprecate some events
Following the discussion in #1253.

The events won't be removed for a while, though. (Or maybe never, unless
we run out of bits for the uint64_t event mask.)

This is not a real change (the events still work, and the alternative
mechanisms were established a few API revisions earlier), but for the
sake of notifying API users, update DOCS/client-api-changes.rst.
2014-11-08 10:19:07 +01:00
wm4 1a5650b628 command: export the flag whether an option was set on commandline
Can be useful for certain scripts; I think someone requested this.
2014-11-07 16:33:41 +01:00
wm4 e002ba74d3 client API: additional documentation comments
(I guess some of the mpv_event contents turned out relatively awkward.)
2014-11-07 16:21:51 +01:00
wm4 c6cf38a4dd client: remove redundant assignment
This is set by send_reply().
2014-11-07 16:21:03 +01:00
wm4 18ade94c89 client API: silence silly clang warning
The values compared here happen to be of unsigned enum types - but the
test is not supposed to break if we somehow force the enum to signed, or
if the compiler happens to use a signed type (as far as I remember, the
exact integer type the compiler can use is implementation-defined).
2014-11-07 15:58:51 +01:00
wm4 b814b7ca84 audio: add --audio-client-name option
The main need I see for this is with libmpv - it would be confusing if
some application showed up as "mpv" on whateverthehell PulseAudio uses
it for (generally it does show up on various PA GUI tools).
2014-11-07 15:54:35 +01:00
wm4 01141198be vo_opengl: initialize renderer after setting size
This silences the warning:

video/out/gl_video.c:1091:51: runtime error: division by zero

when running with clang -fsanitize=undefined. Division by zero is legal
according to IEEE, but I guess clang doesn't care about standard. While
triggering this warning isn't actually avoided in all cases, it's
avoided in the common case and also makes people shut up about it.
2014-11-07 15:28:12 +01:00
Kevin Mitchell 351608e5cc command: add display-names property
Call VOCTRL_GET_DISPLAY_NAMES it when the property is
requested. The vo should return the names of the displays that the mpv
window is covering.  For example, with x11 vos, xrandr names LVDS1,
HDMI1, etc.
2014-11-07 01:14:03 -08:00
Kevin Mitchell 83aab1d4be vo/x11: implement VOCTRL_GET_DISPLAY_NAMES with xrandr names (e.g., "LVDS1")
XRRGetOutputInfo contains a "name" element which corresponds to to the
display names given to the user by the "xrandr" command line
utility. Copy it into the xrandr_display struct for each display.
On VOCTRL_GET_DISPLAY_NAMES, send a copy of the names
of the displays spanned by the mpv window on.
2014-11-07 01:14:03 -08:00
wm4 c920a3920e ipc: make sure --input-file=/dev/stdin always works
It's not necessarily available on Unix systems other than Linux (sigh).
2014-11-07 09:50:29 +01:00
wm4 97b4b4c8e0 vo_wayland: drop redundant "const" 2014-11-07 09:28:58 +01:00
wm4 68ad0fce1f vo_vaapi: fix broken error checks 2014-11-07 09:28:47 +01:00
wm4 a54b99d1e5 ao_oss: wait for events with poll()
The intention is to avoid using the timeout-based fallback.

There's some minor hope that this will help with OpenBSD (see #1239),
although it probably won't.

Some chance that this will cause trouble with obscure OSS
implementations or emulations.
2014-11-06 01:17:36 +01:00
wm4 3d2e278029 audio/out/push: when using audio wait fallback, recheck condition
If calling ao->driver->wait() fails, we need to fallback to timeout-
based waiting. But it could be that at this point, the mutex was already
released (and then re-acquired). So we need to recheck the condition in
order to avoid missed wakeups.

This probably wasn't an actually occurring problem, but still could
cause a small race-condition window if the dynamic fallback is actually
used.
2014-11-06 01:15:44 +01:00
wm4 e36f4b6bc1 sub: load .mks files as external subtitles 2014-11-06 00:18:58 +01:00
wm4 b77ac78fed demux_mkv: fix indentation
Meh.
2014-11-05 23:17:55 +01:00
wm4 24e52f6643 demux_mkv: for subtitle preroll, consider all clusters
This considered only index entries that were for the same track ID as
the track used for seeking. This doesn't make much sense for preroll;
it'll just possibly skip clusters, and select an earlier cluster.

One possible negative side-effect is that the preroll might be too tight
now, and miss subtitle packets more often.
2014-11-05 21:54:28 +01:00
wm4 6ab364df4b demux_mkv: apply subtitle preroll only if needed, based on cue index
The demuxer has a hack to seek to the cluster before the target cluster
in order to "catch" subtitle lines that start before the seek target,
but overlap with the video after the seek target.

Avoid this hack if the cue index indicates that there are no overlapping
subtitle packets that can be caught by seeking to the previous cluster.
2014-11-05 21:52:20 +01:00
wm4 805e952d82 demux_mkv: read CueRelativePosition/CueDuration elements
Nothing is done with them yet. This is preparation for the following
commit.

CueRelativePosition isn't even saved anywhere, because I don't intend to
use it. (Too messy for no gain.)
2014-11-05 21:52:07 +01:00
wm4 8f992515cd demux_mkv: index all packets
Instead of indexing only 1 packet per cluster (which is enough for
working seeking), add every packet to the index.

Since on seek, we go through every single index entry, this probably
makes seeking slower. On the other hand, this code is used for files
without index only (e.g. incomplete files), so it probably doesn't
matter much.

Preparation for the following commits.
2014-11-05 21:51:43 +01:00
wm4 ea613c2592 command: use playback time as reference for sub_seek
update_subtitle() already uees playback_pts to make subtitles work
better in no-audio mode. Using get_current_time() usually gets
playback_pts, but also has the advantage that it will use the seek
target time during seeks. This will result in multiple sub_seek commands
doing the right thing (at least as long as they're far enough apart so
that seeking is actually initiated when the second command is run).
2014-11-05 18:47:12 +01:00
wm4 a821e72b81 demux: report 0s readahead time as fallback in some situations
If no packets are queued, the readahead time is obviously 0.

If the end time is smaller than the start time, the problem is probably
that audio and video start at slightly different times - report 0 in
this case too.

Do this because seeing "???" as readahead time is a bit annoying.
2014-11-05 03:03:27 +01:00
wm4 a7686e86ff video: remove swapped-endian image format aliases
Like the previous commit, this removes names only, not actual support
for these formats.
2014-11-05 01:52:20 +01:00
wm4 fce77c05f5 vo_wayland: don't use endian-specific defines
Instead, use the native-endian alias, and switch the wayland format
depending on the target platform's endian.

This drops support for swapped-endian formats, but I think that is ok.
Not only are the affected formats rather ancient and backwards, but
using swapped formats probably does not make any sense for performance
either.

Untested.
2014-11-05 01:52:20 +01:00
wm4 91471deecc video: remove aliases for some rarely referenced image formats
These formats are still supported; you just can't reference them via a
defined constants directly. They are now handled via the generic
passthrough.

(If you want to use such a format, you either have to add the entry
back, or use AV_PIX_FMT_* directly.)
2014-11-05 01:52:19 +01:00
wm4 5fc29e459f video: add image format test program 2014-11-05 01:52:19 +01:00
wm4 7333bc6536 video: passthrough unknown AVPixelFormats
This is a rather radical change: instead of maintaining a whitelist of
FFmpeg formats we support, we automatically support all formats.

In general, a format which doesn't have an explicit IMGFMT_* name will
be converted to a known format through libswscale, or will be handled
by code which can treat pixel formats in a generic way using the pixel
format description, like vo_opengl.

AV_PIX_FMT_UYYVYY411 is a special-case. It's packed YUV with chroma
subsampling by 4 in both directions. Its component order is documented
as "Cb Y0 Y1 Cr Y2 Y3", meaning there's one UV sample for 4 Y samples.
This means each pixel uses 1.5 bytes (4 pixels have 1 UV sample, so
4 bytes + 2 bytes). FFmpeg can actually handle this format with its
generic mechanism in an extremely awkward way, but it doesn't work for
us. Blacklist it, and hope no similar formats will be added in the
future.

Currently, the AV_PIX_FMT_*s allowed are limited to a numeric value of
500. More is not allowed, and there are some fixed size arrays that need
to contain any possible format (look for IMGFMT_END dependencies).

We could have this simpler by replacing IMGFMT_* with AV_PIX_FMT_*
through the whole codebase. But for now, this is better, because we
can compensate for formats missing in Libav or older FFmpeg versions,
like AV_PIX_FMT_RGB0 and others.
2014-11-05 01:52:19 +01:00
wm4 9548f63943 video: handle endian detection in a more generic way
FFmpeg has only a AV_PIX_FMT_FLAG_BE flag, not a LE one, which causes
problems for us: we want to have the LE flag too, so code can actually
detect whether a format is non-native endian. Basically, we want to
reconstruct the LE/BE suffix all AV_PIX_FMT_*s have.

Doing this is hard due to the (messed up) way AVPixFmtDescriptor works.
The worst is AV_PIX_FMT_RGB444: this group of formats describe an
endian-independent access (since no component actually spans 2 bytes,
you only need byte accesses with a fixed offset), so we have to go
through some pain.
2014-11-05 01:41:35 +01:00
wm4 3a50bbf563 video: refuse to allocate image data for hwaccel formats
Makes no sense.
2014-11-05 01:41:35 +01:00
wm4 ffe9c03502 video: get hwaccel flag from pixdesc 2014-11-05 01:41:34 +01:00
wm4 5e9dfe932f player: fix --secondary-sid
Use the "default" selection for the ff-index, not the "no" selection.

Broken by commit f0f83ff.
Fixes #1243.
2014-11-04 18:53:36 +01:00
wm4 bebfaae666 vo_opengl: minimal EGL on X11 support
Pretty useless and only good for testing.

Does not include any form of GLES support.
2014-11-04 01:41:37 +01:00
wm4 dc1d851c92 x11: rely on the Atom cache
XInternAtom() has a 64 entry hash table to avoid network accesses. Rely
on this cache, instead of caching these manually.
2014-11-03 23:01:27 +01:00
wm4 c54f0adacd demux: unbreak build with Libav
....
2014-11-03 22:30:07 +01:00
wm4 5438a8b32e demux: don't account known range for streams that are EOF
This influences the demuxer readahead display. If a stream has reached
EOF, we want to ignore it for the purpose of this calculation.

Note that if a stream contains no packets, it still should cause the
value 0s to be displayed (unless it's EOF), because that's just the
actual situation.
2014-11-03 21:59:20 +01:00
wm4 7c2c1dbe80 demux: fix PTS comparison
This was relying on the fact that timestamps will always be numerically
larger than MP_NOPTS_VALUE, but the trick didn't actually work for
MP_PTS_MIN. Be a bit more sincere, and don't rely on this anymore. This
fixes the comparison, and avoids the readahead amount displaying as
"???" in some situations (since one of the values was NOPTS).
2014-11-03 21:54:49 +01:00
wm4 71d5dd0916 demux: don't consider stream EOF an underrun
In this case, we didn't find any new packets for this stream, even
though we've read ahead as much as possible. (If reading ahead in this
case, the "Too many packets in the demuxer packet queues" error is
normally printed.)

If we do consider this an underrun, handle_pause_on_low_cache() will
pause and show the "buffering" state, which is not useful.

Could also happen on very bad interleaving.
2014-11-03 21:22:12 +01:00
wm4 458a766dc9 demux_mkv: remove minor code duplication 2014-11-03 20:25:21 +01:00
wm4 4e87ac8231 demux_mkv: implement audio skipping/trimming
This mechanism was introduced for Opus, and allows correct skipping of
"preroll" data, as well as discarding trailing audio if the file's
length isn't a multiple of the audio frame size.

Not sure how to handle seeking. I don't understand the purpose of the
SeekPreRoll element.

This was tested with correctness_trimming_nobeeps.opus, remuxed to mka
with mkvmerge v7.2.0. It seems to be correct, although the reported file
duration is incorrect (maybe a mkvmerge issue).
2014-11-03 20:20:28 +01:00
wm4 93e1db0bff ad_lavc: allow skip samples amount to be larger than 1 packet
Apparently we actually need this. At least the following commit would
break without this.
2014-11-03 19:56:38 +01:00
wm4 416c86f3cb command: add window-minimized property (X11 only)
More or less requested by #1237.

Should be simple to extend this to other backends.
2014-11-02 20:55:07 +01:00
wm4 4e2574f025 command: make window-scale property observable
Add a generic mechanism to the VO to relay "extra" events from VO to
player. Use it to notify the core of window resizes, which in turn will
be used to mark all affected properties ("window-scale" in this case) as
changed.

(I refrained from hacking this as internal command into input_ctx, or to
poll the state change, etc. - but in the end, maybe it would be best to
actually pass the client API context directly to the places where events
can happen.)
2014-11-02 20:53:56 +01:00
wm4 61b06f3756 client API: nothing uses the result parameter of mpv_command_node()
Add a comment about this to avoid confusing users of this function. The
parameter is essentially unused, but exists so that we don't need to
add extra APIs if the need for it arises.
2014-11-02 17:46:53 +01:00
wm4 3a95a0887c command: expose mpv version as property
A client API user has no other way to know the version.
2014-11-02 17:44:24 +01:00
wm4 12212a1685 common: fix version variable declarations
This was stupid.
2014-11-02 17:38:07 +01:00
wm4 975e98b3fe player: print anamorphic size only if video is anamorphic
Has been annoying me since forever.
2014-11-02 17:34:02 +01:00
wm4 969757baa0 player: always use demux_chapter
Instead of defining a separate data structure in the core.

For some odd reason, demux_chapter exported the chapter time in
nano-seconds. Change that to the usual timestamps (rename the field
to make any code relying on this to fail compilation), and also remove
the unused chapter end time.
2014-11-02 17:29:41 +01:00
wm4 1cebd16350 player: add --chapters-file option
Note that you can't pass .cue or .edl files to it, at least not yet.

Requested in context of allowing to specify custom chapters. For that
to work well, we probably need to add some sort of chapter metadata
pseudo-demuxer.
2014-11-02 17:23:04 +01:00
wm4 95a5624946 manpage: update --playlist comments
Using the --playlist option is no longer recommended.

A while ago, mpv rewrote all playlist parsers and added some minimal
security mechanisms (like not allowing local file access or unsafe
protocols in remote playlists). Further, mpv can load playlists by
passing them as normal file arguments, without the option.

Now, --playlist is needed only in these situations:
1) loading plaintext files
2) disabling additional security mechanisms
   (e.g. using a remote playlist to play local files)
2014-11-02 16:05:58 +01:00
wm4 0c3df23335 osd: properly wakeup when the OSD function disappears
Fixes #1236.
2014-11-01 17:32:34 +01:00
Stefano Pigozzi 98b1f861cb cocoa: fix fullscreen delay when paused
NSDisableScreenUpdates came to hunt me in the end and when mpv was paused, it
did wait for a frame that never came (because of interaction with the live
resizing code)!
2014-11-01 17:29:10 +01:00
Stefano Pigozzi fccd08f43b build: remove bundle support from waf
Use TOOLS/osxbundle.py instead. It's just better and less hacky.
2014-11-01 17:29:10 +01:00
wm4 dbc41ea3bb ipc: make it possible to receive log messages
The receiving part was implemented, but since no messages are enabled
by default, it couldn't be used.
2014-11-01 15:45:41 +01:00
wm4 de59b87609 ipc: add a command to retrieve API version 2014-11-01 15:45:41 +01:00
wm4 a1e7daf942 ipc: verify resume/suspend commands
Calling mpv_resume() too often is considered an API usage violation,
and will trigger an internal assertion somewhere.
2014-11-01 15:45:40 +01:00
wm4 d915ef7f0f manpage: ipc: fix command name for observe_property 2014-11-01 15:45:40 +01:00
Stefano Pigozzi fba8fedf66 build: remove bundle support from waf
Use TOOLS/osxbundle.py instead. It's just better and less hacky.
2014-11-01 11:00:03 +01:00
wm4 dab6cbca16 player: update meaning of drop_frame_cnt
Rename the variable, update comments, and update the documentation of
the property which returns its value.
2014-11-01 01:07:21 +01:00
wm4 0e97808fc5 player: show AV-desync message in all framedrop modes
This was shown only if decoder-framedropping was enabled, and only if at
least 50 frames were dropped by it. Since drop_frame_cnt used to mean
"number of late frames", this code made sense, but this is not the case
anymore: drop_frame_cnt can be even 0, all while video gets hopelessly
behind audio.

One problem with this is that short desync spikes (which usually can
probably dealt with) will also cause this message to be shown. If it
gets triggered too often, the code will need to be adjusted.
2014-11-01 01:06:22 +01:00
wm4 b66669ef2c build: fix 'ar' invocation when cross-compiling
This shouldn't use the host's 'ar' when building static libs. It only
worked until now because Linux 'ar' is usually built with PE support.

Couldn't confirm whether it works, because this dumb crap is just
broken when cross-compiling to mingw.
2014-11-01 00:28:19 +01:00
wm4 650b57cd6e cache: don't relay STREAM_CTRL_AVSEEK if it's unsupported
Thanks to STREAM_CTRL_HAS_AVSEEK, we actually know whether CTRL_AVSEEK
is implemented at all, and we can avoid a blocking wait on the cache if
demux_lavf sends CTRL_AVSEEK even if it won't wait. I'm hoping this
can't currently happen, but why hope if we can explicitly prevent it.
It'll make us more robust against future changes in libavformat.
2014-11-01 00:05:24 +01:00
wm4 3f3a6b13bd sub: remove osd_get_sub()
Trades one strange thing against another, but seems slightly less
strange.
2014-11-01 00:02:01 +01:00
wm4 75afef6463 command: don't require whitespace before ';' or '#'
This change is probably too simplistic, but most things appear to work,
so I don't care about that now.

Fixes #1232.
2014-10-31 23:56:17 +01:00
wm4 13d408fe8d sub: be more flexible about changes to how subtitles are rendered
For example, if --force-window is used, and video is switched off during
playback, then you need to redecide the rendering method to get subs
displayed correctly.

Do this by moving the state setup code into a function, and call it on
every frame.
2014-10-31 23:43:22 +01:00
wm4 0afc99b33f osdep: potentially fix compilation on OpenBSD
The <pthread_np.h> header expects that <pthread.h> was already included.
We were including <pthread.h> only later via our threads.h.
2014-10-31 19:44:42 +01:00
wm4 8607b0c44b ao_alsa: don't make snd_pcm_hw_params_set_buffer_time_near() error fatal
Apparently this can "sometimes" return an error. In my opinion, this
should never return an error: neither the semantics of the function,
nor the ALSA documentation or ALSA sample code seem to indicate that
a failure is to be expected. I'm not perfectly sure about this though
(I blame ALSA being a weird, big, underdocumented API).

Since it causes problems for some users, and since there is really no
reason why we should abort on such an error, turn it into a warning.

Fixes #1231.
2014-10-31 01:09:53 +01:00
wm4 b17585e636 player: change framedrop display in the status line
Hopefully less confusing, and hopefully doesn't exceed the terminal
width in any situation.
2014-10-31 01:01:58 +01:00
wm4 6ddd2b8e03 player: improve exit message in some scenarios
If you played e.g. an audio-only file and something bad happened that
interrupted playback, the exit message could say "No files played".
This was awkward, so show a different message in this case.

Also overhaul how the exit status is reported in order to make this
easier. This includes things such as not reporting a playback error
when loading playlists (playlists contain no video or audio, which
was considered an error).

Not sure if I'm happy with this, but for now it seems like a slight
improvement.
2014-10-31 00:51:52 +01:00
wm4 733936f376 options: accept --audio-channels=auto
This sounds much more intuitive, while "empty" was a bit of a WTF.
2014-10-30 22:58:17 +01:00
wm4 6c469dc9d9 demux_lavf, stream_lavf: drop local buffers on time-seeks
There was chance that some data was left in various local buffers after
time-seeks. Probably doesn't actually matter.
2014-10-30 22:50:44 +01:00
wm4 a77a171b7f demux_lavf: mark as seekable if protocol supports seeking by time
Basically, this will mark the demuxer as seekable with rtmp* and mmsh
protocols. These protocols have network-level time seeking, and whether
you can seek on the byte level does not matter.

Until now, seeking was typically only enabled because of the cache, and
a (nonsensical) warning was shown accordingly.

It still could happen that the server doesn't actually support thse
requests (or simply rejects them), so this is somewhat imperfect.
2014-10-30 22:46:36 +01:00
wm4 56b852710a demux_playlist: redirect ASF streaming to mmsh://
I'm not sure if this could be done in libavformat instead. Probably not,
because libavformat doesn't seem to have any mechanism for trying one
protocol and reverting (or redirecting) to another one if needed.

This commit is sort of a hack too, because it redirects the URL by
pretending the http:// link is  a playlist containing the mmsh:// link.

The list of mime types is borrowed from MPlayer (which has completely
different code to handle this).
2014-10-30 22:25:08 +01:00
wm4 8c3baffadb client API: qthelper: add set_option_variant() 2014-10-30 11:29:45 +01:00
wm4 aa6b7fa07b vo_opengl: draw OSD twice in 3D mode case
Apparently this is needed for correct 3D mode subtitles. In general,
it seems you need to duplicate the whole "GUI", so it's done for all
OSD elements.

This doesn't handle the "duplication" of the mouse pointer. Instead,
the mouse can be used for the top/left field only. Also, it's possible
that we should "compress" the OSD in the direction it's duplicated, but
I don't know about that.

Fixes #1124, at least partially.
2014-10-29 23:14:46 +01:00
wm4 fb4d26e769 input: cascade-load input.conf
If there are several input.confs in the set of valid config paths, load
them all.
2014-10-29 22:54:03 +01:00
wm4 06bb1e0fc4 demux: fix demux_seek signature
Probably doesn't matter much.
2014-10-29 22:47:25 +01:00
wm4 71e73b6c8e demux: move some seek flag sanitation to generic code
No reason why only demux_mkv.c should do this.
2014-10-29 22:45:21 +01:00
wm4 a1083fb461 demux_mkv: implement percentage seeking with no index
It was implemented only for the case the index exists (pretty useless).
2014-10-29 22:34:40 +01:00
wm4 f2f9d23e79 demux_mkv: export packet file position
This gives us approximate fallback playback percentage position if the
duration is unknown.
2014-10-29 22:08:50 +01:00
wm4 2bb02879aa player: don't display zero duration for files with unknown duration
On OSD/terminal, just don't display the duration if unavailable.

Make the "length" property unavailable if duration is unavailable.
2014-10-29 21:54:59 +01:00
wm4 2c320fb609 player: add an option to abort playback on partial init failures
This is probably what libmpv users want; and it also improves error
reporting (or we'd have to add a way to communicate such mid-playback
failures as events).
2014-10-28 20:30:12 +01:00
wm4 0c71ae0528 player: handle DVB demuxer reloading correctly
This was probably done incorrectly in cases when the currently selected
channel had no data. I'm not sure if this codepath is functional at all,
though. Maybe not.

Untested due to lack of DVB hardware.
2014-10-28 20:30:12 +01:00
wm4 65db3291b3 client API: better error reporting
Give somewhat more information on playback failure.
2014-10-28 20:30:12 +01:00
wm4 3cde02fe22 client API: add an enum for mpv_event_end_file.reason
Using magic integer values was an attempt to keep the API less verbose.
But it was probably not a good idea.

Reason 1 (restart) is not made explicit, because it is not used anymore
starting with the previous commit. For ABI compatibility, the value is
left as a hole in the enum.
2014-10-28 20:30:12 +01:00
wm4 77b06fa017 player: handle edition reloading slightly differently
Use the codepath that is normally used for DVD/BD title switching and
DVB channel switching. Removes some extra artifacts from the client API:
now MPV_EVENT_END_FILE will never be called on reloads (and neither is
MPV_EVENT_START_FILE).
2014-10-28 20:30:12 +01:00
wm4 0da9ee79e7 demux: seek to position 0 when loading, instead of restoring it
This was originally done for DVD/BD/DVB, where the start position could
be something different from 0, and seeking back to 0 would mess it up
completely.

Since we're not quite sure that these streams are unseekable, we can
simplify this somewhat, and also make sure we also start at 0 for normal
files. Helps a little bit with the following edition reloading commit.
2014-10-28 20:30:11 +01:00
wm4 98356b81b4 client API: clarify statement about thread-safety
The only reason for mpv_wait_event() not being thread-safe is that it
returns a pointer to a mpv_event struct member in the mpv_handle
context, which in turn is done for ABI-safety (user doesn't allocate or
manage the struct), and to avoid the need additional memory management.

Some users were interpreting this incorrectly.
2014-10-28 20:30:11 +01:00
Stefano Pigozzi 0c0ff638a3 coreaudio: only list output devices 2014-10-28 14:11:50 +01:00
wm4 0f70d0e927 manpage: clarify loadfile append-play mode
Documents the behavior introduced with the previous commit.
2014-10-28 10:18:46 +01:00
Alessandro Ghedini 650e889752 command: play the correct entry with loadfile ... append-play
The playlist may be non-empty even if the player is idle. Instead of playing the
first entry, play the entry that was just added.
2014-10-27 21:50:43 +01:00
wm4 963edf5765 player: don't spam video-reconfig event
Without --force-window, this is called on every iteration or so, and
calling uninit_video_out() sends the video-reconfig event. Avoid sending
redundant events.

Fixes #1225 (using an alternative patch).
2014-10-27 21:05:21 +01:00
Stefano Pigozzi 1d7ae5829e cocoa: fix small leak 2014-10-27 19:18:29 +01:00
Stefano Pigozzi 55396ee554 libmpv: cocoa: fix view leak on uninit
The code was lacking a -removeFromSuperview call which resulted in a leak on
our part if the parent view in the client was not released.
2014-10-27 19:14:55 +01:00
Stefano Pigozzi 58effd3fec libmpv: cocoa: add basic menu 2014-10-27 19:14:55 +01:00
Alessandro Ghedini c18cf4394d command: try 'icy-title' metadata for media-title as well 2014-10-27 16:21:50 +01:00
wm4 fcc360ccad x11: fix display FPS detection for interlaced modes
In interlaced modes, we output fields, not complete frames, so the
framerate doubles.

The method to calculate this was borrowed from xrandr code.

Hopefully fixes #1224.
2014-10-27 16:17:55 +01:00
James Ross-Gowan a95ce07273 dxva2: use gpu_memcpy with unmatched strides
Like memcpy_pic, this checks if the strides match first.
2014-10-27 12:37:25 +01:00
wm4 dced2aa81b command: add audio-device property
Meant for changing the --audio-device at runtime.
2014-10-27 12:18:25 +01:00
wm4 d5b081152a audio: add command/function to reload audio output
Anticipated use: simple solution for dealing with audio APIs which
request configuration changes via events.
2014-10-27 11:52:42 +01:00
James Ross-Gowan ac35e3b308 dxva2: fix copying surfaces with different stride 2014-10-27 10:56:00 +01:00
wm4 f22acd94af dxva2: fix crash on initialization failure
If dxva2_init() fails, dxva2_uninit() will be called twice.
2014-10-26 15:42:47 +01:00
wm4 078f5f300d TOOLS/lua/autoload: fix operation outside of working dir
Fixes #1222. (This commit is based on a patch posted there.)
2014-10-26 14:34:46 +01:00
wm4 dd91c09a71 TOOLS/lua/autoload: don't shadow local variable
"dir" is already used somewhere above. This was ok, but not nice.
2014-10-26 14:34:37 +01:00
Alessandro Ghedini 3a7ecf65e2 manpage: options: various fixes 2014-10-26 14:13:55 +01:00
James Ross-Gowan 0166f2c7a0 dxva2: gpu_memcpy: fix build for GCC 4.8.3 2014-10-26 13:56:41 +01:00
wm4 3b34f0078d vo_direct3d: support nv12/nv21 directly 2014-10-26 02:36:15 +02:00
wm4 bb80204de2 video: clarify what IMFMT_DXVA2 is 2014-10-26 02:35:38 +02:00
James Ross-Gowan 52b52800ce dxva2: use optimized memcpy
At least on my machine, reading back the frame with system memcpy is
slower than just using software rendering. Use the optimized gpu_memcpy
from LAV to speed things up.
2014-10-26 02:34:15 +02:00
wm4 f2d51171f7 lua: subprocess: fix dumb 2014-10-26 01:52:31 +02:00
wm4 d0643fa02d lua: subprocess: tunnel stderr through mp_log
Pretty much a fringe-feature, but also it's awkward if something appears
on the terminal with no indication for the source.

This is made quite awkward by the fact that stderr and stdout could be
closed at different times, and that poll() doesn't accept "holes" in its
FD list. Invalid (.e.g negative) FDs just make it return immediately, as
required by the standard. So sparse_poll() takes care of the messy
details.
2014-10-26 01:40:36 +02:00
wm4 6f88bc7761 osdep: add helper for creating a sane pipe()
Or in other words, a pipe that has the CLOEXEC flag set. Needed since
Linux' pipe2() is not in POSIX yet.
2014-10-26 01:40:36 +02:00
wm4 38546d5a99 lua: parse_json(): fix inverted condition for trail argument
It accidentally had the opposite meaning.
2014-10-26 01:40:36 +02:00
wm4 0cfada604d lua: subprocess: don't distinguish pipe errors/EOF
What was the purpose of that? Probably none.

Also simplify another thing: if we get the cancel signal through FD,
there's no reason to check it separately.
2014-10-26 01:40:36 +02:00
Stefano Pigozzi 90e3e99021 build: fix Lua detection
We need to manually define the flag since we are using a separate identifier
for each of the Lua checks. This was done before 9b45b48 by the composed check
with a define_key (see waftools/checks/generic.py).

The pkg-config check was the only one to not redefine a define key because Waf
already does that automatically when we call the generated function with the
same identifier as the generator function. Now if they are called with two
different arguments we will get two different definitions.

Fixes #1218
2014-10-25 23:05:50 +02:00
wm4 9b45b48c46 Drop libquvi support
No development activity (or even any sign of life) for almost a year.

A replacement based on youtube-dl will probably be provided before the
next mpv release. Ask on the IRC channel if you want to test.

Simplify the Lua check too: libquvi linking against a different Lua
version than mpv was a frequent issue, but with libquvi gone, no
direct dependency uses Lua, and such a clash is rather unlikely.
2014-10-25 20:18:22 +02:00
wm4 423a7de676 video: initial dxva2 support
Shamelessly stolen from ffmpeg. It probably doesn't work - you can debug
it yourself.
2014-10-25 19:25:22 +02:00
wm4 c63c0d1cb1 manpage: use the proper environment variable for CSIDL_APPDATA 2014-10-25 18:21:52 +02:00
wm4 34f2970157 tv: remove some differences between immediate/normal mode
The immediate mode (which is the default) uses a tiny ringbuffer and
doesn't grab timestamps. This leads to quite bad behavior due to the
fact that there's an additional buffer between playloop and TV code (the
demuxer thread, which doesn't exist in MPlayer).

Always grab the timestamps and use a decently-sized buffer. I still have
no clue what I'm doing, and hacked it until it appeared to work. Report
regressions if you experience any.
2014-10-25 17:57:22 +02:00
wm4 c6a1b8ebcc tv: reduce waiting loop from 10ms to 1ms
I can't believe how shitty this (MPlayer-derived) code is. Maybe it
should be fixed or be replaced with using libavdevice, but that doesn't
seem worth the effort.

Anyway, for now reduce the time it's blocking to wait for new frames
from 10ms to 1ms, because 10ms might be a bit too tight: it could
deliver the frame up to 10ms late - now it's only up to 1ms. (And yes,
it does that instead of using condition variables. It also abuses
volatile variables as atomics. It's hilarious.)
2014-10-25 17:57:22 +02:00
wm4 5b91f89852 lua: fix some more lua_tostring() mistakes
Why can't it just raise an error?
2014-10-25 17:20:25 +02:00
wm4 a10321835e build: enable cdda:// by default again
Apparently people want this. (???)

See #1214.
2014-10-25 17:20:18 +02:00
wm4 aaa29eb81e stream: fix --stream-dump dropping the file header
stream_rar.c peeks the first few bytes when trying to open, which means
that opening any stream reads at least 2KB of data (internal buffer
size) on opening. This broke --stream-dump, which saved only the data
following this initial buffer.

Hack it around by writing the current buffer to the capture file too,
and move stream_capture_write() above stream_set_capture_file() for this
purpose.

Cleaner solutions might include: handling the terrible rar thing
differently, or using the "proper" stream API for dumping. (The latter
is not done, because --stream-dump shares code with the --stream-capture
misfeature.)

Fixes #1215.
2014-10-25 17:20:18 +02:00
wm4 1e919b4c12 stream: remove duplicate message 2014-10-25 17:20:17 +02:00
wm4 2c11dd5434 tv: remove duplicated crap
The logging functions already add a prefix. Original MPlayer devs must
have liked code duplication a lot.
2014-10-25 17:20:17 +02:00
wm4 3c9f2bef92 tv: unqueue buffers correctly (maybe, maybe not)
I clue no idea what I'm doing, but at least it doesn't hang anymore when
closing a tv:// stream using a v4l2 loopback device.
2014-10-25 17:20:15 +02:00
wm4 ef252b2314 lua: lua_tostring() on an error value can return NULL
Lua is so clever it allows values that can't be converted to strings, in
which case lua_tostring() returns NULL. Trigger undefined behavior.
2014-10-24 21:57:06 +02:00
wm4 55e3dab7eb command: finish hook execution if client fails
Translation: if the (to be added) youtube-dl Lua script crashes, don't
wait forever when opening something.
2014-10-24 21:57:02 +02:00
wm4 b330f16fed input: resolve ~ and similar for --input-file
Because why not.
2014-10-24 21:28:07 +02:00
wm4 51a3f13705 TOOLS/umpv: create FIFO in user directory
Makes these security measures unnecessary.
2014-10-24 21:27:38 +02:00
Stefano Pigozzi 7822b97033 cocoa: perform VOCTRL_SET_UNFS_WINDOW_SIZE asyncronously
Apparently if resizing a NSWindow from a secondary thread Cocoa will
automatically protect itself using NSViewHierarchyLock and in our case,
cause a deadlock.

Fixes #1210
2014-10-24 20:30:53 +02:00
wm4 480f82fa96 demux: don't access stream while lock is held
Although this is fine when the stream cache is active (which caches
these and returns the result immediately), it seems cleaner not to
rely on this detail.

Remove the update_cache() call from demux_thread(), because it's sort
of in the way. I forgot why it exists, and there's probably no good
reason for it to exist anyway.
2014-10-24 16:04:56 +02:00
wm4 07cca2500e demux: cache STREAM_CTRL_GET_BASE_FILENAME
It's needed for some obscure feature in combination with .rar reading.
However, it's unconditionally used by the subtitle loader code, so take
care of not blocking the main thread unnecessarily.

(Untested.)
2014-10-24 15:40:01 +02:00
wm4 f1481df0b6 command: add vo-configured property
So a client API user can know when a window is created or destroyed.

Also might be useful for the OSC: it could disable itself if video is
disabled.

Before this commit, there were only indirect ways of detecting this.
2014-10-24 15:34:53 +02:00
wm4 96b339fc07 player: disable --force-window if VO fails
Otherwise, it'd retry creating the window all the time.
2014-10-24 15:34:39 +02:00
wm4 f4ad398b28 video: send MPV_EVENT_VIDEO_RECONFIG on uninit
This event basically means "something about video changed", and uninit
is certainly an important change.
2014-10-24 15:34:28 +02:00
wm4 db86eaad3d player: adjust uninit order of components
Most things should be allowed to access the client API unconditionally
(for example for sending events), so move destroying the client API
down. Also, mp_uninit_ipc() should happen before the point at which all
clients are shutdown, or there will be a small time window in which new
clients can be created after destroying them all.
2014-10-24 15:34:04 +02:00
wm4 986d15ea9c command: fix debug output
It was a bit ugly/annoying.
2014-10-24 13:42:02 +02:00
ChrisK2 223d9b6bc9 osc: make text squuezing layout dependent
Wether and when the text of a button should be squeezed when it
gets too long can now be configured in the layout:

lo.button.maxchars = <number>
nil = no squeezing (default)

If the button text has more than <maxchars> characters, it will
be squeezed to the estimated width of <maxchars>.
2014-10-24 01:56:15 +02:00
ChrisK2 bff5948f00 osc: make tooltip_an default property 2014-10-24 01:16:04 +02:00
wm4 7593706af0 terminal: drop ncurses/terminfo/termcap support
It was disabled since the last release, and nobody complained loudly.

Further details see commit 4b5c3ea7.
2014-10-23 19:48:42 +02:00
wm4 a037f7b464 terminal: strictly don't read terminal input if stdout is not a terminal
Doing that doesn't make sense anyway: it's meant for interactive input,
and if the output of the player is not on the terminal, how will you
interact with it?

It was also quite in the way when trying to read verbose output with
e.g. less while the player was running, because the player would grab
half of all input meant for less (simply because stdin is still
connected to the terminal).

Remove the now redundant special-casing of pipe input.
2014-10-23 19:27:49 +02:00
wm4 c9234d769d player: fix exiting if both audio and video fail initializing
The player was supposed to exit playback if both video and audio failed
to initialize (or if one of the streams was not selected when the other
stream failed). This didn't work; for one this check was missing from
one of the failure paths. And more importantly, both checked the
current_track array incorrectly.

Fix these issues, and move the failure handling code into a common
function.

CC: @mpv-player/stable
2014-10-23 18:31:43 +02:00
wm4 809fbc6fc1 ao_alsa: move parameter append code to a function
Why not. (I thought I needed this, but my other experiments failed. So
this is merely a minor cleanup.)
2014-10-23 18:06:17 +02:00
wm4 626dcf1772 lua: fix non-sense
Let's actually test our code next time.
2014-10-23 15:13:05 +02:00
wm4 7cf18a8db9 client API: print properties set with -v
Useful for debugging. Considered doing this in command.c, but it's
easier here.
2014-10-23 15:13:05 +02:00
wm4 4590ac2082 m_option: format mpv_node as json
Useful for debugging and informational purposes. Not sure if it's sane
in any form.
2014-10-23 15:13:05 +02:00
wm4 dd77f0d37e command: print executed commands with -v 2014-10-23 15:13:05 +02:00
Martin Herkt 6f958be325 osd: slightly change default style
Wider vertical margins, slightly thicker border and larger font
size should be an improvement.
2014-10-23 14:33:11 +02:00
wm4 7e27663b7b command: add a "cached" mode to sub_add
This avoids reloading a subtitle if it was already added. In all cases,
the subtitle is selected.
2014-10-23 13:13:23 +02:00
Martin Herkt 5a3c6563e4 osc.lua: add “bottombar” and “topbar” layouts 2014-10-23 13:02:32 +02:00
wm4 41c91d87d6 command: return error on invalid/absent IDs with ff-sid/ff-aid
Instead of just disabling the stream.

Also, check if the selected track has the right type, or we'd crash.
2014-10-23 12:03:26 +02:00
wm4 df6435be50 manpage: ipc: comment about invalid UTF-8
Some rationale for the documented/suggested behavior:

It's not really clear what to do with invalid UTF-8, since JSON simply
can't transport this information. Maybe you could transfer such strings
as byte arrays, but that would be very verbose and inconvenient, and
would pose the problem that it's hard to distinguish between strings
encoded in this way and actual arrays.

There are many other ways how this could be handled. For example, you
could replace invalid sequences with '?'. Or you could do it like
Python, and use certain reserved unicode codepoints to "tunnel" through
invalid bytes.

Which of these works really depends on the application. And since this
can be done entirely on the byte level (invalid UTF-8 sequences can
appear only in strings in our case), it's best to leave this to the
receiver.
2014-10-23 11:13:59 +02:00
wm4 34373032b5 win32: change config path priorities
Assume mpv.exe is located in $mpv_exe_dir, then config files were
preferably loaded from "$mpv_exe_dir/mpv". This was mostly traditional,
and inherited from MPlayer times.

Reverse the config path priority order, and prefer $CSIDL_APPDATA/mpv as
main config path. This also fixes behavior when writing watch_later
configs, and mpv is installed in a not-writable path.

It's possible that this will cause regressions for some users, if the
change in preference suddenly prefers stale config files (which may
happen to longer around in the appdata config dir) over the user's
proper config.

Also explicitly document the behavior.
2014-10-23 10:51:51 +02:00
Stefano Pigozzi 474461244e rename ao_coreaudio_device.c -> ao_coreaudio_exclusive.c
This is so that the source file name matches the AO name
2014-10-23 09:55:17 +02:00
Stefano Pigozzi c5366dd337 reflect recent coreaudio changes in the manual 2014-10-23 09:50:54 +02:00
Stefano Pigozzi f8d0a75b50 coreaudio: redirect IEC61937 to coreaudio_exclusive 2014-10-23 09:16:39 +02:00
wm4 32720cdc17 audio/out: add redirection-on-init mechanism
Looks like this will help us with making --audio-device and spdif work
as expected on OSX. To be used ina  following commit.
2014-10-22 17:12:08 +02:00
wm4 42158b819a audio/out: missing error check
Oops.
2014-10-22 16:57:28 +02:00
wm4 67d63bc948 audio/out: don't add special devices to --audio-device list
Since the list associated with --audio-device is supposed to enable
simple user-selection, it doesn't make much sense to include overly
special things like ao_pcm or ao_null in the list. Specifically,
ao_pcm is harmful, because it will just dump all audio to a file
named audiodump.wav in the current working directory. The user can't
choose the filename (it can be customized, but not through this
option), and the working directory might be essentially random,
especially if this is used from a GUI.

Exclude "strange" entries. We reuse the fact that there's already a
simple list ordered by auto-probe priority in order to avoid having to
add an additional flag. This is also why coreaudio_exclusive was moved
above ao_null: ao_null ends auto-probing and marks the start of
"special" outputs, which don't show up on the device, but we want
coreaudio_exclusive to be selectable (I think).
2014-10-22 16:16:35 +02:00
wm4 2a74704d76 audio/out: include coreaudio_exclusive in auto-probing
Move it above ao_null, so that it can be selected during auto-probing
(even if it's only last). I see no reason why it should not be included,
and it makes the following commit slightly more elegant. (See
explanations there.)
2014-10-22 16:15:49 +02:00
wm4 be950351d9 player: show busy symbol on OSD if seeking takes too long
Same as it's done on the terminal.
2014-10-22 16:11:44 +02:00
wm4 0e4658c99c command: make trailing sub_add actually optional
This was always intended. Also fixes subtitle-file drag & drop.
2014-10-22 07:58:38 +02:00
wm4 65ba6f9f57 lua: don't let temporary values take the place of arguments
Because Lua is so terrible, it's easy to confuse temporary values pushed
to the Lua stack with arguments if the arguments are checked after that.

Add a hack that should fix this.
2014-10-22 01:10:15 +02:00
wm4 2e81698d28 osdep: NetBSD pthread_setname_np()
From: bugmen0t on github

Fixes #1207.
2014-10-22 01:04:52 +02:00
wm4 7eb047b241 command: make reverse cycle_values match up with forward one
The behavior of reverse cycling (with the "!reverse" magic value) was a
bit weird and acted with a "delay". This was because the command set the
value the _next_ command should use. Change this and make each command
invocation select and use the next command directly. This requires an
"uninitialized" special index in the counter, but that is no problem at
all.
2014-10-21 23:55:32 +02:00
wm4 4d5903f915 command: fix video-rotate update when paused
Due to the way video-rotate currently works, the state will be
automatically updated once new video is decoded. So the filter chain
doesn't need to be reinitialized automatically, but there is a need to
trigger the video instant refresh code path instead.

Also move the support function closer to an annoying similar yet
different function. They probably can be unified next time major changes
are done to this code.
2014-10-21 23:34:56 +02:00
wm4 bd315dfaf9 lua: don't use "output" as identifier
I suspect this clashes with libcs,w hich define "stdout" as macro.
Hopefully fixes #1206.
2014-10-21 13:44:21 +02:00
wm4 bc1893e036 command: add cursor-autohide property
Allows properly changing/updating the cursor state. Useful for client
API window embedding, because the host application may not want the mpv
window to grab mouse input, and this has to manually handle the cursor.
Changing the cursor of foreign windows is usually not sane.

It might make sense to allow changing the cursor icon, but that would be
much more complicated, so I won't add it unless someone actually
requests it.
2014-10-21 13:42:15 +02:00
wm4 0fa9e2bff0 command: add playback-abort property
Now this is obscure.
2014-10-21 13:38:41 +02:00
wm4 cdbc865ad0 command: add video-rotate property 2014-10-21 13:31:30 +02:00
wm4 f8e254864c options: allow selecting track ID 0 too
Blergh. Now needed for --ff-aid and friends.
2014-10-21 13:22:38 +02:00
wm4 f0f83ff366 player: add stream selection by ffmpeg index
Apparently using the stream index is the best way to refer to the same
streams across multiple FFmpeg-using programs, even if the stream index
itself is rarely meaningful in any way.

For Matroska, there are some possible problems, depending how FFmpeg
actually adds streams. Normally they seem to match though.
2014-10-21 13:19:20 +02:00
wm4 bcc3d72995 sd_lavc: strictly letter-box PGS subtitles
Getting subtitle scaling and positioning right even if there are video
filters, which completely change the image (like cropping), doesn't seem
to have a single, correct solution. To some degree, the results are
arbitrary, so we may as well do what is most useful to the user.

In this case, if the PGS resolution aspect ratio and the video output
aspect ratio mismatch, letter-box it, instead of stretching the subs
over the video frame. (This will require additional fixes, should it
turn out that there are PGS subtitles which are stretched by design.)

Fixes #1205.
2014-10-21 11:37:32 +02:00
wm4 38420eb49e json: handle >\\"< fragments correctly
It assumed that any >\"< sequence was an escape for >"<, but that is not
the case with JSON such as >{"ducks":"\\"}<. In this case, the second
>\< is obviously not starting an escape.
2014-10-21 02:59:30 +02:00
Kevin Mitchell bbf4a8aa5d TOOLS/lua: update README.md 2014-10-21 00:55:15 +02:00
Kevin Mitchell 3617399a46 TOOLS/lua: remove tabs from some lua scripts 2014-10-21 00:55:15 +02:00
Kevin Mitchell e68cc34c99 TOOLS/lua: add autodeint.lua
This isn't quite as robust as idet.sh as the default detection
interval is only 4 seconds vs 35 for idet.sh. idet.sh can have such a
large sample time since it turns off the vo and uses --untimed, which
is currently not possible from lua.
2014-10-21 00:55:15 +02:00
Kevin Mitchell 599c510902 command: add field-dominance property 2014-10-21 00:55:15 +02:00
wm4 40d6b5ca85 lua: add convenience function for hooks
So the user doesn't have to care about the awkward low-level details.
2014-10-21 00:38:56 +02:00
wm4 131633b4e5 command: extend sub_add command 2014-10-21 00:15:04 +02:00
wm4 b79f291f4b command: remove hook cancellation mechanism
I doubt anyone will actually use this correctly. Also, there was a bug
(a typo) which prevented it from working at all.
2014-10-20 23:43:10 +02:00
wm4 a67be5dd05 command: allow sub_add at an earlier stage 2014-10-20 23:33:46 +02:00
wm4 d38e36b98f osdep: shorten thread name on glibc only
Instead of affecting every platform, do this for glibc only (where it's
known to be a problem), and only if the right error is returned.
2014-10-20 21:50:49 +02:00
Ben Boeckel c918b8a3f3 manpage: fix a typo 2014-10-20 00:23:55 +02:00
wm4 600221e723 osdep: limit thread names to 16 characters
It turns out the glibc people are very clever and return an error if the
thread name exceeds the maximum supported kernel length, instead of
truncating the name. So everyone has to hardcode the currently allowed
Linux kernel name length limit, even if it gets extended later.

Also the Lua script filenames could get too long; use the client name
instead.

Another strange thing is that on Linux, unrelated threads "inherit" the
name by the thread they were created. This leads to random thread names,
because there's not necessarily a strong relation between these threads
(e.g. script command leads to filter recreation -> the filter's threads
are tagged with the script's thread name). Unfortunate.
2014-10-20 00:17:11 +02:00
wm4 1aae992585 stream: stupid compilation workaround for win32
On win32, open() is a function-like macro. The line of code changed
with this commit accidentally expanded the macro. Prevent this macro
expansion. Not sure why that happened now. Since as far as I remember
system functions can be defined as macros, this affects in theory not
only win32.
2014-10-19 23:49:42 +02:00
wm4 9ba6641879 Set thread name for debugging
Especially with other components (libavcodec, OSX stuff), the thread
list can get quite populated. Setting the thread name helps when
debugging.

Since this is not portable, we check the OS variants in waf configure.
old-configure just gets a special-case for glibc, since doing a full
check here would probably be a waste of effort.
2014-10-19 23:48:40 +02:00
wm4 c6dca55665 manpage: ipc: mention unavailability on Windows
Windows doesn't have unix domain sockets, and can't handle sockets and
pipes in an uniform way. Only the libwaio fallback code is available,
which doesn't do JSON.
2014-10-19 22:35:45 +02:00
wm4 2f559ac70b player: shutdown all clients before actual uninit
This seems safer. It might be possible that commands sent by the clients
could recreate e.g. audio or video outputs.
2014-10-19 22:34:37 +02:00
wm4 2cd25891b6 manpage: ipc: mention the socat tool
This is not realy obvious, so I assume this is a helpful hint.

Although the usefulness of such an approach is probably influenced by
the fact that the player might send events that arrive in the short
window while the socket is connected.
2014-10-19 22:34:37 +02:00
wm4 d089772b69 ipc: skip empty and commented lines 2014-10-19 22:34:37 +02:00
wm4 cf627fd3de ipc: accept both JSON and "old" commands
Minimizes the differences between --input-file and --input-unix-socket.
2014-10-19 22:34:37 +02:00
wm4 f8f0098560 ipc: fix minor error cleanup issues
The ipc_thread can exit any time, and will free the mp_ipc_ctx when
doing this, leaving a dangling pointer. This was somewhat handled in the
original commit by setting mpctx->ipc_ctx to NULL when the thread
exited, but that was still a race condition.

Handle it by freeing most things after joining the ipc_thread. This
means some resources will not be freed until player exit, but that
should be ok (it's an exceptional error situation).

Also, actually close the pipe FDs in mp_init_ipc() on another error
path.
2014-10-19 21:04:38 +02:00
wm4 f4c589418c ipc: decouple from MPContext
Just a minor refactor to keep unneeded dependencies on the core low.
2014-10-19 20:44:29 +02:00
wm4 c854ce934e audio: quote devices in --audio-device=help
The output is a bit confusing. Quoting the device name probably helps a
little bit; also add minimal explanations to the manpage.
2014-10-19 16:36:38 +02:00
Stefano Pigozzi 7e66a35969 fix build on OS X and BSD 2014-10-19 12:55:29 +02:00
ChrisK2 78151efc7e Merge pull request #1195 from kevmitch/luafix
lua: fix lua_objlen -> lua_rawlen for lua 5.2
2014-10-19 08:10:10 +02:00
Kevin Mitchell 60ed674fce lua: fix lua_objlen -> lua_rawlen for lua 5.2 2014-10-18 22:37:46 -07:00
wm4 ff029cb4cf lua: strictly free memory on errors
Thanks to the recently introduced mp_lua_PITA(), this is "simple" now.
It fixes leaks on Lua errors. The hack to avoid stack overflows
manually isn't needed anymore, and the Lua error handler will take
care of this.
2014-10-19 05:51:37 +02:00
wm4 5548c75e55 lua: expose JSON parser
The JSON parser was introduced for the IPC protocol, but I guess it's
useful here too.

The motivation for this commit is the same as with 8e4fa5fc (again).
2014-10-19 05:51:37 +02:00
wm4 987146362e lua: add an utility function for starting processes
Because 1) Lua is terrible, and 2) popen() is terrible. Unfortunately,
since Unix is also terrible, this turned out more complicated than I
hoped. As a consequence and to avoid that this code has to be maintained
forever, add a disclaimer that any function in Lua's utils module can
disappear any time. The complexity seems a bit ridiculous, especially
for a feature so far removed from actual video playback, so if it turns
out that we don't really need this function, it will be dropped again.

The motivation for this commit is the same as with 8e4fa5fc.

Note that there is an "#ifndef __GLIBC__". The GNU people are very
special people and thought it'd be convenient to actually declare
"environ", even though the POSIX people, which are also very special
people, state that no header declares this and that the user has to
declare this manually. Since the GNU people overtook the Unix world with
their very clever "embrace, extend, extinguish" strategy, but not 100%,
and trying to build without _GNU_SOURCE is hopeless; but since there
might be Unix environments which support _GNU_SOURCE features partially,
this means that in practice "environ" will be randomly declared or not
declared by system headers. Also, gcc was written by very clever people
too, and prints a warning if an external variable is declared twice (I
didn't check, but I suppose redeclaring is legal C, and not even the gcc
people are clever enough to only warn against a definitely not legal C
construct, although sometimes they do this), ...and since we at mpv hate
compiler warnings, we seek to silence them all. Adding a configure test
just for a warning seems too radical, so we special-case this against
__GLIBC__, which is hopefully not defined on other libcs, especially not
libcs which don't implement all aspects of _GNU_SOURCE, and redefine
"environ" on systems even if the headers define it already (because they
support _GNU_SOURCE - as I mentioned before, the clever GNU people wrote
software THAT portable that other libcs just gave up and implemented
parts of _GNU_SOURCE, although probably not all), which means that
compiling mpv will print a warning about "environ" being redefined, but
at least this won't happen on my system, so all is fine. However, should
someone complain about this warning, I will force whoever complained
about this warning to read this ENTIRE commit message, and if possible,
will also force them to eat a printed-out copy of the GNU Manifesto, and
if that is not enough, maybe this person could even be forced to
convince the very clever POSIX people of not doing crap like this:
having the user to manually declare somewhat central symbols - but I
doubt it's possible, because the POSIX people are too far gone and only
care about maintaining compatibility with old versions of AIX and HP-UX.

Oh, also, this code contains some subtle and obvious issues, but writing
about this is not fun.
2014-10-19 05:51:37 +02:00
wm4 0328fa2252 command: add "estimated-vf-fps" change notifcation 2014-10-19 05:51:37 +02:00
wm4 daab65693c lua: add a helper to auto-free temporary C memory
Using the Lua API is a big PITA because it uses longjmp() error
handling. That is, a Lua API function could any time raise an error and
longjmp() to a lower part of the stack. This kind of "exception
handling" is completely foreign to C, and there are no proper ways to
clean up the "skipped" stack frames.

Other than avoiding such situations entirely, the only way to deal with
this is using Lua "userdata", which is basically a malloc'ed data block
managed by the Lua GC, and which can have a destructor function
associated (__gc metamethod).

This requires an awful lot of code (because the Lua API is just so
terrible), so I avoided this utnil now. But it looks like this will make
some of the following commits much easier, so here we go.
2014-10-19 05:51:25 +02:00
wm4 76af31b0eb win32: remove an unneeded mechanism
Instead of relying on the macro-defined lseek(), just use _lseeki64
directly, and avoid a minor mess.
2014-10-19 05:51:25 +02:00
wm4 2458f0628e win32: remove outdated comment 2014-10-19 05:51:24 +02:00
Stefano Pigozzi fa904150bf cocoa: reintroduce async resize
After removing synchronous libdispatch calls, this looks like it doesn't
deadlock anymore. I also experimented with pthread_mutex_trylock liek wm4
suggested, but it leads to some annoying black flickering. I will fallback to
that only if some new deadlocks are discovered.
2014-10-18 18:30:22 +02:00
Stefano Pigozzi 421bce0077 Revert "cocoa: perform init and uninit synchronously"
This reverts commit a0ac8b6331.
2014-10-18 14:28:47 +02:00
wm4 f5a19f6328 manpage: ipc: explain security implications
It's kind of obvious, since the protocol by design has to allow you to
read (loadfile) and write (screenshot_to) random files, but better
make it explicit so that nobody accidentally does something insecure.
2014-10-17 23:03:08 +02:00
wm4 fd7bf67019 DOCS/client_api_examples: qtexample: don't require Qt 5.x
Exclude the worthless Qt 5.0-only demo code on Qt 4.x.
2014-10-17 22:36:23 +02:00
wm4 70cc42655d ipc: fix a small memory leak 2014-10-17 22:31:14 +02:00
wm4 d15df00643 win32: clear window handle on destruction
As I understand, otherwise, the code will try to destroy the same
window again in the cleanup part of the gui_thread(), which makes no
sense and is potentially dangerous.
2014-10-17 22:22:10 +02:00
wm4 201a656350 win32: get rid of mp_stat in the normal source code
mp_stat() instead of stat() was used in the normal code (i.e. even
on Unix), because MinGW-w64 has an unbelievable macro-mess in place,
which prevents solving this elegantly.

Add some dirty workarounds to hide mp_stat() from the normal code
properly. This now requires replacing all functions that use the
struct stat type. This includes fstat, lstat, fstatat, and possibly
others. (mpv currently uses stat and fstat only.)
2014-10-17 22:15:19 +02:00
wm4 a7eb363ac1 win32: make lseek() fail on pipes
On MingGW seeking on pipes succeeds.

This fix is quite similar to Gnulib's (lib/lseek.c).
2014-10-17 21:43:18 +02:00
wm4 0abe9b0e0a old-build: adjust to latest changes 2014-10-17 21:35:28 +02:00
Alessandro Ghedini 3deb6c3d4f input: implement --input-file on unix using the IPC support 2014-10-17 20:47:43 +02:00
Alessandro Ghedini e0f0f6fe26 manpage: add JSON IPC documentation 2014-10-17 20:46:31 +02:00
Alessandro Ghedini 13039414f5 input: implement JSON-based IPC protocol 2014-10-17 20:46:31 +02:00
wm4 c01151e0bf misc: add JSON parser 2014-10-17 20:46:31 +02:00
Stefano Pigozzi eb902efb04 cocoa: allow mouse events to bubble up with no-input-cursor
Previously we didn't report events to the core, but still prevented the events
to travel on the responder chain.
2014-10-17 19:19:45 +02:00
Stefano Pigozzi 49b6fa8779 cocoa: allow to disable apple remote at compile time
Actually doesn't remove the related flags so that one can still pass the
option with the option doing nothing.
2014-10-17 19:16:58 +02:00
wm4 a0acb6eaa7 demux: print a warning if stream is not seekable 2014-10-17 18:18:20 +02:00
wm4 01e1d0948d options: don't load per-file config files by default
Generally useless feature, and might be slightly dangerous if paths
can "escape" from the profile dir. (Normally this shouldn't be
possible, though.)
2014-10-17 02:55:31 +02:00
wm4 41b2927f39 sub: adjustments to --ass-style-override option
Now requires newest libass git. Since this feature wasn't part of a
libass release yet, I'm not bothering making the mpv code compatible
with as how it was previously implemented (it will just be disabled
with any older libass).

CC: @mpv-player/stable (because mpv-build uses libass git, and this
                        breaks the feature)
2014-10-17 02:06:08 +02:00
wm4 ca038d9a22 audio: don't go to sleep after audio reinit
It possibly goes to sleep without actually starting to decode audio.
Possibly fixes a problem with --no-osc --no-video reported on IRC.

CC: @mpv-player/stable
2014-10-17 01:10:49 +02:00
wm4 0a7a70f198 input: don't add weird padding when formatting keycode
No idea what this was for. It has no purpose and looks weird.
2014-10-17 00:53:55 +02:00
wm4 b5ca94af5c terminal: recognize ^h
Fixes #1185.

CC: @mpv-player/stable
2014-10-17 00:53:47 +02:00
wm4 a121331186 stream: better error message for unmatched protocol
See #1187.
2014-10-17 00:05:02 +02:00
wm4 708ca05cc6 vo_opengl: fix wrong comments
The previous commit was actually incorrect, and the change had
absolutely no effect. The two formats are (fortunately) the same. I'm
probably too tired.
2014-10-16 23:51:36 +02:00
wm4 b52c7273f4 vo_opengl: fix theoretical format mismatch issue
This would have been wrong for hw decoders which pass us NV12 or NV21.
The format the GL shader filter chain gets is stored in p->image_desc,
while p->image_format still contains the "real" input format (which in
case of hw decoding is an opsque hw accel format). Since no hw decoder
did this, this is really just a theoretical fix and doesn't fix any
actual bugs.
2014-10-16 23:44:10 +02:00
Stefano Pigozzi a0ac8b6331 cocoa: perform init and uninit synchronously
This is slightly safer and without the resize redraw, should not cause any
deadlock.
2014-10-16 22:53:08 +02:00
wm4 63f103e05d DOCS/client_api_examples: qtexample: set a magic Qt flag
Otherwise, other magic Qt stuff can be magically broken.

(No, I don't know the real reasons for this.)
2014-10-16 21:19:30 +02:00
wm4 b836a2295c DOCS/client_api_examples: qtexample: embedding works on Cocoa 2014-10-16 21:18:01 +02:00
shdown dc5d60611e player: quote %-starting strings
Leading percent sign is a quote indicator so it needs to be quoted
itself.
2014-10-16 21:17:01 +02:00
shdown df6ded7c94 common: fix \x-style escaping
This was rejecting correct escapes and accepting incorrect ones.
2014-10-16 21:17:01 +02:00
shdown 040c5a9f68 TOOLS/vf_dlopen/ildetect.sh: remove duplicated assigment 2014-10-16 21:17:01 +02:00
shdown f7c76120c0 manpage: fix reference to a defunct option
The change was made with faad40aad9.
2014-10-16 21:17:01 +02:00
wm4 0e0dc5c5be player: fix crash on early audio uninit
Could crash when exiting playback in very early stages of
initialization.

CC: @mpv-player/stable
2014-10-16 01:03:02 +02:00
wm4 5a6a5695bb player: free subtitle renderer on exit
This was probably commented as an oversight. Since the subtitle renderer
was uninitialized on reinitialization anyway, this had no negative
consequences, except a memory on exit.
2014-10-16 01:01:27 +02:00
wm4 8e4fa5fcd1 command: add a mechanism to allow scripts to intercept file loads
A vague idea to get something similar what libquvi did.

Undocumented because it might change a lot, or even be removed. To give
an idea what it does, a Lua script could do the following:

--                      type       ID priority
mp.commandv("hook_add", "on_load", 0, 0)
mp.register_script_message("hook_run", function(param, param2)
    -- param is "0", the user-chosen ID from the hook_add command
    -- param2 is the magic value that has to be passed to finish
    -- the hook
    mp.resume_all()
    -- do something, maybe set options that are reset on end:
    mp.set_property("file-local-options/name", "value")
    -- or change the URL that's being opened:
    local url = mp.get_property("stream-open-filename")
    mp.set_property("stream-open-filename", url .. ".png")
    -- let the player (or the next script) continue
    mp.commandv("hook_ack", param2)
end)
2014-10-16 01:00:22 +02:00
wm4 bc0ed90481 command: allow setting per-file options at runtime
The intended use-case is for doing this at load time, after the load
command was issued. (See following commit.)
2014-10-15 22:39:33 +02:00
wm4 312531c08c audio/out/push: reset projected EOF time on new data
Seems like this could theoretically happen in low buffer situations, but
I haven't spotted this behavior in the wild.
2014-10-14 22:07:04 +02:00
wm4 fe5ba6e217 client API: qthelper: remove commented code
This is already taken care of by Q_DISABLE_COPY().
2014-10-14 22:05:15 +02:00
wm4 9241e1bf10 demux_lavf: set stream network options if applicable
Normally, we pass libavformat demuxers a wrapped mpv stream. But in some
cases, such as HLS and RTSP, we let libavformat open the stream itself.
In these cases, set typical network properties like useragent according
to the mpv options.

(We still don't set it for the cases where libavformat opens other
streams on its own, e.g. when opening the companion .sub file for .idx
files - not sure if we maybe should always set these options.)
2014-10-14 21:01:30 +02:00
wm4 ffd3ae1fad demux_lavf: let libavformat open HLS streams directly
Fixes opening some streams.

This means the HLS playlist will be opened twice, but that's not much of
a problem, considering it's pretty small, and HLS will make many other
http accesses anyway.
2014-10-14 20:43:27 +02:00
wm4 7c69848e3e player: fix OSD cycling
OSD cycling attempted to remove the current message by setting an empty
message with duration 0. Duration 0 tripped up a corner case causing no
OSD to be displayed (until the next message was set), so exclude this
explicitly.
2014-10-14 19:20:36 +02:00
wm4 aa14143578 stream_lavf: expose concat://
Apparently there's an use for this; see #1178.

I won't redocument obscure FFmpeg features, so add a hint to the
manpage that some protocols are documented in FFmpeg instead.
2014-10-14 18:50:18 +02:00
wm4 bf382270f2 osd: properly redraw external overlays when they are set 2014-10-14 18:33:31 +02:00
wm4 5bddff6a24 client API: allow returning float properties as integers
I'm starting to think that being type-strict with this interface
actually sucks. This commit is a step towards being less strict.
2014-10-14 15:54:03 +02:00
wm4 596231bc97 player: fix --frames
This could produce an extra frame, because reaching the maximum merely
signals the playloop to exit, without strictly enforcing the limit.

Fixes #1181.

CC: @mpv-player/stable
2014-10-14 13:29:38 +02:00
wm4 cb6be26181 DOCS/client_api_examples: qtexample: remove debugging code
Forgotten.
2014-10-14 13:20:24 +02:00
wm4 95dda1050d client API: qthelper: fix bugs
Pretty dumb oversights.
2014-10-14 13:20:05 +02:00
wm4 2ad0be8592 DOCS/client_api_examples: qtexample: stuff
Dump chapters and track list to the log for demo purposes.

Compile in debug mode.
2014-10-13 23:55:57 +02:00
wm4 1c5dbdbfc2 client API: add qthelper.hpp
This provides some helper functions and classes for C++/Qt. As the top
of qthelper.hpp says, this is built on top of the client API, and is a
mere helper provided for convenience.

Maybe this should be a separate library, but on the other hand I don't
see much of a point in that. It's also header-only, but C++ people like
such things. This makes it easier for us, because we don't need to care
about ABI compatibility.

The client API doesn't change, but bump it so that those who are using
this header can declare a proper dependency.
2014-10-13 23:54:19 +02:00
wm4 be0896c173 ta/README: fix typos 2014-10-13 18:56:42 +02:00
wm4 e9b0a61444 ao_wasapi: implement device listing 2014-10-13 18:21:45 +02:00
wm4 fb7cc7274e ao_dsound: implement device listing 2014-10-13 18:21:35 +02:00
wm4 19f543ecbb ao_portaudio: implement device listing 2014-10-13 16:43:05 +02:00
wm4 859d02b40e ao_openal: implement device listing 2014-10-13 16:42:56 +02:00
wm4 2e52cc8f2e audio/out: add "auto" pseudo-device
Also, don't set an empty string for the fallback device if an AO doesn't
list any devices.
2014-10-13 16:42:44 +02:00
wm4 057384baa6 demux_mkv: fix undefined behavior
With some files, the extradata variable can remain uninitialized, but
will be used for memory access.

CC: @mpv-player/stable (with high priority)
2014-10-13 16:42:00 +02:00
wm4 ceba1d446a vf_vapoursynth: add debug message when returning error from GetFrame
Some filters still (or will) behave badly on these errors, so explicitly
log when it happens.
2014-10-13 14:35:03 +02:00
wm4 7266ceeb8e x11: don't wait for asynchronous X resizing with window-scale
Instead of letting the window-scale property return the old value until
X11 actually executed the resize, just set the new assumed internal
window size immediately. This avoids a "lag" between setting and reading
the window-scale property, like OSD controls typically do.

Remove the additional calls from vo_x11_highlevel_resize() - they're
pointless and slightly wrong, and resize events will take care of
updating these things correctly anyway.

Fixes #1176.

("window-scale" works via VOCTRL_[S|G]ET_UNFS_WINDOW_SIZE.)
2014-10-13 09:57:31 +02:00
wm4 385e1ccbce vf_vapoursynth: don't error if invoke() doesn't return a clip
Not all functions are for creating filters. Consider for example
LoadPlugin.
2014-10-12 20:25:25 +02:00
wm4 7b0c58ab49 vf_vapoursynth: resolve paths relative to home/config
This affects the script filename passed to the filter. Resolve "~" (and
some other variants) as described in the "Paths" section of mpv.rst.
2014-10-12 20:24:20 +02:00
wm4 5a07ce758e demux: fix a comment
Don't refer to fields that were removed.
2014-10-12 20:22:47 +02:00
Stefano Pigozzi 7c07da57e3 coreaudio: use the new device selection API
The CoreAudio API is built around device IDs so we store the integer as string
and read it back.
2014-10-12 12:22:17 +02:00
wm4 240266d12c af_lavcac3enc: fix byte order
Oops.

Fixes #1172.

CC: @mpv-player/stable
2014-10-12 11:33:35 +02:00
wm4 6c34081095 DOCS/edl-mpv: minor clarification 2014-10-12 01:33:10 +02:00
wm4 9c0389e841 gl_x11: distinguish missing GLX and too old GLX versions
This probably led to confusing output.

CC: @mpv-player/stable
2014-10-12 01:33:10 +02:00
wm4 3093d93e1f vf_vapoursynth: add standalone Lua scripting 2014-10-12 01:33:10 +02:00
wm4 1b4f51ae73 vf_vapoursynth: abstract scripting backend
In theory, vsscript should be doing it, but it's not there yet, neither
did there seem to be any interest in making it flexible enough to handle
more than 1 scripting language.
2014-10-12 01:33:09 +02:00
Stefano Pigozzi c2eca2e4b7 libmpv/cocoa: allow clients to use mpv event system
This allows mpv's view to take key and send events to mpv's core.
To set key status correctly, clients must call -[NSWindow selectNextKeyView:]
during reconfig on the main thread. All is 'documented' in the cocoabasic
example.

If someone knows a better way to handle giving key to the embedded view,
let me know!
2014-10-12 00:19:44 +02:00
Stefano Pigozzi 8b6b84f36b cocoa: remove usage of Objective-C categories
Objective-C categories need special linker flags from the user when statically
linking (-ObjC LDFLAG), so make everyone's life simpler and remove them.
2014-10-12 00:19:44 +02:00
wm4 b9077214cf command: don't display non-sense if volume is unavailable
Showed "Volume: (unavailable)%". That was dumb.

The message string is now a bit convoluted; mostly because the property
expand syntax can't do "if-else", just "if".

CC: @mpv-player/stable
2014-10-11 21:35:08 +02:00
wm4 a3bf75279e command: make volume/mute unavailable if audio is not initialized
This does nothing good. This reverts a change made over a year ago - I
don't remember why this was originally done this way.

The main problem is that even if the volume option is set (something
like "--volume=75"), the volume property will always return "100" until
audio is initialized. If audio is uninitialized again, the volume
property will remain frozen at its last value.
2014-10-11 21:35:08 +02:00
Stefano Pigozzi f2ef3e664b build: remove useless function 2014-10-11 21:03:13 +02:00
Stefano Pigozzi d906d09162 build: update waf to version 1.8.1
Fixes #1164
2014-10-11 20:54:42 +02:00
wm4 227e470ee2 vf_vapoursynth: return dummy frames if frames are requested during init
An attempt at fixing #1168.

I see black frames flashing, so it's certainly not perfect.
2014-10-11 18:17:20 +02:00
wm4 46b16cf206 vf_vapoursynth: factor stuff 2014-10-11 18:16:09 +02:00
wm4 54e2ca809c vf_vapoursynth: when seeking, recreate only if it's already created 2014-10-11 18:15:38 +02:00
wm4 cea7528b39 x11: don't wait until window is destroyed
This can hang if the window was destroyed externally (or that's what I
suspect happens), and we somehow didn't receive the DestroyNotify event.
I'm not sure why we wouldn't receive this event (since it should just be
in the xlib event queue), but on the other hand there's no real need to
wait for window destruction.

This essentially reverts 97fc74e2.
2014-10-11 16:30:58 +02:00
wm4 bce2be7b3e build: install input config files into doc dir
Users using binary packages don't have obvious access to them, so this
seems like a good idea.
2014-10-11 16:16:02 +02:00
James Ross-Gowan 2782f06491 client API: check result ptr in mpv_command_node
This follows the docs, which say the result parameter is optional.
2014-10-12 00:56:41 +11:00
James Ross-Gowan e48b2bd4d1 libmpv/mpv.def: add mpv_command_node[_async] 2014-10-12 00:56:40 +11:00
Philip Sequeira 977ff1034f build: make zsh completion directory configurable
Also, use the zsh default location (rather than the Debian one).
2014-10-11 13:26:12 +02:00
wm4 ab41b8d27b vf_vapoursynth: fail gracefully if filter init requests frames
Some VS filters will requests frames from their parent filters while
they're initialized. Thy do this in a blocking manner, and
initialization will not succeed until the frame request is satisfied.
This deadlocked mpv, because we can feed frames to the filter only after
initialization is finished.

Return an error instead of deadlocking.

Note that we (probably) can handle frames being requested during init
fine, as long as the requests don't block initialization. But we can
distinguish this situation, and a simple test seems to indicate VS
usually doesn't do this.

See #1168.
2014-10-11 13:25:38 +02:00
wm4 c5c21abf78 lua: add command_native() function
This is the Lua equivalent of mpv_command_node().
2014-10-11 00:33:09 +02:00
wm4 63e2b6c4ae client API: add mpv_command_node[_async]
Allows passing native types as arguments.

Also some minor doc improvements, including giving some (natural)
improvements to mpv_free_node_contents().

Note: mpv_command_node_async() is completely untested.
2014-10-11 00:33:09 +02:00
wm4 84a126b5b5 etc/mplayer-input.conf: fix off by one error
playlist-pos is 0-based, but everyone thinks it's 1-based. Stupid crap.

(The "not the same as MPlayer" refers to a playlist manipulation command
that doesn't exist anymore in mpv.)

CC: @mpv-player/stable
2014-10-10 23:07:31 +02:00
wm4 e970113932 input: remove some unneeded code 2014-10-10 23:05:33 +02:00
wm4 d0f77b5615 input: cosmetics: move code 2014-10-10 23:01:00 +02:00
wm4 c9f45ea93e input: use mpv_node parser for char** command parsers
Minor simplification, also drops some useless stuff.
2014-10-10 22:58:28 +02:00
wm4 63903c27bd input: add a function to parse mpv_node as command
For future client API enhancements.
2014-10-10 22:37:11 +02:00
wm4 2f28e071c8 command: make audio device list available to the client API 2014-10-10 19:49:10 +02:00
wm4 04a5d25bf7 audio: don't list encoder AO with --audio-device=help 2014-10-10 19:45:25 +02:00
wm4 8417d86ce6 player: fix terminal status in idle mode
That's what this variable is for. This was missed in commit 9d5d031b.
2014-10-10 18:54:47 +02:00
wm4 3fc9f9d132 player: don't mess up cursor visibility state
Manually setting can break things forever, because it puts the VO cursor
state out of sync with the remembered state by handle_cursor_autohide().
Use the normal autohide code during idle mode too instead. (Originally
the idea was to make the cursor always visible in idle mode, but not so
important.)

Regression since e1e8b07c. Fixes #1166.

CC: @mpv-player/stable
2014-10-10 18:51:44 +02:00
wm4 f432a584b9 ao_pulse: implement AO device listing API
While conceptually this sink stuff in PulseAudio does just the right
thing, actually listing the sinks is unbelievable complicated. Not only
is the idea that listing them should happen asynchronously completely
bullshit (who the fuck runs the PulseAudio server on a separate
computer), but the way this is done is full of bullshit too. Why
separate callbacks for each device? Why this obtuse mainloop shit?
Especially the mainloop shit makes it actively worse than doing things
manually with pthread primitives, and the reason for that (different
mainloop implementations for GUIs?) is laughable too. It's like they
chose the most complicated API possible just because they attempted
to "abstract" basic mechanisms in order to handle "everything". While
I don't claim to design the best APIs, this API is fucking terrible
without any excuse. (End of rant.)
2014-10-10 18:42:43 +02:00
wm4 a25e936540 ao_pulse: move setup code to separate function
All the dumb crap in pa_init_boilerplate() is needed to talk to the
audio server at all. Might also fix some subtle bugs in the init code
(which is strange, because the original file was contributed by the
devil himself).
2014-10-10 18:42:06 +02:00
wm4 edad4fc29b audio: change internal device listing API
Now we run ao_driver->list_devs on a dummy AO instance, which will
probably confuse everyone. This is done for the sake of PulseAudio.
2014-10-10 18:27:21 +02:00
wm4 19d21103e5 player: exit if audio init fails and there's no video
Seems logical. For some reason, the player allows deselecting both audio
and video stream without quitting (a deliberate feature of which I have
no idea why it was added years ago), so this is needed.
2014-10-10 15:15:58 +02:00
wm4 299bf5c017 player: signal EOF when using --frames 2014-10-10 15:14:11 +02:00
wm4 4758866a18 player: minor simplification 2014-10-10 15:13:04 +02:00
wm4 ad541c26f7 player: don't close audio device in gapless mode
I don't see much of a reason for this extra corner case.
2014-10-10 14:49:18 +02:00
wm4 f93419f6b2 player: --save-position-on-quit should always work (2)
This reimplements the feature reverted in the previous commit in a
different way.
2014-10-10 14:44:22 +02:00
wm4 d4b2a96d90 Revert "player: --save-position-on-quit should always work"
This reverts commit 45c8b97efb.

Some else complained (github issue #1163).

The feature requested in #1148 will be implemented differently in
the following commit.
2014-10-10 14:27:45 +02:00
wm4 26bc6b4831 Add some missing "const"s
The one in msg.c was mistakenly removed with commit e99a37f6.

I didn't actually test the change in ao_sndio.c (but obviously "ap"
shouldn't be static).
2014-10-10 13:44:08 +02:00
wm4 7e4491a7a7 audio/out/push: make draining slightly more robust
Don't wait after the audio thread has pushed the remaining audio to the
AO. Avoids hard hangs if the heuristic fails completely (could still
happen if get_delay returns absurd values).

CC: @mpv-player/stable
2014-10-10 13:21:43 +02:00
wm4 bd41fc7723 audio/out/push: fix EOF heuristic
Since the internal AO driver API has no proper way to determine EOF, we
need to guess by querying get_delay. But some AOs (e.g. ao_pulse with
no-latency-hacks set) may never reach 0, maybe because they naively add
the latency to the buffer level. In this case our heuristic can break.

Fix by always using the delay to estimate the EOF time. It's not even
that important - it's mostly used to avoid blocking draining. So this
should be ok.

CC: @mpv-player/stable (maybe)
2014-10-10 13:18:53 +02:00
Stefano Pigozzi a8ec044d54 fix -Wvisibility warnings with clang
Now everything compiles with no warnings! yay!
2014-10-09 22:22:48 +02:00
Stefano Pigozzi 8a25a4af65 cocoa: post keydown and keyup events without event monitor
Our code worked under the assumption that the event monitor is always active
and we did remove the keydown and keyup overrides from our cocoa view.
2014-10-09 22:14:41 +02:00
Stefano Pigozzi e99a37f635 fix -Wduplicate-decl-specifier warnings with clang 2014-10-09 22:14:41 +02:00
Stefano Pigozzi dba2b90d9a libmpv/cocoa: don't start the event monitor
The event monitor is used to get keyboard events when there is no window, but
since it is a global monitor to the current process, we don't want it in a
library setting.
2014-10-09 22:14:41 +02:00
Stefano Pigozzi 58f62891fa cocoa: fix 'uninitalized' access
I think this doesn't make a difference, since in Objective-C nil responds as
a NullObject, but better not depend on this crappy language feature.
2014-10-09 22:14:41 +02:00
Stefano Pigozzi ca353fcf92 libmpv/cocoa: make global events work and get rid of is_cplayer
After @frau's split of macosx_events from macosx_application, `is_cplayer' is
not needed anymore. At the moment only global events such as Media Keys and
Apple Remote work, because the VO-level ones were hardcoded to be disabled.
(that will be fix in a later commit ).
2014-10-09 22:14:41 +02:00
Alessandro Ghedini d1e8bb0f9b manpage: fix --audio-pitch-correction description
Add closing ">" and specify what is the default value.
2014-10-09 22:07:41 +02:00
wm4 a13e01cc3e x11: fix inverted condition
Worryingly wrong. Fixes #1162.

Also fix another issue (window title was set anyway), which was why I
didn't notice this and testing it seemed to be fine.
2014-10-09 21:26:03 +02:00
wm4 e96d6197d7 client API: add an explanatory comment
So someone reading this at least has a chance to find out what this is
needed for.
2014-10-09 21:23:46 +02:00
wm4 f1efd83ef7 ao_alsa: implement device listing & selection
Unfortunately, ALSA is particularly bad with this, because mpv has to
add all sorts of magic crap to the device name to make things work. The
device selection overrides this, so explicitly selecting devices will
most likely break your audio. This has yet to be solved.
2014-10-09 21:22:44 +02:00
wm4 35649a990a audio: add device selection & listing with --audio-device
Not sure how good of an idea this is.

This commit doesn't add support for this to any AO yet; the AO
implementations will follow later.
2014-10-09 21:21:31 +02:00
wm4 8989019271 manpage: improve --wid description
In particular, add a basic description of how Cocoa embedding works.
2014-10-09 20:17:52 +02:00
wm4 e294656cb1 client API: rename --input-x11-keyboard to --input-vo-keyboard
Apparently we need this for Cocoa too. (The option was X11 specific in
the hope that only X11 would need this hack.)
2014-10-09 18:28:37 +02:00
wm4 fef9ea5f62 vf_lavfi: proper rounding for lavfi->mpv aspect ratio
Or so I think. Not like it matters anyway.
2014-10-09 18:18:05 +02:00
wm4 bc6b8caa6d video: try harder to decode cover art picture only once
For cover art, we pretend that the video stream is infinite, but also
stop decoding once we have an image on the VO (this seems advantageous
for the case when strange filters are inserted or the VO image gets
lost). Since a while ago, the video chain started decoding 2 images
though ("Non-monotonic video pts: 0.000000 <= 0.000000"), which is
annoying and wasteful.

Improve this by handling a certain corner case at initialization, which
will decode a second image while the first one is still stuck in the
filter chain. Also, just in case there are filters which buffer a lot,
also force EOF filtering (which means we tell the filters to flush
buffered frames).

CC: @mpv-player/stable
2014-10-09 17:57:17 +02:00
wm4 69673271e8 player: don't reset buffering pausing state on seeks
This was added with commit 3cbd79b3, but it turns out this
unintentionally enables "real" pausing when seeking while buffering. It
was done for ensuring correct state of the "cache-buffering-state"
property, but it also turns out that this was unneeded (another variable
that is reset when seeking happens to take care of this).
2014-10-09 17:57:10 +02:00
Stefano Pigozzi 69fa956f50 cocoa: allow to embed into an arbitrary NSView
Basically add if guards on all the problematic features. I'm still thinking
about a better way to handle this, but for the time being, this will do.
2014-10-08 19:38:35 +02:00
wm4 06ecf54fdf msg: fix unwanted blank lines
Was broken in a commit earlier this day.
2014-10-08 15:03:48 +02:00
wm4 0ec5d35d57 client API: introduce numeric log levels
Maybe using strings for log levels was a mistake (too broad and too
impractical), so I'm adding numeric log level at least for the receiver
side. This makes it easier to map mpv log levels to other logging
systems.

I'm still too stingy to add a function to set the log level by a numeric
value, though.

The numeric values are not directly mapped to the internal mpv values,
because then almost every file in mpv would have to include the client
API header.

Coalesce this into API version 1.6, since 1.6 was bumped just yesterday.
2014-10-08 14:17:33 +02:00
wm4 ab5d58c3d9 DOCS/client_api_examples: qtexample: add a log window
For the purpose of demonstration.

Also make the windows larger. I'm not exactly sure how Qt determines
the default window sizes, but here they are a bit tiny, so force them
larger.
2014-10-08 13:34:06 +02:00
wm4 f73778ad82 msg, client API: buffer partial lines
The API could return partial lines, meaning the message could stop
in the middle of a line, and the next message would have the rest of
it (or just the next part of it). This was a pain for the user, so do
the nasty task of buffering the lines ourselves.

Now only complete lines are sent. To make things even easier for the
API user, don't put multiple lines into a single event, but split them.

The terminal output code needed something similar (inserting a prefix
header on start of each line). To avoid code duplication, this commit
refactors the terminal output so that lines are split in a single
place.
2014-10-08 13:11:55 +02:00
wm4 2632ea3de6 msg, client API: never send the status line as log message
The status line is a bit special; for example it uses special control
codes by design and is not terminated with a newline character in order
to update it on the terminal without scrolling. It's not helpful for
client API users either, and would require special-casing them
(emulating aspects of a terminal?). Also, the status line code is
explicitly disabled on osd.c unless the --terminal option is enabled,
so there was no good way to even enable the status line for the API.

Just pretend that the status line does not exist as far as the client
API is concerned. It won't be sent as MPV_EVENT_LOG_MESSAGE.
2014-10-08 12:51:12 +02:00
wm4 046ad8c5ae msg: set an explicit overflow message
So client API users don't have to worry about this specifically.

Also document the overflow case. (Not sure if we really need to do
this; maybe it'd be better not to, since this just adds more noise
to the docs.)
2014-10-08 12:49:04 +02:00
wm4 014547bdc2 vf_lavfi: fix compilation failure
Apparently this fails to compile with clang6. Patch by someone else.

CC: @mpv-player/stable
2014-10-08 12:44:47 +02:00
wm4 8d90528826 stream: change internal instead of external pos when dropping buffers
stream provides a read buffer (so even something like stream_read_char()
is very fast). This means the stream reads ahead by a few KBs, and
implies that the internal position (s->pos, which would match e.g. the
file position in stream_file.c), and the external position
(stream_tell()) can be different. stream_tell() shows how these are
related.

When dropping buffers, which happens on byte-level discontinuities with
a bunch of streams (including DVB), we should not change the position as
seen by the demuxer. On the other hand, the internal position is not
really meaningful, since these streams aren't seekable anyway. So just
change the code such that stream_drop_buffers() doesn't change the
demuxer visible position.

I'm hoping that this will fix a few problems with DVB. (Also see
previous commit.)
2014-10-08 00:58:21 +02:00
wm4 34571b3c24 stream_dvb: use stream_drop_buffers() 2014-10-08 00:52:39 +02:00
wm4 cd367198c0 player: minor cosmetic change 2014-10-08 00:24:35 +02:00
wm4 f47269a074 x11: disable various features when embedding the window 2014-10-07 23:37:47 +02:00
wm4 ac54f10490 player: remove unnecessary code
This part is already done by open_stream_async().
2014-10-07 22:13:36 +02:00
wm4 3cbd79b35b command: add cache-buffering-state property 2014-10-07 22:13:36 +02:00
wm4 5feec17ca8 client API: improve mpv_observe_property docs
Document the "normal" behavior (if MPV_FORMAT_NONE is not used) first,
and then introduce MPV_FORMAT_NONE as exception.

The actual semantics didn't change in mpv; this is only clarification.
2014-10-07 21:22:05 +02:00
wm4 128bb68d29 client API: clarify pause/unpause events, modify core-idle property
Whether you consider the semantics weird or not depends on your use
case, but I suppose it's a bit confusing anyway. At this point, we keep
MPV_EVENT_PAUSE/UNPAUSE for compatibility only.

Make the "core-idle" property somewhat more useful in this context.
2014-10-07 21:01:19 +02:00
James Ross-Gowan 9541537e32 DOCS/client_api_examples: qtexample: set the locale
QApplication sets the locale, so change the LC_NUMERIC category back to
"C" for libmpv.

See: http://qt-project.org/doc/qt-5/qcoreapplication.html#locale-settings
2014-10-07 08:45:48 +02:00
James Ross-Gowan 476fc65b0f bstr: check strings before memcmp/strncasecmp
bstr.start can be NULL when bstr.len is 0, so don't call memcmp or
strncasecmp if that's the case. Passing NULL to string functions is
invalid C, even when the length is 0, and it causes Windows to raise an
invalid parameter error.

Should fix #1155
2014-10-07 08:45:27 +02:00
wm4 ec7bc388d1 matroska: look for all known matroska file extensions
For segment linking (this mechanism matches file extensions to avoid
opening files which are most likely not Matroska files in order to speed
up scanning).
2014-10-06 22:33:21 +02:00
wm4 a9e6ba1b9a osd: don't let slow commands cut OSD messages short
Done for screenshot commands, requested by a user.
2014-10-06 22:19:24 +02:00
wm4 45c8b97efb player: --save-position-on-quit should always work
Now any action that stops playback of a file (even playlist navigation)
will save the position. Normal EOF is of course excluded from this, as
well as commands that just reload the current file.

The option name is now slightly off, although you could argue what the
word "quit" means.

Fixes #1148 (or at least this is how I understood it).
2014-10-06 22:07:35 +02:00
wm4 332808bc0d demux_lavf: blacklist jpeg files
We handle them under demux_mf.c for stupid reasons; mostly so that
an image is shown for a second instead of just flashing it.

CC: @mpv-player/stable
2014-10-06 21:49:32 +02:00
wm4 4b2f81a36f ao_pulse: don't use pa_format_info_to_sample_spec()
This function is available starting with PulseAudio 2.0, while we only
require 1.0. This broke compilation on Ubuntu 12.04.5 LTS.

Use our own function to calculate the buffer size, which is actually
simpler and needs slightly less code.

Hopefully fixes #1154.
CC: @mpv-player/stable
2014-10-06 21:49:26 +02:00
wm4 5fb05940f1 player: open stream and demuxer asynchronously
Run opening the stream and opening the demuxer in a separate thread.
This should remove the last code paths in which the player can normally
get blocked on network.

When the stream is opened, the player will still react to input and so
on. Commands to abort opening can also be handled properly, instead of
using some of the old hacks in input.c. The only thing the user can
really do is aborting loading by navigating the playlist or quitting.
Whether playback abort works depends on the stream implementation; with
normal network, this will depend on what libavformat (via "interrupt"
callback) does.

Some pain is caused by DVD/BD/DVB. These want to reload the demuxer
sometimes. DVB wants it in order to discard old, inactive streams.
DVD/BD for the same reason, and also for reloading stream languages
and similar metadata. This means the stream and the demuxer have to
be loaded separately.

One minor detail is that we now need to copy all global options. This
wasn't really needed before, because the options were accessed on
opening only, but since opening is now on a separate thread, this
obviously becomes a necessity.
2014-10-06 21:49:26 +02:00
wm4 d26104351b m_config: add function to copy all options
Needed to copy the global option struct in the next commit.
2014-10-06 21:49:26 +02:00
Stefano Pigozzi f440c0626e cocoa: try to fix sizing bugs on retina displays
untested, no hardware.
2014-10-06 09:58:59 +02:00
Stefano Pigozzi ba994bc0dd cocoa: fix mouse autohide
broken in 547b62f
2014-10-05 23:49:09 +02:00
Stefano Pigozzi 69508dc507 cocoa: remove a debug commento
fixup previous commit
2014-10-05 23:41:39 +02:00
Stefano Pigozzi 547b62f45e cocoa: separate video view and events view 2014-10-05 23:38:39 +02:00
Stefano Pigozzi cb0f342ab2 cocoa: fix fullscreen with bundle 2014-10-05 23:38:12 +02:00
wm4 9e3e5ca598 audio/out/push: fix some AOs freezing on exit
Caused by a dumb deadlock.
2014-10-05 23:05:54 +02:00
Stefano Pigozzi ea83a2b9bc cocoa: readd some function calls 2014-10-05 22:38:26 +02:00
Stefano Pigozzi c655fdc38f cocoa: actually reset the event flags 2014-10-05 22:32:23 +02:00
Stefano Pigozzi 62bc735c1a cocoa: remove some useless flags 2014-10-05 19:31:21 +02:00
Stefano Pigozzi 2cb97454f5 cocoa: disable some features when embedding in another window
ontop, fullscreen and window title change to be precise
2014-10-05 19:16:23 +02:00
Stefano Pigozzi c6b68c28f4 cocoa: remove --fs-missioncontrol
This is the first of a series of commits that will change the Cocoa way in a
way that is easily embeddable inside parent views. To reach that point common
code must avoid referencing the parent NSWindow since that could be the host
application's window.
2014-10-05 18:07:27 +02:00
Stefano Pigozzi 7968814470 cocoa: fix some pointer casts to be 32bit safe
credits: wm4
2014-10-05 15:22:17 +02:00
Stefano Pigozzi c8ed4736ef cocoa/libmpv: allow to embed mpv GL view in another window
This is just temporary code but is a good base for future work (and baby
steps are required for these changes). The 'final destination' is embedding
the video view into any NSView but that requires some more work (the mechanism
will be the same: pass the view's pointer casted to int64_t through -wid).

For instance we will need to remove as much usage of the window instance
as possible, and use nil guards where not possible. For this reason I will
remove stuff like the mission control fullscreen feature (it's a cute feature
but annoying to support and quite limited, go make your GUIs), and a way to
lookup the current screen directly from the NSView absolute coordinates
(this is needed for ICC detection mostly, and reporting back the screen to
mpv's core).

Moreover the current view.m will need to be separated into 2 views: the actual
video view that will be embedded, and a parent view that will not be embedded
and will be responsibile for tracking events.
2014-10-05 14:28:33 +02:00
Stefano Pigozzi 3137b7ac5f examples/cocoa: never instance NSApplication with new
Cocoa expects the you instance NSApplications only through the singleton
method sharedApplication.
2014-10-05 10:06:46 +02:00
Stefano Pigozzi 11609ab389 examples/cocoa: set activation policy to mimic nib applications 2014-10-05 09:33:56 +02:00
Stefano Pigozzi 0ec14ec597 cocoa: simplify the config code and run it on the main thread
This could be dangerous because we initialize the window asynchronously and
return immediately from config, but since the OpenGL context is already
created, this seems to work correctly and doesn't cause weird deadlock cases.
2014-10-05 09:33:00 +02:00
wm4 c5ebaca31e etc: add an input config file that reverts recent key binding changes
This is for users who don't like changes. I'm hoping it will make the
process of cleaning up key bindings less bumpy.

It should be mentioned in the release notes of the next release.
2014-10-05 01:58:12 +02:00
wm4 aeefb8511c audio/out/push: make draining more robust
It was more complicated than it had to be: the audio thread already
determines whether audio has ended, so we can use that. Remove the
separate logic for draining.
2014-10-05 00:31:20 +02:00
wm4 6431e09fb3 audio/out/push: limit fallback sleep time to reasonable limits 2014-10-05 00:13:00 +02:00
wm4 0d4e245de7 ao_pulse: change suspend circumvention logic
Commit 957097 attempted to use PA_STREAM_FAIL_ON_SUSPEND to make
ao_pulse exit if the stream was started suspended.

Unfortunately, PA_STREAM_FAIL_ON_SUSPEND is active even during playback.
If you pause mpv, pulseaudio will close the actual audio device after a
while (or something like this), and unpausing won't work. Instead, it
will spam "Entity killed" error messages.

Undo this change and check for suspended audio manually during init.

CC: @mpv-player/stable
2014-10-04 23:30:07 +02:00
wm4 80e10b0058 manpage: changes: random corrections and additions 2014-10-04 22:39:08 +02:00
wm4 36ee9a5e90 manpage: changes: move internal changes section to the end 2014-10-04 22:19:07 +02:00
wm4 bd169a313c options: add --no-keepaspect-window
Seems silly, but was requested.
2014-10-04 22:17:36 +02:00
Stefano Pigozzi 1651d96583 cocoa: don't reset presentation options on uninit
This doesn't look to be needed anymore. Fullscreening with both the NSView
and the NSWindow API works correctly. I guess this was forgotten in from older
code which changed presentation options directly for going fullscreen.
2014-10-04 19:10:36 +02:00
Stefano Pigozzi e75ce6c869 cocoa: only call resize for view changing frame 2014-10-04 17:39:43 +02:00
Stefano Pigozzi 0541151b40 cocoa: remove pointless drawRect
Apparently it causes deadlocks, and at the moment it does nothing.

Fixes #778
2014-10-04 17:31:18 +02:00
Stefano Pigozzi d980c30851 cocoa: make fullscreening look like an atomic operation
At the moment when you fullscreen mpv there is a very small time interval
where the fullscreen windows is semi-transparent. Apparently whem moving the
view to another parent it's better to make Cocoa not draw anything globally.

An Apple engineer said it, so it must be correct:
http://www.cocoabuilder.com/archive/cocoa/142020-preventing-flicker-on-moving-nsview-to-different-superview.html

I know I will regret this in the future.
2014-10-04 17:31:18 +02:00
Stefano Pigozzi b915852f9f cocoa: make resizing wake the vo thread 2014-10-04 17:31:18 +02:00
Stefano Pigozzi c1d5b182b4 cocoa: remove dead code 2014-10-04 17:31:18 +02:00
Alessandro Ghedini d02275d35a vf_stereo3d: fix "auto" input format with libav 2014-10-04 16:28:30 +02:00
Alessandro Ghedini a17ecd30ca manpage: refactor MPlayer -> mpv changes section
Merge duplicate entries, organize entries in subsections, reword some entries.
2014-10-04 15:15:29 +02:00
wm4 54fd93856a x11: stupid workaround for XMonad
--x11-netwm=yes now forces NetWM fullscreen, while --x11-netwm=auto
(detect whether NetWM fullsctreen support is available) is the old
behavior and still the default.

See #888.
2014-10-04 15:03:02 +02:00
wm4 f679c5de1b ad_lavc: avoid warning messages on older FFmpeg or Libav
If the flag doesn't exist, the av_opt_set() API will print warning
messages.
2014-10-04 12:30:34 +02:00
Stefano Pigozzi d1bdf9ea11 cocoa: move to a simpler threading model
Unfortunately using dispatch_sync for synchronization turned out to be really
bad for us. It caused a wide array of race conditions, deadlocks, etc.

Moving to a very simple mutex. It's not clear to me how to do liveresizing
with this, for now it just flickers with is unacceptable (maybe I'll draw
black instead).

This should fix all the threading cocoa bugs. Reopen if it's not the case!

Fixes #751
Fixes #1129
2014-10-04 11:47:17 +02:00
Stefano Pigozzi d10b8c7e84 build: fix examples target paths
I 'broke' it in 78c362b. Sorry!
2014-10-04 11:46:51 +02:00
Stefano Pigozzi 78c362bfb8 build: allow to compile the cocoabasic.m example 2014-10-04 11:05:22 +02:00
Kevin Mitchell d4d37245a6 manpage: improve consistency with new ~/.config/mpv default
Signed-off-by: wm4 <wm4@nowhere>
2014-10-04 01:29:12 +02:00
wm4 cc9973f4e0 player: move some libass setup code to sub.c
Also recreate ASS_Library on every file played. This means we can move
the code out of main.c as well.

Recreating the ASS_Library object has no disadvantages, because it
literally stores only the message callback, the (per-file) font
attachment as byte arrays, and the set of style overrides. Hopefully
this thing can be removed from the libass API entirely at some point.

The only reason why the player core creates the ASS_Renderer, instead
of the subtitle renderer, is because we want to cache the loaded fonts
across ordered chapter transitions, so this probably still has to stay
around for now.
2014-10-03 23:10:18 +02:00
wm4 e64ce83182 player: properly wakeup when delaying OSD
Not sure in which situations this could make a difference; probably
none in practice, but it's more correct.

CC: @mpv-player/stable
2014-10-03 23:10:08 +02:00
wm4 a74a324b98 video: return responsibility of video redraw back to playloop
When the VO was moved it its own thread, responsibility for redrawing
was given to the VO thread itself. So if there was a condition that
indicated that redrawing was required, like expose events or certain
VOCTRLs, the VO thread was redrawing itself.

This worked fine, but there are some corner cases where this works
rather badly. E.g. if I fullscreen the player and hit panscan controls
with mpv's default autorepeat rate, playback stops. This happens because
the VO redraws itself after every panscan change command. Running each
(repeated) command takes so long due to redrawing and (involuntary)
waiting on vsync, that it never leaves the input processing loop while
the key is held down. I suspect that in my case, redrawing in fullscreen
mode just gets slow enough that it takes 2 vsyncs instead of 1 on
average, and the processing time gets larger than the autorepeat delay.

Fix this by taking redraw control from the VO, and instead let the
playloop issue a "real" redraw command to the VO if needed. This
basically reverts redraw handling to what it was before moving the VO to
a thread.

CC: @mpv-player/stable
2014-10-03 23:07:08 +02:00
wm4 9d5d031b6d player: remove central uninit_player() function and flags mess
Each subsystem (or similar thing) had an INITIALIZED_ flag assigned. The
main use of this was that you could pass a bitmask of these flags to
uninit_player(). Except in some situations where you wanted to
uninitialize nearly everything, this wasn't really useful. Moreover, it
was quite annoying that subsystems had most of the code in a specific
file, but the uninit code in loadfile.c (because that's where
uninit_player() was implemented).

Simplify all this. Remove the flags; e.g. instead of testing for the
INITIALIZED_AO flag, test whether mpctx->ao is set. Move uninit code
to separate functions, e.g. uninit_audio_out().
2014-10-03 23:05:09 +02:00
wm4 9570976255 ao_pulse: refuse to start suspended
Sometimes, ao_pulse starts in suspended mode, which means playback is
essentially paused in pulseaudio. This gives the impression that mpv is
hanging, since it times video against the audio playback progress, and
audio never makes progress in this state.

I'm not sure if this will help - possibly it does with mixed
pulseaudio/alsa setups. However, if the alsa setup has the pulseaudio
plugin, alsa will hang too. But there's still a chance we get less
blame for pulseaudio messes.
2014-10-03 23:04:12 +02:00
wm4 cf2add4ff9 audio: skip samples and adjust timestamps ourselves
This gets rid of this warning:

  Could not update timestamps for skipped samples.

This required an API addition to FFmpeg (otherwise it would instead
doing arithmetic on the timestamps itself), so whether it works depends
on the FFmpeg version.
2014-10-03 23:03:22 +02:00
Stephen Caraher a037313c10 man: replaced : with , in broken --lua-opts osc example
--lua-opts is a key-value list, so the option parser accepts only commas.

Signed-off-by: wm4 <wm4@nowhere>
CC: @mpv-player/stable
2014-10-03 14:24:07 +02:00
wm4 1482a6fece command: don't show message on "osd" command by default
Apparently this was not very popular.

CC: @mpv-player/stable
2014-10-03 03:43:14 +02:00
wm4 4332105352 command: allow passing memory addresses to overlay_add
For the sake of libmpv. Might make things much easier for the user,
especially on Windows. On the other hand, it's a bit sketchy that a
command exists that makes the player access arbitrary memory regions.
(But do note that input commands are not meant to be "secure" and never
were - for example, there's the "run" command, which obviously allows
running random shell commands.)
2014-10-03 01:24:48 +02:00
wm4 3e899b102e command: restructure overlay_add code
Somewhat more flexible: now there's a separate overlay struct, and you
don't need to coerce all state into struct sub_bitmap. Also, removing
the previous mapping (munmap call) is now all in one place, the
replace_overlay function.

Makes the next commit easier to implement.
2014-10-03 01:22:07 +02:00
wm4 44d5a26bd6 manpage: remove non-existing ratio-pos property
Use percent-pos instead, which is exactly the same, except with the
range 0.0-100.0.

I'm not sure how this got there; it was probably introduced and then
removed again as percent-pos got more precise.

CC: @mpv-player/stable
2014-10-02 18:37:22 +02:00
wm4 6dad7d6fe7 x11: fix --wid=0
Another fallout resulting from the changes whether or not to wait for
mapping the window. In this case, it obviously makes no sense to wait
for mapping, because the root window is always mapped. Mapping will
never happen, and it would wait forever.

Fixes #1139.
CC: @mpv-player/stable
2014-10-02 18:14:30 +02:00
wm4 7ffb621434 manpage: redocument audio delay key bindings
Fixes #1131.
CC: @mpv-player/stable
2014-10-02 03:14:54 +02:00
wm4 f62f984404 player: don't print audio/video init failure message twice
The messages "Audio: no audio" and "Video: no video" could be printed
twice each if initializing them failed. Prevent his silliness.

CC: @mpv-player/stable
2014-10-02 03:12:45 +02:00
wm4 ae2e2b9740 audio: enable pitch correction by default when playing fast
Apparently this is what users want. When playing with normal speed,
nothing is done. When playing slower than normal, resampling is used
instead, because scaletempo (which does the pitch correction) adds
too many artifacts.
2014-10-02 02:58:52 +02:00
wm4 b5942f80de audio/filter: allow removing filters by label
Although the "af" command already could do this, it seems it's better
to introduce a lower level mechanism for now. This avoids some messy
issues, since that code would recursive call reinit_audio_chain().

To be used by the next commit.
2014-10-02 02:50:12 +02:00
wm4 c3e2a1febc command: move setting playback speed to a separate function 2014-10-02 02:49:05 +02:00
wm4 7dd3822d09 audio: refactor some aspects of filter chain setup
There's no real reason why audio_init_filter() should exist. Just use
af_init or af_reinit directly. (We lose a useless message; the same
information is printed in a quite close place with more details.)

Requires less code, and the way the filter chain is marked as having
failed to initialize allows just switching off audio instead of
crashing if trying to insert a volume filter in mixer.c fails, and
recreating the old filter chain fails too.
2014-10-02 02:42:23 +02:00
wm4 2e16dfbf93 audio/filter: don't wipe full filter chain if adding a filter fails
There's no need for that, and in fact makes it more likely that it
recovers normally.
2014-10-02 01:20:01 +02:00
wm4 2064fc2990 sub: round scaled subtitles
Simple fix for issue #1137.

Since all sub-bitmaps are packed on a larger texture, there's still a
"fall off" on the border due to the linear scaling. This could be
fixed by constraining each sub-bitmap to its own texture, or by
clamping on the shader level, but I don't care for now.
2014-10-02 00:06:08 +02:00
wm4 64fb37c173 vo_vdpau: don't try to create surfaces of size 0
At least on kwin, we decide to proceed without waiting for the window
being mapped (due to the frame exts hack, see commit 8c002b79). But that
leaves us with a window size of 0x0, which causes VdpOutputSurfaceCreate
to fail. This prints some warnings, although vo_vdpau recovers later and
this has no other bad consequences.

Do the following things to deal with this:
- set the "known" window size to the suggested window size before the
  window is even created
- allow calling XGetGeometry on the window even if the window is not
  mapped yet (this should work just fine)
- make the output surface minimum size 1x1

Strictly speaking, only one of these would be required to make the
warning disappear, but they're all valid changes and increase robustness
and correctness. At no point we use a window size of 0x0 as magic value
for "unset" or unknown size, so keeping it unset has no purpose anyway.

CC: @mpv-player/stable
2014-10-01 17:29:24 +02:00
wm4 7759c182cb demux_disc: bluray: fix stream language (2)
Commit 50e131b43e happened to make it work for DVD (because the higher
bits of the ID are masked in the DVD case), but failed for Bluray. This
probably fixes it, although I don't have a sample to multiple streams to
confirm it really does it right.

CC: @mpv-player/stable
2014-09-30 23:38:01 +02:00
Kevin Mitchell 61ebe6137e man: fix to->too typo 2014-09-30 11:24:38 -07:00
wm4 4ea05577bd audio: remove --audiodrop
This would play some silence in case video was slower than audio. If
framedropping is already enabled, there's no other way to keep A/V
sync, short of changing audio playback speed (which would give worse
results). The --audiodrop option inserted silence if there was more
than 500ms desync.

This worked somewhat, but I think it was a silly idea after all. Whether
the playback experience is really bad or slightly worse doesn't really
matter. There also was a subtle bug with PTS handling, that apparently
caused A/V desync anyway at ridiculous playback speeds.

Just remove this feature; nobody is going to use it anyway.
2014-09-30 18:05:55 +02:00
James Ross-Gowan f23827d557 w32_common: quit event loop on destroy
When embedding, if the parent window is destroyed, it will cause mpv's
window to be destroyed as well. Since WM_USER wakeups are sent to the
window, destroying the window will prevent wakeups and cause uninit to
hang.

Fix this by quitting the event loop on WM_DESTROY. Events should only be
processed for the lifetime of the window, from CreateWindowEx to
WM_DESTROY. After the event loop is finished, mp_dispatch_queue_process
can handle any remaining requests.
2014-09-30 23:01:06 +10:00
wm4 c2592be4f0 vd_lavc: fix a small memory leak on init error
The private context wasn't free'd when codec init failed. Restructure
the code so that it can't happen.
2014-09-29 20:37:12 +02:00
wm4 053196de84 x11: always wait for mapped when using --wid
Might help with embedding with mozplugger. I can't confirm whether it
fixes the issue.

See #1090.
2014-09-29 18:06:45 +02:00
wm4 50e131b43e demux_disc: export BD/DVD audio language
This was "forgotten".
2014-09-29 18:06:45 +02:00
wm4 b9e4eefdb1 stream: don't drop buffers on failed seeks
Might matter when libavformat tries to do tiny seekbacks in an
unseekable stream, and the seekback buffer isn't large enough. In this
case, seeking would fail, and would drop the current buffer. The
seekback would end up dropping future data.

This change probably doesn't have any observable effects. libavformat
normally has its own stream buffer, and demux_mkv.c tries carefully
never to seek back.
2014-09-29 18:06:44 +02:00
wm4 6b9aee20bd cache_file: refuse to cache unseekable streams
This makes no sense to use with DVD/BD/DVB and some others, and these
streams happen to be unseekable.

Also, other kinds of unseekable streams (like reading from pipe) should
work, but will exhibit sketchy behavior if they need to seek. So just
disable it, and leave these problems to the memory cache (cache.c).
2014-09-29 18:06:44 +02:00
wm4 b0cb2977ed demux_lavf: bluray: don't skip stream data when flushing
This code meant to flush demuxer internal buffers by doing a byte seek
to the current position. In theory this shouldn't drop any stream data.
However, if the stream positions mismatch, then avio_seek() (called by
av_seek_frame()) stops being a no-op, and might for example read some
data to skip to the seek target. (This can happen if the distance is
less than SHORT_SEEK_THRESHOLD.)

The positions get out of sync because we drop data at one point (which
is what we _want_ to do). Strictly speaking, the AVIOContext flushing is
done incorrectly, becuase pb->pos points to the start of the buffer, not
the current position. So we have to increment pb->pos by the buffered
amount.

Since there are other weird reasons why the positions might go out of
sync (such as stream_dvd.c dropping buffers itself), and they don't
necessarily need to be in sync in the first place unless AVIOContext has
nothing buffered internally, just use the sledgehammer approach and
correct the position manually.

Also run av_seek_frame() after this. Currently, it shouldn't read
anything, but who knows how that might change with future libavformat
development.

This whole change didn't have any observable effect for me, but I'm
hoping it fixes a reported problem.
2014-09-29 18:06:44 +02:00
wm4 39451732e9 demux_disc: bluray: potentially fix some aspects of seeking
When flushing the AVIOContext, make sure it can't seek back to discarded
data. buf_ptr is just the current read position, while buf_end - buffer
is the actual buffer size. Since mpegts.c is littered with seek calls,
it might be that the ability to seek could read

Mark the stream (which the demuxer uses) as not seekable. The cache can
enable seeking again (this behavior is sometimes useful for other
things). I think this should have had no bad influence in theory, since
seeking BD/DVD first does the "real" seek, then flushes libavformat and
reads new packets.
2014-09-29 18:06:44 +02:00
Alessandro Ghedini 0fee6537bb mpv.desktop: add more ogg-related mime types
Also adds audio/ogg and video/ogg.
2014-09-29 18:06:44 +02:00
Otto Modinos cbfb6de667 lua: add mpv/lua directories to the lua path
Signed-off-by: wm4 <wm4@nowhere>
2014-09-28 20:23:38 +02:00
wm4 34fc0720f7 DOCS/client_api_examples: qtexample: remove broken resizing
The intention was to adjust the window size to video size. It never
worked well; it prevented the user to make the window smaller. For
unknown reason it stopped resizing properly as well.

This is just a cheap example, and I don't intend to fight with Qt, so
replace the "demonstration" behavior by something slightly lamer.
2014-09-28 20:18:18 +02:00
wm4 3273db1ef7 client API, X11: change default keyboard input handling again
Commit 64b7811c tried to do the "right thing" with respect to whether
keyboard input should be enabled or not. It turns out that X11 does
something stupid by design. All modern toolkits work around this native
X11 behavior, but embedding breaks these workarounds.

The only way to handle this correctly is the XEmbed protocol. It needs
to be supported by the toolkit, and probably also some mpv support. But
Qt has inconsistent support for it. In Qt 4, a X11 specific embedding
widget was needed. Qt 5.0 doesn't support it at all. Qt 5.1 apparently
supports it via QWindow, but if it really does, I couldn't get it to
work.

So add a hack instead. The new --input-x11-keyboard option controls
whether mpv should enable keyboard input on the X11 window or not. In
the command line player, it's enabled by default, but in libmpv it's
disabled.

This hack has the same problem as all previous embedding had: move the
mouse outside of the window, and you don't get keyboard input anymore.
Likewise, mpv will steal all keyboard input from the parent application
as long as the mouse is inside of the mpv window.

Also see issue #1090.
2014-09-28 20:11:00 +02:00
wm4 aeaa1767e9 Fix build with libavfilter disabled
Although I'm not sure why we even support this.
2014-09-28 19:10:50 +02:00
wm4 295b6dc169 stream_bluray: autodetect AVCHD directories
Fixes #1127.
2014-09-27 18:33:36 +02:00
wm4 cdb25d5a21 video: change automatic rotation and 3D filter insertion
We inserted these filters with fixed parameters, which was ok. But this
also didn't change image parameters for the filters down the filter
chain and the VO. For example, if rotation by 90° was requested by the
file, we would insert a filter and rotate the video, but the VO would
still receive image parameters that direct rotation by 90°.

This wasn't a problem, but it could become one.

Fix this by letting the filters automatically pick up the image params.
The image params are reset on application. (We could probably also
always try to apply and reset image params in a filter, instead of
having special "auto" parameters. This would probably work, and video.c
would insert a "rotate=0" filter. But I'm afraid this would be confusing
and the current solution is cosmetically slightly nicer.)

Unfortunately, the vf_stereo3d.c change turned out a big mess, but once
the "internal" filter is fully replaced with libavfilter, most of this
can be radically simplified.
2014-09-27 18:31:59 +02:00
wm4 0ec6df2ddf vf_lavfi: make chaining from other filters more flexible
Some filters exists only to create a specific lavfi graph. Allow these
filters to reset the graph exactly on reconfig, and allow them to modify
some image parameters too. Also make vf_lw_update_graph() behave like
vf_lw_set_graph() - they had a subtitle difference with filter==NULL.

Useful for the following commit.
2014-09-27 17:21:29 +02:00
wm4 cbf7180c90 input: copy options automatically
Originally, all options were copied to ensure that input_ctx remins
thread-safe, even if options are changed asynchronously. But this got
a bit inconsistent. Copy them automatically and reduce some weirdness.
2014-09-27 16:25:29 +02:00
wm4 b4d1494336 input: separate creation and loading of config
Until now, creating the input_ctx was delayed until the command line
and config files were parsed. Separate creation and loading so that
input_ctx is available from start.

This should make it possible to simplify some things. For example,
some complications with Cocoa were apparently only because input_ctx
was available only "later". (Although I'm not sure if this is still
relevant, or if the Cocoa code should even be organized this way.)
2014-09-27 16:01:55 +02:00
Bruno George Moraes acf6aef882 stream: change malloc+memset to calloc
Also removed some memset that were left on some calloc that was already in
the code.

Signed-off-by: wm4 <wm4@nowhere>
2014-09-27 16:01:49 +02:00
wm4 650af29471 audio/out/push: clean up properly on init error
Close the wakeup pipes, free the mutex and condition var.
2014-09-27 04:54:17 +02:00
wm4 e79de41b97 audio/out: check device buffer size for push.c only
Should fix #1125.
2014-09-27 04:52:46 +02:00
wm4 d778130dc4 audio/out: disable ao_sndio by default
Don't build it, move it down the autoprobe list even if it's enabled. It
doesn't work well enough.
2014-09-26 15:52:29 +02:00
wm4 4784ca32c9 audio/out: fail init on unknown audio buffer
A 0 audio buffer makes push.c go haywire. Shouldn't normally happen.
2014-09-26 15:50:04 +02:00
wm4 387d5f55e6 ao_sndio: print a warning when draining audio
libsndio has absolutely no mechanism to discard already written audio
(other than SIGKILLing the sound server). sio_stop() will always block
until all audio is played. This is a legitimate design bug.

In theory, we could just not stop it at all, so if the player is e.g.
paused, the remaining audio would be played. When resuming, we would
have to do something to ensure get_delay() returns the right value. But
I couldn't get it to work in all cases.
2014-09-26 15:46:39 +02:00
wm4 da1918b894 ao_sndio: update buffer status on get_delay
get_delay needs to report the current audio buffer status. It's
important for A/V sync that this information is current, but functions
which update it were called on play() or get_space() calls only.
2014-09-26 15:46:36 +02:00
wm4 3208f8c445 ao_sndio: change p->delay to samples
This was in bytes, but it's more convenient to use samples (or frames;
in any case the smallest unit of audio that includes all channels).

Remove the ao->bps line too; it will be set after init() returns.
2014-09-26 15:46:33 +02:00
wm4 12d93fdfef ao_sndio: set non-blocking flag
Otherwise the feed thread and the playloop will get randomly blocked.

This seems to fix most A/V sync issues.
2014-09-26 15:46:30 +02:00
wm4 1b1421866d ao_sndio: fix some incorrect comments
The AO API always uses sample counts.
2014-09-26 15:46:23 +02:00
wm4 17d031f88c old-configure: minor improvements
Use a trap to remove the temp dir on exit. Write config.log to old_build
instead of the top-level dir.
2014-09-26 13:53:20 +02:00
wm4 8fd954ac8e build: add -Wno-format-zero-length
This warning makes absolutely no sense. Passing an empty string to
printf-like functions is perfectly fine. In the OSD case, it just sets
an empty message, practically clearing the OSD.
2014-09-26 13:52:55 +02:00
wm4 fdf40743bc demux_mkv: don't use default_duration for parsed packets
Makes it behave slightly better for VP9. This is also the behavior
libavformat has.

Also while we're at it, don't set duration except for the first packet.
Normally we don't use the duration except for subtitles (which are never
parsed or "laced"), so this should make no observable difference.
2014-09-26 01:25:48 +02:00
wm4 d6c27855d7 stream_bluray: allow opening BDMV directories directly
Similar as the previous commits.

Most of the code is actually copied from the stream_dvdnav.c code, but
I'd rather prefer to duplicate it, than to entangle them. The latter
would probably result in terrible things in a few years.
2014-09-26 00:30:21 +02:00
wm4 c3f7773138 stream_dvdnav: allow opening DVD directories directly
Same hack as with stream_dvd.c.

VIDEO_TS.IFO files are now opened via stream_dvdnav.c. Directories
containing a VIDEO_TS.IFO or VIDEO_TS/VIDEO_TS.IFO file are also
opened with it.
2014-09-26 00:30:21 +02:00
wm4 d191de8564 stream_dvd: better .ifo probing
stream_dvd.c includes a pseudo-protocol that recognizes .IFO files, and
plays them using libdvdread. This was relatively lazy, and could perhaps
easily trigger with files that just had the .ifo extension.

Make the checks stricter, and even probe the file header. Apparently the
first bytes in an .ifo file are always "DVDVIDEO-VTS", so check for
this.

Refuse to load the main "video_ts.ifo". The plan is to use stream_dvdnav
for it.

This also removes at least 1 memory leak.
2014-09-25 23:54:18 +02:00
wm4 d8f993705c player: do not wrongly clear OSD bar stops, reindent
set_osd_bar_chapters() always cleared the OSD bar stops, even if the
current bar was not the seek bar. Obviously it should leave the state of
the bar alone in this case.

Also change the function control flow so that we can drop one
indentation level, and do the equivalent change for the other OSD bar
functions.
2014-09-25 21:32:56 +02:00
wm4 ed116e8b06 player: simplify OSD message handling code
Eliminate the remains of the OSD message stack. Another simplification
comes from the fact that we do not need to care about time going
backwards (we always use a monotonic time source, and wrapping time
values are practically impossible). What this code was pretty trivial,
and by now unnecessarily roundabout.

Merge get_osd_msg() into update_osd_msg(), and add_osd_msg() into
set_osd_msg_va().
2014-09-25 21:32:56 +02:00
wm4 07668e50de player: move code to make playloop smaller
This is basically a cosmetic change, although it weirdly also affects
the percent position in encoding mode.
2014-09-25 21:32:56 +02:00
wm4 d23ffd243f player: rate-limit OSD text update
There's no need to update OSD messages and the terminal status if nobody
is going to see it. Since the player doesn't block on video display
anymore, this update happens to often and probably burns slightly more
CPU than necessary. (OSD redrawing is handled separately, so it's just
mostly useless text processing and such.)

Change it so that it's updated only on every video frame or all 50ms
(whatever comes first).

For VO OSD, we could in theory try to lock to the OSD redraw heuristic
or the display refresh rate, but that's more complicated and doesn't
work for the terminal status.
2014-09-25 21:32:56 +02:00
wm4 9537e33057 player: fix OSD redraw heuristic with audio-only mode
When using --force-window (and no video or cover art), this heuristic
prevents any redrawing during seeking. It should be applied only if
there is any form of video.
2014-09-25 21:32:56 +02:00
wm4 5116c6c242 sub: approximate subtitle display in no-video mode
This makes subtitle display somewhat work if no video is displayed, but
a VO window exists (--force-window or cover art display).

The main problem with normal subtitle display is that it's locked to
video: it uses the video PTS as reference, and the subtitles advance
only if a new video frame is displayed. In audio-only mode on the other
hand, no video frame is ever displayed (or only 1 in the cover art
case). You would need a workaround to adjust the subtitle PTS, and you
would have to decide with what frequency to update the display. In
general, there is no "right" display FPS for subtitles. Some formats
(ASS) have animations parameterized by time, and any refresh rate could
be used.

Sidestep these problems by enabling the text OSD-based subtitle
mechanism. This is similar to --no-sub-ass, and updates and renders
subtitles with plain OSD. It has some caveats: no bitmap subs, somewhat
incorrect timing, no formatting. Timing in particular is a bit strange
and depends how often the audio output asks for new data, or other
events that happen to wakeup the playloop.
2014-09-25 21:32:56 +02:00
wm4 debbff76f9 Remove mpbswap.h
This was once central, but now it's almost unused. Only vf_divtc still
uses it for extremely weird and incomprehensible reasons. The use in
stream.c is trivial. Replace these, and remove mpbswap.h.
2014-09-25 21:32:55 +02:00
wm4 09b7956ca5 stream_cdda, demux_raw: always use s16le
stream_cdda's output format is linked to demux_raw's default audio
format, and at least we don't care enough to provide a separate
mechanism to let stream_cdda explicitly set the format, so they must
match.

Judging from the existing code, it looks like CDDA always outputs little
endian. stream_cdda.c changed this back to native endian (what demux_raw
expects). Just make them both little endian. This requires less code,
and also having a raw demuxer's behavior depend on the endianness of the
machine isn't very sane anyway.
2014-09-25 21:32:06 +02:00
ChrisK2 1c9f30cca7 osc: update cache display
now similar to what the status line displays
2014-09-25 11:57:49 +02:00
wm4 7aa933cc9e demux_mkv: get rid of MS structs
See previous commits. This finally replaces directly reading the file
data into a struct with reading them manually. In theory this is more
portable (no alignment issues and other things). For the most part,
it's nice seeing this gone.
2014-09-25 02:22:50 +02:00
wm4 9c3c199558 audio: remove WAVEFORMATEX from internal demuxer API
Same as with the previous commit. A bit more involved due to how the
code is written.
2014-09-25 01:56:51 +02:00
wm4 fd7dde404d video: remove BITMAPINFOHEADER from internal demuxer API
MPlayer traditionally did this because it made sense: the most important
formats (avi, asf/wmv) used Microsoft formats, and many important
decoders (win32 binary codecs) also did. But the world has changed, and
I've always wanted to get rid of this thing from the codebase.

demux_mkv.c internally still uses it, because, guess what, Matroska has
a VfW muxing mode, which uses these data structures natively.
2014-09-25 00:59:15 +02:00
wm4 e977624d87 audio: confine demux_mkv audio PCM hack
Let codec_tags.c do the messy mapping.

In theory we could simplify further by makign demux_mkv.c directly use
codec names instead of the MPlayer-inherited "internal FourCC" business,
but I'd rather not touch this - it would just break things.
2014-09-24 23:33:21 +02:00
wm4 9ac86d9e99 audio: decouple demux and audio decoder/filter sample formats
For a while, we used this to transfer PCM from demuxer to the filter
chain. We had a special "codec" that mapped what MPlayer used to do
(MPlayer passes the AF sample format over an extra field to ad_pcm,
which specially interprets it).

Do this by providing a mp_set_pcm_codec() function, which describes a
sample format in a generic way, and sets the appropriate demuxer header
fields so that libavcodec interprets it correctly. We use the fact that
libavcodec has separate PCM decoders for each format. These are
systematically named, so we can easily map them.

This has the advantage that we can change the audio filter chain as we
like, without losing features from the "rawaudio" demuxer. In fact, this
commit also gets rid of the audio filter chain formats completely.
Instead have an explicit list of PCM formats. (We could even just have
the user pass libavcodec PCM decoder names directly, but that would be
annoying in other ways.)
2014-09-24 22:55:50 +02:00
wm4 8a8f65d73d ao_sndio: fix U24 bit width
This was wrong since the initial commit.
2014-09-24 21:32:15 +02:00
wm4 1d45a3a163 TOOLS/umpv: drop unnecessary check
This was supposed to make sure that argv[1:] does not fail, but Python
actually allows mismatching bounds for slicing.
2014-09-24 21:29:30 +02:00
shdown 546c0f0b25 TOOLS/umpv: use python octal notation 2014-09-24 02:12:30 +02:00
shdown c6d0e41335 TOOLS/mpv_identify.sh: remove pointless escape 2014-09-24 02:08:49 +02:00
shdown 7e5f707baf TOOLS/idet.sh: add description
Just a copy of c0cd58e3f5 commit message
(with a small fix: ildetect.sh+ildetect.so, not
ildetect.sh+ildetect.sh).
2014-09-24 02:08:47 +02:00
shdown 3eae8b7170 TOOLS/idet.sh: remove unused and duplicated assignments 2014-09-24 02:08:45 +02:00
wm4 735a9c39d7 player: change --keep-open semantics
By popular request.
2014-09-24 01:56:53 +02:00
wm4 53c288d364 player: show correct playback time with --keep-open --no-video
Whatever.
2014-09-24 01:37:07 +02:00
wm4 e12fae8ef5 player: --loop-file takes precedence before --keep-open 2014-09-24 01:31:45 +02:00
wm4 7954017b56 ao_oss: improve format negotiation, and hopefully fix pass-through
Digital pass-through was probably broken. Possibly fix it (no way to
test). This also should make the logic slightly saner.

Fortunately, it's unlikely that anyone who uses OSS has a spdif setup.
2014-09-24 01:12:14 +02:00
wm4 bf927531aa ao_coreaudio: fix build failure
Commit 5b5a3d0c broke this. The really funny thing is that this code was
actually always under "#if BYTE_ORDER == BIG_ENDIAN". The breaking
commit just edited this code slightly, but it must have failed to
compile on big endian long before (since over 1 year ago, commit d3fb58).
2014-09-24 00:05:18 +02:00
wm4 429260a35c ao_oss: unbreak
Oops.
2014-09-23 23:34:30 +02:00
wm4 c2fa9f6629 ao_pulse: digital pass-through
Should be able to pass-through AC3, DTS, and others.

It seems PulseAudio wants players to fallback to PCM on certain events
signaled by the server, but we don't implement that. There's not much
documentation available anyway.
2014-09-23 23:11:55 +02:00
wm4 7230d88c7e ao_pulse: correctly wait for stream state
This works similar to condition variables; for some reason this
apparently worked fine until now, but it breaks with passthrough mode.
2014-09-23 23:11:55 +02:00
wm4 601fb2f93a ao_pulse: use pa_stream_new_extended()
Needed for compressed audio pass-through later.
2014-09-23 23:11:55 +02:00
wm4 81bf9a1963 audio: cleanup spdif format definitions
Before this commit, there was AF_FORMAT_AC3 (the original spdif format,
used for AC3 and DTS core), and AF_FORMAT_IEC61937 (used for AC3, DTS
and DTS-HD), which was handled as some sort of superset for
AF_FORMAT_AC3. There also was AF_FORMAT_MPEG2, which used
IEC61937-framing, but still was handled as something "separate".

Technically, all of them are pretty similar, but may use different
bitrates. Since digital passthrough pretends to be PCM (just with
special headers that wrap digital packets), this is easily detectable by
the higher samplerate or higher number of channels, so I don't know why
you'd need a separate "class" of sample formats (AF_FORMAT_AC3 vs.
AF_FORMAT_IEC61937) to distinguish them. Actually, this whole thing is
just a mess.

Simplify this by handling all these formats the same way.
AF_FORMAT_IS_IEC61937() now returns 1 for all spdif formats (even MP3).
All AOs just accept all spdif formats now - whether that works or not is
not really clear (seems inconsistent due to earlier attempts to make
DTS-HD work). But on the other hand, enabling spdif requires manual user
interaction, so it doesn't matter much if initialization fails in
slightly less graceful ways if it can't work at all.

At a later point, we will support passthrough with ao_pulse. It seems
the PulseAudio API wants to know the codec type (or maybe not - feeding
it DTS while telling it it's AC3 works), add separate formats for each
codecs. While this reminds of the earlier chaos, it's stricter, and most
code just uses AF_FORMAT_IS_IEC61937().

Also, modify AF_FORMAT_TYPE_MASK (renamed from AF_FORMAT_POINT_MASK) to
include special formats, so that it always describes the fundamental
sample format type. This also ensures valid AF formats are never 0 (this
was probably broken in one of the earlier commits from today).
2014-09-23 23:11:54 +02:00
wm4 308d72a02e ao_wasapi: fix fragile format-mapping code
This code tried to play with the format bits, and potentially could
create invalid formats, or reinterpret obscure formats in unexpected
ways.

Also there was an abort() call if the winapi or mpv used a format with
unexpected bit-width. This could probably easily happen; for example,
mpv supports at least one 64 bit format. And what would happen on 8 bit
formats anyway?

Untested.
2014-09-23 23:09:29 +02:00
wm4 b745c2d005 audio: drop swapped-endian audio formats
Until now, the audio chain could handle both little endian and big
endian formats. This actually doesn't make much sense, since the audio
API and the HW will most likely prefer native formats. Or at the very
least, it should be trivial for audio drivers to do the byte swapping
themselves.

From now on, the audio chain contains native-endian formats only. All
AOs and some filters are adjusted. af_convertsignendian.c is now wrongly
named, but the filter name is adjusted. In some cases, the audio
infrastructure was reused on the demuxer side, but that is relatively
easy to rectify.

This is a quite intrusive and radical change. It's possible that it will
break some things (especially if they're obscure or not Linux), so watch
out for regressions. It's probably still better to do it the bulldozer
way, since slow transition and researching foreign platforms would take
a lot of time and effort.
2014-09-23 23:09:25 +02:00
wm4 5b5a3d0c46 audio: remove swapped-endian spdif formats
IEC 61937 frames should always be little endian (little endian 16 bit
words). I don't see any apparent need why the audio chain should handle
swapped-endian formats.

It could be that some audio outputs might want them (especially on big
endian architectures). On the other hand, it's not clear how that works
on these architectures, and it's not even known whether the current code
works on big endian at all. If something should break, and it should
turn out that swapped-endian spdif is needed on any platform/AO,
swapping still could be done in-place within the affected AO, and
there's no need for the additional complexity in the rest of the player.

Note that af_lavcac3enc outputs big endian spdif frames for unknown
reasons. Normally, the resulting data is just pulled through an auto-
inserted conversion filter and turned into little endian. Maybe this was
done as a trick so that the code didn't have to byte-swap the actual
audio frame. In any case, just make it output little endian frames.

All of this is untested, because I have no receiver hardware.
2014-09-23 19:34:14 +02:00
wm4 1f4a74cbed vf_vapoursynth: make it possible to get filter output incrementally
Until now, we always required the playback core to decode a new frame to
get more output from the filter. That seems to be completely
unnecessary, because filtered results may arrive before that.

Add a filter_out callback, and restructure the code such that it can
return any filtered frames, or block if it hasn't read at least one
frame.

In the worst case, it still can happen that bursts of input requests and
output requests happen. (This commit tries to reduce burst-like
behavior, but it's not entirely possible due to the indeterministic
nature of VS threading.)

This is a similar change as with 95bb0bb6.
2014-09-23 00:35:57 +02:00
wm4 9fe076f02a player: allow passing number of loops to --loop-file
E.g. --loop-file=2 will play the file 3 times (one time normally, and 2
repeats).

Minor syntax issue: "--loop-file 5" won't work, you have to use
"--loop-file=5". This is because "--loop-file" still has to work for
compatibility, so the "old" syntax with a space between option name and
value can't work.
2014-09-22 22:56:00 +02:00
wm4 9ce4526139 audio: prefer libavcodec over libmpg123
libavcodec/libavformat now handles gapless audio better. In theory, this
could be implemented with ad_mpg123 too, but since libavformat strips
metadata from mp3 files and passes pure mp3 packets to the decoders
only, this can't work by itself. Instead, the player must pass this
metadata separately. libav* do this relatively transparently over packet
"side data" (attached to AVPacket).

It might also be possible to let libmpg123 handles all this by
implementing it as demuxer that outputs PCM, but that would have other
problems, and I think it's better to make libavformat work correctly.

libmpg123 can still be used with '--ad=mpg123:mp3'.

Also see issue #1101.
2014-09-22 22:38:06 +02:00
wm4 2cfc35892c command: no space before "%" in volume default OSD message
More consistent with other output, such as the terminal status line.

Also see issue #1103.
2014-09-22 18:07:34 +02:00
wm4 f605b03f63 video: filter new frames at a better time (2)
We generally want 2 things:
1. minimal wakeups for decoding each frame
2. minimal number of frames decoded on continuous seeking

Commit 35810cb8 changed this a bit, and fixed 1. But it broke 2., and
now it decodes 2 frames instead of 1 when you keep seeking (arrow key
held down or such). This made seeking appear slower.

Fix this by making the logic more explicit. In particular, call the
filters only if we actually try to get a new frame.

When playing with --no-audio and all other distractions disabled (like
OSC), it still wakes up 2 times per frame - but the second time is
merely because the VO didn't accept the new frame yet.
2014-09-22 18:06:59 +02:00
wm4 63a2024a8b osd: fix --term-osd=no
It didn't actually disable it.

I'm actually not sure what this option is useful for, but fixing it
can't harm.
2014-09-22 00:29:45 +02:00
wm4 14ff4cf318 command: improve "osd" command
Be less annoying, print the actual OSD level instead of something
meaningless, but still clear the OSD if OSD level 0 (no OSD) is set.

Remove the special handling for terminal OSD, that was just dumb.
2014-09-22 00:25:59 +02:00
wm4 709002a3b2 command: use show_property_osd() sub_step
Simpler and more consistent.
2014-09-22 00:08:19 +02:00
wm4 c99a966251 command: when changing a property, always show it on OSD
This means that if a property not listed in property_osd_display[] is
changed, it will be shown on the OSD as "name: ${name}".

Properties that are listed in property_osd_display[] and have osd_name
not set stay invisible by default. This is used for "pause" and
"fullscreen", which (like before this commit) are not shown by default,
because it would be annoying.

The defaults still can be changed with command prefixes (osd-msg,
no-osd, others).
2014-09-21 23:54:33 +02:00
wm4 903bd1d893 command: simplify OSD property display code
Probably not many user-visible changes. One notable change is that the
terminal OSD code for OSD bar fallback handling is removed with no
replacement. Instead, terminal OSD gets the same text message as normal
OSD. For volume, this is ok, because the text message is reasonable.
Other properties will look worse, but could be adjusted, and there are
in fact no other such properties that would be useful in audio-only
mode.

The fallback message for seeking falls away as well, but that message
was useless anyway - the terminal status line provides all information
anyway.

I believe the show_property_osd() code is now much easier to follow.
2014-09-21 23:48:24 +02:00
wm4 4a0bbe256e command: allow changing some OSD-related options even with no VO
If no VO was open, these options couldn't be changed or even queried.
Although these properties are nearly useless if no VO exists, there's
actually no good reason to forbid querying or setting them. Also, even
if the VO is created, it doesn't mean the VO window was created.
2014-09-21 16:01:53 +02:00
wm4 60ca2d8f4d command: remove unneeded ifdefs
Why bother?

Also, since now some properties could be mapped to non-existing options,
but mp_property_generic_option() is used, deal with this case and return
a not-found error code.
2014-09-21 16:00:03 +02:00
wm4 a0cee03394 command: always show OSD message when changing volume etc.
If there's a command that uses the OSD by default, then always print the
associated message (or a fallback made of name + value), even if the
command has an associated OSD bar.

This means volume, gamma, panscan, etc. all show both a message and a
OSD bar.

Also, add a '%' to the volume message. The extra_msg thing is not needed
anymore.

See issue #1103.
2014-09-21 15:55:22 +02:00
wm4 58db0a55f3 options: remove --volstep
It's just confusing; users are encouraged to edit input.conf instead
(changing the argument to the "add" command).

Update input.conf to keep the old behavior.
2014-09-21 15:41:33 +02:00
Ben Boeckel 54d1dae687 TOOLS: idet: remove extra '$' in $(()) expansion 2014-09-21 15:06:47 +02:00
wm4 b12a287227 manpage: clarify vf_pp docs
Make the note about quoting more prominent.
Add a warning that this filter is useless for new files.
2014-09-21 11:10:52 +02:00
wm4 a4241f9de6 video: fix redrawing when pausing after framedrop
When pausing after a frame was just dropped, we're logically at the
dropped frame, and thus should redraw the dropped frame. This was
implemented, but didn't work after unpausing for the second time,
because of a minor logic bug.
2014-09-21 10:06:06 +02:00
wm4 1cf229f462 video: fix some vo_direct3d crashes due to FFmpeg nonsense
For incomprehensible reasons, AV_PIX_FMT_GRAY8 (and some others) have a
palette. This literally makes no sense and this issue has bitten us
before, but it is how it is.

This also caused a crash with vo_direct3d: this mapped a texture as
IMGFMT_Y8 (i.e. AV_PIX_FMT_GRAY8), and when copying this, it tried to
copy the non-existent palette.

Fixes #1113.
2014-09-21 09:33:51 +02:00
shdown bb005a385a TOOLS/umpv: make URL detection consistent with mpv method
See mp_is_url in options/path.c.
2014-09-20 15:18:53 +02:00
shdown dfbb4d03ee TOOLS/umpv: print error message to stderr 2014-09-20 15:18:51 +02:00
shdown 5332ecf651 TOOLS/umpv: use MPV environment variable, not UMPV_OPTIONS
Just like the rest of TOOLS/*.sh scripts.
2014-09-20 15:18:49 +02:00
wm4 68b7217d41 vo_vdpau: better integration with the generic framedrop code
vo_vdpau uses its own framedrop code, mostly for historic reasons. It
has some tricky heuristics, of which I'm not sure how they work, or if
they have any effect at all, but in any case, I want to keep this code
for now. One day it might get fully ported to the vo.c framedrop code,
or just removed.

But improve its interaction with the user-visible framedrop controls.
Make --framedrop actually enable and disable the vo_vdpau framedrop
code, and increment the number of dropped frames correctly.

The code path for other VOs should be equivalent. The vo_vdpau behavior
should, except for the improvements mentioned above, be mostly
equivalent as well. One minor change is that frames "shown" during
preemption are always count as dropped.

Remove the statement from the manpage that vo_vdpau is the default; this
hasn't been the case for a while.
2014-09-20 15:17:12 +02:00
wm4 461c78e4d9 vo_vdpau: fix confusion around vsync_interval
vc->vsync_interval and vsync_interval should be the same value, but
actually vc->vsync_interval was updated after vsync_interval was
initialized. This was probably not intended. Fix this by removing the
duplicate local variable. There were probably no bad effects.
2014-09-20 14:54:19 +02:00
wm4 5e6c9963d8 input: explain why we use semaphores
Also switch function names for better self-documentation.
2014-09-20 04:22:37 +02:00
wm4 34fac3bf68 osdep: hack to fix build with low quality pthreads-w32 headers
When compiling semaphore_osx.c on win32, the following error happened:

/usr/i686-w64-mingw32/include/semaphore.h:160:6: error: unknown type name 'mode_t'

This is because this system header references symbols that are not
not defined anywhere. This is clearly a bug in pthreads-w32, but has
been known and unfixed since 2012, so add a hack to fix it.

We build semaphore_osx.c this way because it saves us an extra configure
check. On win32, Linux, etc. it's empty and contains
"#include <semaphore.h>" only.

Should fix #1108.
2014-09-20 04:18:40 +02:00
wm4 7329101478 mixer: always restore volume (even with pulse), don't unmute
Be less clever, and restore the volume state even with AOs like pulse,
which have per-application audio.

Before this commit we didn't do this, because the volume is global (even
if per-application), so the volume will persist between invocations. But
to me it looks like always restoring is less tricky and makes for easier
to understand semantics.

Also, don't always unmute on exit. Unmuting was done even with ao_pulse,
and interfered with user expectations (see #1107).

This might annoy some users, because mpv will change the volume all the
time. We will see.

Fixes #1107.
2014-09-20 02:02:29 +02:00
wm4 f64199fcdc manpage: document terminal status line components
(The classic MPlayer documentation had this in separate files, but we
deleted them ages ago.)
2014-09-20 00:50:04 +02:00
wm4 f5fb1e915e player: rename "Late:" field to "SD:"
Follow up to previous commit.

This is probably confusing from a user point of view, since this field
shouldn't show up normally anymore. (Before this commit, it could show
up sporadically when a slow operation was performed during playback,
such as switching fullscreen.)
2014-09-20 00:48:30 +02:00
wm4 771583c285 video: actually count decoder-dropped frames
Normally, feeding a packet to the decoder should always return a frame
_if_ we received a frame before. So while we can't know exactly whether
a frame was dropped, at least the normal case is easily detectable.

This means we display something closer to the actual framedrop count,
instead of a bad guess.
2014-09-20 00:45:39 +02:00
wm4 4047e7e6cb video: improve decoder-based framedropping mode
This is the "old" framedropping mode (derived from MPlayer). At least in
the mplayer2/mpv source base, it stopped working properly years ago (or
maybe it never worked properly). For one, it depends on the video
framerate, which assume constant framerate. Another problem was that it
could lead to freezing video display: video could get so much behind
that it couldn't recover from framedrop.

Make some small changes to improve this.

Don't use the current audio position to check how much we are behind.
Instead, use the last known A/V difference. last_av_difference is
updated only when a video frame is scheduled for display. This means we
can keep stop dropping once we're done catching up, even if video is
technically still behind. What helps us here that this forces a video
frame to be displayed after a while. Likewise, we reset the
dropped_frames count only when scheduling a new frame for display as
well.

Some inspiration was taken from earlier work by xnor (see issue #620),
although the implementation turned out quite different.

This still uses the demuxer-reported (possibly broken) FPS value. It
also doesn't account for filters changing FPS. We can't do much about
this, because without decoding _and_ filtering, we just can't know how
long a frame is. In theory, you could derive that from the raw packet
timestamps and the filter chain contents, but actually doing this is
too involved. Fortunately, the main thing the FPS affects is actually
the displayed framedrop count.
2014-09-20 00:45:11 +02:00
wm4 65e816b3fe player: make code more obvious
Or at least I think so.
2014-09-20 00:45:11 +02:00
wm4 116d1d0dfa player: use backwards flag for seeking external tracks
Otherwise, the external track could end up at a position that's too
late.
2014-09-20 00:45:10 +02:00
wm4 70f4721574 player: reset last_av_difference if not applicable
Don't let stale values linger around.

Also fix a slightly related case in audio.c.
2014-09-20 00:44:37 +02:00
wm4 c86b4790a8 af_hrtf: initialize coefficient arrays
Sometimes, --af=hrtf produces heavy artifacts or silence. It's possible
that this commit fixes these issues. My theory is that usually, the
uninitialized coefficients quickly converge to sane values as more audio
is filtered, which would explain why there are often artifacts on init,
with normal playback after that. It's also possible that sometimes, the
uninitialized values were NaN or inf, so that the artifacts (or silence)
would never go away.

Fix this by initializing the coefficients to 0. I'm not sure if this is
correct, but certainly better than before.

See issue #1104.
2014-09-19 21:16:42 +02:00
Alexander Preisinger 30175538fe input: add locking for repeat info 2014-09-19 17:48:06 +02:00
Alexander Preisinger b99c67f9bb build: update minimum wayland version
Uh oh.
2014-09-19 17:40:26 +02:00
Alexander Preisinger 29467736cf wayland: use reported rete and delay
If native-keyrepeat is true then we set the rate and delay reported by the
compositor.
2014-09-19 17:38:24 +02:00
Alexander Preisinger be516022b6 input: add function for setting repeat info
Let us set a different rate and delay.

Needed for the following commit where we set rate and delay reported by weston.
But only if the option native-keyrepeat is set.
2014-09-19 17:36:37 +02:00
wm4 95bb0bb671 vf_lavfi: fetch output frames incrementally
Uses the new mechanism introduced in the previous commit.

Depending on the actual filter, this distributes CPU load more evenly
over time, although it probably doesn't matter.
2014-09-18 19:36:55 +02:00
wm4 580cf433bd video/filter: allow better dataflow
Consider a filter which turns 1 frame into 2 frames (such as an
deinterlacer). Until now, we forced filters to produce all output frames
at once. This was done for simplicity.

Change the filter API such that a filter can produce frames
incrementally.
2014-09-18 19:36:27 +02:00
wm4 5c8549ac68 video: separate calling decoder/filter
Rename video_decode_and_filter to video_filter, and add a new
video_decode_and_filter function. This function now calls the decoder.
This is done so that we can check filters a second time after decoding,
which avoids a useless playloop iteration.

(This and the previous commits are really just microoptimizations, which
simply reduce the number of times the playloop has to recheck
everything.)
2014-09-18 19:35:23 +02:00
wm4 e37ad620aa video: check whether there are enough frames after filtering
Move the check to a function. Run the check a second time after
decoding/filtering. This second check is strictly speaking redundant
(which is why it wasn't done until now), but it avoids a useless
playloop iteration.
2014-09-18 19:34:56 +02:00
wm4 35810cb8b4 video: filter new frames at a better time
Move this code below the code that "shifts" the newly filtered frame.
This allows us to skip a useless playloop iteration later, because
obviously we need to filter a new frame after the previous frame has
been "shifted", and not before that.
2014-09-18 19:32:25 +02:00
wm4 ea2b19f646 player: allow overriding OSD message for all OSD levels
Until now, you could override only level 3 with --osd-status-msg. Extend
this, add add --osd-msg1 to --osd-msg3 (one for each OSD level). OSD
level 0 always means disable OSD, so that isn't included.

--osd-msg3 corresponds to --osd-status-msg, but they're not exactly the
same. To allow more customization, --osd-msgN do not include the OSD
symbol. The symbol can be manually added with "${osd-sym-cc}". We keep
the "old" option for some short-term compatibility.

--osd-msg1 should be particularly useful; for example you could do:

    --osd-msg1='${?pause==yes:${osd-sym-cc}}'

to display a "paused" symbol when paused, and nothing during normal
playback. (Although admittedly, the syntax is quite a bit of work.)
2014-09-18 01:23:33 +02:00
wm4 6c3d25e6f5 command: allow using ASS tags on OSD messages
We don't allow this by default, because it would be silly if random
external data (like filenames or file tags) could accidentally trigger
them.

Add a property that magically disables this ASS tag escaping.

Note that malicious input could still disable ASS tag escaping by
itself. This would be annoying but harmless.
2014-09-18 00:49:55 +02:00
wm4 a522441bbe command: add osd-sym-cc property
This allows you to reproduce the OSD symbol.
2014-09-18 00:12:59 +02:00
Rudolf Polzer a173d3a2fb TOOLS/idet.sh: Handle the case of multiple Parsed_idet_0: output lines.
This seems to happen frequently now. It is handled by adding their values.
2014-09-17 14:11:56 +02:00
wm4 396756e58a ao_oss: prevent hang when unpausing after device was lost
Pausing/unpausing while the audio device can't be reopened, and then
unpausing again when the device is finally reopened, can hang the
player for a while.

This happens because p->prepause_samples grows without bounds each
time the player is unpaused while the device is lost. On unpause,
ao_oss plays prepause_samples of silence to compensate for A/V timing
issues due to the partially lost buffer (we can't pause the device at
an arbitrary sample position, and the current period will be lost).
This in turn will make the player appear to be frozen if too much
audio is queued. (Normally, play() must never block, but here it
happens because more data is written than get_space() reports. A
better implementation would never let prepause_samples grow larger
than the period size.)

The unbounded growth happens because get_space() always returns that
the device can be written while the device is lost. So limit it to
200ms. (A better implementation would limit it to the period size.)

Also see #1080.
2014-09-17 00:33:40 +02:00
wm4 c158e4641a ao_oss: move code around
More logical, and preparation for the next commit. No functional
changes.
2014-09-17 00:14:21 +02:00
shdown f2c46bc1d1 TOOLS: eliminate echoes with variable substitutions
echo behaviour with backslash escapes seems to be non-portable: dash does
expand such an escapes and bash does not, so use cat/printf instead.
2014-09-17 00:00:05 +02:00
shdown 02d0b2f31c TOOLS/mpv_identify.sh: simplify line-by-line reading
Use here-document idiom to read mpv output line-by-line.
2014-09-16 23:59:56 +02:00
wm4 6ef40cb910 video: wake up core as soon as possible
There's no reason to let the core wait until the frame is done
displaying. In practice, the core normally didn't need this additional
wakeup, and the VO was quick enough to fetch the new frame, before the
core even attempted to queue a new frame. But it wasn't entirely clean,
and the correct wakeup handling might matter in some cases.
2014-09-16 23:59:13 +02:00
wm4 60f5e53f60 options: change --volstep to 2
With default settings, this allows you to hit the 100% mark (with
default --softvol-max in the middle) even if you've reached min or max
volume before. This is because 50 is not divisible by 3 (old default)
but by 2 (new default).

Not really sure why there still can be issues with higher --softvol-max
and --volstep=1, but this is where I stop caring.
2014-09-16 19:12:02 +02:00
wm4 d83a9f7f03 player: don't let multiline filenames set options on resume
If --write-filename-in-watch-later-config is used, and the filename
contains newline characters (as generally allowed on Unix), then the
newline will be written to the resume file literally, and the parts
after the newline character are interpreted as options.

This is possibly security relevant.

Change newline characters (and in fact any other special characters)
to '_'.

Reported as #1099 (this commit is a reimplementation of the proposed
pull request).

CC: @mpv-player/stable
2014-09-16 18:23:01 +02:00
wm4 caaeb15318 demux: gracefully handle packet allocation failures
Now the packet allocation functions can fail.
2014-09-16 18:11:00 +02:00
wm4 26e0cce969 TOOLS/mpv_identify.sh: mark as executable 2014-09-16 17:34:19 +02:00
Otto Modinos 33a63d8e6e options.lua: call msg.debug after resolving 'identifier' 2014-09-16 17:34:08 +02:00
Ben Boeckel b41ece5ad4 command: avoid a double -> int cast
Just check against zero directly.

Changes behavior, but that should be ok.

Signed-off-by: wm4 <wm4@nowhere>
2014-09-16 17:33:47 +02:00
Ben Boeckel 5fd8660f5f TOOLS: idet: use quotes for the verdict value
ShellCheck warns about "vara-varb" about not being in $(()), but we
actually want the literal string, so quote it. Also fix a typo.
2014-09-16 17:32:39 +02:00
Ben Boeckel 11c044aa48 TOOLS: shellcheck: quote variable expansions 2014-09-16 17:32:33 +02:00
Ben Boeckel 45e2345a7f TOOLS: shellcheck: remove '$' on variables in $(()) expansion 2014-09-16 17:29:46 +02:00
Ben Boeckel ec2c6a17dc TOOLS, version.sh: shellcheck: replace cmd with $(cmd)
Signed-off-by: wm4 <wm4@nowhere>
2014-09-16 17:29:39 +02:00
Ben Boeckel ba2a3f40ac TOOLS: idet: remove unused code 2014-09-16 17:29:11 +02:00
Alexander Preisinger 95053ba78b vo_wayland: remove unnecessary check
buffer_pool_get_front now returns always a valid buffer.
No need for corner cases.
2014-09-16 15:54:10 +02:00
Alexander Preisinger 20643b6c91 wayland/buffer: use buffer macros consistently 2014-09-16 15:48:07 +02:00
Aleksey Andreev 9e1ea9b3cd manpage: fix typo in input.rst
Signed-off-by: wm4 <wm4@nowhere>
2014-09-15 23:23:26 +02:00
wm4 cfdeb9d8ce input.conf: map ESC to exiting fullscreen
Apparently making ESC exit fullscreen mode is the more popular
convention compared to ESC quitting the program.

It was also concluded that ESC should do nothing when the windows is
already in normal state.

See discussion in #973.
2014-09-15 23:22:21 +02:00
wm4 b2b1b848da af_lavrresample: fix crash with size 0
The filter output size can be 0. Due to how filtering works, this is
nothing unusual, but avresample_convert() will return 0. The same case
is already handling with "normal" resampling (this commit fixes the
reordering code).

Additionally, don't use an assert(). avresample_convert() failing is
unusual, but might also happen due to e.g. internal out of memory
conditions, so we shouldn't just crash on it.

Curiously observed with --ao=oss --audio-channels=5.1 when changing
speed.
2014-09-15 23:14:19 +02:00
wm4 7c2fb859ab ao_oss: don't break playback when device can't be reopened
Apparently NetBSD users want/need this (see issue #1080).

In order not to break playback, we need at least to emulate get_delay().
We do this approximately by using the system clock.

Also, always close the audio device on reset. Reopen it on play only. If
we can't reopen it, don't retry until after the next time reset or
resume is called, to avoid spam and unexpectedly "stealing" back the
audio device.

Also do something about framestepping causing audio desync.
2014-09-15 23:08:19 +02:00
wm4 d5b8b5b901 ao_oss: audio_buf_info isn't state
The context struct had an audio_buf_info field, but there's no reason
why this would be needed. It's a tiny struct, and it isn't permanent
state. It's always returned by SNDCTL_DSP_GETOSPACE. Keeping this as
field is just confusing, so get rid of it.
2014-09-15 22:02:04 +02:00
wm4 b951326a38 ao_oss: remove duplicate audio device open code
The code for reopening the audio device was separate, and duplicated
some of the "real" open code. This was very badly done, and major
required parts of initialization were skipped. Fix this by removing
the code duplication. This consists mainly of moving the code for
opening the device to a separate function, and adding some changes
to handle format changes gracefully. (We can't change the audio
format on the fly, but we can at least not explode and play noise
when that happens.)

As a minor change, actually always use SNDCTL_DSP_RESET when closing
the audio device. We don't want to wait until the rest of the buffer
is played.

Also, don't use strerror() when printing the error message that
reopening failed, simply because reopen_device() takes care of this,
and also errno might be clobbered at this point.
2014-09-15 22:02:04 +02:00
wm4 9ca1582953 ao_oss: assume audio format reinit is not needed with SNDCTL_DSP_RESET
I have no idea whether this is true, because there literally doesn't
seem to exist documentation for SNDCTL_DSP_RESET. But at least on
Linux' OSS emulation, it is true. Also, it would be quite insane if
it would be needed.
2014-09-15 21:56:46 +02:00
wm4 2308eda2b8 ao_oss: don't use SNDCTL_DSP_RESET when pausing on NetBSD
It seems on NetBSD SNDCTL_DSP_RESET exists, but using it for pausing
is not feasible. We still use it to discard the audio buffer when
closing the audio device.
2014-09-15 21:54:28 +02:00
wm4 8efc4b7e24 ao_oss: fix incorrect comments using bytes instead of samples
MPlayer uses bytes, mpv uses sample counts in the AO API.
2014-09-15 20:22:12 +02:00
wm4 8c002b79d3 x11: if the WM supports _NET_FRAME_EXTENTS, don't wait for map
Some window managers can prevent mapping of a window as a feature. i3
can put new windows on a certain workspace (with "assign"), so if mpv is
started on a different workspace, the window will never be mapped.

mpv currently waits until the window is mapped (blocking almost all of
the player), in order to avoid race conditions regarding the window
size. We don't want to remove this, but on the other hand we also don't
want to block the player forever in these situations.

So what we need is a way to know when the window manager is "done" with
processing the map request. Unfortunately, there doesn't seem to be a
standard way for this. So, instead we could do some arbitrary
communication with the WM, that may act as "barrier" after map request
and the "immediate" mapping of the window. If the window is not mapped
after this barrier, it means the window manager decided to delay the
mapping indefinitely. Use the _NET_REQUEST_FRAME_EXTENTS message as such
a barrier. WMs supporting this message must set the _NET_FRAME_EXTENTS
property on the mpv window, and we receive a PropertyNotify event. If
that happens, we always continue and cancel waiting for the MapNotify
event.

I don't know if this is sane or if there's a better mechanism. Also,
this works only for WMs which support this message, which are not many.
But at least it appears to work on i3. It may reintroduce flickering on
fullscreen with other WMs, though.
2014-09-15 19:19:01 +02:00
wm4 930c61b64c DOCS/client_api_examples: qtexample: resize to video size
This is pretty imperfect, but it's just a demo.

The main purpose is clarifying how and when to get the video size.

In theory, retrieving the properties this way has a race condition:
after reading dwidth, the video could resize again. But the worst that
can happen are mismatching dwidth/dheight values, and the
MPV_EVENT_VIDEO_RECONFIG event would be immediately received again,
which would fix the mismatch. You could read the full video-out-params
property to absolutely avoid it, but it's not worth the trouble.
2014-09-15 18:38:42 +02:00
wm4 ac2047e02e manpage: clarify description of dwidth/dheight 2014-09-15 18:29:53 +02:00
Ben Boeckel 9bfa38add6 img_convert: sanitizer: avoid invalid left-shifts
(a << 24) is not in the valid int range when a is 255, so use an
unsigned instead.

Signed-off-by: wm4 <wm4@nowhere>
2014-09-14 21:10:09 +02:00
Ben Boeckel 3f6212cd8d sanitizer: avoid divide-by-zero instances
Merges pull request #1094, with some minor changes. mpv expects IEEE,
and IEEE allows divisions by 0 for floats, so these shouldn't actually
be a problem, but do it anyway for the sake of clang.

Signed-off-by: wm4 <wm4@nowhere>
2014-09-14 21:07:30 +02:00
wm4 e0b4daf3ad input: use libwaio for pipe input on Windows
Use libwaio to read from pipes (stdin or named pipes) on Windows. This
liberates us from nasty issues, such as pipes (as created by most
programs) not being possible to read in a non-blocking or event-driven
way. Although it would be possible to do that in a somewhat sane way
on Vista+, it's still not easy, and on XP it's especially hard. libwaio
handles these things for us.

Move pipe.c to pipe-unix.c, and remove Windows specific things. Also
adjust the input.c code to make this work cleanly.
2014-09-14 16:24:01 +02:00
wm4 b44571abab x11: remove unused function 2014-09-14 15:59:10 +02:00
wm4 955671f64a player: shorten skip heuristic for playlist_prev to 1 second
See issue #1084.
2014-09-14 10:32:24 +02:00
wm4 08116feec7 input: fix nested commands
Regression from today.
2014-09-13 18:41:34 +02:00
wm4 b6d8d5e05c stream: fix build with emulated atomics
This code was legal with C11 atomics, but it fails with our
compatibility wrapper.
2014-09-13 17:08:47 +02:00
wm4 b799bf0dbf client API: use playback abort mechanism
If you send the "quit" or "stop" command with the client API, it will
now attempt to kill network I/O immediately (same as normal input in the
previous commits).
2014-09-13 16:52:42 +02:00
wm4 893f4a0fee input: distinguish playlist navigation and quit commands for abort
Refine the ugly hack from the previous commit, and let the "quit"
command and some others abort playback immediately. For
playlist_next/playlist_prev, still use the old hack, because we can't
know if they would stop playback or not.
2014-09-13 16:47:30 +02:00
wm4 2e91d44e20 stream: redo playback abort handling
This mechanism originates from MPlayer's way of dealing with blocking
network, but it's still useful. On opening and closing, mpv waits for
network synchronously, and also some obscure commands and use-cases can
lead to such blocking. In these situations, the stream is asynchronously
forced to stop by "interrupting" it.

The old design interrupting I/O was a bit broken: polling with a
callback, instead of actively interrupting it. Change the direction of
this. There is no callback anymore, and the player calls
mp_cancel_trigger() to force the stream to return.

libavformat (via stream_lavf.c) has the old broken design, and fixing it
would require fixing libavformat, which won't happen so quickly. So we
have to keep that part. But everything above the stream layer is
prepared for a better design, and more sophisticated methods than
mp_cancel_test() could be easily introduced.

There's still one problem: commands are still run in the central
playback loop, which we assume can block on I/O in the worst case.
That's not a problem yet, because we simply mark some commands as being
able to stop playback of the current file ("quit" etc.), so input.c
could abort playback as soon as such a command is queued. But there are
also commands abort playback only conditionally, and the logic for that
is in the playback core and thus "unreachable". For example,
"playlist_next" aborts playback only if there's a next file. We don't
want it to always abort playback.

As a quite ugly hack, abort playback only if at least 2 abort commands
are queued - this pretty much happens only if the core is frozen and
doesn't react to input.
2014-09-13 16:09:51 +02:00
wm4 2dd819705d input: "quit_watch_later" and "stop" are abort commands
This means they get special handling for asynchronously aborting
playback, even if the player is "stuck".

Also document "stop". It seems somewhat useful for client API users
(although that will be implemented properly only in the following
commits.)
2014-09-13 14:10:10 +02:00
Philip Sequeira 7c77f0b803 TOOLS/zsh.pl: complete options that take file names 2014-09-13 02:03:09 +02:00
Alessandro Ghedini 1273febc44 options: add M_OPT_FILE flag to mark options that want a file(list) 2014-09-13 02:03:09 +02:00
wm4 b5d253a5cb m_config: fix theoretic undefined behavior
The memcpy() is actually not enough: the types are incompatible, and no
memcpy, union, etc. will change that. (Although no real compiler will
ever break this.) Attempt to make this theoretically correct by actually
using a struct pointer. It's not the same struct type, but supposedly
it's ok, because all struct pointers always have the same size and
representation in standard C.
2014-09-13 01:27:54 +02:00
wm4 8bf57b8192 player: fix idle mode event handling
Idle mode went to sleep too early, e.g. just pressing "ESC" did nothing,
until the next event happened. This was because it directly went to
sleep after processing commands. What we should do instead is rechecking
all state after processing commands, redraw OSD, and then go to sleep.
This also fixes some strange OSD-related behavior.

Also move some other code around to separate idle mode initialization
from the normal run loop.
2014-09-13 01:14:07 +02:00
wm4 b0a3d38b4c input: don't autorepeat cycle_values command
Not sure why this was originally added as autorepeated. It makes no
sense, because switching between choices should never autorepeat. (For
the normal "add"/"cycle" commands, autorepeat is usually enabled, but
command.c tries to disable it specifically for choice properties.)
2014-09-13 01:14:07 +02:00
wm4 a3b393d68c input: simplify
Just some minor things. In particular, don't call mp_input_wakeup()
manually, but make it part of queuing commands (as far as possible).
2014-09-13 01:14:07 +02:00
wm4 fc5df2b970 input: fix autorepeat
Mismatching units in timeout calculation.

Also, as a near-cosmetic change, explicitly wake up the core on the
right time. Currently this does nothing, because the core is woken up
anyway - but it will matter with the next commit.
2014-09-13 01:14:07 +02:00
wm4 f93dd45ac1 manpage: document shift+pgup/pgdwn bindings 2014-09-13 01:14:07 +02:00
wm4 d26a0ae111 ao_oss: fix audio device leak on error
Close the audio device if it was already opened, but the rest of
initialization failed.
2014-09-11 02:05:12 +02:00
wm4 5f80e3f91a ao_oss: use poll(), drop --disable-audio-select support
Replace select() usage with poll() (and reduce code duplication).

Also, while we're at it, drop --disable-audio-select, since it has the
wrong name anyway. And I have doubts that this is needed anywhere. If
it is, it should probably fallback to doing the right thing by default,
instead of requiring the user to do it manually. Since nobody has done
that yet, and since this configure option has been part of MPlayer ever
since ao_oss was added, it's probably safe to say it's not needed.

The '#ifdef SNDCTL_DSP_GETOSPACE' was pointless, since it's already used
unconditionally in another place.
2014-09-11 02:03:15 +02:00
wm4 f744aadb77 ao_pulse: dump library version etc.
Might help with debugging.

Unfortunately, there doesn't seem to be a way to get the actual
pulseaudio server version.
2014-09-10 23:14:06 +02:00
wm4 f790d6aafd old-build: fix build with wayland 2014-09-10 23:10:43 +02:00
Alexander Preisinger 369868e404 wayland_common: fix changing videos when fullscreen
I broke it again.
2014-09-10 19:21:52 +02:00
Alexander Preisinger 94fe57856d vo_wayland: pixel perfect buffers
1.  Separate buffer and temporary file handling from the vo to make maintenance
    and reading code easier

2.  Skip resizing as much as possible if back buffer is still busy.

3.  Detach and mark osd buffers for deletion if we want to redraw them and they
    are still busy. This could be a possible case for the video buffers as
    well. Maybe better than double buffering.

All the above steps made it possible to have resizing without any artifacts
even for subtitles. Also fixes dozen of bugs only I knew, like broken subtitles
for rgb565 buffers. I can now sleep at night again.
2014-09-10 19:10:19 +02:00
Diogo Franco (Kovensky) 5bbf5ee103 osdep/semaphore_osx.c: Include osdep/semaphore.h before #ifdef
osdep/semaphore.h is the file that defines the very #define that is
tested in the #ifdef that wraps its inclusion, so it was never compiled.
2014-09-10 17:22:20 +09:00
wm4 302a04091b build: fix everything
A missing dependency entry made ./waf configure always fail.
2014-09-10 04:09:06 +02:00
wm4 524db3384b osdep: fix windows build
Oops.
2014-09-10 03:29:24 +02:00
wm4 e9b756c7ad input: remove central select() call
This is now unused. Get rid of it and all surrounding infrastructure,
and replace the remaining "wakeup pipe" with a semaphore.
2014-09-10 03:24:45 +02:00
wm4 564b957cc3 osdep: add POSIX semaphore emulation for OSX
OSX is POSIX conformant, but it's a sad joke: it provides the
<semaphore.h> prototype as the standard demands, but they're empty
wrappers, and all functions just return ENOSYS.

Emulate them similar to how osdep/io.h emulate filesystem functions on
Windows. By including the header, working sem_* functions become
available.

To make it async-signal safe, use a pipe for wakeup (write() is AS-safe,
but mutexes can't be). Actually I'm not sure anymore if we really need
AS-safety, but for now the emulation can do it.

On Linux, the system provides a far more efficient and robust
implementation. We definitely want to avoid using the emulation if
possible, so this code is active on OSX only. For convenience we always
build the source file though, even if the implementation is disabled and
no actual code is generated.

(Linux provides working semaphores, but is formally not POSIX
conformant. On OSX it's the opposite. Is POSIX a complete joke?)
2014-09-10 03:24:19 +02:00
wm4 ae63702a2c input: remove useless joystick.h/lirc.h include files
These really just waste space.
2014-09-10 00:51:36 +02:00
wm4 e2a093df02 input: use an input thread for joystick 2014-09-10 00:48:59 +02:00
wm4 fe0ca7559c input: use an input thread for lirc 2014-09-10 00:48:45 +02:00
wm4 5be678386b input: add convenience function for running input sources in threads 2014-09-10 00:48:12 +02:00
wm4 256fea7655 input: make some fields internal 2014-09-10 00:48:12 +02:00
wm4 49a0b61880 terminal-unix: don't read from stdin if it's not a terminal
I'm not quite sure what we should actually do (maybe read input
commands?), but interpreting input as terminal key sequences is
definitely weird. So just do nothing.
2014-09-10 00:48:12 +02:00
wm4 28fc13977e terminal-unix: move to thread
Do terminal input with a thread, instead of using the central select()
loop. This also changes some details how SIGTERM is handled.

Part of my crusade against mp_input_add_fd().
2014-09-10 00:48:12 +02:00
wm4 d0b525121a terminal-win: minor simplification
Code should be equivalent.
2014-09-10 00:48:12 +02:00
wm4 670f965f1a win32: don't request window size larger than the screen
An attempt at fixing #1070. Apparently something goes wrong if the
video size is equal to the screen size. Since the window decorations
add to the window size, it must actually be larger than the screen.
Actually I don't know what exactly is going wrong, but since this
commit also slightly improves the behavior otherwise, it's a win
anyway.

Try to keep the window size strictly below screen size, even accounting
for window decorations. Size it down and center the window so that it
fits (by either touching the left/right or top/bottom screen borders).
I haven't found any information on what is the maximum allowed size and
position of a window so that it doesn't collide with the task bar, so
assume that we can use the entire screen, minus 1 pixel to avoid
triggering fullscreen semantics (if that is even possible).
2014-09-10 00:48:07 +02:00
wm4 e1e8b07cfa player: reset some VO state when video is terminated
Useful for idle mode or if video is switched off during playback, and
--force-window is used.
2014-09-09 01:23:10 +02:00
wm4 c0fbab7a7c player: deal with some corner cases with playlist navigation
The purpose is making accessing the current playlist entry saner when
commands are executed during initialization, termination, or after
playlist navigation commands.

For example, the "playlist_remove current" command will invalidate
playlist->current - but some things still access the playlist entry even
on uninit. Until now, checking stop_play implicitly took care of it, so
it worked, but it was still messy.

Introduce the mpctx->playing field, which points to the current playlist
entry, even if the entry was removed and/or the playlist's current entry
was moved (e.g. due to playlist navigation).
2014-09-09 01:23:10 +02:00
wm4 9cb1e2c58c player: normalize playlist entries on add
This is not necessarily more correct, but it's less trouble.
2014-09-09 01:23:10 +02:00
wm4 76f9eede34 input: fix missed wakeups, simplify
mp_input_read_cmd() reset the wakeup flag, but only mp_input_wait()
should be able to do that.
2014-09-09 01:23:09 +02:00
wm4 b578abe81b ao_pulse: fix typo in error message
Closes #1076.
2014-09-08 17:19:53 +02:00
wm4 4ef531f815 input: fix use after free with legacy commands
To handle legacy commands, string replacement is used; the modified
string is returned by parse_cmd_str(), but it also frees all temporary
memory, which includes the replaced string.

Closes #1075.
2014-09-08 15:13:11 +02:00
wm4 3b5f28bd0f input: fix exiting with signals
Quitting through SIGTERM etc. was accidentally ignored since commit
f5af5962 from today.
2014-09-08 01:11:32 +02:00
wm4 8c7a9b0cd0 stream: change cache return values
Basically a cosmetic change, because currently the player just continues
even if the cache fails initializing.
2014-09-07 20:45:39 +02:00
wm4 f5af596237 player: some more input refactoring
Continues commit 348dfd93. Replace other places where input was manually
fetched with common code.

demux_was_interrupted() was a weird function; I'm not entirely sure
about its original purpose, but now we can just replace it with simpler
code as well. One difference is that we always look at the command
queue, rather than just when cache initialization failed. Also, instead
of discarding all but quit/playlist commands (aka abort command), run
all commands. This could possibly lead to unwanted side-effects, like
just ignoring commands that have no effect (consider pressing 'f' for
fullscreen right on start: since the window is not created yet, it would
get discarded). But playlist navigation still works as intended, and
some if not all these problems already existed before that in some
forms, so it should be ok.
2014-09-07 20:44:54 +02:00
wm4 5546af421f win32: copy event flags after running VOCTRLs
reinit_window_state() will set VO_EVENT_RESIZE when it runs, so we
don't need to set it manually depending on the VOCTRL.

Probably avoids duplicated resize events. I don't expect this actually
fixes anything, but might help spotting other bugs easier (if there
are any).
2014-09-07 13:22:50 +02:00
wm4 017b3fa9db lua: synchronously wait until scripts are loaded
This makes the player wait until each script is loaded. Do this to give
the script a chance to setup all its event handlers. It might also be
useful to allow a script to change options that matter for playback.

While waiting for a script to be loaded, the player actually accepts
input. This is needed because the scripts can execute player commands
anyway while they are being "loaded". The player won't react to most
commands though: it can't quit or navigate the playlist in this state.

For deciding whether a script is finally loaded, we use a cheap hack: if
mpv_wait_event() is called, it's considered loaded. Let's hope this is
good enough. I think it's better than introducing explicit API for this.
Although I'm sure this will turn out as too simplistic some time in the
future, the same would probably happen with a more explicit API.
2014-09-06 17:02:47 +02:00
wm4 348dfd93c4 player: minor refactoring
Expose the central event handling functions explicitly, so that other
parts of the player can use them.

No functional changes. Preparation for the next commit.
2014-09-06 16:57:46 +02:00
wm4 94113e632f audio/out: fix active waiting during pause again
This was fixed in commit 8432eaefa, and commit 39609fc1 of course broke
it again. This was pretty stupid.
2014-09-06 16:25:27 +02:00
Stefano Pigozzi a1d3afb395 vo_corevideo: remove this VO
This was kept in the codebase because it is slightly faster than --vo=opengl
on really old Intel cards (from the GMA era). Time to kill it, and let it rest.

Fixes #1061
2014-09-06 14:10:22 +02:00
wm4 a6774d3a83 stream_lavf: assume icy title data is terminated with ';'
Should fix #1071.
2014-09-06 13:46:17 +02:00
wm4 7791e25fa0 audio: fix initial sync with huge AO buffer
With e.g --start=-3 --audio-buffer=10 the decoder entered EOF state
before the initial sync was finished, entered STATUS_EOF, and just
started playing audio from a random position.

This doesn't handle seeking outside of the file, which is a different
case. E.g. --start=30:00 with audio and video enabled in a file shorter
than 30:00 will play a random last part of audio. This could perhaps be
fixed by using the hr-seek target for cutting audio, instead of the
video PTS, but that would be kind of intrusive, so don't do it for now.
The simpler solution, assuming audio EOF on video EOF, wouldn't work,
because we allow audio to start before video, or to last after video.
2014-09-06 13:33:29 +02:00
wm4 39609fc19a audio/out/push: redo audio waiting
Improve the logic how the audio thread decides how to wait until the AO
is ready for new data. The previous commit makes some of this easier,
although it turned out that it wasn't required, and we still can handle
AOs with bad get_space implementation (although the new code prints an
error message, and it might fail in obscure situations).

The new code is pretty similar to the old one, and the main thing that
changes is that complicated conditions are tweaked. AO waiting is now
used better (mainly instead of max>0, r>0 is used). Whether to wakeup
is reevaluated every time, instead of somehow doing the wrong thing
and compensating for it with a flag.

This fixes the specific situation when the device buffer is full, and
we don't want to buffer more data. In the old code, this wasn't handled
correctly: the AO went to sleep forever, because it prevented proper
wakeup by the AO driver, and as consequence never asked the core for new
data. Commit 4fa3ffeb was a hack-fix against this, and now that we have
a proper solution, this hack is removed as well.

Also make the refill threshold consistent and always use 1/4 of the
buffer. (The threshold is used for situations when an AO doesn't
support proper waiting or chunked processing.)

This commit will probably cause a bunch of regressions again.
2014-09-06 12:59:04 +02:00
wm4 769ac6fb7b audio/out: always round get_space on period size
Round get_space() results in the same way play() rounds the input size.
Some audio APIs do this for various reasons.

This affects only "push" based AOs. Some of these need no change,
because they either do it already right (like ao_openal), or they seem
not to have any such requirements (like ao_pulse).

Needed for the following commit.
2014-09-06 12:59:00 +02:00
wm4 d9941e01cc ao_sndio: fix a comment
Whether this code was written with the correct assumptions in mind, I
don't know.
2014-09-06 12:58:57 +02:00
wm4 6c9ce5bee2 ao_pcm: minor simplification 2014-09-06 12:58:54 +02:00
wm4 4962a1ece3 ao_oss: minor simplification
Equivalent code.
2014-09-06 12:58:48 +02:00
wm4 cf04ddca38 mplayer-input.conf: fix broken binding
"#" starts a comment, so the # key needs to be handled specially.
MPlayer has the same issue, but its input.conf is wrong. Or at least I
think it's wrong; looking at the MPlayer code it's doubtful they somehow
special-case and handle this.
2014-09-06 02:49:28 +02:00
wm4 439a05d8c3 audio/out: remove old things
Remove the unnecessary indirection through ao fields.

Also fix the inverted result of AOCONTROL_HAS_TEMP_VOLUME. Hopefully the
change is equivalent. But actually, it looks like the old code did it
wrong.
2014-09-06 02:30:57 +02:00
wm4 197f18402e sub: fix possible deadlock with --no-sub-ass and similar
This is a deadlock caused by a lock order issue: sub/osd.c locks the OSD
first, then the subtitle decoder lock. player/sub.c does the reverse.

Fix this by discussing away the requirement for locking (see below),
which allows us to drop the broken sub lock. sub_get_text() still
acquires and releases the sub decoder lock, but it's not held at the
same time as the OSD lock anymore, so it should be fine.

Originally, the sub lock was acquired because sub_get_text() returns a
pointer to a mutable string. We simply declare that it's ok to call it
unlocked, as long as only 1 thread accesses it, which works out fine in
this case.
2014-09-06 00:16:15 +02:00
wm4 bdf49d137e audio/out: make EOF handling properly event-based
With --gapless-audio=no, changing from one file to the next apparently
made it hang, until the player was woken up by unrelated events like
input. The reason was that the AO doesn't notify the player of EOF
properly. the played was querying ao_eof_reached(), and then just went
to sleep, without anything waking it up.

Make it event-based: the AO wakes up the playloop if the EOF state
changes.

We could have fixed this in a simpler way by synchronously draining the
AO in these cases. But I think proper event handling is preferable.

Fixes: #1069
CC: @mpv-player/stable (perhaps)
2014-09-05 23:45:54 +02:00
wm4 6b59d6a47b vo_sdl: fix typo 2014-09-05 22:10:20 +02:00
wm4 ce246296b3 af_hrtf: request required samplerate, instead of erroring out
It seems hrtf works in 48khz only - and if that wasn't the input, the
filter just exited with an error. Make it request the 48khz instead. The
player will insert a resampling filter.

Not sure why it wasn't done like this in the first place.
2014-09-05 20:49:35 +02:00
wm4 5f29073abf af_hrtf: cosmetics: reindent misaligned code block 2014-09-05 20:47:54 +02:00
wm4 eaa1f16564 audio: correctly initialize output buffer
Just like the previous commit, this takes care of fallout from commit
7ab228, which fixed a bug, but introduced some new ones.

CC: @mpv-player/stable
2014-09-05 17:51:45 +02:00
James Ross-Gowan eba8eeda78 player: check for null in resume config search
Signed-off-by: wm4 <wm4@nowhere>

CC: @mpv-player/stable
2014-09-05 17:51:45 +02:00
James Ross-Gowan 5c3f3fd3da win32: add tmpfile() replacement
The Windows version of tmpfile is actually pretty broken. It tries to
create the file in the root directory of the current drive, which means
on Vista and up, it normally fails due to insufficient permissions.
Replace it with a version that uses GetTempPath.

Also remove the Windows-specific note about automatic deletion of the
cache file. FILE_FLAG_DELETE_ON_CLOSE is available in NT, and it should
be pretty reliable.
2014-09-05 17:51:44 +02:00
wm4 15a882d2ed audio: fix random crashes on uninit
I added this non-sense earlier this day. Oops.
2014-09-05 04:33:24 +02:00
wm4 545c2d7206 manpage: fix sub_add description
It is in fact selected. The manpage wasn't updated when this was
changed.
2014-09-05 02:42:25 +02:00
Bruno George de Moraes bca4219dd0 malloc+memset(0) to calloc
Signed-off-by: wm4 <wm4@nowhere>
2014-09-05 01:59:11 +02:00
wm4 a7d737a698 audio: make buffer size configurable
Really only for testing.
2014-09-05 01:53:10 +02:00
wm4 7ab228629e audio: fix obscure audio resync failure with timelines
Somehow, there was a larger misunderstanding in the code: ao_buffer
does not need to be preserved over audio reinit for proper support of
gapless audio. The actual AO internal buffer takes care of this.

In fact, preserving ao_buffer just breaks audio resync. In the ordered
chapter case, end_pts is used, which means not all audio data in the
buffer is played, thus some data is left over when audio decoding
resumes on the next segment. This triggers some code that aborts resync
if there's "audio decoded" (ao_buffer contains something), but no PTS
is known (nothing was actually decoded yet).

Simplify, and always bind the output buffer to the decoder.

CC: @mpv-player/stable (maybe)
2014-09-05 01:53:10 +02:00
wm4 787839e8ec cosmetics: remove a stray ';' 2014-09-05 01:53:10 +02:00
wm4 b518142236 build: handle insane libavcodec API bullshit
The oldest supported FFmpeg release doesn't provide
av_vdpau_alloc_context(). With these versions, the application has no
other choice than to hard code the size of AVVDPAUContext. (On the other
hand, there's av_alloc_vdpaucontext(), which does the same thing, but is
FFmpeg specific - not sure if it was available early enough, so I'm not
touching it.)

Newer FFmpeg and Libav releases require you to call this function, for
ABI compatibility reasons. It's the typcal lakc of foresight that make
FFmpeg APIs terrible. mpv successfully pretended that this crap didn't
exist (ABI compat. is near impossible to reach anyway) - but it appears
newer developments in Libav change the function from initializing the
struct with all-zeros to something else, and mpv vdpau decoding would
stop working as soon as this new work is relewased.

So, add a configure test (sigh).

CC: @mpv-player/stable
2014-09-05 01:52:29 +02:00
wm4 e267ff93f3 video: rename VOCTRL_GET_WINDOW_SIZE
Make it clear that this accesses the un-fullscreened window size.
2014-09-05 01:52:16 +02:00
wm4 c15957b43a ebml: warn if there are too many subelements
Seems like a good idea.
2014-09-04 19:21:19 +02:00
wm4 d9aaf78530 demux_mkv: allow up to 256 MB of extradata to make broken files work
What the flying fuck?

Unfortunately, these are already in the wild.

CC: @mpv-player/stable
2014-09-04 19:20:47 +02:00
Stefano Pigozzi 7b0de4aa0e build: add a check_program check
This wraps waf's find_program in our own check boilerplate code so that it
can be used in the declarative dependencies section of the wscript.

Can be used like this:

    }, {
        'name': 'sed',
        'desc': 'sed program',
        'func': check_program('sed', 'SED'),
    }, {

First argument is the program name, and the second is the waf variable name
where the program path will be stored. In this example we will be able to
refer to sed with ${{SED}} when creating waf Tasks in wscript_build.

/cc @giselher: I think you need this for wayland-scanner.
2014-09-03 23:52:56 +02:00
Alexander Preisinger fc68c9269d wayland: print some useful outptu info
Prints output informations, useful for finding out if we detect the right mode
and for debugging.
2014-09-03 21:35:26 +02:00
Alexander Preisinger 8bd5df3ac1 wayland: only save current mode of outputs
Other ones are not needed.
2014-09-03 21:35:26 +02:00
Kenneth Zhou 98b9d47482 x11: add rewind and forward keys
Signed-off-by: wm4 <wm4@nowhere>
2014-09-03 21:08:54 +02:00
wm4 0835e093e2 path: remove XDG bullshit
Don't worry, your ~/.config/... paths are safe. This merely removes
handling of $XDG_CONFIG_DIRS for global paths.

Maybe there is a better solution for this, like still including the
"traditional" config dir. But I will leave the fine reading of this
(crappy) spec and fixing the code accordingly to someone else. So, if
anyone has interest in getting this behavior back, you will have to
write a patch. This patch should _also_ not break expected behavior.

Fixes #1060.
2014-09-03 02:07:36 +02:00
wm4 9e512c5a98 demux: allow increasing filepos only
The last demuxed file position (demuxer->filepos) is used to estimate
the total playback percentage in files with possible timestamp resets
(like MPEG-PS). Until know, reading from any stream set this position
freely. This makes the position jump around.

Fix this by allowing icnreasing file position only. Reset it on seeking.
With crazy formats, this still could go wrong, but there's only so much
you can do.
2014-09-03 02:00:18 +02:00
wm4 bf74a4cc46 player: add --media-title option
Requested by ChrisK2.
2014-09-02 22:28:11 +02:00
wm4 6c1e528518 player: properly resume playlists loaded at runtime
If a playlist is loaded from the internal playlist (like
"mpv playlist.m3u"), then attempt to resume from it.

CC: @mpv-player/stable
2014-09-02 22:16:20 +02:00
wm4 2da246b9f7 player: add --osd-playing-msg option 2014-09-02 00:12:52 +02:00
wm4 291d986810 player: show HLS bitrate as fallback for track titles
HLS streams as demuxed by libavformat have no track title metadata. So
show the HLS bitrate if no title is set. Could be useless or annoying,
so it's a bit controversial, I guess.
2014-09-01 23:50:25 +02:00
wm4 5f14543668 player: simplistic HLS bitrate selection
--hls-bitrate=min/max lets you select the min or max bitrate. That's it.
Something more sophisticated might be possible, but is probably not even
worth the effort.
2014-09-01 23:47:27 +02:00
wm4 8d92128f6b command: remove broken quvi-format property
Never really worked, and libquvi is probably a lost cause anyway.
2014-09-01 23:27:33 +02:00
wm4 2f537bafa5 demux: get rid of old wrapper
demux_info_get() used to be central, but was turned into a wrapper, and
now there was only one caller left. Get rid of it.
2014-09-01 22:12:39 +02:00
wm4 0aaf688c2d command: make m_property_strdup_ro with NULL mean unavailable
This catches a few cases which basically call:

    m_property_strdup_ro(..., ..., NULL)

which would return NULL strings. This should generally be avoided
(although it's allowed due to reasons), and it seems most callers
actually intend this to mean M_PROPERTY_UNAVAILABLE.
2014-09-01 21:50:54 +02:00
wm4 4124a175e1 command: disable some commands/properties properly in idle mode
In particular, don't allow to add any external subtitle tracks in idle
mode. This make no sense and would just lead to leaks or worse.
2014-09-01 21:44:54 +02:00
wm4 e87617593f player: reset playback-related fields right on start 2014-09-01 21:02:43 +02:00
Martin Herkt 27a065182c man: fix a whole bunch of typos 2014-09-01 04:27:13 +02:00
wm4 5ea84e17c0 player: don't allow remote playlists to load local files
Because that might be a bad idea.

Note that remote playlists still can use any protocol marked with
is_safe and is_network, because the case of http-hosted playlists
containing URLs using other streaming protocols is not unusual.
2014-09-01 00:13:22 +02:00
wm4 129a7c056a playlist: don't add the base path twice
Loading a playlist with --playlist from a sub-directory added the
playlist's base path twice: one time in the playlist demuxer, and then
again in playlist_parse_file(). The latter function is used only for
--playlist, so it worked when loading the playlist directly.

(This is probably a mess-up when the MPlayer playlist parsers were
replaced with newer code.)

CC: @mpv-player/stable
2014-09-01 00:13:10 +02:00
wm4 f59f1e532e client API: fix memory leak with rejected events
The event was copied early, and wasn't released if it was rejected
instead of being added to the event queue. Fix by copying the event at a
point when it's certainly added to the event queue.

The dup_event_data() function is merely moved.
2014-08-31 19:51:41 +02:00
wm4 866e0e1670 player: always load playlists
Until now, you had to use --load-unsafe-playlists or --playlist to get
playlists loaded. Change this and always load playlists by default.

This still attempts to reject unsafe URLs. For example, trying to invoke
libavdevice pseudo-demuxer is explicitly prevented. Local paths and any
http links (and some more) are always allowed.
2014-08-31 19:49:39 +02:00
wm4 fc0fa9a221 audio: go to draining state instead of EOF if audio starts later
Probably no observable effect, but it's more correct. Setting audio to
EOF could have bad effects otherwise (anywhere the player logic for
example decides whether EOF was reached, and such).
2014-08-31 14:48:58 +02:00
wm4 fd4045965e video: adjust some Matroska 3D formats
There is no proper and exact spec (Matroska tradition), so we probably
have to rely on guessing for this.

Also see issue #1045.
2014-08-31 14:48:58 +02:00
wm4 8432eaefa0 audio/out: prevent burning CPU when seeking while paused
The audio/video sync code in player/audio.c calls ao_reset() each time
audio decoding is entered, but the player is paused, and there would be
more than 1 sample to skip to make audio start match with video start.
This caused a wakeup feedback loop with push.c.

CC: @mpv-player/stable
2014-08-31 14:48:58 +02:00
wm4 64b7811c28 x11: when using --wid, inherit event flags from parent window
When embedding a X window, it's hard to control whether it receives
mouse/keyboard input or not. It seems the X protocol itself makes this
hard (basically due to the outdated design mismatching with modern
toolkits), and we have to take care of these things explicitly.

Simply do this by manually querying and using the parent window event
flags.

This restores some MPlayer behavior (it doesn't add back exactly the
same code, but it's very similar).

This probably has some potential to interfere with libmpv embedding, so
bump the client API minor.

CC: @mpv-player/stable (if applied, client-api-changes.rst has to be
    adjusted to include the 0.5.2 release)
2014-08-31 14:48:26 +02:00
Otto Modinos a910b5c6df lua: expose mp_getcwd through mp.utils 2014-08-31 00:58:27 +02:00
wm4 8956878448 manpage: be more explicit about "estimated-..." properties
In particular, use the note markup. The issue about rounded timestamps
is mostly with respect to Matroska (which usually rounds them to
milliseconds), which somewhat adds to the reliability issue.
2014-08-31 00:22:01 +02:00
wm4 94140e0897 csputils: adjust comment
Make it clear that the value is linked to the StereoMode element. You
can't change this without adjusting demux_mkv.c.
2014-08-30 23:54:19 +02:00
wm4 8599c959fe video: initial Matroska 3D support
This inserts an automatic conversion filter if a Matroska file is marked
as 3D (StereoMode element). The basic idea is similar to video rotation
and colorspace handling: the 3D mode is added as a property to the video
params. Depending on this property, a video filter can be inserted.

As of this commit, extending mp_image_params is actually completely
unnecessary - but the idea is that it will make it easier to integrate
with VOs supporting stereo 3D mogrification. Although vo_opengl does
support some stereo rendering, it didn't support the mode my sample file
used, so I'll leave that part for later.

Not that most mappings from Matroska mode to vf_stereo3d mode are
probably wrong, and some are missing.

Assuming that Matroska modes, and vf_stereo3d in modes, and out modes
are all the same might be an oversimplification - we'll see.

See issue #1045.
2014-08-30 23:24:46 +02:00
wm4 c80adac077 cache_file: add a mode that creates a temporary file
Since we have to be portable, our options for creating temporary files
are somewhat limited. tmpfile() happens to be available everywhere, so
use that. This function doesn't allow having a "visible" filename or
location, so we use the magic string "TMP" for this.
2014-08-30 20:03:31 +02:00
wm4 829fdef219 player: reduce default demuxer cache
A (hopefully) temporary hack to make stream switching delays tolerable.
It's not clear how this should be handled (either executing a precise
seek on track switching, or always enabling all streams), so get this
issue out of the way for now by picking a rather low value.
2014-08-30 19:37:21 +02:00
shdown b8f2f0d69e TOOLS/mpv_identify.sh: simplify $MPV handling 2014-08-30 19:23:42 +02:00
shdown 4a976c469c TOOLS/mpv_identify.sh: various style improvements
Double-quote everything, eliminate unneeded evals and deprecated
`backtits` substitution syntax.
2014-08-30 19:23:42 +02:00
shdown 880d5c8a4a TOOLS/mpv_identify.sh: move script body to a function
Don't prepend each variable with __midentify__, just make them local
to the function.
2014-08-30 19:23:42 +02:00
shdown cbe03b6255 TOOLS/youtube-dl_mpv.sh: simplify $MPV handling 2014-08-30 19:23:42 +02:00
shdown 43d4667028 TOOLS/youtube-dl_mpv.sh: disable globbing before expanding $video_url
$video_url can contain a question mark, which can be expanded to a
character in an existing file name if globbing is enabled.
2014-08-30 19:23:41 +02:00
wm4 948dfe651d manpage: document that --cache-file doesn't work with ordered chapters 2014-08-30 19:17:44 +02:00
wm4 b7fa981899 stream: correctly propagate uncached stream type
This makes the ordered chapter code not think that a stream from the
local filesystem is not a local file (it checks uncached_type).
2014-08-30 19:05:57 +02:00
wm4 98ef68bdfd demux_lavf: print a warning if av_read_frame() returns an error
Because why not.
2014-08-30 15:15:38 +02:00
shdown 730d94741c vf_softpulldown: handle null mpi_image correctly
Check if mpi is NULL before accessing mpi->fields.
2014-08-30 15:15:38 +02:00
shdown 3307af43c5 input: make ar_rate and ar_delay fields of input_ctx signed
ar_rate is set to -1 when autorepeat is disabled; there is no reason
for ar_delay to stay unsigned.
2014-08-30 15:15:37 +02:00
shdown 8ee1bcf1fa input: handle reaching MP_MAX_FDS correctly
Don't dereference fd and increment ictx->num_fds on fail.
2014-08-30 15:15:37 +02:00
shdown e2ecf3d03d demux_mkv: eliminate redundant branch
In the else branch pict_type is always 3, so pict_type != 3 is always
false. (Note that I have no idea of what it was supposed to do and it is
just an equivalent of the old behaviour.)
2014-08-30 15:15:37 +02:00
shdown f49099b94d demux: eliminate redundant check
pkt can't be NULL since it's initialized from ds->head, which is checked
at the beginning.
2014-08-30 15:15:37 +02:00
shdown 5bc3b7c368 demux_disc: handle new_sh_stream() fail correctly
Break the cycle on fail. Old code was checking if sh is NULL after
accessing it's fields.
2014-08-30 15:15:37 +02:00
Alexander Preisinger 593e5e4a25 gl_wayland: fix crash after eglInitialze failed
Only execute most of the opengl termination procedure if we actually have an
egl context.
2014-08-30 10:17:51 +02:00
wm4 ce93ee8bd0 manpage: fix minor grammar issue 2014-08-29 20:56:08 +02:00
Bin Jin 225f2e67b7 vo_opengl: remove macro operator from shader
Removes '##' operator from OpenGL shader code.
2014-08-29 20:56:03 +02:00
wm4 a8299cec29 TOOLS/youtube-dl_mpv: allow playing multiple URLs
Unfortunately this also means you can't pass extra mpv options after the
URL anymore. You can prefix the script with MPV='mpv --options' though.
2014-08-29 20:20:29 +02:00
wm4 7d79cd57ff player: fix quit handling when seeking past EOF while paused
The player didn't quit when seeking past EOF in audio-only mode while
paused. The only case when we don't want to quit is when the last video
frame is displayed while paused.

This logic was probably broken a while ago, but I'm not exactly sure.

CC: @mpv-player/stable
2014-08-29 19:13:34 +02:00
wm4 68ff8a0484 Move compat/ and bstr/ directory contents somewhere else
bstr.c doesn't really deserve its own directory, and compat had just
a few files, most of which may as well be in osdep. There isn't really
any justification for these extra directories, so get rid of them.

The compat/libav.h was empty - just delete it. We changed our approach
to API compatibility, and will likely not need it anymore.
2014-08-29 12:31:52 +02:00
wm4 4bc9c52a12 bstr: preparation for next commit
Just so I can move this file without modifying its contents in the next
commit.

compat/compiler.h is to be moved to osdep/ with the next commit, so add
a dummy header.
2014-08-29 12:16:55 +02:00
wm4 ac2502141d stream: tweaks to network reconnection code
Don't reconnect to the cache (since the cached stream already handles
reconnection). This is necessary, because since commit 0b428e44 the
"streaming" field (which also controls whether attempting to reconnect
makes sense at all) is inherited to the cache stream wrapper.

Also, let the stream reset its own position on reconnect. This removes
some assumptions and messy handling from the reconnect function.

Make sure the cache is dropped on reconnect. This takes care of
readjusting the stream position if necessary. (Also drop the cache on
DVB channel switching commands.)
2014-08-29 11:58:49 +02:00
Ryan Jacobs 66f158b89b command: remove extra space
Signed-off-by: wm4 <wm4@nowhere>
2014-08-29 11:58:25 +02:00
wm4 ff7a1c21ce options: more detailed output for --vf-... error message 2014-08-28 17:51:33 +02:00
wm4 e47a9bd721 command: export demuxer cache info properties 2014-08-28 17:49:10 +02:00
wm4 fb1266c98b player: update cache state only if requested
Add a mechanism to the client API code, which allows the player core to
query whether a client API event is needed at all. Use it for the cache
update.

In this case, this is probably a pure microoptimization; but the
mechanism will be useful for other things too.
2014-08-28 17:49:09 +02:00
wm4 f9f436a490 audio: restore old speed change behavior
Don't attempt to resync after speed changes. Note that most other cases
of audio reinit (like switching tracks etc.) still resync, but other
code paths take care of setting the audio_status accordingly.

This restores the old behavior of not trying to fix audio desync, which
was probably changed with commit 261506e3.

Note that the code as of now wasn't even entirely correct, since the A/V
sync values are slightly shifted. The dsync depends on the audio buffer
size, so a larger buffer size will show more extreme desync. Also see
mplayer2 commit 213a224e, which should fixed this - it was not merged
into mpv, because it disabled audio for too long, resulting in a worse
user experience. This is similar to the issue this commit attempts to
fix.

Fixes: #1042 (probably)
CC: @mpv-player-stable
2014-08-28 14:26:38 +02:00
Ben Boeckel 7c0a5698eb posix: use STD*_FILENO constants
Rather than "magic" numbers, use meaningful constant names provided by
unistd.h.
2014-08-28 12:03:17 +02:00
Ben Boeckel 2a44e2d1b2 tv: initialize frequencies to 0 2014-08-28 12:02:50 +02:00
Ben Boeckel 9780ff9642 player: simplify chapter display name code
The display name is always recomputed, so we can always toss the input
name.
2014-08-28 12:02:41 +02:00
Ben Boeckel e023524481 player: don't sort a NULL list
This can occur if the directory does not have any files in it which
causes files to never be non-NULL for qsort.
2014-08-28 12:02:09 +02:00
wm4 a95cfac078 vo_opengl: don't pass (char*)NULL as %s printf argument
glGetString(GL_SHADING_LANGUAGE_VERSION) can return NULL; I suppose this
happens on legacy OpenGL, while all the other fields are guaranteed to
exist.
2014-08-28 01:52:15 +02:00
wm4 2c99464b47 vo_opengl: fix shader
Regression since commit f14722a4. For some reason, this worked on
nvidia, but rightfully failed on mesa.

At least in C, the ## operator indeed needs two macro arguments, and
you can't just concatenate with non-arguments.

This change will most likely fix it.

CC: @bjin
2014-08-28 00:40:37 +02:00
wm4 f8a1bd1253 player: dynamically change cache wait times
Remove the hardcoded wait time of 2 seconds. Instead, adjust the wait
time each time we unpause: if downloading the data took longer than its
estimated playback time, increase the amount of data we wait for. If
it's shorter, decrease it.

The +/- is supposed to avoid oscillating between two values if the
elapsed time and the wait time are similar. It's not sure if this
actually helps with anything, but it can't harm.
2014-08-27 23:24:55 +02:00
wm4 cb642e7c84 player: slightly better cache underrun detection
Use the "native" underrun detection, instead of guessing by a low cache
duration. The new underrun detection (which was added with the original
commit) might have the problem that it's easy for the playloop to miss
the underrun event. The underrun is actually not stored as state, so if
the demuxer thread adds a new packet before the playloop happens to see
the state, it's as if it never happened. On the other hand, this means
that network was fast enough, so it should be just fine.

Also, should it happen that we don't know the cached range (the
ts_duration < 0 case), just wait until the demuxer goes idle (i.e.
read_packet() decides to stop). This pretty much should affect broken or
unusual files only, and there might be various things that could go
wrong. But it's more robust in the normal case: this situation also
happens when no packets have been read yet, and we don't want to
consider this as reason to resume playback.
2014-08-27 23:12:49 +02:00
wm4 7bb1afb8ea demux_lavf: don't reject av:// if cache is enabled
Enabling the cache doesn't make much in this situation, but there's also
no reason not to reject it.
2014-08-27 23:12:49 +02:00
wm4 1c44db2992 demux: reset idle state on seeks 2014-08-27 23:12:49 +02:00
wm4 c7208319d3 player: better cache status on status line
The cache percentage was useless. It showed how much of the total stream
cache was in use, but since the cache size is something huge and
unrelated to the bitrate or network speed, the information content of
the percentage was rather low.

Replace this with printing the duration of the demuxer-cached data, and
the size of the stream cache in KB.

I'm not completely sure about the formatting; suggestions are welcome.
Note that it's not easy to know how much playback time the stream cache
covers, so it's always in bytes.
2014-08-27 23:12:47 +02:00
wm4 dad90f616d player: fix basic playback
The "buffering" logic was active even if the stream cache was disabled.
This is contrary to what the manpage says. It also breaks playback
because of another bug: the demuxer cache is smaller than 2 seconds,
and thus the resume condition never becomes true.

Explicitly run this code only if the stream cache is enabled. Also, fix
the underlying problem of the breakage, and resume when the demuxer
thread stops reading in any case, not just on EOF.

Broken by previous commit. Unbreaks playback of local files.
2014-08-27 10:59:22 +02:00
wm4 0b428e4482 player: redo how stream caching and pausing on low cache works
Add the --cache-secs option, which literally overrides the value of
--demuxer-readahead-secs if the stream cache is active. The default
value is very high (10 seconds), which means it can act as network
cache.

Remove the old behavior of trying to pause once the byte cache runs
low. Instead, do something similar wit the demuxer cache. The nice
thing is that we can guess how many seconds of video it has cached,
and we can make better decisions. But for now, apply a relatively
naive heuristic: if the cache is below 0.5 secs, pause, and wait
until at least 2 secs are available.

Note that due to timestamp reordering, the estimated cached duration
of video might be inaccurate, depending on the file format. If the
file format has DTS, it's easy, otherwise the duration will seemingly
jump back and forth.
2014-08-27 03:39:04 +02:00
wm4 a8513f8b37 demux: reduce wakeups if no cache is active
The purpose of the unconditional pthread_cond_signal() when reading
cached DEMUXER_CTRLs and STREAM_CTRLs was apparently to update the
stream cache state. Otherwise, the cached fields would never be updated
when the stream is e.g. paused.

The same could be said about other CTRLs, but these aren't as important,
since they are normally updated while reading packet data.

In order to reduce wakeups, make this logic explicit.
2014-08-27 00:20:38 +02:00
Bin Jin 08b5dccd12 vo_opengl: add parameter to gaussian filter
Add a new parameter 'p' to gaussian filter. The new formula used
 a different base taken from fmtconv plugin, so that the
 new parameter is exactly same as the one used in Avisynth and
 Vapoursynth.

 The new default value is 2 / log(2) * 10, with the default value it
 conforms to the original kernel taken from vector-agg.
2014-08-26 22:19:32 +02:00
Bin Jin b3e788d3f4 vo_opengl: add radius options for filters
Add two new options, make it possible for user to set the radius
for some of the filters with no fixed radius.

Also add three new filters with the new radius parameter supported.
2014-08-26 22:19:30 +02:00
Bin Jin f14722a40f vo_opengl: add cparam1 and cparam2 options
Although cscale is rarely used, it's possible that params of cscale
are accidentally set to lparam1 and lparam2, which might cause
unexpected results.
2014-08-26 22:19:27 +02:00
Bin Jin a8b67c66f2 vo_opengl: add spline64 filter kernel
The coefficients are taken from fmtconv plugin for vapoursynth:
https://github.com/vapoursynth/fmtconv/blob/master/src/fmtc/ContFirSpline64.cpp

The package is licensed under WTFPL, and it's from the same author
of Dither plugin for avisynth.
2014-08-26 22:18:55 +02:00
wm4 3ec6705e34 TOOLS: youtube wrapper: allow overriding mpv binary 2014-08-26 20:47:30 +02:00
wm4 3cc3dea915 player: fix weird behavior when framestepping over format changes
When video format changes, the frame before the frame with the new
format sets video_status briefly to STATUS_DRAINING. This caused the
code to handle the EOF case to kick in, which just pauses the player
when trying to step past the last frame. As a result, trying to
framestep over format changes resulted in pausing the player.

Fix by testing against the correct status.
2014-08-26 20:45:41 +02:00
wm4 b7f72aa2f4 input: make key bindings like "Shift+X" work (for ASCII)
"Shift+X" didn't actually map any key, as opposed to "Shift+x". This is
because shift usually changes the case of a character, so a plain
printable character like "X" simply can never be combined with shift.

But this is not very intuitive. Always remove the shift code from
printable characters. Also, for ASCII, actually apply the case mapping
to uppercase characters if combined with shift. Doing this for unicode
in general would be nice, but that would require lookup tables. In
general, we don't know anyway what character a key produces when
combined with shift - it could be anything, and depends on the keyboard
layout.
2014-08-26 20:39:28 +02:00
wm4 480febf043 input: make all modifier flags unsigned 2014-08-26 20:39:23 +02:00
Otto Modinos cc971c06f4 manpage: mention that mp.commandv doesn't expand properties
The little lua snippet at #488 as well as the actual implementation
seems to indicate that not expanding properties is indeed the correct
behavior.  Document that.

Signed-off-by: wm4 <wm4@nowhere>
2014-08-25 22:18:25 +02:00
wm4 6410c4c8ef input: stdin is 0, not 1
Oops. I can never remember this right.
2014-08-25 21:39:24 +02:00
wm4 f104ef1282 player: minor changes
This shouldn't change anything functionally.

Change the A/V desync message. --framedrop is enabled by default now, so
the text must be changed a little. I've never heard of audio outputs
messing up A/V sync recently, so remove that part.

Remove the unused ao_pts field.

Reorder 2 A/V sync related expressions so that they look the same.
2014-08-25 21:39:24 +02:00
Stefano Pigozzi f4ccf22e16 coreaudio_device: fix overwriting of user input
Fixes #1030
2014-08-25 10:08:54 +02:00
wm4 740f0f61d8 input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.

This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.

On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.

Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.

Tested on wine; might not work on a real Windows.
2014-08-25 01:00:21 +02:00
wm4 cae22ae3b6 msg: allow duplicating a mp_log
Trivial; this is mostly just reindenting the normal codepath.
2014-08-25 00:48:56 +02:00
wm4 95286cd8b8 command: change OSD formatting of "speed" property
The "x   " prefix annoyed some users.
2014-08-25 00:48:55 +02:00
wm4 12509fabc7 options: compatibility hack for --slave-broken
Seems some programs were still relying on it. Whatever, it's not hard to
support.

CC: @mpv-player/stable
2014-08-25 00:48:55 +02:00
wm4 20d88a6dea input: change verbosity of some message levels
For --input-test, print messages on terminal by default.

Raise message level for enabling input sections, because the OSC makes
this very extremely annoying.
2014-08-25 00:48:55 +02:00
wm4 f7eea070f0 vo_opengl: don't cut off feature list output 2014-08-25 00:48:55 +02:00
wm4 758f8f7bd4 demux: always use AVPacket
This is a simplification, because it lets us use the AVPacket
functions, instead of handling the details manually.

It also allows the libavcodec rawvideo decoder to use reference
counting, so it doesn't have to memcpy() the full image data. The change
in av_common.c enables this.

This change is somewhat risky, because we rely on the following AVPacket
implementation details and assumptions:
- av_packet_ref() doesn't access the input padding, and just copies the
  data. By the API, AVPacket is always padded, and we violate this. The
  lavc implementation would have to go out of its way to make this a
  real problem, though.
- We hope that the way we make the AVPacket refcountable in av_common.c
  is actually supported API-usage. It's hard to tell whether it is.

Of course we still use our own "old" demux_packet struct, just so that
libav* API usage is somewhat isolated.
2014-08-25 00:46:26 +02:00
James Ross-Gowan ef1c6e9295 win32: correct SGR sequence handling
This should get colour working again on the Windows console.

Fixes #1032.
2014-08-24 13:23:11 +02:00
James Ross-Gowan 67c6335efc win32: correct HANDLE type
The correct type is HANDLE, not HANDLE*, though this change shouldn't
affect functionality.
2014-08-24 13:23:09 +02:00
wm4 c31a91230d demux: avoid unnecessary wakeups
If a packet is appended to a stream, and there were already packets
queued, nothing about the state changed, as far as the user (i.e. the
player) is concerned. Thus no wakeup is needed.

The pthread_cond_signal() call following this is not interesting - it
will simply be a NOP if there are actually no waiters.
2014-08-24 13:21:32 +02:00
wm4 2c114db2f1 sd_lavc: remove ineffective code
It makes no sense to set the packet duration, because libavcodec doesn't
know the timebase. And in fact, no subtitle decoder accesses the packet
duration, except text subtitle converters, which are not relevant here.
So this code did nothing - drop it.

Also fix a blatantly incorrect comment.
2014-08-24 12:26:34 +02:00
wm4 1cedb323ad video: avoid unnecessary frame dropping
If duration<0, it means the duration is unknown. Disable framedropping,
because end_time makes no sense in this case.

Also, strictly never drop the first frame.

This fixes weird behavior with the cover-art case (for the 100th time).
2014-08-23 12:48:45 +02:00
wm4 39b42814e0 player: restore silent seeking
Commit 846257da introduced an accidental feature: if you kept seeking
(so playback never really resumes), the audio would never be played.
This was nice, but commit 4c25b000 accidentally removed it again (due
to the video_next_pts being earlier available than it used to be, so
audio could be played before the player executed the next queued seek).

Implicitly reintroduce the old behavior again by not decoding a second
video frame immediately. Usually, the second frame is used to compute
the frame duration needed to for accurate framedropping, but since the
first frame after a seek is never dropped, we don't need this.

Now the video code will queue the new frame to the VO immediately, and
since fill_audio_out_buffers() is called in the playloop before
write_video() and execute_queued_seek(), it never gets the chance to
enter STATUS_READY, and seeks will be silent.

This also has a nice side-effect: since the second frame is not decoded
and filtered, seeking becomes slightly faster (back to the same level
as with framedrop disabled).

It seems this still sometimes plays a period of audio when keeping a
seek key down. In my tests, this appeared to happen because the seek
finished before the next key repeat was sent.
2014-08-23 12:02:40 +02:00
wm4 21f52aeeba audio: minor improvements to timeline switching
In theory, timestamps can be negative, so we shouldn't just return -1
as special value.

Remove the separate code for clearing decode buffers; use the same code
that is used for normal seek reset.
2014-08-23 11:39:07 +02:00
wm4 b55e093075 demux_lavf: fix crash with unknown streams
Could happen with DVD .vob files.
2014-08-23 04:49:54 +02:00
ChrisK2 4386b80f2e osc: Use osd-font for playlist buttons
Now that we use the symbols from the font, we should also
actually use the font.
2014-08-22 23:50:50 +02:00
wm4 005f592d54 player: some more debugging output 2014-08-22 16:25:55 +02:00
wm4 d5fa5a96a8 video: some debugging output 2014-08-22 16:21:58 +02:00
wm4 d0b64a6fc4 input.conf: bind ctrl+c
Just like I can terminate it on the terminal with this key combination,
I want to be able to do the same on the X window.
2014-08-22 16:18:09 +02:00
wm4 26500425f6 ao_dsound: raise default buffer size to 200ms, make it configurable 2014-08-22 16:12:47 +02:00
wm4 4c25b000b5 player: fix recent speed change regression
Commit 5afc025c broke this. The reason is that mpctx->delay is updated
when a new video frame is added. This value is also needed to resync
audio, but it will be for the wrong PTS. They must be consistent with
each other, and if they aren't, initial sync will be off by N video
frames, which results at least in worse user experience.

This can be reproduced by for example heavily switching between normal
and 2x speed, or similar.

Fix by readding the video_next_pts field (keeping its use minimal,
instead of reverting the commit that removed it).
2014-08-22 15:36:48 +02:00
wm4 75005ec06d player: don't clobber playback position on video end
If video reaches EOF, and audio is also EOF (or is otherwise not
meaningful, like audio disabled), then the playback position was briefly
set to 0. Fix this by not trying to use a bogus audio PTS.

CC: @mpv-player/stable (maybe)
2014-08-22 14:22:06 +02:00
wm4 e9e73f8d03 video: refactor queue handling
This simplifies the code, and fixes an odd bug: the second-last frame
was displayed for a very short duration if framedrop was enabled. The
reason was that basically the time difference between second-last and
last frame were skipped, because at this point EOF was already
signaled. Also see commit b0959488 for a similar issue in the
same code.

This removes the messiness of the next_frame 2-frame queue, and
strictly runs the "new frame" code when a frame is moved to the first
position of the queue, instead of somehow messing with return codes.

This also merges update_video() into video_output_image().
2014-08-22 14:22:06 +02:00
wm4 5afc025cc9 video: get rid of video_next_pts field
Not really needed anymore. Code should be mostly equivalent.

Also get rid of some other now-unused or outdated things.
2014-08-22 14:22:06 +02:00
wm4 7b3a889c92 video: move some code around
No functional changes. init_vo() is now needed a bit further down, and
moving it keeps definition and use close. adjust_sync() will be used by
a function further up in one of the following commits.
2014-08-22 14:22:06 +02:00
wm4 bc90f71d35 video: minor simplification
This is mostly equivalent, but simpler, and reduces some duplication.
2014-08-22 14:22:06 +02:00
Bin Jin aeb3f08280 manpage: remove duplicated content
Probably be accidentally added in b6b8bffd.

CC: @mpv-player/stable
Signed-off-by: wm4 <wm4@nowhere>
2014-08-22 14:22:06 +02:00
Bin Jin 1e12afa80a vf_vapoursynth: add more VS frame properties
Add the missing frame properties in 48587e88.
2014-08-22 14:22:06 +02:00
Bin Jin 96c2021cb1 vf_vapoursynth: add display resolution support
Add two new script environment variables 'video_in_dw' and
'video_in_dh', representing the display resolution of video. Along
with video resolution, sample ratio aspect can be calculated in
scripts.

Currently it's impossible to change sample ratio aspect with single
vapoursynth filter since '_SARNum' and '_SARDen' frame properties
from output clip will be ignored. A following 'dsize' filter is
necessary for this purpose.
2014-08-22 14:22:04 +02:00
wm4 e2d27cded7 osc: revert disabling use_suspend
It was an unintended/accidental change.
2014-08-21 22:46:33 +02:00
wm4 c41fdfb4ef build: disable terminfo and termcap code by default
If nobody complains soon enough, I will remove the code completely.
2014-08-21 22:45:58 +02:00
wm4 4b5c3ea7a7 terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.

It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)

Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).

Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.

This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.

This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 22:45:58 +02:00
wm4 58a9610acf terminal-win: read input from a thread
Surprisingly, WaitFor* works on console handles. We can simply run the
code for reading the console in a thread, and don't have to worry about
crazy win32 crap in the rest of the player's input code anymore.

This also fixes the issue that you couldn't unpause the player from the
terminal, because the player would stop polling for input.
2014-08-21 22:45:58 +02:00
wm4 5890e59dbc terminal: some cleanups
In particular, remove all the stupid debug printfs from the win code.
2014-08-21 22:45:58 +02:00
wm4 070c54dff4 terminal-win: remove nonsensical code
Something about a non-working MinGW thing? Really, I don't care. It
also prevents using the console API properly.
2014-08-21 22:45:58 +02:00
wm4 47b29094c3 win32: emulate some ANSI terminal escape codes
We already redirect all terminal output through our own wrappers (for
the sake of UTF-8), so we might as well use it to handle ANSI escape
codes.

This also changes behavior on UNIX: we don't retrieve some escape codes
per terminfo anymore, and just hardcode them. Every terminal should
understand them.

The advantage is that we can pretend to have a real terminal in the
normal player code, and Windows atrocities are locked away in glue
code.
2014-08-21 22:45:58 +02:00
wm4 218ace2b02 audio: limit on low (and not high) buffer size
The original intention was probably to avoid unnecessarily high numbers
of wakeups. Change it to wait at most 25% of buffer time instead of 75%
until refilling. Might help with the dsound problems in issue #1024, but
I don't know if success is guaranteed.
2014-08-21 22:45:58 +02:00
wm4 f1e78306cb vaapi: try dealing with Intel's braindamaged shit drivers
So talking to a certain Intel dev, it sounded like modern VA-API drivers
are reasonable thread-safe. But apparently that is not the case. Not at
all. So add approximate locking around all vaapi API calls.

The problem appeared once we moved decoding and display to different
threads. That means the "vaapi-copy" mode was unaffected, but decoding
with vo_vaapi or vo_opengl lead to random crashes.

Untested on real Intel hardware. With the vdpau emulation, it seems to
work fine - but actually it worked fine even before this commit, because
vdpau was written and designed not by morons, but competent people
(vdpau is guaranteed to be fully thread-safe).

There is some probability that this commit doesn't fix things entirely.
One problem is that locking might not be complete. For one, libavcodec
_also_ accesses vaapi, so we have to rely on our own guesses how and
when lavc uses vaapi (since we disable multithreading when doing hw
decoding, our guess should be relatively good, but it's still a lavc
implementation detail). One other reason that this commit might not
help is Intel's amazing potential to fuckup anything that is good and
holy.
2014-08-21 22:45:58 +02:00
ChrisK2 03f97e4cae osd+osc: Add left-arrow to osd-font
For use as playlist navigation button in OSC, now the osd-font
carries all symbols needed by the OSC.
2014-08-21 18:45:41 +02:00
wm4 c3cc9e8b88 etc/mpv.desktop: add audio/flac mimetype
Fixes #1025.

CC: @mpv-player/stable
2014-08-21 01:06:18 +02:00
wm4 7758c15e95 video: don't assume query_format is thread-safe
Although it's probably safe for most VOs, there's no guarantee.
2014-08-20 21:35:45 +02:00
wm4 09897bed7f terminal-unix: eliminate unnecessary variable 2014-08-20 21:19:20 +02:00
Alexander Preisinger 614ff883bc wayland: replace deprecated xkbcommon functions
Available and stable since forever (xkbcommon 0.2).
2014-08-20 17:16:18 +02:00
Alexander Preisinger 631be0774d options.rst: fix warning 2014-08-20 16:44:19 +02:00
Alexander Preisinger 759fdcb2f9 vo_wayland: fix formatting inconsistencies 2014-08-20 16:40:33 +02:00
Alexander Preisinger 3bf83f7642 vo_wayand: save the flip time in the frame handler
This value is more accurate than the default value.
2014-08-20 16:35:06 +02:00
Andrey Morozov 1cb15316b0 command: add estimated-frame-count & estimated-frame-number properties
Signed-off-by: wm4 <wm4@nowhere>
2014-08-19 21:47:14 +02:00
wm4 960f0ccfa1 example.conf: demuxer-thread is now enabled by default
Provide a more useful example instead.
2014-08-19 20:10:26 +02:00
wm4 3c07e86fd3 TOOLS/stats-conv.py: improvements
This is still pretty useful for debugging timing-dependent things.
2014-08-19 20:09:46 +02:00
wm4 3d968fc620 video: add VOCTRL_GET_RECENT_FLIP_TIME
This could be used by VO implementations to report a recent vsync time
to the generic VO code, which in turn will use it and the display FPS
to estimate at which point in time the next vsync will happen.
2014-08-18 23:04:31 +02:00
wm4 cd2e4db8a5 vo_opengl: add check-pattern suboption for testing
This uses glXGetVideoSyncSGI() to check how many vsyncs happened since
the last flip_page() call. It allows checking a pattern of vsync
increments of at most 2 elements. For example, to check ~24 fps playback
on a ~60 Hz monitor, this can be used:

--vo=opengl:check-pattern=[3-2]:waitvsync

Whether the reported results are accurate or just plain wrong may depend
on the driver and if the waitvsync sub-option is used. There are no
guarantees.

This option is undocumented, and may be removed again in the near or
distant future.
2014-08-18 23:04:31 +02:00
wm4 aaadcef52f video: dump vsync phase into stats file
For debugging (drawing fun plots with TOOLS/stats-conv.py).

Also move last_flip under the correct comment: it's not protected by the
lock, and can be accessed by the VO thread only.
2014-08-18 23:04:28 +02:00
wm4 7520d39e8b vaapi: we need more surfaces
Playing with high framedrop could make it run out of surfaces. In
theory, we wouldn't need an additional surface, if we could just clear
the vo_vaapi internal surface - but doing so would probably be a pain,
so I don't care.
2014-08-18 22:59:01 +02:00
Alexander Preisinger 752dce9284 wayland: dynamically report display fps
Only reports the most recently entered output if the window is displayed on
2 or more outputs. Should be changed to the lowest fps of all outputs the
window is visible. Until no one complains this will have to wait.

Look for the VO framedropping for more information on this topic.
2014-08-18 22:00:39 +02:00
wm4 39b8b0a41f manpage: fix opengl-hq defaults
The FBO format was changed some time ago.

CC: @mpv-player/stable
2014-08-18 02:05:06 +02:00
wm4 52ead45f05 command: drop " %" from "cache" property OSD-formatting 2014-08-18 01:42:43 +02:00
wm4 9f31b73cda player: never print status messages before playback begins
After a new file is loaded, playback never starts instantly. Rather, it
takes some playloop iterations until initial audio and video have been
decoded, and the outputs have been (lazily) initialized. This means you
will get status line updates between the messages that inform of the
initialized outputs. This is a bit annoying and clutters the terminal
output needlessly.

Fix this by never printing the status line before playback isn't fully
initialized. Do this by reusing the --term-playing-msg code (which
prints a message once playback is initialized). This also makes sure the
status line _is_ shown during playback restart when doing seeks.

It's possible that the change will make the output more confusing if for
some reason is stuck forever initializing playback, but that seems like
an obscure corner case that never happens, so forget about it.
2014-08-18 01:25:59 +02:00
wm4 eb2924054f player: remove unneeded call
print_status() is called at a later point anyway (and before sleeping),
so this code has little effect. This code was added in commit a4f7a3df5,
and I can't observe any problems with idle mode anymore.

Now print_status() is called from a single place only, within osd.c.
2014-08-18 01:21:21 +02:00
wm4 0cee4498f1 DOCS/tech-overview.txt: some updates 2014-08-18 01:21:13 +02:00
wm4 1e04c474ab x11: listen to xrandr events
If the Xrandr configuration changes, re-read it. So if you change
display modes or screen configuration, it will update the framedrop
refresh rate accordingly.

This passes the rootwin to XRRSelectInput(), which may or may not be
allowed. But it works, and the documentation (which is worse than used
toilet paper, great job Xorg) doesn't forbid it, or in fact say anything
about what the window parameter is even used for.
2014-08-17 15:39:18 +02:00
Philip Sequeira b36ed6d9f9 TOOLS/zsh.pl: protect global environment 2014-08-17 12:51:10 +02:00
Philip Sequeira c7e67d008a TOOLS/zsh.pl: fix a ret that hadn't been changed to rc 2014-08-17 12:51:10 +02:00
Philip Sequeira 4b8f512217 TOOLS/zsh.pl: complete profiles
Implemented in shell, because it has to be done at runtime.
2014-08-17 12:51:10 +02:00
wm4 3778e63330 x11: fix xrandr conditional compilation
Oops.

Fixes #1020.
2014-08-17 04:35:24 +02:00
wm4 61b0163d58 af_lavrresample: minor cosmetics 2014-08-17 03:29:09 +02:00
wm4 513779d3b8 video: make vo_opengl the default over vo_vdpau
Nvidia's vdpau implementation is pretty good, but other factors make it
much less attractive for use as default VO. For example, Mesa often has
low quality drivers (mess up things with the presentation queue and the
vdpau API time source). Intel ruins things completely, and we're likely
to run on emulation via OpenGL. Compositing has unknown effects (to me
anyway), but appears to reduce the vdpau advantages.

One important reason to prefer vo_vdpau was that it could do proper
framedropping. Framedropping got fixed for the other VOs, so this reason
is going away.
2014-08-17 02:54:50 +02:00
wm4 761037dcc6 video: enable framedropping by default 2014-08-17 02:51:13 +02:00
wm4 5b64f5ad35 video: take refresh rate changes into account
This works only on X11, and only if the refresh rate changes due to the
window being moved to another screen (detected by us). It doesn't
include system screen reconfiguration yet.

This calls VOCTRL_GET_DISPLAY_FPS on every frame, which makes me uneasy.
It means extra thread communication with the win32 and Cocoa backends.
On the other hand, a frame doesn't happen _that_ often, and the
communication should still be pretty cheap and fast, so it's probably
ok.

Also needs some extra fuzz for vo_vdpau.c, because that does everything
differently.
2014-08-17 02:50:59 +02:00
wm4 4822056db7 x11: fix memory leaks
Oh, we have to free this stuff. OK.
2014-08-17 02:47:44 +02:00
wm4 d811f6a9ed build: use pkg-config for xscreensaver 2014-08-16 22:00:00 +02:00
wm4 f8f3a1b4a1 build: drop check for XF86keysym.h
This is always included in the Xorg development headers. Strictly
speaking it's not necessarily available with other X implementations,
but these are hopefully all dead.
2014-08-16 21:57:51 +02:00
wm4 fe782a6e95 x11: use xrandr to retrieve display refresh rate
Drop use of the ancient XF86VM, and use the slightly less ancient Xrandr
extension to retrieve the refresh rate. Xrandr has the advantage that it
supports multiple monitors (at least the modern version of it).

For now, we don't attempt any dynamic reconfiguration. We don't request
and listen to Xrandr events, and we don't notify the VO code of changes
in the refresh rate. (The later works by assuming that X coordinates map
directly to Xrandr coordinates, which probably is wrong with compositing
window manager, at least if these use complicated transformations. But I
know of no API to handle this.)

It would be nice to drop use of the Xinerama extension too, but
unfortunately, at least one EWMH feature uses Xinerama screen numbers,
and I don't know how that maps to Xrandr outputs.
2014-08-16 21:56:22 +02:00
wm4 925c431ff7 demux: enable thread by default
And change the defaults for the other queue options to reduce latency.
2014-08-16 17:15:51 +02:00
wm4 b822faa6cf demux: add option to control the readahead buffer by a duration value
--demuxer-readahead-secs now controls how much the demuxer should
readahead by an amount of seconds. This is based on the raw packet
timestamps. It's not always very exact. For example, h264 in Matroska
does not store any linear timestamps (only PTS values which are going
to be reordered by the decoder), so this heuristic is usually off by
several hundred milliseconds.

The decision whether to readahead is basically OR-ed with the other
--demuxer-readahead-packets options. Change the manpage descriptions
to subtly convey these semantics.
2014-08-16 17:10:08 +02:00
wm4 e6e3bc7cd9 demux: remove unused function 2014-08-16 17:10:08 +02:00
wm4 14c1d864d9 player: cosmetics: make code more compact 2014-08-16 17:10:08 +02:00
wm4 a4cfab7ee0 vo_wayland: fix redrawing logic
I must have broken it some time ago. The error case dealing with an
unavailable backbuffer was broken, and didn't handle memory management
correctly.
2014-08-16 17:09:59 +02:00
wm4 4f984b987c video: add --display-fps switch to control framedrop FPS
Since the display FPS is currently detected on X11 only (and even there
it's known to be wrong on certain setups), it seems like a good idea to
make this user-configurable.
2014-08-16 00:05:02 +02:00
wm4 07aba86b37 audio: add a mode to insert silence on severe A/V desync
This is probably a stupid idea, but it can't be denied that this
actually allows playing video without larger desync, even if video is
too slow.
2014-08-15 23:52:42 +02:00
wm4 72ee9bb56c vo_opengl: optional support for using GLX_SGI_video_sync
I'm not sure about the merit, though it does print nice numbers if debug
output is enabled.

Basically, this tries to achieve similar results as the glFinish()
business, but again it entirely depends on the drivers whether this
does anything meaningful, or whether it's actively harmful.
2014-08-15 23:36:13 +02:00
wm4 db65151890 gl_common: add SGI_video_sync extension 2014-08-15 23:36:10 +02:00
wm4 4a297554bc vo_opengl: if glfinish is used, also call it after swappping
It seems that at least on nvidia systems with composting disabled, we
can get it to block deterministically on the actual vsync event, which
should improve framedropping.
2014-08-15 23:36:02 +02:00
wm4 543ba6c114 video: add VO framedropping mode
This mostly uses the same idea as with vo_vdpau.c, but much simplified.

On X11, it tries to get the display framerate with XF86VM, and limits
the frequency of new video frames against it. Note that this is an old
extension, and is confirmed not to work correctly with multi-monitor
setups. But we're using it because it was already around (it is also
used by vo_vdpau).

This attempts to predict the next vsync event by using the time of the
last frame and the display FPS. Even if that goes completely wrong,
the results are still relatively good.

On other systems, or if the X11 code doesn't return a display FPS, a
framerate of 1000 is assumed. This is infinite for all practical
purposes, and means that only frames which are definitely too late are
dropped. This probably has worse results, but is still useful.

"--framedrop=yes" is basically replaced with "--framedrop=decoder". The
old framedropping mode is kept around, and should perhaps be improved.
Dropping on the decoder level is still useful if decoding itself is too
slow.
2014-08-15 23:33:33 +02:00
wm4 22a9529012 vo: eliminate a redundant variable
Originally, I probably had plans to allow NULL images to handle things
like the last frame case, but that idea was dropped later.
2014-08-15 23:32:45 +02:00
wm4 fa7c421588 player: use virtual time for --audio-file with ordered chapters
Apparently users prefer this behavior.

It was used for subtitles too, so move the code to calculate the video
offset into a separate function. Seeking also needs to be fixed.

Fixes #1018.
2014-08-15 23:32:37 +02:00
wm4 318e8da250 lua: wake up the core when setting OSD
The OSD is marked as changed, but the core isn't notified and this
doesn't immediately wakeup. (Possibly the OSD code should wakeup the
core instead, but maybe that woudl be overkill.)

Observed when using "mp.use_suspend = false" in the OSC, and pausing,
and moving the mouse pointer out of the window. The last part of the
fade remained visible for longer than intended.
2014-08-15 23:32:31 +02:00
ChrisK2 364e06261a osc: Overhaul (wip)
Code reorganized to make layouts exchangeable
alternative test layout can be tested with
layout=slimbox
in the OSC config

timers are now used to properly animate the fade out when the
player is paused

duplicate seeks are discarded again
2014-08-15 15:24:22 +02:00
wm4 d5940fabcd sub: add option to workaround broken mkv files
See additions to options.rst.
2014-08-14 23:59:35 +02:00
wm4 498644afaf sub: call sub_reset() on seeks only
sub_reset() was called on cycling subtitle tracks and on seeking. Since
we don't want that subtitles disppear on cycling, sd_lavc.c didn't clear
its internal subtitle queue on reset, which meant that seeking with PGS
subtitles could leave the subtitle on screen (PGS subtitles usually
don't have a duration set).

Call it only on seeking, so we can also strictly clear the subtitle
queue in sd_lavc.

(This still can go very wrong if you disable a subtitle, seek, and
enable it again - for example, if used with libavformat that uses "SSA"
style demuxed ASS subtitle packets. That shouldn't happen with newer
libavformat versions, and the user can "correct" it anyway by executing
a seek while the subtitle is selected.)
2014-08-14 23:53:53 +02:00
wm4 a7107686d7 client API: directly lock playloop
Until recently, vo_opengl could be accessed from a single thread only,
due to the OpenGL API context being thread-specific. This issue doesn't
exist anymore, because VOs run on their own thread. This means we can
simply lock/unlock the playloop instead of doing something complicated
to get the playloop thread to execute our code.
2014-08-14 19:40:43 +02:00
wm4 8f77d9df4a lua: allow disabling suspend
I'd like to enable this by default, but unfortunately the OSC seems to
have some problems with it.
2014-08-14 19:30:35 +02:00
wm4 a31330608b client API: adjust documentation for mpv_suspend()
It's not true anymore that the core will stop replying for 50ms
(waiting for video) without calling this function. Simplify the
documentation accordingly. Accessing properties that go through
the VO still have this problem, though.
2014-08-14 19:29:21 +02:00
wm4 51a7070e26 vo: remove unused libavutil include 2014-08-14 19:29:02 +02:00
wm4 de399278fc vo: fix mingw compilation 2014-08-14 01:30:20 +02:00
wm4 061a5af544 demux_lavf: support new metadata update API
This Libav-invented API is of course completely different from the
FFmpeg-one. (The fun part is that I approved of both.)
2014-08-14 01:18:18 +02:00
Alessandro Ghedini e7cab32fae TOOLS/zsh.pl: properly set the return value
The previous commit made the completion script always return non-zero, even when
a match is found. This explicitly sets the return value to zero whenever a match
is found but defaults to non-zero in case nothing is matched.
2014-08-13 23:42:38 +02:00
c_14 fd98863b1f TOOLS/zsh.pl: properly return non-zero when no matches are found
Returning a non-zero value signals to the zsh completion system that no matches
were added by the script so that it can try the user-defined matchers (e.g.
those defined with matcher-list).

Fixes #1008.
2014-08-13 22:57:59 +02:00
Alexander Preisinger 69a160f187 wayland: pointer interface is created after theme
Just always load the theme. It gets freed properly and dosn't bother anyone.

Fixes #1012.

CC: @mpv-player/stable
2014-08-13 22:34:18 +02:00
wm4 3eaa407c6f video: reduce non-sense messages when playing coverart
Don't print PTS warnings by skipping the normal video path.
2014-08-13 22:01:10 +02:00
wm4 b0959488d1 video: don't run new frame processing on every iteration
This ran adjust_sync() on every playloop iteration, instead of every
newly decoded frame. It seems this was idempotent in the common case,
but the code was originally designed to be run once only, so restore
that.
2014-08-13 22:01:10 +02:00
wm4 4a325a8592 video: move some more code around
No functional changes.
2014-08-13 22:01:09 +02:00
wm4 48bd1294eb video: move some code around 2014-08-13 21:53:47 +02:00
wm4 311ce60b16 video: exit early when nothing to do
These cases were probably confusing. Exit early, which makes it much
clearer what's going on. Should not change anything functionally.
2014-08-13 21:51:26 +02:00
wm4 d4e0fc76bb video: minor simplification of the old framedrop code
No changes in functionality, other than being slightly more correct at
stream EOF.
2014-08-13 21:50:23 +02:00
wm4 010b86fd34 player: don't quit with --loop-file
Fixes #1009.

CC: @mpv-player/stable
2014-08-13 21:50:01 +02:00
Alessandro Ghedini 2607d6e419 vdpau: correctly mark invalid mixer as such on vdp_video_mixer_create() failure
Otherwise vdp_video_mixer_destroy() would later fail when called on an invalid
video mixer handle. With mesa r600 vdpau driver, this would cause a segfault.
2014-08-13 17:57:19 +02:00
Jan Palus 69d5356d76 build: fix libmpv build when using system waf
Since the 'syms' tool is shipped in waf's extras, when using system waf the
default tool overrides our own. Force our syms tool by providing the tooldir.

Fixes #1006
2014-08-13 17:09:45 +02:00
wm4 9ed9c68fda vo_vdpau: fix screenshots with anamorphic video
Fixes #1007.

CC: @mpv-player/stable
2014-08-13 00:52:05 +02:00
wm4 f6f93b6336 x11: vdpau GLX interop needs X11 threads
Xlib is not thread-safe. Or actually it is, but it's an incomprehensible
hack that was added later, and which needs to be acitvated manually
(this makes no sense). And it appears that the vdpau accesses X from the
decoder thread if GLX interop is used (and not in any other situations -
this doesn't make too much sense either).

So, just call the magic function that enables Xlib thread-safety.
2014-08-13 00:26:13 +02:00
wm4 defa0a20e0 af_lavcac3enc: lower minimum channel number to 3
It seems only stereo PCM should be passed through.
2014-08-12 23:45:41 +02:00
FRAU KOUJIRO 060ba226e6 docs: cocoa example uses wakeup callback API
Also, imitate the qt example somewhat.
2014-08-12 23:40:58 +02:00
FRAU KOUJIRO dcf4ee905b docs: simple cocoa API usage example 2014-08-12 23:40:55 +02:00
wm4 be792c085a af_lavcac3enc: change default bitrate to 640
No reason to use less.

Since the name "default" is misleading now, replace it with "auto"
(still recognize the old name).
2014-08-12 23:34:28 +02:00
wm4 5ed7bc6321 video: fix and simplify video format changes and last frame display
The previous commit broke these things, and fixing them is separate in
this commit in order to reduce the volume of changes.

Move the image queue from the VO to the playback core. The image queue
is a remnant of the old way how vdpau was implemented, and increasingly
became more and more an artifact. In the end, it did only one thing:
computing the duration of the current frame. This was done by taking the
PTS difference between the current and the future frame. We keep this,
but by moving it out of the VO, we don't have to special-case format
changes anymore. This simplifies the code a lot.

Since we need the queue to compute the duration only, a queue size
larger than 2 makes no sense, and we can hardcode that.

Also change how the last frame is handled. The last frame is a bit of a
problem, because video timing works by showing one frame after another,
which makes it a special case. Make the VO provide a function to notify
us when the frame is done, instead. The frame duration is used for that.

This is not perfect. For example, changing playback speed during the
last frame doesn't update the end time. Pausing will not stop the clock
that times the last frame. But I don't think this matters for such a
corner case.
2014-08-12 23:24:08 +02:00
wm4 df58e82237 video: move display and timing to a separate thread
The VO is run inside its own thread. It also does most of video timing.
The playloop hands the image data and a realtime timestamp to the VO,
and the VO does the rest.

In particular, this allows the playloop to do other things, instead of
blocking for video redraw. But if anything accesses the VO during video
timing, it will block.

This also fixes vo_sdl.c event handling; but that is only a side-effect,
since reimplementing the broken way would require more effort.

Also drop --softsleep. In theory, this option helps if the kernel's
sleeping mechanism is too inaccurate for video timing. In practice, I
haven't ever encountered a situation where it helps, and it just burns
CPU cycles. On the other hand it's probably actively harmful, because
it prevents the libavcodec decoder threads from doing real work.

Side note:

Originally, I intended that multiple frames can be queued to the VO. But
this is not done, due to problems with OSD and other certain features.
OSD in particular is simply designed in a way that it can be neither
timed nor copied, so you do have to render it into the video frame
before you can draw the next frame. (Subtitles have no such restriction.
sd_lavc was even updated to fix this.) It seems the right solution to
queuing multiple VO frames is rendering on VO-backed framebuffers, like
vo_vdpau.c does. This requires VO driver support, and is out of scope
of this commit.

As consequence, the VO has a queue size of 1. The existing video queue
is just needed to compute frame duration, and will be moved out in the
next commit.
2014-08-12 23:24:08 +02:00
wm4 a1be3cf147 DOCS: mark the recent release in client-api-changes.rst
Also add instructions to release-policy.md, since this can be easily
forgotten.

CC: @mpv-player/stable
2014-08-12 23:01:19 +02:00
wm4 52f2f67553 input.conf: add some bindings for changing audio-delay
Requested on: https://github.com/mpv-player/mpv/commit/90ec3334174e80c16f00971886223a3afabc1aca#commitcomment-7331673

Might remove or remap them again later.
2014-08-11 23:40:35 +02:00
wm4 3f353f1219 input.conf: make explanatory text more readable
Or at leats this is the intention. It's a bit hard to tell which
information is needed, and which not.
2014-08-11 23:32:37 +02:00
wm4 b8f025a58a video: don't keep multiple pointers to hwdec info struct
This makes a certain corner case simpler at a later point.
2014-08-11 23:09:39 +02:00
wm4 056622c33e vaapi: fix uninitialized value read
Found with valgrind. This is somewhat terrifying, because the VA-API API
function is supposed to fill these values, and we access them only if
the API functions return success. So this shouldn't have happened.
2014-08-11 21:57:41 +02:00
wm4 beceb2fedc vf_vapoursynth: print more diagnostics on error 2014-08-11 21:57:15 +02:00
wm4 bead9766bc manpage: update keybindings 2014-08-11 21:56:37 +02:00
wm4 f9d2ad6c17 Move status-line.lua
Looks like TOOLS/lua/ is now established as dumping ground for random
Lua scripts, so DOCS/lua_examples/ is not needed anymore.
2014-08-11 17:08:32 +02:00
wm4 0ed48f5ec9 player: remove cache status from video OSD 2014-08-11 17:01:20 +02:00
wm4 9dd160ea97 demux: reduce log spam if threading is disabled 2014-08-11 15:55:12 +02:00
wm4 37357e2265 video: fix dangling pointer issue
The function video_decode_and_filter(), called between initializing the
local vf variable and using it, can actually destroy and recreate the
filter. Thus, the vf variable turns into a dangling pointer if that
happens.

Could be observed with: --hwdec=vda --deinterlace=yes --vf=yadif

(Also happens with vdpau/vaapi.)
2014-08-11 15:37:13 +02:00
wm4 33a8e2a9ad vdpau: allocate surfaces by age
Whether this helps is probably questionable and depends on the GPU. But
the vaapi code does it too.
2014-08-11 14:03:53 +02:00
wm4 ef9b399020 input: fix event wakeup
When a new event was added, merely a flag was set, instead of actually
waking up the core (if needed). This was ok in ancient times when all
event sources were part of the select() loop. But now there are several
cases where other threads can add input, and then you actually need to
wakeup the core in order to make it read the events at all.
2014-08-11 13:50:56 +02:00
wm4 bce48f30d2 input.conf: change LEFT/RIGHT keys to seek 5s instead of 10s 2014-08-11 13:37:18 +02:00
wm4 a87005b7fa command: for OSD, format cache property as integer
For convenience. Use ${=cache} to get the old formatting.
2014-08-11 13:30:08 +02:00
wm4 b016f92309 command: fix dangling pointer issue in script key bindings code
This code was sending a string to a different thread, and then
deallocated the string shortly after, which means most of the time
the other thread was accessing a dangling pointer.

It's possible that this is the cause for #1002.
2014-08-11 13:00:57 +02:00
wm4 ece61bfa10 player: don't delay OSD redraw when paused
We want this heuristic to trigger during normal playback only.
2014-08-10 13:24:29 +02:00
wm4 f5257e2c7d vo_sdl: fix redrawing issue
vo_sdl.c has broken event handling and just polls. The polling time was
quite low, so the playloop OSD redrawing heuristic inhibited redraws,
which made the window appear frozen when paused.
2014-08-10 13:24:29 +02:00
wm4 2a403092cd input.conf: map shift+pgup/dwn to the old seek bindings 2014-08-09 02:24:10 +02:00
wm4 8dfe0c73c9 video: remove "hard" framedrop mode
Completely useless, and could accidentally be enabled by cycling
framedrop modes. Just get rid of it.

But still allow triggering the old code with --vd-lavc-framedrop, in
case someone asks for it. If nobody does, this new option will be
removed eventually.
2014-08-09 00:35:35 +02:00
wm4 91be5e5c31 etc/example.conf: update cache options
Some of them changed semantics or got renamed.

Note that the replacements in the example.conf are not necessarily the
equivalents of the replaced options.
2014-08-09 00:13:16 +02:00
wm4 26d69758f6 command: run OSD display code even if a property is unavailable
Trying to jump chapters in a gile that has no chapters does nothing,
not even show a warning. This is confusing. The reason is that the
"add chapter" command will just bail out completely if the property
is unavailable.

This was because it exited when it couldn't get the property type.
Instead of exiting, just don't enter the code that needs the type.

(I'm not sure when this behavior changed. I consider it a regression.
It was probably caused by changes to the chapter code, which perhaps
started returning UNAVAILABLE instead of OK if there are no chapters.)
2014-08-09 00:08:04 +02:00
wm4 e0fb2a4f2d etc: add mplayer-input.conf 2014-08-09 00:08:04 +02:00
wm4 8b48b3fd3b input.conf: switch chapter seek next/previous keys
"UP" seeks forward, so "PGUP" should skip to the next chapter.

Fixes #998.
2014-08-08 23:26:03 +02:00
wm4 c4feba847c manpage: update key bindings 2014-08-08 12:06:01 +02:00
Alexander Preisinger b6b8bffd2d manpage: add sections and order by usage
Split the options into the following sections:

 * Playback Control
 * Program Behaviour
 * Video
 * Audio
 * Subtitles
 * Window
 * Disc Devices
 * Equalizer
 * Demuxer
 * Input
 * OSD
 * Screenshot
 * Software Scaler
 * Terminal
 * TV
 * Cache
 * Network
 * DVB
 * PVR
 * Miscellaneous

Most options are sorted by usefullness and how often they're used or how
important they are.
This makes finding the right options easier and adds some sort of structure.
2014-08-08 08:30:06 +02:00
wm4 b4f72b46e5 ao_dsound: reduce default buffer size
Reduce from 1000ms to 100ms. Since there is an audio thread updating AOs
quickly enough now, requesting such a large buffer size makes no sense
anymore.
2014-08-08 01:56:23 +02:00
wm4 90ec333417 input.conf: unmap some more obscure bindings
Changing audio-delay is probably not needed.

Changing balance "works", but not as expected (sets up a pan matrix to
change left/right contributions to each other, rather than changing the
relative volumes of each channel).

I expect that the rest are not in use by anyone.
2014-08-08 00:43:14 +02:00
wm4 fa682af6ee command: add a "seeking" property
The client API exports this state via events already, but maybe it's
better to explicitly provide this property in order to facilitate use on
OSD and similar cases.
2014-08-08 00:16:20 +02:00
wm4 5f042864f5 player: indicate on the status line whether a seek is active
This is delayed by 300ms - before that, the status doesn't change. I
feel like it would too annoying if the status line would "flicker" on
normal seek by quickly showing and hiding the indicator.
2014-08-08 00:05:24 +02:00
wm4 e1ff914679 input.conf: remap pgup/dwn to chapter seeks
As discussed in #973.

Keep the old bindings for now; there's no reason to unmap them yet.
2014-08-07 23:55:09 +02:00
wm4 7898169484 build: add hacks to force waf to generate valid .pc files
Don't like this? You're invited to fix this crap.
2014-08-07 23:45:40 +02:00
wm4 5906041343 input: fix off by one error in command parser
Should fix #989.
2014-08-07 18:21:36 +02:00
wm4 886ac09699 audio: fix encoding mode
If this code is not skipped, encoding (or dumping with --ao=pcm) will
attempt to adjust video timing to audio. Since another commit (0cce8fe6)
already avoids writing audio ahead, this didn't slow down encoding to
realtime, but it was still significantly slower.

This change should actually remove all extra sleeping.
2014-08-07 18:07:43 +02:00
wm4 483595e2d4 client API: qtexample: don't pass deallocated strings to mpv
The temporary QByteArray is deallocated already at the end of the
statement in C++, instead of the end of the scope (like in C).
2014-08-07 00:35:38 +02:00
wm4 1483fd443a demux: fix playback abort if --demuxer-thread is not used
Switching tracks caused cached_demux_control() to catch the command to
switch tracks, even if no thread was running. Thus, the tracks were
never really switched, and EOF happened immediately on playback start.

Fix it by not using the cache at all if the demuxer thread is disabled.
The cache code still has to be called somewhere, though, because it
handles stream metadata update.

Regression from today.
2014-08-07 00:34:14 +02:00
wm4 af57444bcb player: remove unused declaration 2014-08-07 00:30:43 +02:00
wm4 dfc5d96916 gitignore: fix manpage entries 2014-08-06 20:35:55 +02:00
wm4 41ff8a661b old-build: HAVE_COCOA_APPLICATION must be set
Also fix a typo in the Makefile manpage rule.
2014-08-06 20:33:51 +02:00
wm4 3234f5a123 stream_dvb: restore --dvbin-file option
Got lost some time ago. Although I'm not sure if it actually does
anything on MPlayer (it exists there, but might broken, not sure).

Fixes #988 (untested).
2014-08-06 20:30:48 +02:00
wm4 796db66174 stream_dvb: fix channels.conf preference order
channels.conf was never used (even though its config path was resolved).

Also remove the non-sense with the access() call.

Fixes #987 (untested).
2014-08-06 20:30:47 +02:00
wm4 19fd67096b vo_direct3d: allow resizing before video init
This can just happen in the time between VO creation, and the first call
to vo_reconfig. It seems the recent threading changes exposed this bug.

Fixes #986.
2014-08-06 20:30:47 +02:00
wm4 77ad49411a win32: never call GetClientRect(0, ...)
Sometimes GetClientRect() appeared to fail during init, and since we
don't check GetClientRect() calls (because they're on our own window,
and logically can never fail), bogus resizes were triggered. This could
cause vo_direct3d to fail initialization.

The reason was that w32->window was set to 0 during early window
initialization: CreateWindow*() can send messages to the new window,
even though it hasn't returned yet. This means w32->window is not yet
set to our window handle, and functions in WndProc may accidentally pass
hwnd=0 to win32 API functions.

Fix it by initializing w32->window on opportunity. This also means we
always strictly expect that the WndProc is used with our own window
only.
2014-08-06 20:30:47 +02:00
wm4 64e1132d39 demux: make track switching asynchronous
Because why not.

This can lead to reordering of operations between seeking and track
switching (happens when the demuxer wakes up after seek and track
switching operations were queued). Do the track switching strictly
before seeks if there is a chance of reordering, which guarantees that
the seek position will always start with key frames. The reverse
(seeking, then switching) does not really have any advantages.

(Not sure if the player relies on this behavior.)
2014-08-06 20:30:47 +02:00
wm4 b38ac38aec client API: trigger MPV_EVENT_VIDEO_RECONFIG on vf recreation
Until now, it was done only on VO reconfig, but this easily can miss
some events, in case the VO output format doesn't change.
2014-08-06 20:30:47 +02:00
wm4 be64535a4e audio: fix inverted condition
Recent regression. Could perhaps make gapless audio fail to work
correctly.
2014-08-06 20:30:46 +02:00
Alexander Preisinger 6ec39b4641 wayland: remove redundant line 2014-08-06 12:58:39 +02:00
Alexander Preisinger f175f2c38f wayland: changes for nested compositors
Adds necessary checks for nested compositors which only have limited
interfaces. Might also be useful for other minimal compositors.
2014-08-06 12:55:51 +02:00
Stefano Pigozzi 2e241c0a47 build: allow to disable building the cplayer 2014-08-06 09:31:59 +02:00
Stefano Pigozzi 212374149f build: expose waf variants to the user
This allows the user to execute multiple configuration and build steps. It
can be used for several scenarios where you need different compiler flags.
2014-08-06 09:31:59 +02:00
Stefano Pigozzi c8cf864bff cocoa: fix build by using the correct HAVE_* macro
This builds but both the libmpv example and the cplayer block infinitely when
building libmpv. That's because we wait inifinitely in `dispatch_sync` as
there's no event loop in the main thread that allows for libdispatch to work..

Whiel we are at it, we should probably investigate how to use mp_dispatch
instead since it is a little lower level and could give us higher control in
building and event loop.
2014-08-06 09:31:59 +02:00
FRAU KOUJIRO b8a431c892 cocoa: macosx_application needs cocoa-application 2014-08-06 09:31:59 +02:00
FRAU KOUJIRO 022a43de8e build: cocoa-application config target
I had to put it after video options because it depends on cocoa;
is there anywhere better to put it rather than making a new group?
2014-08-06 09:31:59 +02:00
FRAU KOUJIRO 0be25a8dbf cocoa: move handleFilesArray: to macosx_events 2014-08-06 09:31:58 +02:00
FRAU KOUJIRO 4fc8dcde2a cocoa: move set_input_context to macosx_events 2014-08-06 09:31:58 +02:00
FRAU KOUJIRO 78a2d99de1 cocoa: sync inputContext inside EventsResponder 2014-08-06 09:31:58 +02:00
FRAU KOUJIRO 78a266d599 cocoa: decouple events from application somewhat 2014-08-06 09:31:58 +02:00
wm4 ff6c387a73 win32: fix build 2014-08-05 23:43:40 +02:00
wm4 5a0db9bf8a build: move def file to libmpv/
This is more consistent with mpv.pc, which is also in libmpv/.
2014-08-05 20:02:41 +02:00
wm4 210c83ab31 win32: create OpenGL context on the GUI thread
This fixes the fullscreen issues on Intel for me. I'm baffled by it and
don't understand why this suddenly works. Intel drivers being shit?
Windows being shit? HWND or HDC being only 97% thread-safe instead of
98%? Me missing something subtle that is not documented anywhere?

Who knows.

Now instead of creating the HDC and OpenGL context on the renderer
thread, they're created on the GUI thread. The renderer thread will
then only call wglMakeCurrent, SwapBuffers, and OpenGL standard
functions.

Probably fixes github issue #968.
2014-08-05 20:02:23 +02:00
wm4 afcbee8305 win32: cleanup OpenGL context creation
Might handle some corner cases better. In particular, always call
wglMakeCurrent() with non-NULL HDC argument.
2014-08-05 19:59:32 +02:00
Stefano Pigozzi 8af0d9fec8 build: syms: reindent
We avoided reindenting this in the past to allow merging upstream changes.
In hindsight these are very unlikely and we are actually doing changes on
the code, so it's better to have the correct indentation and formatting in
our source file.
2014-08-05 12:57:34 +02:00
Stefano Pigozzi b34621e1b1 build: syms: fix *.def file for mach-o binary format
There was a missing trailing newline which caused some warnings when calling
`ld`.
2014-08-05 12:13:27 +02:00
wm4 9a6d7af074 options: fix key-value-list options
The parser can be called with dst (the target) set to NULL if the option
should be verified only. The code didn't respect this, and could result
in crashes when used in config profiles or filter sub-options.

Fixes #981.
2014-08-05 02:24:45 +02:00
wm4 43ddf2099b client API: add and use the MPV_MAKE_VERSION macro
This is probably nicer. The actual version number doesn't change (other
than the minor being incremented).

The "| 0UL" is to make the type unsigned long int, like it was before.
2014-08-05 02:23:14 +02:00
wm4 bdf607ea5f build: list exported symbols explicitly
Instead of using a regex to match names to be exported from the libmpv
dynamic shared library, use a libmpv.def file, which lists all exported
functions explicitly.

This reduces the platform specifics in syms.py. I'm not sure if the
separate compile_sym task is still needed (it could probably be
collapsed, which would concentrate the platform specifics into one
place).
2014-08-05 02:21:29 +02:00
wm4 62a79ae556 build: fix export of libmpv symbols on mingw
The _ usually prefixed to functions on Windows was unexpectedly missing.
2014-08-05 01:02:54 +02:00
wm4 91fbaa7d34 build: fix cross-compilation of libmpv
libmpv requires nm for creating the list of exported symbols (this is
done in syms.py). We should probably just make this list static instead,
but since this involves platform-specific code, for now this quick-fix
will do.
2014-08-05 00:20:31 +02:00
wm4 d634f7b01a vdpau: don't crash on flipped images
It seems the vdpau API does not support these.

Do a semi-expensive emulation of it. On the other hand, it's not like
this is a commonly-used feature. (It might be better to make --vf=flip
always copy instead of flipping it via pointer tricks - but everything
allows flipped images, and even decoders or libavfilter filters could
output them.)
2014-08-05 00:18:57 +02:00
wm4 ee6df2f76c sub: fix subtitle timing for TS
The subtitle timing logic always used the demuxer's start time as video
offset. This made external subtitle files "just work" with file formats
like TS, which usually have a non-0 start time. But it was wrong for
subtitles muxed with the TS, so adjust the time offset explicitly with
external files only.
2014-08-04 18:17:30 +02:00
wm4 922b1d8504 sub: don't read packets if video and audio are disabled
Although disabling both video and audio is surely an obscure corner
case, it's allowed, and we don't want the demuxer to skip arbitrary
packets.

Basically, make the heuristic for checking interleaved files affect
external files only.
2014-08-04 18:17:30 +02:00
Michael Forney 618361c697 gl_wayland: Don't try to resize the egl_window before it exists
If the compositor sends a configure event immediately after a window is
created (for example, if it implements tiling window management), mpv
will attempt to call wl_egl_window_resize before it has actually created
the egl_window, causing a crash.
2014-08-04 09:50:24 +02:00
wm4 913b49fcbc input.conf: remap 2 keys
Nobody uses 'c' (except accidentally) - remove.

Everyone agrees that OSD level cycling on 'o' is dumb, so map it to
show_progress instead. Cycling the OSD level is now available on 'O'.
No reason to ummap 'P' yet.

Also see issue #973.
2014-08-03 21:15:33 +02:00
wm4 0f5aed9c62 player: some further playloop cleanups
Handle --term-playing-msg at a better place.

Move MPV_EVENT_TICK hack into a separate function. Also add some words
to the client API that you shouldn't use it. (But better leave breaking
it for later.)

Handle --frames and frame_step differently. Remove the mess from the
playloop, and do it after frame display. Give up on the weird semantics
for audio-only mode (they didn't make sense anyway), and adjust the
manpage accordingly.
2014-08-03 20:31:00 +02:00
wm4 0ddbf92d06 player: make quit exit immediately
Stopping playback canceled waiting, but executed the remainder of the
playloop, including things like executing pointless seeks.
2014-08-03 20:30:39 +02:00
wm4 575314eafa player: allow redrawing screen during seeks
If seeks take very long, it's better not to freeze up the display.

(This doesn't handle the case when decoding video frames is extremely
slow; just if hr-seek is used, or the demuxer is threaded and blocks on
network I/O.)
2014-08-03 20:30:34 +02:00
wm4 27301ee691 manpage: be more explicit where input.conf is located 2014-08-02 06:57:36 +02:00
wm4 d68a759fa4 Improve setting AVOptions
Use OPT_KEYVALUELIST() for all places where AVOptions are directly set
from mpv command line options. This allows escaping values, better
diagnostics (also no more "pal"), and somehow reduces code size.

Remove the old crappy option parser (av_opts.c).
2014-08-02 03:12:33 +02:00
wm4 0c6c2da8bc manpage: explain how to replace --slave-broken 2014-08-02 03:12:33 +02:00
wm4 c94e8bcdd6 player: don't show the path part for external subtitle files
Show the filename only. Feature request on IRC.
2014-08-02 03:12:31 +02:00
wm4 733bdebcb9 client API: minor optimizations for property notification
Internally, there are two mechanisms which can trigger property
notification as used with "observed" properties in the client API.

The first mechanism associates events with a group of properties that
are potentially changed by a certain event. mp_event_property_change[]
declares these associations, and maps each event to a set of strings.
When an event happens, the set of strings is matched against the list of
observed properties of each client. Make this more efficient by
comparing bitsets of events instead. This way, only a bit-wise "and" is
needed for each observed property. Even better, we can completely skip
clients which have no observed properties that match.

The second mechanism just updates individual properties explicitly by
name. Optimize this by using the property index instead. It would be
nice if we could reuse the first mechanism for the second one, but
there are too many properties to fit into a 64 bit mask.

(Though the limit on 64 events might get us into trouble later...)
2014-08-02 01:53:22 +02:00
wm4 82a223e4e0 TOOLS: add test script for property change notifications 2014-08-02 01:53:21 +02:00
wm4 be337aa415 command: add a property that returns a list of all properties
Also remove the undocumented Lua mp.property_list() function.
2014-08-02 01:53:21 +02:00
wm4 16e5ec88e1 manpage: remove duplicated misplaced description of a command 2014-08-02 01:53:18 +02:00
wm4 aa46968ed0 win32: fix assertion failure
If OpenGL 3.x doesn't work, the fallback to legacy GL will call the
function to create the DC again, and it will assert. Just make it not
to, and also simplify the code a bit.

Fixes #974.
2014-08-01 23:03:52 +02:00
wm4 bf5b1e9a05 Remove the last remains of slave mode
Almost nothing was left of it.

The only thing this commit actually removes is support for reading
input commands from stdin. But you can emulate this via:

 --input-file=/dev/stdin --input-terminal=no

However, this won't work on Windows. Just use a named pipe.
2014-08-01 22:57:56 +02:00
Stefano Pigozzi 6aac17cebb vda: only support the new hwaccel 1.2 API (remove old code)
Since the new hwaccel API is now merged in ffmpeg's stable release, we can
finally remove support for the old API.

I pretty much kept lu_zero's new code unchanged and just added some error
printing (that we had with the old glue code) to make the life of our users
less miserable.
2014-08-01 10:38:18 +02:00
Stefano Pigozzi 33137606e9 travis: use homebrew to build ffmpeg on OS X
This allows us to use a newer version of ffmpeg and to test the build of our
VDA code.
2014-08-01 10:38:18 +02:00
wm4 33f465d9a7 player: don't ignore first chapter
It's a mystery why this was done this way. If the first chapter starts
later than the current position, we do have to return -1.
2014-07-31 22:54:57 +02:00
wm4 de8e9ca9d2 video: fix attached picture mode
Playing audio files with embedded cover art broke due to some of the
recent changes. Treat video EOF properly, and don't burn the CPU.
Disable hrseek for video in attached picture mode, since the decoder
will always produce a new image, which makes hrseek never terminate.

Fixes #970.
2014-07-31 21:57:11 +02:00
wm4 4cf3f3ca2c audio: simplify condition
The expression added with the previous commit (0cce8fe6) looked slightly
more complicated than it has to be. The code is equivalent.
2014-07-31 21:11:49 +02:00
wm4 0cce8fe64f audio: fix A/V sync in encoding mode
In encoding mode, the AO pretends to be infinitely fast (it will take
whatever we write, without ever rejecting input). Commit 261506e3 broke
this somehow. It turns out an old hack dealing with this was accidentally
dropped.

This is the hunk of code whose semantics were (partially) dropped:

    if (mpctx->d_audio && (mpctx->restart_playback ? !video_left :
                           ao_untimed(mpctx->ao) && (mpctx->delay <= 0 ||
                                                     !video_left)))
    {
        int status = fill_audio_out_buffers(mpctx, endpts);
        // Not at audio stream EOF yet
        audio_left = status > -2;
    }

This if condition is pretty wild, and it looked like it was pretty much
for audio-only mode, rather than subtle handling for encoding mode.
2014-07-31 04:49:44 +02:00
wm4 a1b54d3b89 client API: don't send internal events to the clients
"Internal" events were added in the previous commits to leverage the
client API property mechanism, without making weird properties public.

But they were sent to clients too (and returned by mpv_wait_event()).
2014-07-31 04:35:23 +02:00
wm4 c1b64cc693 command: add cache-idle property 2014-07-31 04:25:39 +02:00
wm4 b4f24544bb client API: make "cache" property and similar observable
Achieve this by polling. Will be used by the OSC. Basically a bad hack -
but the point is that the mpv core itself is in the best position to
improve this later.
2014-07-31 04:19:41 +02:00
wm4 aaa90e1a33 client API: fix deadlock when calling mpv_terminate_destroy before init
This is perfectly allowed, but was ignored, because it's a corner case.

It doesn't actually wait for other clients to be destroyed, but on the
other hand I think there's no way to have other clients before
initialization.

CC: @mpv-player/stable
2014-07-31 03:12:18 +02:00
wm4 dacbaea1a8 player: rename a variable
Make it clear that this condition happens when switching to a new
timeline segment. It doesn't even need to coincide with a chapter.
2014-07-30 23:29:01 +02:00
wm4 1423bd0bfd player: move video display code out of the playloop
Basically move the code from playloop.c to video.c. The new function
write_video() now contains the code that was part of run_playloop().

There are no functional changes, except handling "new_frame_shown"
slightly differently. This is done so that we don't need new a new
MPContext field or a return value for write_video() to signal this
condition. Instead, it's handled indirectly.
2014-07-30 23:29:00 +02:00
wm4 8f2e9f1d61 player: split seek_reset()
This also reduces some code duplication with other parts of the code.

The changfe is mostly cosmetic, although there are also some subtle
changes in behavior. At least one change is that the big desync message
is now printed after every seek.
2014-07-30 23:29:00 +02:00
wm4 c38013bffb video: actually flush filter chain
Frames buffered in filters weren't flushed, so on EOF, the last frames
were dropped, depending on how much filters buffered. Oops.

Test case: "mpv something.jpg --vf=buffer"
2014-07-30 23:29:00 +02:00
wm4 f8ab732ac3 video/filter: add vf_buffer
Mostly useful for debugging.
2014-07-30 23:29:00 +02:00
wm4 8d990408d7 audio: better sync behavior on bogus EOF
In situations when the demuxer reports EOF, but immediately "recovers"
after that and returns new data, it could happen that audio sync was
skipped. Deal with this by actually entering the EOF state, instead of
assuming this will happen later.
2014-07-30 23:29:00 +02:00
wm4 6afa1a2afc ao_alsa: disable use of non-interleaved formats by default
Some ALSA plugins take non-interleaved audio, but treat it as
interleaved, which results in various funny bugs. Users keep hitting
this issue, and it just doesn't seem worth the trouble.

CC: @mpv-player/stable
2014-07-30 23:28:44 +02:00
Stefano Pigozzi c3d15b50b4 cocoa: fix key equivalent dispatching
Prior to this commit we had a list of key modifiers and checked against that.
Actually, the Cocoa framework has a built in way to do it and it involves
calling performKeyEquivalent: on the menu instance.

Fixes #946

cc @mpv-player/stable: this should apply with no conflicts
2014-07-30 11:26:49 +02:00
wm4 471dfba018 client API: fix typos in documentation 2014-07-30 03:33:37 +02:00
wm4 0dd5228626 demux_lavf: don't consider EAGAIN as EOF condition
This happens apparently randomly with rtmp:// and after seeks. This
eventually leads to audio decoding returning an EOF status, which
basically disables audio sync. This will lead to audio desync, even if
audio decoding later "recovers" when the demuxer actually returns audio
packets.

Hack-fix this by special-casing EAGAIN.
2014-07-30 03:32:56 +02:00
wm4 6856d81c68 stream: hack-fix rtmp-level seeking
This didn't work, because the timebase was wrong. According to the
ffmpeg doxygen, if the stream index is -1 (which is what we used), the
timebase is AV_TIME_BASE. But this didn't work, and it really expected
the stream's timebase. Quite "surprising", since this feature
(avio_seek_time) is used by rtmp only.

Fixing this properly is too hard, so hack-fix our way around it.
STREAM_CTRL_SEEK_TO_TIME is also used by DVD/BD, so a new
STREAM_CTRL_AVSEEK is added. We simply pass-through the request
verbatim.
2014-07-30 02:21:51 +02:00
wm4 26d973ce82 stream_lavf: allow setting AVOptions with --stream-lavf-o
This commit also creates a private option struct for stream_lavf.c, but
since I'm lazy, I'm not moving any existing options to it.
2014-07-30 01:15:42 +02:00
wm4 da780309d7 audio: better initial sync for files where audio starts later
Some files have the first audio much later into the video (for whatever
reasons). Instead of appending large amounts of silence to the audio
buffer (and refusing to sync if the audio to append is "too large"),
just wait until enough video has played.
2014-07-30 00:40:45 +02:00
wm4 1cd2b5976d audio: cosmetics: remove unused return value 2014-07-30 00:24:57 +02:00
wm4 6b928fa2a0 demux_mf: allow seeking past the end
How's this for a corner case.
2014-07-30 00:23:16 +02:00
wm4 593ad996e0 player: fix time display wheen seeking past EOF with --keep-open
Regression since commit 261506e3. Internally speaking, playback was
often not properly terminated, and the main part of handle_keep_open()
was just executed once, instead of any time the user tries to seek. This
means playback_pts was not set, and the "current time" was determined by
the seek target PTS.

So fix this aspect of video EOF handling, and also remove the now
unnecessary eof_reached field.

The pause check before calling pause_player() is a lazy workaround for
a strange event feedback loop that happens on EOF with --keep-open.
2014-07-30 00:22:38 +02:00
wm4 b6a7c321db player: let explicitly imprecise seeks cancel precise seeks
If an imprecise seek is issues while a precise seek is ongoing,
don't wait up to 300ms (herustistic which usually improves user
experience), but instead let it cancel the seek.

Improves responsiveness of the OSC after the previous commit.

Note that we don't do this on "default-precise" seeks, because we
don't know if they're going to be precise or not.
2014-07-29 20:04:08 +02:00
ChrisK2 48f4f791f4 osc: Do precise seeks on simple clicks on seekbar 2014-07-29 19:26:32 +02:00
wm4 63d1d53d2f audio: ignore (some) decoding errors on initialization
It probably happens relatively often that the first packet (or even the
first N packets) of a stream will fail to decode, but decoding will
eventually succeed at a later point. Before commit 261506e3, this was
handled by an explicit retry loop (although this was also for other
purposes), but with then was changed to abort on the first error. This
makes it impossible to decode some audio streams.

Change this so that errors are ignored for the first 50 packets, which
should make it equivalent to the old code.
2014-07-29 18:05:55 +02:00
wm4 862d7d8a1a player: fix desync when seeking and switching external tracks
If you for example use --audio-file, disable the external track, seek,
and enable the external track again, the playback position of the
external file was off, and you would get major A/V desync. This was
actually supposed to work, but broke at some time ago (probably commit
2b87415f). It didn't work, because it attempted to seek the stream if it
was already selected, which was always true due to
reselect_demux_streams() being called before that.

Fix by putting the initial selection and the seek together.
2014-07-29 17:55:28 +02:00
wm4 6d15c491b0 player: remove a pointless field 2014-07-29 01:00:54 +02:00
wm4 25ceb3289d player: disable hr-seek in .ts files
Seeking in .ts files (and some other formats) is too unreliable, so
there's a separate code path for this case. But it breaks hr-seek.

Maybe hr-seek could actually be enabled in this case if we're careful
enough about timestamp resets, but for now nothing changes.
2014-07-29 00:59:00 +02:00
wm4 d6445d7ab6 player: allow precise seeking with percent seeks
I'm not sure why this was explicitly disabled. It's from mplayer2 times.
2014-07-29 00:26:52 +02:00
wm4 ecad4a20de manpage: lua: document timer timeout and oneshot fields
Might be useful for scripts, so document them. (Which means scripts
are allowed to use them, without risking breakage.)
2014-07-29 00:22:21 +02:00
wm4 fa34b4920a vdpau: don't upload video images in advance
With software decoding, images were uploaded to vdpau surfaces as they
were queued to the VO. This makes it slightly more complicated
(especially later on), and has no advantages - so stop doing it.

The only reason why this was done explicitly was due to attempts to keep
the code equivalent (instead of risking performance regressions). The
original code did this naturally for certain reasons, but now that we
can measure that it has no advantages and just requires extra code, we
can just drop it.
2014-07-29 00:21:02 +02:00
wm4 d563dc8cb9 player: update playback position on seek
If the actual PTS is not known yet right after a seek, the "time-pos"
property will just return the seek target PTS. For this purpose, trigger
a change event to make the client API update the "time-pos" and related
properties. (MPV_EVENT_TICK triggers this update.)
2014-07-29 00:20:54 +02:00
wm4 846257da13 player: logically speed up seek logic
Commit 261506e3 made constant seeking feel slower, because a subtle
change in the restart logic makes it now waste time showing another
video frame. The slowdown is about 20%.

(Background: the seek logic explicitly waits until a video frame is
displayed, because this makes it easier for the user to search for
something in the video. Without this logic, the display would freeze
until the user stops giving seek commands.)

Fix this by letting the seek logic issue another seek as soon as the
first video frame is displayed. This will prevent it from showing a
(useless, slow) second frame. Now it seems to be as fast as before the
change.

One side-effect is that the next seek happens after the first video
frame, but _before_ audio is restarted. Seeking is now silent. I guess
this is ok, so we don't do anything about it. Actually, I think whether
this happens is probably random; the seeking logic simply doesn't make
this explicit, so anything can happen.
2014-07-28 22:13:42 +02:00
wm4 26bfcc9c82 vo_x11: fix build with older Libav versions
Why does this happen everytime...
2014-07-28 21:48:43 +02:00
Niklas Haas d0a8b571c9 video: add a default color space for files with no video
Usually mp_image_params_guess_csp takes care of finding *some* default
for a video channel, but files with no video (or with extremely broken
configurations) end up leaving the colorspace information as
MP_CSP_PRIM_AUTO, which has no associated primaries.

As a result of this, color managed OSD messages could not display
because they were being color managed to match the (non-existing/absurd)
video channel. With this change, such non-spaces will have BT.709
primaries as far as color management and the OSD is concerned.

This fixes #961.

CC: @mpv-player/stable

Signed-off-by: wm4 <wm4@nowhere>
2014-07-28 21:24:44 +02:00
wm4 261506e36e audio: change playback restart and resyncing
This commit makes audio decoding non-blocking. If e.g. the network is
too slow the playloop will just go to sleep, instead of blocking until
enough data is available.

For video, this was already done with commit 7083f88c. For audio, it's
unfortunately much more complicated, because the audio decoder was used
in a blocking manner. Large changes are required to get around this.
The whole playback restart mechanism must be turned into a statemachine,
especially since it has close interactions with video restart. Lots of
video code is thus also changed.

(For the record, I don't think switching this code to threads would
make this conceptually easier: the code would still have to deal with
external input while blocked, so these in-between states do get visible
[and thus need to be handled] anyway. On the other hand, it certainly
should be possible to modularize this code a bit better.)

This will probably cause a bunch of regressions.
2014-07-28 21:20:37 +02:00
wm4 58255e0e2b input: be stricter about rejecting mouse input with --no-input-cursor
Apparently this switch means all mouse input should be strictly
rejected. Some VO backends (such as X11) explicitly disable all mouse
events if this option is set, but others don't. So check them in
input.c, which increases consistency.
2014-07-27 22:00:55 +02:00
wm4 4c533fbb16 vo: remove vo_mouse_movement() wrapper
So that VO backends don't have to access the VO just for that.
2014-07-27 21:53:29 +02:00
wm4 89391e7c94 vo: different hack for VOs which need to mangle mouse input
Follow up on commit 760548da. Mouse handling is a bit confusing, because
there are at least 3 coordinate systems associated with it, and it
should be cleaned up. But that is hard, so just apply a hack which gets
the currently-annoying issue (VO backends needing access to the VO) out
of the way.
2014-07-27 21:33:11 +02:00
wm4 bc6359313f ao_pulse: allow disabling timing bug workarounds
Add an option that enables using native PulseAudio auto-updated timing
information, instead of the manual calculations added in mplayer2 times.
You can use --ao=pulse:no-latency-hacks to enable the new code. The code
is almost the same as the code that was removed with commit de435ed5,
but I didn't readd some bits I didn't understand. Likewise, the option
will disable the code added with that commit.

In my tests this seemed to work well, though the A/V sync display looks
funny when seeking.

The default is still the old behavior.

See issue #959.
2014-07-26 23:20:09 +02:00
wm4 77d9e4b8a9 ao_pulse: remove hacks for ancient PulseAudio versions
This was needed by very old (0.9) versions only. Get rid of it.

Unfortunately, I can't cross-check with the original bug report, since
the bug URL leads to this:

Internal Server Error

TracError: IOError: [Errno 2] No such file or directory: '/home/lennart/svn/trac/pulseaudio/VERSION'
2014-07-26 23:19:48 +02:00
wm4 3c7675ae9a manpage: eliminate the word "movie"
It's evil and sounds outdated. Use the words "media" and "video"
instead.

Closes #935.
2014-07-26 23:19:47 +02:00
wm4 025431a7ae win32: remove minor non-sense
This is done in the wrong thread. Was harmless and had no effect at all.
2014-07-26 23:19:43 +02:00
wm4 97a82bcd56 win32: move window handling to a separate thread
The windows message loop now runs in a separate thread. Rendering,
such as with Direct3D or OpenGL, still happens in the main thread.

In particular, this should prevent the video from freezing if the
window is dragged. (The reason was that the message dispatcher won't
return while the dragging is active, so mpv couldn't update the
video at all.)

This is pretty "rough" and just hacked in, and there's no API yet to
make this easier for other backends. It will be cleaned up later
once we're sure that it works, or when we know how exactly it should
work. One oddity is that OpenGL is actually completely managed in the
renderer thread, while e.g. Cocoa (which has its own threading code)
creates the context in the GUI thread, and then lets the renderer
thread access it.

One strange issue is that we now have to stop WM_CLOSE from actually
closing the window. Instead, we wait until the playloop handles the
close command, and requests the VO to shutdown. This is done mainly
because closing the window apparently destroys it, and then WM_USER
can't be handled anymore - which means the playloop has no way to
wakeup the GUI thread. It seems you can't really win here... maybe
there's a better way to have a thread receive messages with and
without a window, but I didn't find one yet.

Dragging the window (by clicking into the middle of it) behaves
strangely in wine, but didn't before the change. Reason unknown.
2014-07-26 20:36:46 +02:00
wm4 760548da28 vo: hack to avoid threading issues with mouse input
VO backends which are or will run in their own thread have a problem
with vo_mouse_movement() calling vo_control(). Restrict this to VOs
which actually need this.
2014-07-26 20:31:26 +02:00
wm4 3f268cc4f2 win32: use gcc TLS instead of WM_NCCREATE tricks for window context
win32 does not provide a proper per-window context pointer. Although it
does allow passing a user-chosen value to WM_CREATE/WM_NCCREATE, this
is not enough - the first message doesn't even have to be WM_NCCREATE.
This gets us in trouble later on, so go the easy route and just use a
TLS variable.

__thread is gcc specific, but Windows is a very "special" platform
anyway. We support only MinGW and Cygwin on it, so who cares. (C11
standardizes __thread as _Thread_local; we can use that later.)
2014-07-26 20:30:52 +02:00
wm4 559fe1daac Add Plan 9-style barriers
Plan 9 has a very interesting synchronization mechanism, the
rendezvous() call. A good property of this is that you don't need to
explicitly initialize and destroy a barrier object, unlike as with e.g.
POSIX barriers (which are mandatory to begin with). Upon "meeting", they
can exchange a value.

This mechanism will be nice to synchronize certain stages of
initialization between threads in the following commit.

Unlike Plan 9 rendezvous(), this is not implemented with a hashtable,
because that would require additional effort (especially if you want to
make it actually scele). Unlike the Plan 9 variant, we use intptr_t
instead of void* as type for the value, because I expect that we will be
mostly passing a status code as value and not a pointer. Converting an
integer to void* requires two cast (because the integer needs to be
intptr_t), the other way around it's only one cast.

We don't particularly care about performance in this case either. It's
simply not important for our use-case. So a simple linked list is used
for waiters, and on wakeup, all waiters are temporarily woken up.
2014-07-26 20:29:48 +02:00
wm4 8ed6d298c5 win32: make a flag explicit
This shouldn't change anything. But it's worth making this explicit,
since it's very subtle and unintuitive: if the X parameter is the
magic value CW_USEDEFAULT, then the Y parameter is used as nCmdShow
parameter to ShowWindow(). And in our case, this is SW_HIDE (0),
because we want to create a hidden window.
2014-07-26 20:29:18 +02:00
wm4 9969694ece win32: simplify some --wid embedding code
This looked a bit overcomplicated. We don't care about the window
position (it should always be 0/0, unless the parent program moved it,
which it shouldn't). We don't care about the global on-screen position.
Also, we will just retrieve a WM_SIZE message if our window is resized,
and we don't need to update it manually.

The only thing we have to do is making sure our window fills the parent
window completely.
2014-07-26 20:28:36 +02:00
wm4 9a3f1f24ca win32: don't use CS_OWNDC
CS_OWNDC will make GetDC() always return the same HDC. This might
become a problem when OpenGL rendering and window management are
on different threads. Although I'm not too sure about this; our
code never requests a HDC outside of the OpenGL backend, and it
depends on whether win32 will internally request DCs. But in any
case, this seems to be cleaner.

Move the GL pixelformat setup code to gl_w32.c, where it's actually
needed. This also fixes that SetPixelFormat() should be called only
once, and not every time video params change.
2014-07-26 20:28:01 +02:00
wm4 7f0d9a95fa win32: remove worthless doxygen comments
These mostly describe self-explanatory things, and fail to explain
actually tricky things. Which means you just waste your time reading
this, and have to figure it out from the code anyway.
2014-07-26 20:27:57 +02:00
wm4 b3169390f5 win32: make private struct private, refactor
Preparation for moving win32 windowing to a separate thread.

The codesize is reduced a bit, because some small functions are
inlined, which reduces noise.

The main change is that now most functions use the private struct
directly, instead of accessing it indirectly through vo->w32.
Accesses to vo are minimalized.

The final goal is adding some sort of new windowing backend API. It
would be cleaner to use that as context pointer for all functions
(like struct vo was previously used), but since this is work in
progress, we just go with this commit.
2014-07-26 20:27:03 +02:00
wm4 7077526ffb ao_null: never fail at initialization
ao_null is used to stop autoprobing (if all AOs before fail to init).
After it come things like ao_pcm, which should never be automatically
selected.

Remove a certain theoretically possible failure case, and force "some"
fallback.
2014-07-26 20:26:57 +02:00
wm4 ac62244983 audio/out: fix initialization failure with win32
mp_make_wakeup_pipe() always fails on win32. If this call fails on Linux
(and e.g. ao_alsa is used), this will probably burn CPU since poll()
won't work on the invalid file descriptor, but whatever, the failure
case is obscure enough.
2014-07-26 20:26:27 +02:00
wm4 ef600041ba audio, client API: check mp_make_wakeup_pipe() return value
Could fail e.g. due to FD exhaustion.
2014-07-25 14:32:45 +02:00
wm4 18c432b83a osdep: don't assume errno is positive
Apparently this is not necessarily the case, so just drop the silly idea
that depended on this assumption.
2014-07-25 14:32:45 +02:00
wm4 f24f960ec7 command: fix and simplify overlay_add
Actually free the old mmap region when readding an overlay of the same
ID without removing it before. (This is explicitly documented as
working.)

Replace the OSD atomically. Before this commit, the overlays were
removed and then readded to avoid synchronization problems.

Simplify the code: now there is no weird mapping between index and ID.
The OSD sub-bitmap list still needs to be prepared to skip unused IDs
(since each sub-bitmap list entry must be in use), but the code for this
is relatively separated now.

Fixes issue #956.
2014-07-25 14:32:45 +02:00
Alessandro Ghedini 08415933db command: append entries to the end of the playlist with loadlist append
Currently entries are added after the current playlist element. This is kinda
confusing, more so given that "loadfile append" appends at the end of the
playlist.
2014-07-25 14:32:34 +02:00
wm4 623eac2b1b audio: cosmetics: collapse a function
There's no need for build_afilter_chain() to be a separate function
anymore.
2014-07-24 15:27:40 +02:00
wm4 69eb056333 audio: fix timestamps
Accidentally broken in b6af44d3. For ad_lavc (and in general), the PTS
was not updated correctly when filtering only parts of audio frames,
and for ad_mpg123 and ad_spdif the PTS was additionally offset by the
frame size.

This could lead to incorrect time display, and possibly broken A/V sync.
2014-07-24 15:27:31 +02:00
wm4 fc28e4af4d audio: adjust format change code
Execute the format change based on whether we logically detected EOF
(after filters), instead of when the decode buffer was drained. It's
slightly cleaner. (The requirement of len>0 existed before.)
2014-07-24 15:26:43 +02:00
wm4 986099d323 audio: fix race condition in EOF code
Don't return an EOF code if there's still buffered data.

Also, don't call demux_stream_eof() in the playloop. There's probably
nothing wrong with it, but it's cleaner not to use it.

Also give AD_EOF its own value, so that a decoding error doesn't drain
audio by causing an EOF condition.
2014-07-24 15:26:07 +02:00
wm4 b77dab0f6e audio: cosmetics
Move a function call, which does not change semantics.

Write the extra buffer sample count in a more straight-forward way; the
old code was not meaningful in any way (anymore).
2014-07-24 15:25:48 +02:00
wm4 6455bcc1da audio: remove unnecessary code
It's true that the decoder can successfully decode, but return no data
(for various reasons). We don't need to handle this specially, though.
We just let the decoder decode some more data. This doesn't increase the
danger of an endless loop either, because audio_decode() already calls
this function until enough is decoded.
2014-07-24 15:25:36 +02:00
wm4 cb4aa2df92 manpage: fix a typo 2014-07-24 15:25:24 +02:00
Rudolf Polzer c19ec6f6f6 encode: deal even more with codec->time_base deprecation.
I assume this works too with Libav 10 and FFmpeg d3e51b41.
2014-07-23 16:09:44 +02:00
wm4 843f5f4723 command: add append-play loadfile mode
"loadfile filename append-play" will now always append the file to the
playlist, and if nothing is playing yet, start playback. I don't want to
change the semantics of "append" mode, so a new mode is needed.

Probably fixes issue #950.
2014-07-23 00:20:53 +02:00
wm4 10debffc06 player: remove something DVD specific
This is not needed anymore, because demux_disc isolates us from this
crap.
2014-07-22 23:49:23 +02:00
wm4 870dc84839 sub: offset subtitle timing to video start PTS
This allows using external subtitle files with e.g. transport stream
files that don't start at time 0.

Note that if the .ts file has timestamp resets, everything goes south.
But I guess this was already the case before, unless there are external
subtitle files that also include timestamp resets, which is unlikely.
(On the other hand, you could for example expect that it works with
embedded DVB subtitles, that were somehow captured from the same stream
and use the same timestamps.)
2014-07-22 23:48:29 +02:00
wm4 aa1a383342 sub: add detection via BOM
Useful for Windows stuff. Actually, ENCA support should catch this, but,
well, whatever, everyone seems to hate ENCA.

Detection with BOM is trivial, although it needs some hackery to
integrate it with the existing autodetection support. For one, change
the default value of --sub-codepage to make this easier.

Probably fixes issue #937 (the second part).
2014-07-22 23:40:48 +02:00
wm4 63373ca424 encode: deal with codec->time_base deprecation
This seems to work with both Libav 10 and FFmpeg d3e51b41.
2014-07-22 23:04:12 +02:00
wm4 1041850523 video: fix corner case with accidental EOF
The video flushing logic was broken: if there are no more packets,
decode_image() will feed flush packets to the decoder. Even if an image
was produced, it will return the demuxer EOF state, and since commit
7083f88c, this EOF state is returned to the caller, which is incorrect.

Revert this part of the change, and explicitly check for VD_WAIT (the
bogus change was intended to forward this error code to the caller).

Also, turn the "r < 1" into something equivalent that doesn't rely on
the exact value of VD_EOF. "r < 0" is ok, because at least here, errors
are always negative.
2014-07-22 21:08:42 +02:00
wm4 8f8d524112 ass: remove some pointless ifdeffery
This will print compiler warnings about unused variables with older
libass versions, but that's harmless.
2014-07-22 20:49:01 +02:00
wm4 6b51b73a04 player: fix idle mode event handling 2014-07-22 19:33:24 +02:00
wm4 80d36a0aa2 ao_pulse: fix potential compilation problem
It seems at least on some platforms (OSX 10.9), the POSIX wait()
function becomes visible, and conflicts with this unrelated function.
Just rename it.
2014-07-22 19:26:53 +02:00
Stefano Pigozzi 12b2465c1e travis: add OS X continous integration
The travis guys were so nice to activate multi OS support for us (it's a beta
feature). So now we build on OS X ass well to check for OS X specific breakage.

Later I might investigate further and build with the minimum supported SDK
version so that we don't break older systems by using newer Cocoa features.
2014-07-21 20:43:39 +02:00
wm4 17256f13dc osd: properly handle OSD bar timeout
This could just remain stuck on the screen, until the playloop happened
to be run again.
2014-07-21 19:35:20 +02:00
wm4 a84517c1d8 player: don't sleep after seeks 2014-07-21 19:31:25 +02:00
wm4 b6af44d31e audio: move initial decode to generic code
This commit mainly moves the initial decoding of data (done to probe the
audio format) to generic code. This will make it easier to make audio
decoding non-blocking in a later commit.

This commit also changes how decoders return data: instead of having
them write the data into a prepared buffer, they return a reference to
an internal buffer (by setting dec_audio.decoded). This makes it
significantly easier to handle audio format changes, since the decoders
don't really need to care anymore.
2014-07-21 19:29:58 +02:00
wm4 1f9e0a15a1 ad_lavc: drop questionable fallback code
If the decoder didn't set a samplerate, it was initialized from the
container samplerate.

This probably didn't make much sense, because it's passed to the
decoder on initialization (so it could definitely use it). It's an
artifact from commit 66a9eb57 (which removed some Matroska-specific non-
sense), and I've never seen it actually happen since it was made into a
warning. Just get rid of it.
2014-07-21 19:29:58 +02:00
wm4 967add9f0f audio: remove unused metadata field
This was used for replaygain at some point, until replaygain info was
passed through explicitly.
2014-07-21 19:29:58 +02:00
wm4 d1bb1bf8af demux: fix timestamp type for seek calls
mpv/mplayer2/MPlayer use double for timestamps, but the demuxer API used
float.
2014-07-21 19:29:58 +02:00
wm4 4b4bd9e5f7 demux: asynchronous seeking
This tells the demuxer thread that it should seek, instead of waiting
until the demuxer thread is ready.

Care has to be taken about the state between seek request and actual
seeking: newly demuxed packets have to be discarded. We can't just
flush when doing the actual seek, because the user thread could read
these packets.

I'm wondering if this could lead to issues due to relaxed ordering of
operations. But it should be fine, since seeking influences packet
reading only, and seeking is always strictly done before that.

Currently, this will have no advantages; unless audio is disabled. Then
seeking as well as normal playback can be non-blocking.
2014-07-21 19:29:50 +02:00
wm4 b6dd1341d2 manpage: correct the --mf options
The MPlayer style syntax ("-mf fps=10:type=png") was removed a while
ago, and now only the flat variants ("--mf-fps=10" etc.) work.

CC: @mpv-player/stable
2014-07-21 19:27:15 +02:00
wm4 0248de84ea player: simplify a condition
Move a condition somewhere else, which makes it conceptually simpler.

Also, the assignment to full_audio_buffers removed with this commit was
dead, and its value never used.
2014-07-20 20:47:30 +02:00
wm4 ba621ac140 manpage: fix wording for --aid 2014-07-20 20:47:03 +02:00
wm4 da1925ae2e player: simplify logic on video errors
Fatal errors in the vidoe chain (such as failing to initialize the video
chain) disable video decoding. Restart the playloop, instead of just
continuing the current iteration.

The resulting behavior should be the same, but it gets rid of possible
corner cases.
2014-07-20 20:43:06 +02:00
wm4 9736f3309a audio: use symbolic constants instead of magic integers
Similar to commit 26468743.
2014-07-20 20:42:03 +02:00
wm4 e982b5b287 player: readd code accidentally removed with commit 61efe87e
Oops.
2014-07-20 20:41:20 +02:00
wm4 5526603a43 demux: don't start reading if no packets were requested yet
Instead of starting to fill the packet queue if at least 1 stream is
selected, wait until there is at least 1 stream had new packets
requested.

In theory this is cleaner, because it allows you to e.g. do a seek and
then reselect streams without losing packets. Seeking marks all streams
as inactive, and without this new logic, the thread would read new
packets anyway right after seek.
2014-07-20 20:13:08 +02:00
wm4 61efe87e48 player: fix regression with ordered chapters
Broken by commit 1301a907. This commit added demuxer threading, and
changed some other things to make them simpler and more orthogonal. One
of these things was ntofications about streams that appear during
playback. That's an obscure corner case, but the change made handling of
it as natural as normal initialization.

This didn't work for two reasons:
1. When playing an ordered chapters file where the initial segment was
not from the main file, its streams were added to the track list. So
they were printed twice, and switching to the next segment didn't work,
because the right streams were not selected.
2. EDL, CUE, as well as possibly certain Matroska files don't have any
data or tracks in the "main" demuxer, so normally the first segment is
picked for the track list. This was simply broken.

Fix by sprinkling the code with various hacks.
2014-07-20 20:13:08 +02:00
wm4 d320695207 command: potentially fix dvd angle setting
This called demux_flush(), but that doesn't make any sense with an
asynchronously running demuxer. It would just keep reading and add new
packets again. Explicitly pause the demuxer, so that this can't happen.
Also, when flushing, data will be missing, so the decoders should
always be reinitialized, even if the operation fails.
2014-07-20 20:13:07 +02:00
foo86 6a556f524e input: enable wakeup on LIRC socket
Commit dc00b14 removed playloop polling. Enable wakeup on LIRC socket,
otherwise remote control doesn't work when paused.
2014-07-20 13:52:06 +02:00
wm4 ded02bb78c demux: make the cache refresh cached STREAM_CTRLs
This fixes the same symptom as the previous commit, but when the demuxer
thread is enabled. In this case, if nothing was read from the demuxer,
the STREAM_CTRLs weren't updated either. To the player, this looked like
the stream cache was never making progress, so playback was kept paused.
2014-07-20 00:19:58 +02:00
wm4 1313d38efb player: don't wait forever with --cache-pause-below behavior
Commit dc00b146, which disables polling by default, missed another
instance of polling: when the player pauses automatically on low cache.

This could lead to apparent freezes when playing network streams.
2014-07-20 00:16:43 +02:00
Tsukasa OMOTO b0ff0527a3 build: enable compiler optimization by default 2014-07-20 00:08:36 +02:00
wm4 887140b7d4 demux: fix a corner case (2)
It can happen that read_packet() doesn't read a packet, even if it
succeeds. Typically this is because a packet was read, but then thrown
away, because it's not part of a selected stream. The result would be a
bogus EOF condition.

Fix by explicitly checking for EOF.
2014-07-19 12:34:07 +02:00
wm4 cfdb1312da demux: ensure demux_read_packet_async() always reads
In corner cases, it might be possible that a demux_read_packet_async()
call fails to make the demuxer thread to read more packets.

If a packet is queued, the function will simply return a packet, without
marking the stream as active. As a consequence, read_packet() might
decide not to read any further packets, and the demuxer will never read
a packet and wake up the playback thread.

This was originally done to align it with demux_read_packet() semantics;
just drop this.
2014-07-19 12:27:25 +02:00
wm4 24efaa3ad7 demux: fix a corner case
demux_read_any_packet() attempts to call read_packet(), but if no stream
is active, it can decide not to read anything. The function will return
NULL, which implies EOF. Fix this by explicitly
setting demux_stream->active if needed.

Also use dequeue_packet() instead of demux_read_packet(), because it's
cleaner. (Shouldn't change behavior.)

Possibly fixes #938.
2014-07-19 12:27:21 +02:00
Stefano Pigozzi c76958d20c cocoa: don't send messages to uninitialized gl contexts
This should fix some crashes where we sent makeCurrentContext to a context that
was being freed from another thread.

/cc @mpv-player/stable
2014-07-19 12:01:53 +02:00
wm4 1942e424e3 demux: fix opening pipes with demux_lavf
We told the demuxer that a pipe (if stream cache is enabled) is
seekable. This is because the stream cache is technically seekable, it's
just that seeking may fail at runtime if a non-cached byte range is
requested.

This caused libavformat to issue seeks on initialization (at least when
piping mp4 youtube videos). Initialization failed completely after
spamming tons of error messages.

So, if an unseekable stream is cached, tell the demuxer that the file is
not seekable. This gets reversed later (when printing a message about
caching an unseekable stream), so the user can still try his luck by
issuing a seek command. The important part is that libavformat
initialization will not take code paths that will unnecessarily seek for
whatever reasons.

CC: @mpv-player/stable: regression from 0.3.x
2014-07-18 16:16:05 +02:00
wm4 2646874369 video: use symbolic constants instead of magic integers
In my opinion this is not really necessary, since there's only a single
user of update_video(), but others reading this code would probably hate
me for using magic integer values instead of symbolic constants.

This should be a purely cosmetic commit; any changes in behavior are
bugs.
2014-07-18 15:11:21 +02:00
wm4 7083f88ca8 video: don't block when reading video packets
Instead of blocking on the demuxer when reading a packet, let packets be
read asynchronously. Basically, it polls whether a packet is available,
and if not, the playloop goes to sleep until the demuxer thread wakes it
up.

Note that the player will still block for I/O, because audio is still
read synchronously. It's much harder to do the same change for audio
(because of the design of the audio decoding path and especially
initialization), so audio will have to be done later.
2014-07-18 15:10:28 +02:00
wm4 848546f2de demux: fix problems with EOF
It was easy to get into a wakeup feedback loop on EOF. The reason that
EOF is complicated is that we try to retry reading when EOF is reached,
in case the EOF state actually disappears (e.g. when watching a
currently downloaded file).

This feature is probably worthless, since in practice you have to do a
seek to "unstuck" it anyway, but since the old code also did this, we
want to keep this behavior for now.

Avoid the feedback loop by introducing another EOF flag (last_eof), that
contains the actual previous EOF state, and is not overwritten when
retrying reading. Wakeup is skipped if the EOF state didn't change.

Also, actually call the wakeup callback when EOF is detected.

The line that adds "ds->active = false;" actually does nothing, but in
theory it's cleaner.
2014-07-18 15:08:38 +02:00
wm4 152a099c3a demux: add function to read packets asychronously 2014-07-18 15:08:31 +02:00
wm4 dc00b146c4 player: remove the last instances of polling
Mouse cursor handling, --heartbeat-cmd, and OSD messages basically
relied on polling. For this reason, the playloop always used a small
timeout (not more than 500ms).

Fix these cases, and raise the timeout to 100 seconds. There is no
reason behind this number; for this specific purpose it's as close to
infinity as any other number.

On MS Windows, or if vo_sdl is used, the timeout remains very small.
In these cases the GUI code doesn't do proper event handling in the
first place, and fixing it requires much more effort.

getch2_poll() still does polling, because as far as I'm aware no event-
based way to detect this state change exists.
2014-07-18 15:04:46 +02:00
wm4 34fdf082d8 dvd, bd: fix A/V sync
Slightly less robust, but simpler, and usually guarantees that audio
and video are properly in sync.
2014-07-18 01:26:46 +02:00
wm4 1d7a68d75c demux: fix debug log output
It printed the PTS instead of the DTS.
2014-07-17 22:03:12 +02:00
wm4 9faa131959 demux: drop some unused definitions 2014-07-17 21:53:44 +02:00
wm4 11944e0b83 manpage: fix documented default for --demuxer-thread 2014-07-17 01:50:29 +02:00
wm4 30542456c3 demux_lavf: reverse rotation direction with new API
The old FFmpeg API and the new Libav API disagree about mp4 display
rotation direction. Well, whatever, fix it trial-and-error-style.

CC: @mpv-player/stable: add
2014-07-17 00:30:03 +02:00
wm4 1301a90761 demux: add a demuxer thread
This adds a thread to the demuxer which reads packets asynchronously.
It will do so until a configurable minimum packet queue size is
reached. (See options.rst additions.)

For now, the thread is disabled by default. There are some corner cases
that have to be fixed, such as fixing cache behavior with webradios.

Note that most interaction with the demuxer is still blocking, so if
e.g. network dies, the player will still freeze. But this change will
make it possible to remove most causes for freezing.

Most of the new code in demux.c actually consists of weird caches to
compensate for thread-safety issues (with the previously single-threaded
design), or to avoid blocking by having to wait on the demuxer thread.

Most of the changes in the player are due to the fact that we must not
access the source stream directly. the demuxer thread already accesses
it, and the stream stuff is not thread-safe.

For timeline stuff (like ordered chapters), we enable the thread for the
current segment only. We also clear its packet queue on seek, so that
the remaining (unconsumed) readahead buffer doesn't waste memory.

Keep in mind that insane subtitles (such as ASS typesetting muxed into
mkv files) will practically disable the readahead, because the total
queue size is considered when checking whether the minimum queue size
was reached.
2014-07-16 23:25:56 +02:00
wm4 69a8f08f3e tags: add copy function 2014-07-16 22:40:12 +02:00
Rudolf Polzer 073b2becfe ao_lavc: Fix design of audio pts handling.
There was confusion about what should go into audio pts calculation and
what not (mainly due to the audio push thread). This has been fixed by
using the playing - not written - audio pts (which properly takes into
account the ao's buffer), and incrementing the samples count only by the
amount of samples actually taken from the buffer (unfortunately this
now forces us to keep the lock too long for my taste).
2014-07-16 16:18:34 +02:00
Rudolf Polzer e257cbfdbb ao_lavc: Add a missing newline for the log. 2014-07-16 16:18:34 +02:00
Rudolf Polzer 2a985716cd ao_lavc: Fix advancing of audio pts. 2014-07-16 16:18:34 +02:00
Rudolf Polzer 35c20c3094 idet.sh: Fix a typo. 2014-07-16 16:15:12 +02:00
Tsukasa OMOTO 1c850ff559 osxbundle: fix detection of user libraries
Previous code would detect for example `libcaca.0.dylib` as a system library,
because it matched the `libc` condition.
2014-07-16 08:36:34 +02:00
Stefano Pigozzi 135ba132a8 cocoa: fix regression preventing window resize
I introduced this bug in b5bbb49. Sorry!
This could fix #943 and #930 even though I can't reproduce those specific bugs.
2014-07-15 21:33:19 +02:00
Rudolf Polzer f5449870e0 idet.sh: Fix telecine detection. 2014-07-15 11:10:24 +02:00
wm4 23a7257cca Revert "Remove DVD and Bluray support"
This reverts commit 4b93210e0c.

*shrug*
2014-07-15 01:49:02 +02:00
wm4 4b93210e0c Remove DVD and Bluray support
It never worked well. Just remux your DVD and BD images to mkv.
2014-07-14 14:34:14 +02:00
wm4 c129e3f666 demux_lavf: don't let metadata update mess up ogm playback
For OGG audio files, we usually merge the per-stream metadata back to
the file-global metadata. Don't do that for OGM, because with OGM most
metadata is actually per-stream.
2014-07-14 14:34:14 +02:00
Stefano Pigozzi ac71cb8611 cocoa: fix compilation on OS X 10.8 2014-07-14 07:21:44 +02:00
wm4 9fadc92eb1 command: don't show VO information in colorspace properties
Until now, changing the properties showed the VO colorspace parameters
on OSD. This didn't work quite well, because it showed the VO parameters
_before_ the change. This is because at least one video frame with the
new parameters has to be shown, and this doesn't happen right after
changing the property, but a bit later.

Also fix a random typo in unrelated code.
2014-07-13 20:12:55 +02:00
wm4 417ffa8b40 Remove some mp_msg calls with no trailing \n
The final goal is all mp_msg calls produce complete lines. We want this
because otherwise, race conditions could corrupt the terminal output,
and it's inconvenient for the client API too. This commit works towards
this goal. There's still code that has this not fixed yet, though.
2014-07-13 20:12:13 +02:00
wm4 d54d21cbd5 config: adjust config parser messages
Some cleanup. Also, try not to call mp_msg multiple times for 1 line.
2014-07-13 20:11:46 +02:00
wm4 9b654fd540 player: remove some inactive code
demux_seek() actually doesn't return seek success. Instead, it fails if
the demuxer is flagged as unseekable (but this is checked explicitly at
the beginning of this function), or if the seek target PTS is
MP_NOPTS_VALUE (which can never happen).
2014-07-13 20:07:29 +02:00
wm4 ae7228c6a3 audio: drop buffered audio when switching tracks or filters
No reason to wait until the audio has been played. This isn't a problem
with gapless audio disabled, and since gapless is now default, this
behavior might be perceived as regression.

CC: @mpv-player/stable
2014-07-13 20:07:14 +02:00
wm4 fb54a1436a audio: don't wait for draining if paused
Logic for this was missing from pull.c. For push.c it was missing if the
driver didn't support it. But even if the driver supported it (such as
with ao_alsa), strange behavior was observed by users. See issue #933.

Always check explicitly whether the AO is in paused mode, and if so,
don't drain.

Possibly fixes #933.

CC: @mpv-player/stable
2014-07-13 20:06:33 +02:00
wm4 b505cab597 dvdnav: fix time display when starting in the middle of the DVD
libdvdnav can actually jump into the middle of the DVD (e.g. scene
selection menus do that). Then time display is incorrect: we start from
0, even though playback time is somewhere else. This really matters when
seeking. If the display time mismatches, a small relative seek will
apparently jump to the beginning of the movie.

Fix this by initializing the PTS stuff on opening. We have to do this
after some small amount of data has been read from the stream (because
libdvdnav is crap and doesn't always update the time between seeks and
the first read; also see STREAM_CTRL_GET_CURRENT_TIME remarks in
cache.c; although this was not observed when testing with scene
selection menus). On the other hand, we want to do it before opening the
demuxer, because that will read large amounts of data and likely will
change the stream position.

Also see commit 49813670.
2014-07-13 20:05:25 +02:00
Alessandro Ghedini 1f98bb3adc stream_dvdnav: suspend read on vts change even if the requested title is not found 2014-07-13 18:26:08 +02:00
Alessandro Ghedini 712cf3342e DOCS/release-policy: mention the release version in the RELEASE_NOTES template
Also suggest adding changes in point releases to RELEASE_NOTES as well.
2014-07-13 15:03:47 +02:00
wm4 a09329bcf7 input: skip BOM in input.conf 2014-07-12 21:25:32 +02:00
wm4 fed69f3637 config: skip BOM 2014-07-12 21:24:55 +02:00
wm4 5b820ff1b4 dvd: potentially fix video aspect ratio
This overwrote the source stream header, instead of the stream header
exported to the decoder.
2014-07-12 20:17:19 +02:00
wm4 c37956b364 stream: don't sleep for reconnecting network if playback is stopped
Also silences the bogus message if that happens.

CC: @mpv-player/stable
2014-07-12 19:19:04 +02:00
wm4 64e3b07a9d cache_file: fix operation if stream size is unknown
Happens when playing from a pipe.

Note that seeking forward doesn't work. It would be possible to create a
workaround for that by reading and skipping data until the target
position is reached (and writing the skipped data into the cache file),
but I'm not sure about that.

Fixes #928.

CC: @mpv-player/stable
2014-07-12 19:18:21 +02:00
ChrisK2 1e8b98af73 osc: improve previous commit 2014-07-10 11:22:05 +02:00
ChrisK2 549afdb9c5 osc: round displayed cache value
Fixes #919
2014-07-10 11:17:51 +02:00
wm4 d68d4dd984 Revert "build: avoid defining _GNU_SOURCE"
This reverts commit 2e6a8f260c.

Too many problems for now, such as with OSX and asprintf().
2014-07-10 09:25:37 +02:00
wm4 f8c2dd1b78 build: include <strings.h> for strcasecmp()
It happens to work without strings.h on glibc or with _GNU_SOURCE, but
the POSIX standard requires including <strings.h>.

Hopefully fixes OSX build.
2014-07-10 08:29:32 +02:00
wm4 e1f2540ede video/out: use strcmp() instead of strcasecmp() for equalizers
This makes it more consistent with the more important VOs.
2014-07-10 08:27:15 +02:00
wm4 1a1e631ccd build: deal with endian mess
There is no standard mechanism for detecting endianess. Doing it at
compile time in a portable way is probably hard. Doing it properly
with a configure check is probably hard too. Using the endian
definitions in <sys/types.h> (usually includes <endian.h>, which is
not available everywhere) works under circumstances, but the previous
commit broke it on OSX.

Ideally all code should be endian dependent, but that is not possible
due to the dependencies (such as FFmpeg, some video output APIs, some
audio output APIs).

Create a header osdep/endian.h, which contains various fallbacks.
Note that the last fallback uses libavutil; however, it's not clear
whether AV_HAVE_BIGENDIAN is a public symbol, or whether including
<libavutil/bswap.h> really makes it visible. And in fact we don't want
to pollute the namespace with libavutil definitions either. Thus it's
only the last fallback.
2014-07-10 00:58:56 +02:00
wm4 2e6a8f260c build: avoid defining _GNU_SOURCE
_GNU_SOURCE defines the kitchen sink, and also prefers glibc definitions
where glibc and POSIX conflict. Even though POSIX is worth less than
toilet paper, we still prefer the POSIX definitions.

rar.c needs asprintf(), which is _GNU_SOURCE-only. So we define
_GNU_SOURCE too specifically for this file.
2014-07-09 22:10:33 +02:00
wm4 5d3f1a17a7 DOCS/tech-overview: minor updates 2014-07-09 02:14:23 +02:00
wm4 93f63214e0 demux: remove accurate_seek field
It's unused now. (Only the dvd code used it until recently.)
2014-07-08 22:20:39 +02:00
Stefano Pigozzi 609187082f cocoa: simplify logic that returns used bits per color 2014-07-08 22:06:57 +02:00
Stefano Pigozzi b5bbb49a1a cocoa: move CGL context creation to gl_cocoa
This approach is similar to what other vo_opengl backends do. It can also be
used in the future to create another cocoa backend that renders offscreen
with IOSurfaces or FBOs.
2014-07-08 21:06:57 +02:00
wm4 469ec23f85 demux_disc: flush slave demuxer packet queue on resync
Technically needed, but not strictly. It seems it works without in
practice, because demux_lavf.c reads exactly one packet for fill_buffer
call, so there are never packets queued.
2014-07-07 19:24:22 +02:00
wm4 4981367021 cache, dvd, bluray: simplify stream time handling
We used a complicated and approximate method to cache the stream
timestamp, which is basically per-byte. (To reduce overhead, it was only
cached per 8KB-block, so it was approximate.)

Simplify this, and read/keep the timestamp only on discontinuities. This
is when demux_disc.c actually needs the timestamp.

Note that caching is currently disabled for dvdnav, but we still read
the timestamp only after some data is read. libdvdread behaves well, but
I don't know about libbluray, and the previous code also read the
timestamp only after reading data, so try to keep it safe.

Also drop the start_time offset. It wouldn't be correct anymore if used
with the cache, and the idea behind it wasn't very sane either (making
the player to offset the initial playback time to 0).
2014-07-07 19:09:37 +02:00
wm4 4d829d750c input: restore ability to combine mouse buttons
Key bindings are decided on the "down" event, so if the prefix is not
unique, the first/shortest will be used (e.g. when both "a" and "a-b"
are mapped, "a" will always be chosen).

This also breaks combining multiple mouse buttons. But it seems users
expect it to work, and it's indeed a bit strange that it shouldn't work,
as mouse bindings are emitted on the key "up" event, not "down" (if the
shorter binding didn't emit a command yet, why shouldn't it be
combinable).

Deal with this by clearing the key history when a command is actually
emitted, instead of when a command is decided. This means if both
MOUSE_BTN0 and MOUSE_BTN0-MOUSE_BTN1 are mapped, the sequence of holding
down BTN0 and then BTN1 will redecide the current command. On the other
hand, if BTN0 is released before BTN1 is pressed, the command is
emitted, and the key history is deleted. So the BTN1 press will not
trigger BTN0-BTN1.

For normal keys, nothing should change, because commands are emitted on
the "down" event already, so the key history is always cleared.

Might fix #902.

CC: @mpv-player/stable (if this fix is successful)
2014-07-07 18:18:41 +02:00
wm4 c07bae02e2 ao_null: disable latency emulation
Doesn't work quite right, and will pause for the latency duration after
seeking. Some users use --ao=null to disable audio (even though they
should probably use --no-audio), and this use-case is broken by this
issue too.

CC: @mpv-player/stable
2014-07-07 18:00:48 +02:00
wm4 19dde186a0 demux: print initial metadata
This was accidentally broken in 7e209185, and metadata was printed only
when it changed.
2014-07-07 18:00:41 +02:00
wm4 e2b0416ae1 osc: fix failure when using DVD menus
[osc] Lua error: mp.assdraw:31: attempt to concatenate local 's' (a nil value)
2014-07-07 18:00:41 +02:00
wm4 02ca42c7f1 lua: redo error handling, print backtraces
The original goal was just adding backtraces, however making the code
safe (especially wrt. to out of memory Lua errors) was hard. So this
commit also restructures error handling to make it conceptually simpler.
Now all Lua code is run inside a Lua error handling, except the calls
for creating and destroying the Lua context, and calling the wrapper C
function in a safe way.

The new error handling is actually conceptually simpler and more
correct, because you can just call any Lua function at initialization,
without having to worry whwther it throws errors or not.

Unfortunately, Lua 5.2 removes lua_cpcall(), so we have to emulate it.
There isn't any way to emulate it in a way that works the same on 5.1
and 5.2 with the same semantics in error cases, so ifdeffery is needed.
The debug.traceback() function also behaves weirdly differently between
the Lua versions, so its output is not as nice as it could be (empty
extra line).
2014-07-07 18:00:41 +02:00
wm4 0ea2bc2778 old-configure: fix Lua tests
This added every Lua that was found on the system.
2014-07-07 18:00:41 +02:00
wm4 acd60736ef Remove stream_pts stuff
This was used by DVD/BD, but its usage was removed with one of the
previous commits.
2014-07-06 19:05:59 +02:00
wm4 a90b5cfddf DOCS/client-api-changes: try to fix rst formatting again 2014-07-06 19:05:45 +02:00
wm4 f512604f02 dvd, bd: enable precise seeking
This should work now, at least kind of. Note that actual success depends
on the behavior of the underlying lib{dvd{nav,read},bluray}
implementation, which could go very wrong.

In the worst case, it could happen that the underlying implementation
seeks a long time before the seek target time. In this case, the player
will just decode video until the target time is reached, even if that
requires e.g. decoding 30 mintues of video before refreshing.

In the not-so-bad but still bad case, it would just miss the seek
target, and seek past it.

In my tests, it works mostly ok, though. Seeking backwards usually
fails, unless something like --hr-seek-demuxer-offset=1 is used (this
makes it seek to 1 second before the target, which may or may not be
enough to compensate for the DVD/BD imprecision).
2014-07-06 19:03:43 +02:00
wm4 7bf090ad24 dvd, bluray: handle playback display time handling differently
This is a pretty big change. Instead of doing a half-hearted passthrough
of the playback timestamp, we attempt to rewrite the raw MPEG timestamps
such that they match with the playback time.

We add the offset between raw start timestamp and playback time to the
packet timestamps. This is the easy part; but the problem is with
timestamp resets. We simply detect timestamp discontinuities by checking
whether they are more than 500ms apart (large enough for all video
faster than 2 FPS and audio with reasonable framesizes/samplerates), and
adjust the timestamp offset accordingly.

This should work pretty well. There may be some problems with subtitles.
If the first packet after a timestamp reset is a subtitle instead of
video, it will fail. Also, selecting multiple audio or video streams
won't work (but mpv doesn't allow selecting several anyway). Trying to
demux subtitles with no video stream enabled will probably fail.

Untested with Bluray, because I have no Bluray sample.

Background:

libdvdnav/libdvdread/libbluray make this relatively hard. They return a
raw MPEG (PS/TS) byte stream, and additionally to that provide a
function to retrieve the current "playback" time. The playback time is
what should be displayed to the user, while the MPEG timestamps can be
completely different. Even worse, the MPEG timestamps can reset. Since
we use the libavformat demuxer (instead of parsing the MPEG packets in
the DVD/BD code), it's hard to associate between these timestamps. As a
result, the time display is special cased in the playloop, and of low
quality (updates only all 1 or 2 seconds, sometimes is incorrect). The
fact that the stream cache can be between demuxer and the stream source
makes things worse.

All the libs seem to provide an event that tells whether timestamps are
resetting. But since this signalling is byte based, it's hard to connect
it to the demuxed MPEG packets. It might be possible to create some sort
of table mapping file positions to discontinuities and new timestamps.
(For simplicity, this table could be 2 entries large, sufficient to
catch all discontinuities if the distance between them is larger than
the total buffering.)
2014-07-06 19:03:12 +02:00
wm4 361be8385b stream_dvdnav: more debugging output 2014-07-06 19:03:05 +02:00
wm4 f3604fc3fb demux: fix a corner case related to demux_disc
It can happen that demux_fill_buffer() adds more than 1 packet, and then
the packets would add up. Affects demux_disc.c only (nothing else uses
this function).
2014-07-06 19:02:58 +02:00
wm4 e3a3b764c8 dvd: fix first subtitle with delayed subtitle streams
This was accidentally broken with moving the DVD code to demux_disc.c.

Also remove an abort() call meant for debugging.
2014-07-06 19:02:49 +02:00
wm4 1d55547adf stream: remove now unused STREAM_CTRL_GET_START_TIME
demux_disc.c takes care of this now.
2014-07-06 19:02:33 +02:00
wm4 de28876222 demux: minor simplification
Oops, should have been part of commit 37085788.
2014-07-06 19:02:21 +02:00
atomnuker e6643abc98 ao_pulse: set icon name
Will replace the generic XDG video icon inherited from media role.
2014-07-05 17:07:16 +02:00
wm4 6fcb34d887 vf_vapoursynth: reset error state on seeking
When seeking, we violently destroy the filter, because vapoursynth has
no proper API for terminating a video with unknown frame count. This
looks like an error to vapoursynth, and the error is returned via the
frame callbacks. The bug is that we remember this error state across
reinitialization, so on the first filter call after reinitialization, we
thought filtering the current frame failed. This caused a shift by 1
frame on each seek.

CC: @mpv-player/stable
2014-07-05 17:07:16 +02:00
wm4 d27a2bc546 build: allow compilation without any atomics
Not all compilers on all platforms have atomics available (even if they
could, technically speaking).

We don't use atomics that much, only the following things rely on it:
1. the audio pull code, and all audio outputs using it
2. updating global msg levels
3. reading log messages through the client API

Just disable 1. and 3. if atomics are not available. For 2., using fake-
atomics isn't too bad; at worst, message levels won't properly update
under certain situations (but most likely, it will work just fine).

This means if atomics are not available, the client API function
mpv_request_log_messages() will do nothing.

CC: @mpv-player/stable
2014-07-05 17:07:16 +02:00
wm4 49df035514 options: remove bogus replacement message for --fstype
CC: @mpv-player/stable
2014-07-05 17:07:16 +02:00
wm4 962b928192 options: add --autosub-match to option replacement list
CC: @mpv-player/stable
2014-07-05 17:07:16 +02:00
wm4 4f00c74491 player: don't use stream position as fallback for percent-pos
This should be unneeded, and the packet position is already sufficient
for this case.

Accessing the stream position directly is going to be a problem when the
stream is accessed from another thread later.
2014-07-05 17:07:15 +02:00
wm4 54a4a25fe9 tv: move demuxer parts to separate file
Now all demuxer implementations (at least demuxer API-wise) are in the
demux directory.
2014-07-05 17:07:15 +02:00
wm4 37085788e4 demux: minor simplification to internal API
Also some other unrelated minor changes.
2014-07-05 17:07:15 +02:00
wm4 de71b50249 dvd: move angle switching code
No need to provide a "nice" API for it; just do this stuff directly in
the command code.
2014-07-05 17:07:15 +02:00
wm4 0cc3594623 dvd: flush buffers properly on seek
Suggested by tholin on github issue #882.

This is not entirely clean, but the fields we're accessing might be
considered internal to libavformat. On the other hand, existence of the
fields is guaranteed by the ABI, and nothing in the libavformat doxygen
suggestes they're not allowed to be accessed.

CC: @mpv-player/stable
2014-07-05 17:07:15 +02:00
wm4 338004bcfc dvd, bluray, cdda: add demux_disc containing all related hacks
DVD and Bluray (and to some extent cdda) require awful hacks all over
the codebase to make them work. The main reason is that they act like
container, but are entirely implemented on the stream layer. The raw
mpeg data resulting from these streams must be "extended" with the
container-like metadata transported via STREAM_CTRLs. The result were
hacks all over demux.c and some higher-level parts.

Add a "disc" pseudo-demuxer, and move all these hacks and special-cases
to it.
2014-07-05 17:07:15 +02:00
wm4 4d2a4afdef discnav: fix a comment 2014-07-05 17:07:15 +02:00
wm4 942619c779 demux: set filepos field when dequeuing a packet
Otherwise the position can be too far ahead.
2014-07-05 17:07:15 +02:00
wm4 85eb2bee3a demux: cosmetics: minimize code 2014-07-05 17:07:15 +02:00
wm4 8d40b1e8ab demux: make start time a simple field
Simpler, especially for later changes.
2014-07-05 17:07:15 +02:00
wm4 7e209185f1 demux, stream: change metadata notification
(Again.)

This time, we simply make it event-based, as it should be. This is done
for both demuxer metadata and stream metadata.

For some ogg-over-icy streams, 2 updates are reported on stream start.
This is because libavformat reports an update right on start, while
including the same info in the "static" metadata. I don't know if that's
a bug or a feature.
2014-07-05 17:07:14 +02:00
wm4 58880c00ee demux: make replaygain per-track
It's unlikely that files with multiple audio tracks and with replaygain
actually happen, but this change might help avoid minor corner cases
with later changes.
2014-07-05 17:07:14 +02:00
wm4 a97256c1d5 demux: move packet functions to a separate source file 2014-07-05 17:07:14 +02:00
wm4 e4221f3189 demux: move packet list functions
Move them to the only place where they are used, demux_subreader.c.
2014-07-05 17:07:14 +02:00
wm4 18e6d07612 demux_lavf: for now, ignore the new libavformat image demuxers
Recently, libavformat added demuxers to open image files like normal
demuxers. This is a good thing, but for now they interfere with the
operation of demux_mf. Add them to the blacklist until there is a proper
solution.

(The list doesn't contain _all_ recognized image formats, just those
that might interfere with demux_mf.)

CC: @mpv-player/stable
2014-07-05 17:07:14 +02:00
wm4 5eb9039c6b demux_lavf: support OTF fonts in Matroska
Apparently it's FFmpeg only.
2014-07-05 17:07:14 +02:00
wm4 1713dc58f1 demux_lavf: don't dump transport stream programs
Probably useless.
2014-07-05 17:07:14 +02:00
wm4 78f3ba73b9 demux_lavf: cleanup debug output
Remove unnecessary prefix, remove some messages.
2014-07-05 17:07:14 +02:00
wm4 bc29e17bcf demux_lavf: fix read_seek return value
This returned a stream error value directly to libavformat, which can't
make sense. For example STREAM_ERROR (0) means success in libavformat
error codes. (The meaning of the libavformat read_seek return value is
underdocumented too.)
2014-07-05 17:07:14 +02:00
wm4 44d7499190 demux_mkv: cosmetics 2014-07-05 17:07:14 +02:00
wm4 e21ecaa18d DOCS, client API: add mpv release versions
The intention is to make it obvious which mpv releases certain changes
will apply to.

Also attempt to fix RST formatting of the list. This is not very proper,
but probably good enough.
2014-07-05 17:07:14 +02:00
Stefano Pigozzi 055bc74ed4 Merge pull request #909 from Nyx0uf/patch-1
OS X bundle: Add more imported UTI
2014-07-05 10:15:14 +02:00
Nyx0uf 22c3de3f8a OS X bundle: Add more imported UTI
Not that there are widely used formats, but it will allow to play them directly from the Finder.
2014-07-04 10:05:52 +02:00
tholin bc5e539d3b stream_dvdnav: check the length of all titles with dvdnav://longest
The last title was ignored before.

CC: @mpv-player/stable

Signed-off-by: wm4 <wm4@nowhere>
2014-07-04 02:24:50 +02:00
tholin f8a7517fb7 stream_dvdnav: free pointer to priv->filename on close
CC: @mpv-player/stable

Signed-off-by: wm4 <wm4@nowhere>
2014-07-04 02:24:50 +02:00
tholin 4bd75313d1 stream_dvdnav: make sure seeking bounds are within range
libdvdnav returns an error is the seek position is out of range.

CC: @mpv-player/stable

Signed-off-by: wm4 <wm4@nowhere>
2014-07-04 02:24:50 +02:00
wm4 fe4fbb5775 DOCS/client_api_examples: add a Qt example
This is pretty dumb and extremely basic. The main purpose is
demonstrating how to integrate mpv into the Qt GUI thread.
2014-07-04 02:24:49 +02:00
wm4 4fedf86b8a client API: allow calling mpv_terminate_destroy(NULL)
This is an oversight and a bug.

CC: @mpv-player/stable
2014-07-04 02:24:49 +02:00
wm4 4a5cfb4323 x11: avoid obscure behavior when --wid is partially garbage
Cast away the "extra" bits (since apparently Window/XID is always
32 bit unsigned). This is not striclty needed, because you're not
supposed to pass garbage to --wid, just because the upper bits are
possibly not interpreted. But if you do so, this change increases
consistency in behavior and removes a strange behavior that was
thought to be a bug.

Also see github issue #906.
2014-07-04 02:23:05 +02:00
Stefano Pigozzi 97f6d7f4ec ao_coreaudio: report hardware latency to ao_read_data
Commit a6a4cd2c88 added reporting of playout latency, this commit also adds
support for reporting hardware and constant audio unit latency.
2014-07-03 20:05:15 +02:00
Alessandro Ghedini 29b047da6f TOOLS/zsh.pl: complete URL schemes based on --list-protocols 2014-07-03 11:03:56 +02:00
Alessandro Ghedini 17d65f9aff TOOLS/zsh.pl: sort options in reverse order by length
This stops options that are prefixes of other options from blocking
completion of values for the longer ones.
2014-07-03 11:03:56 +02:00
Philip Sequeira e940afec15 TOOLS/zsh.pl: untabify 2014-07-03 11:03:56 +02:00
Philip Sequeira 7450a7f531 TOOLS/zsh.pl: fix _arguments line
Don't use _x_arguments, as we don't support X arguments.

Get rid of -s, because we don't support multiple single-letter options
in one argument.

Add -S, because we ignore options after "--".
2014-07-03 11:03:56 +02:00
Philip Sequeira bbc005825a TOOLS/zsh.pl: don't consume extra arguments
Completion now uses "--opt=value" instead of "--opt value". Once the
user presses space and starts a new argument, the option just
completed is out of the picture, whether or not it was given an
argument. This handles options with no arguments or optional arguments
much better; previously, completing such an option would effectively
disable completion for the next argument.

Custom completed options such as "--ao" and friends will no longer
claim to consume an extra argument.
2014-07-03 11:03:56 +02:00
Philip Sequeira fd09578f0f TOOLS/zsh.pl: escape all colons in option descriptions 2014-07-03 11:03:56 +02:00
wm4 4d9ce2993f command: include new "playback-time" property in update mechanism 2014-07-03 01:26:19 +02:00
wm4 0004aaf788 DOCS: add a file listing API changes for the client API 2014-07-03 01:26:19 +02:00
Stefano Pigozzi 0bda8f48e2 manpage: reflect new coreaudio changes 2014-07-02 23:17:44 +02:00
Stefano Pigozzi a6a4cd2c88 ao_coreaudio: report latency more correctly
Previous code was completly wrong. This still doesn't report the device
latency, but we report the buffer latency (as before the AO refactoring) and
the AudioUnit's latency (this is a new 'feature').

Apparently we can also report the device actual latency and we should also
calculate the actual sample rate of the audio device instead of using the
nominal sample rate, but I'll leave this for a later commit.
2014-07-02 23:17:44 +02:00
wm4 703de5d84e cache_file: use unicode on windows
This enables the MinGW Windows crap wrapper for fopen().
2014-07-02 22:01:56 +02:00
Stefano Pigozzi 4f5f034ba2 ao_coreaudio: move channel mapping away from utils
Channel mapping functions are only used in the AUHAL based coreaudio, so move
them there.
2014-07-02 21:43:08 +02:00
Stefano Pigozzi c8fc02612e ao_coreaudio: use mpv's internal pull API 2014-07-02 21:43:08 +02:00
Stefano Pigozzi d16e4b836a ao_coreaudio: remove useless comments 2014-07-02 21:43:08 +02:00
Stefano Pigozzi 0ffbd05e99 ao_coreaudio: rename init_lpcm -> init_audiounit 2014-07-02 21:43:08 +02:00
Stefano Pigozzi 80ec0ba6d0 ao_coreaudio: fill asbd with an helper function 2014-07-02 21:43:07 +02:00
Stefano Pigozzi fa85bfde69 ao_coreaudio: split control to helper functions 2014-07-02 21:43:07 +02:00
Stefano Pigozzi f317d24a39 ao_coreaudio: move device related functions to the new AO 2014-07-02 21:43:07 +02:00
Stefano Pigozzi a8ef70b0f8 ao_coreaudio: remove useless call to print_asbd 2014-07-02 21:43:07 +02:00
Stefano Pigozzi 041557b639 ao_coreaudio: move spdif code to a new AO
The mplayer1/2/mpv CoreAudio audio output historically contained both usage
of AUHAL APIs (these go through the CoreAudio audio server) and the Device
based APIs (used only for output of compressed formats in exclusive mode).

The latter is a very unwieldy and low level API and pretty much forces us to
write a lot of code for little workr. Also with the widespread of HDMI, the
actual need for outputting compressed audio directly to the device is getting
lower (it was very useful with S/PDIF for bandwidth constraints not allowing
a number if channels transmitted in LPCM).

Considering how invasive it is (uses hog/exclusive mode), the new AO
(`ao_coreaudio_device`) is not going to be autoprobed but the user will have
to select it.
2014-07-02 21:43:07 +02:00
wm4 7084e800be cache: clear DVD timestamps
When resizing the cache, the buffer for the DVD timestamps is
initialized with 0. This causes the player to always return playback
position 0 with any file format (not just DVD), and also makes all
relative seeks relative to position 0. Fix this by clearing the
timestamps explicitly.

Closes #899.

CC: @mpv-player/stable
2014-07-02 19:01:47 +02:00
wm4 6d38ad1410 x11: clear window only on initial map
Apparently clearing on every map can cause problems with vdpau when
switching virtual desktops and such. This was observed with at least
XMonad and nvidia-340.17. It's not observed on some other setups without
XMonad.

It's not clear why this happens. Normally, the window background is not
saved, so clearing should have no additional affect. It's a complete
mystery. Possible, the use of legacy X drawing commands (used to clear
the window) interferes with vdpau operation in non-trivial ways.

Work this around by clearing on initial map only. This probably only
hides the underlying issue, but good enough.

Closes #897.

CC: @mpv-player/stable
2014-07-02 02:07:06 +02:00
wm4 4b5fbb3ee0 command: remove some code duplication in cache properties
This also means that the printed size is always rounded to KBs, because
the cache properties are returned in KB. I think this doesn't matter
much. But if it does, the cache properties should probably changed to
return bytes in the first place.
2014-07-02 01:46:04 +02:00
wm4 94450bf410 command: cache can actually have full-size 0
Then it's simply empty.
2014-07-02 01:32:05 +02:00
Andrey Morozov b1969c0eba command: change cache perentage to float, add cache-free and cache-used 2014-07-02 01:28:11 +02:00
wm4 9fee8fd3b3 demux: drop AVI special code
I'm pretty sure libavformat does this automatically, and we don't have
other demuxers where this could happen.

Still, slightly "risky" - so let's see.
2014-07-02 00:32:46 +02:00
wm4 bb131f4c66 demux_mkv: minor improvement to overflow check
CC: @mpv-player/stable
2014-07-02 00:14:18 +02:00
wm4 9a210ca2d5 Audit and replace all ctype.h uses
Something like "char *s = ...; isdigit(s[0]);" triggers undefined
behavior, because char can be signed, and thus s[0] can be a negative
value. The is*() functions require unsigned char _or_ EOF. EOF is a
special value outside of unsigned char range, thus the argument to the
is*() functions can't be a char.

This undefined behavior can actually trigger crashes if the
implementation of these functions e.g. uses lookup tables, which are
then indexed with out-of-range values.

Replace all <ctype.h> uses with our own custom mp_is*() functions added
with misc/ctype.h. As a bonus, these functions are locale-independent.
(Although currently, we _require_ C locale for other reasons.)
2014-07-01 23:11:08 +02:00
wm4 0208ad4f3b demux: minor cleanups 2014-07-01 21:53:23 +02:00
Alessandro Ghedini 2224ac5190 README: fix link to release policy document 2014-06-30 23:23:50 +02:00
Alessandro Ghedini ab241c05c8 options: add --list-protocols option 2014-06-30 23:20:10 +02:00
Alessandro Ghedini 211ca98e9c build: set default cdrom and dvd devices on linux 2014-06-30 23:19:53 +02:00
wm4 1c0939cb80 options: fix --gapless-audio default value
It was intended to be set to "weak" (and that was even documented), but
the actual setting was "no".

Closes #890.

CC: @mpv-player/stable
2014-06-30 18:24:35 +02:00
wm4 dd9420471f demux_mkv: cosmetics 2014-06-29 23:28:47 +02:00
wm4 37251cef69 demux_mkv: add some overflow checks etc.
Some of these might be security relevant.

The RealAudio code was especially bad. I'm not sure if all RealAudio
stuff still plays correctly; I didn't have that many samples for
testing. Some checks might be unnecessary or overcomplicated compared
to the (obfuscated) nature of the code.

CC: @mpv-player/stable
2014-06-29 23:27:28 +02:00
Tsukasa OMOTO 1646584058 player: fix start position when specifying with percent 2014-06-29 20:39:49 +02:00
Tsukasa OMOTO 1aef780b6c options: support setting start time relative to start PTS
Signed-off-by: wm4 <wm4@nowhere>
2014-06-29 20:39:49 +02:00
Tsukasa OMOTO a73415584c player: make the time display relative to start PTS
This commit makes the playback start time always at time 0.

Signed-off-by: wm4 <wm4@nowhere>
2014-06-29 20:39:49 +02:00
wm4 7412257305 av_common: remove unneeded field
This is actually needed for encoding only, and not decoding. Drop it.
2014-06-29 20:39:32 +02:00
Mohammad Alsaleh 8b06fc86f3 af_volume: fix calculations including replay-gain
rgain is not an additive value. It's a multiplier/gain.

Previous behaviour produced negative level values in some cases
(when rgain < 1.0) which caused volume to be louder when its value
was lowered.

CC: @mpv-player/stable

Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
Signed-off-by: wm4 <wm4@nowhere>
2014-06-28 15:56:16 +02:00
wm4 88225d0afb sub: fix undefined behavior with dvd://
The string could get reallocated.

CC: @mpv-player/stable
2014-06-28 15:55:24 +02:00
wm4 6eb955e274 manpage: update config file locations
Also add some explanations how the config paths are determined.
2014-06-28 15:55:09 +02:00
wm4 07bc199e35 scripting: shorten a line
Also allows it to deal with NULL return values, which currently is not
needed, but may or may not be required at some point in the future (what
if malloc fails).
2014-06-26 19:56:45 +02:00
wm4 3e631b9cb8 config: use the same signature for win32/OSX specific path functions
Seems like a good idea, even if it's basically unused (yet).

Also document requirements on the functions (they're not obvious).

OSX changes untested.
2014-06-26 19:56:45 +02:00
wm4 7f55a39646 config: handle --no-config case directly in mp_config_dirs()
Requires less special-casing, and probably also avoids that starting mpv
with --no-config creates a config dir (even if nothing is loaded).
2014-06-26 19:56:45 +02:00
wm4 b4d64ac434 config, player: avoid some temporary talloc contexts
IMO a semi-bad concept, that the mpv code unfortunately uses way too
much.
2014-06-26 19:56:45 +02:00
wm4 3e1c0e5853 config: make passing talloc context optional for some functions
Until now, the config functions added various allocations to the user-
provided talloc context. Make it so that they're all under the returned
allocation instead. This allows avoiding having to create an extra
temporary context for some callers, and also avoids adding random memory
leaks by accidentally passing a NULL context.

mp_find_all_config_files() has to be changed not to return a pointer
into the middle array for this to work. Make it add paths in order
(instead of reverse), and then reverse the array entries after that.

Also remove the declarations for the win-specific private functions.
Remove STRNULL(); it's barely needed anymore and the functions are
not called with NULL filenames anymore.
2014-06-26 19:56:45 +02:00
wm4 0dcde951b9 player: create config dir if it doesn't exist
This was dropped in the commit adding XDG support, probably
accidentally.

Also normalize some whitespace.
2014-06-26 19:43:23 +02:00
wm4 236fcd3648 config: prefer the old config dir if it exists, but XDG doesn't
This means normally the XDG config dir will be used. But if the old
config dir (~/.mpv) exists and the XDG config dir does not, then don't
create it.

To simplify the code, also make mp_path_exists() accept NULL paths. In
that case it's considered as not existing. (Funnily, on Linux this
already worked, because the string is passed directly to the kernel,
and the kernel will just return EFAULT on invalid memory.)
2014-06-26 19:41:48 +02:00
wm4 c63378d41c player: remove some minor code duplication in config loader code
It's better to keep the logic in one place.

Also drop that a broken config file aborts loading of the player. I
don't see much reason for this, and it inflates the code slightly.
2014-06-26 19:37:26 +02:00
Kenneth Zhou cb250d490c Basic xdg directory implementation
Search $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS for config files.
This also negates the need to have separate user and global variants of
mp_find_config_file()

Closes #864, #109.

Signed-off-by: wm4 <wm4@nowhere>
2014-06-26 19:37:25 +02:00
401 changed files with 29583 additions and 17281 deletions

No files matched your search

+6 -6
View File
@@ -20,12 +20,12 @@
/demux/ebml_types.h
/sub/osd_font.h
/player/lua/*.inc
/DOCS/man/*/mpv.1
/DOCS/man/*/mpv.aux
/DOCS/man/*/mpv.log
/DOCS/man/*/mpv.out
/DOCS/man/*/mpv.pdf
/DOCS/man/*/mpv.toc
/DOCS/man/mpv.1
/DOCS/man/mpv.aux
/DOCS/man/mpv.log
/DOCS/man/mpv.out
/DOCS/man/mpv.pdf
/DOCS/man/mpv.toc
/waf
/build
+41 -9
View File
@@ -1,16 +1,41 @@
language: c
os:
- linux
- osx
env:
- LIBAV=libav-stable
- LIBAV=libav-git
- LIBAV=ffmpeg-stable
- LIBAV=ffmpeg-git
matrix:
- LIBAV=libav-stable
- LIBAV=libav-git
- LIBAV=ffmpeg-stable
- LIBAV=ffmpeg-git
global:
# Coverity token
- secure: "H21mSRlMhk4BKS0xHZvCFGJxteCP0hRVUxTuNfM2Z9HBsyutuLEYMtViLO86VtM+Tqla3xXPzUdS4ozLwI72Ax/5ZUDXACROj73yW6QhFB5D6rLut12+FjqC7M33Qv2hl0xwgNBmR5dsm1ToP37+Wn+ecJQNvN8fkTXF+HVzOEw="
compiler:
- clang
- gcc
branches:
only:
- master
- ci
- coverity_scan
matrix:
exclude:
- os: osx
env: LIBAV=libav-stable
- os: osx
env: LIBAV=libav-git
- os: osx
env: LIBAV=ffmpeg-git
- os: osx
compiler: gcc
- os: linux
env: LIBAV=ffmpeg-stable
- os: linux
compiler: clang
before_install: ./travis-deps libass-stable $LIBAV
script:
@@ -18,13 +43,20 @@ script:
- ./waf configure
- ./waf build
notifications-policy: &notifications-policy
on_success: change
on_failure: always
notifications:
email: false
irc:
channels:
- "irc.freenode.org#mpv-player-dev"
<<: *notifications-policy
on_success: change
on_failure: always
addons:
coverity_scan:
project:
name: "mpv-player/mpv"
description: "Build submitted via Travis CI"
notification_email: mpv-team@googlegroups.com
build_command_prepend: "./bootstrap.py && ./waf configure"
build_command: "./waf build"
branch_pattern: coverity_scan
+74
View File
@@ -0,0 +1,74 @@
Introduction
============
This file lists all changes that can cause compatibility issues when using
mpv through the client API (libmpv and ``client.h``). Since the client API
interfaces to input handling (commands, properties) as well as command line
options, this list is interesting for other uses of mpv, such as the Lua
scripting interface, key bindings in ``input.rst``, or plain command line
usage.
Normally, changes to the C API that are incompatible to previous iterations
receive a major version bump (i.e. the first version number is increased),
while C API additions bump the minor version (i.e. the second number is
increased). Changes to properties/commands/options may also lead to a minor
version bump, in particular if they are incompatible.
The version number is the same as used for MPV_CLIENT_API_VERSION (see
``client.h`` how to convert between major/minor version numbers and the flat
32 bit integer).
Also, read the section ``Compatibility`` in ``client.h``.
API changes
===========
::
--- mpv 0.7.0 is released ---
1.10 - deprecate/disable everything directly related to script_dispatch
(most likely affects nobody)
1.9 - add enum mpv_end_file_reason for mpv_event_end_file.reason
- add MPV_END_FILE_REASON_ERROR and the mpv_event_end_file.error field
for slightly better error reporting on playback failure
- add --stop-playback-on-init-failure option, and make it the default
behavior for libmpv only
- add qthelper.hpp set_option_variant()
- mark the following events as deprecated:
MPV_EVENT_TRACKS_CHANGED
MPV_EVENT_TRACK_SWITCHED
MPV_EVENT_PAUSE
MPV_EVENT_UNPAUSE
MPV_EVENT_METADATA_UPDATE
MPV_EVENT_CHAPTER_CHANGE
They are handled better with mpv_observe_property() as mentioned in
the documentation comments. They are not removed and still work.
1.8 - add qthelper.hpp
1.7 - add mpv_command_node(), mpv_command_node_async()
1.6 - modify "core-idle" property behavior
- MPV_EVENT_LOG_MESSAGE now always sends complete lines
- introduce numeric log levels (mpv_log_level)
--- mpv 0.6.0 is released ---
1.5 - change in X11 and "--wid" behavior again. The previous change didn't
work as expected, and now the behavior can be explicitly controlled
with the "input-x11-keyboard" option. This is only a temporary
measure until XEmbed is implemented and confirmed working.
Note: in 1.6, "input-x11-keyboard" was renamed to "input-vo-keyboard",
although the old option name still works.
1.4 - subtle change in X11 and "--wid" behavior
(this change was added to 0.5.2, and broke some things, see #1090)
--- mpv 0.5.0 is released ---
1.3 - add MPV_MAKE_VERSION()
1.2 - remove "stream-time-pos" property (no replacement)
1.1 - remap dvdnav:// to dvd://
- add "--cache-file", "--cache-file-size"
- add "--colormatrix-primaries" (and property)
- add "primaries" sub-field to image format properties
- add "playback-time" property
- extend the "--start" option; a leading "+", which was previously
insignificant is now significant
- add "cache-free" and "cache-used" properties
- OSX: the "coreaudio" AO spdif code is split into a separate AO
--- mpv 0.4.0 is released ---
1.0 - the API is declared stable
+181
View File
@@ -0,0 +1,181 @@
// Plays a video from the command line in a window provided by mpv.
// You likely want to play the video in your own window instead,
// but that's not quite ready yet.
// You may need a basic Info.plist and MainMenu.xib to make this work.
#include "../../libmpv/client.h"
#include "shared.h"
#import <Cocoa/Cocoa.h>
@interface CocoaWindow : NSWindow
@end
@implementation CocoaWindow
- (BOOL)canBecomeMainWindow { return YES; }
- (BOOL)canBecomeKeyWindow { return YES; }
@end
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
mpv_handle *mpv;
dispatch_queue_t queue;
NSWindow *w;
}
@end
static void wakeup(void *);
@implementation AppDelegate
- (void)createWindow {
int mask = NSTitledWindowMask|NSClosableWindowMask|
NSMiniaturizableWindowMask|NSResizableWindowMask;
self->w = [[CocoaWindow alloc]
initWithContentRect:NSMakeRect(0,0, 1280, 720)
styleMask:mask
backing:NSBackingStoreBuffered
defer:NO];
[self->w setTitle:@"cocoabasic example"];
[self->w makeMainWindow];
[self->w makeKeyAndOrderFront:nil];
NSMenu *m = [[NSMenu alloc] initWithTitle:@"AMainMenu"];
NSMenuItem *item = [m addItemWithTitle:@"Apple" action:nil keyEquivalent:@""];
NSMenu *sm = [[NSMenu alloc] initWithTitle:@"Apple"];
[m setSubmenu:sm forItem:item];
[sm addItemWithTitle: @"Shutdown mpv" action:@selector(shutdown) keyEquivalent:@"s"];
[NSApp setMenu:m];
[NSApp activateIgnoringOtherApps:YES];
}
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
atexit_b(^{
// Because activation policy has just been set to behave like a real
// application, that policy must be reset on exit to prevent, among
// other things, the menubar created here from remaining on screen.
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
});
// Read filename
NSArray *args = [NSProcessInfo processInfo].arguments;
if (args.count < 2) {
NSLog(@"Expected filename on command line");
exit(1);
}
NSString *filename = args[1];
[self createWindow];
// Deal with MPV in the background.
queue = dispatch_queue_create("mpv", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
mpv = mpv_create();
if (!mpv) {
printf("failed creating context\n");
exit(1);
}
int64_t wid = (intptr_t) [self->w contentView];
check_error(mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid));
// Maybe set some options here, like default key bindings.
// NOTE: Interaction with the window seems to be broken for now.
check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes"));
// for testing!
check_error(mpv_set_option_string(mpv, "input-media-keys", "yes"));
check_error(mpv_set_option_string(mpv, "input-cursor", "no"));
check_error(mpv_set_option_string(mpv, "input-vo-keyboard", "yes"));
// request important errors
check_error(mpv_request_log_messages(mpv, "warn"));
check_error(mpv_initialize(mpv));
// Register to be woken up whenever mpv generates new events.
mpv_set_wakeup_callback(mpv, wakeup, (__bridge void *) self);
// Load the indicated file
const char *cmd[] = {"loadfile", filename.UTF8String, NULL};
check_error(mpv_command(mpv, cmd));
});
}
- (void) handleEvent:(mpv_event *)event
{
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN:
// Clean up and shut down.
mpv_terminate_destroy(mpv);
mpv = NULL;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSApplication sharedApplication] terminate:nil];
});
break;
case MPV_EVENT_LOG_MESSAGE: {
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
printf("[%s] %s: %s", msg->prefix, msg->level, msg->text);
}
case MPV_EVENT_VIDEO_RECONFIG:
dispatch_async(dispatch_get_main_queue(), ^{
[self->w selectNextKeyView:nil];
});
default:
printf("event: %s\n", mpv_event_name(event->event_id));
}
}
- (void) readEvents
{
dispatch_async(queue, ^{
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
[self handleEvent:event];
}
});
}
static void wakeup(void *context) {
AppDelegate *a = (__bridge AppDelegate *) context;
[a readEvents];
}
// Ostensibly, mpv's window would be hooked up to this.
- (BOOL) windowShouldClose:(id)sender
{
[self shutdown];
if (self->w)
[self->w release];
return YES;
}
- (void) shutdown
{
if (mpv) {
const char *args[] = {"quit", NULL};
mpv_command(mpv, args);
}
}
@end
// Delete this if you already have a main.m.
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *delegate = [AppDelegate new];
app.delegate = delegate;
[app run];
}
return EXIT_SUCCESS;
}
+219
View File
@@ -0,0 +1,219 @@
// License: pick one of: public domain, WTFPL, ISC, Ms-PL, AGPLv3
// This example can be built with: qmake && make
#include <clocale>
#include <sstream>
#include <QtGlobal>
#include <QFileDialog>
#include <QStatusBar>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QApplication>
#include <QTextEdit>
#if QT_VERSION >= 0x050000
#include <QJsonDocument>
#endif
#include <mpv/qthelper.hpp>
#include "qtexample.h"
static void wakeup(void *ctx)
{
// This callback is invoked from any mpv thread (but possibly also
// recursively from a thread that is calling the mpv API). Just notify
// the Qt GUI thread to wake up (so that it can process events with
// mpv_wait_event()), and return as quickly as possible.
MainWindow *mainwindow = (MainWindow *)ctx;
QCoreApplication::postEvent(mainwindow, new QEvent(QEvent::User));
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setWindowTitle("Qt embedding demo");
setMinimumSize(640, 480);
QMenu *menu = menuBar()->addMenu(tr("&File"));
QAction *on_open = new QAction(tr("&Open"), this);
on_open->setShortcuts(QKeySequence::Open);
on_open->setStatusTip(tr("Open a file"));
connect(on_open, SIGNAL(triggered()), this, SLOT(on_file_open()));
menu->addAction(on_open);
statusBar();
QMainWindow *log_window = new QMainWindow(this);
log = new QTextEdit(log_window);
log->setReadOnly(true);
log_window->setCentralWidget(log);
log_window->setWindowTitle("mpv log window");
log_window->setMinimumSize(500, 50);
log_window->show();
mpv = mpv_create();
if (!mpv)
throw "can't create mpv instance";
// Create a video child window. Force Qt to create a native window, and
// pass the window ID to the mpv wid option. Works on: X11, win32, Cocoa
mpv_container = new QWidget(this);
setCentralWidget(mpv_container);
mpv_container->setAttribute(Qt::WA_DontCreateNativeAncestors);
mpv_container->setAttribute(Qt::WA_NativeWindow);
// If you have a HWND, use: int64_t wid = (intptr_t)hwnd;
int64_t wid = mpv_container->winId();
mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);
// Enable default bindings, because we're lazy. Normally, a player using
// mpv as backend would implement its own key bindings.
mpv_set_option_string(mpv, "input-default-bindings", "yes");
// Enable keyboard input on the X11 window. For the messy details, see
// --input-vo-keyboard on the manpage.
mpv_set_option_string(mpv, "input-vo-keyboard", "yes");
// Let us receive property change events with MPV_EVENT_PROPERTY_CHANGE if
// this property changes.
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE);
mpv_observe_property(mpv, 0, "chapter-list", MPV_FORMAT_NODE);
// Request log messages with level "info" or higher.
// They are received as MPV_EVENT_LOG_MESSAGE.
mpv_request_log_messages(mpv, "info");
// From this point on, the wakeup function will be called. The callback
// can come from any thread, so we use the Qt QEvent mechanism to relay
// the wakeup in a thread-safe way.
mpv_set_wakeup_callback(mpv, wakeup, this);
if (mpv_initialize(mpv) < 0)
throw "mpv failed to initialize";
}
void MainWindow::handle_mpv_event(mpv_event *event)
{
switch (event->event_id) {
case MPV_EVENT_PROPERTY_CHANGE: {
mpv_event_property *prop = (mpv_event_property *)event->data;
if (strcmp(prop->name, "time-pos") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double *)prop->data;
std::stringstream ss;
ss << "At: " << time;
statusBar()->showMessage(QString::fromStdString(ss.str()));
} else if (prop->format == MPV_FORMAT_NONE) {
// The property is unavailable, which probably means playback
// was stopped.
statusBar()->showMessage("");
}
} else if (strcmp(prop->name, "chapter-list") == 0 ||
strcmp(prop->name, "track-list") == 0)
{
// Dump the properties as JSON for demo purposes.
#if QT_VERSION >= 0x050000
if (prop->format == MPV_FORMAT_NODE) {
QVariant v = mpv::qt::node_to_variant((mpv_node *)prop->data);
// Abuse JSON support for easily printing the mpv_node contents.
QJsonDocument d = QJsonDocument::fromVariant(v);
append_log("Change property " + QString(prop->name) + ":\n");
append_log(d.toJson().data());
}
#endif
}
break;
}
case MPV_EVENT_VIDEO_RECONFIG: {
// Retrieve the new video size.
int64_t w, h;
if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 &&
mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 &&
w > 0 && h > 0)
{
// Note that the MPV_EVENT_VIDEO_RECONFIG event doesn't necessarily
// imply a resize, and you should check yourself if the video
// dimensions really changed.
// mpv itself will scale/letter box the video to the container size
// if the video doesn't fit.
std::stringstream ss;
ss << "Reconfig: " << w << " " << h;
statusBar()->showMessage(QString::fromStdString(ss.str()));
}
break;
}
case MPV_EVENT_LOG_MESSAGE: {
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
std::stringstream ss;
ss << "[" << msg->prefix << "] " << msg->level << ": " << msg->text;
append_log(QString::fromStdString(ss.str()));
break;
}
case MPV_EVENT_SHUTDOWN: {
mpv_terminate_destroy(mpv);
mpv = NULL;
break;
}
default: ;
// Ignore uninteresting or unknown events.
}
}
bool MainWindow::event(QEvent *event)
{
// QEvent::User is sent by wakeup().
if (event->type() == QEvent::User) {
// Process all events, until the event queue is empty.
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
handle_mpv_event(event);
}
return true;
}
return QMainWindow::event(event);
}
void MainWindow::on_file_open()
{
QString filename = QFileDialog::getOpenFileName(this, "Open file");
if (mpv) {
const QByteArray c_filename = filename.toUtf8();
const char *args[] = {"loadfile", c_filename.data(), NULL};
mpv_command_async(mpv, 0, args);
}
}
void MainWindow::append_log(const QString &text)
{
QTextCursor cursor = log->textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertText(text);
log->setTextCursor(cursor);
}
MainWindow::~MainWindow()
{
if (mpv)
mpv_terminate_destroy(mpv);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Qt sets the locale in the QApplication constructor, but libmpv requires
// the LC_NUMERIC category to be set to "C", so change it back.
std::setlocale(LC_NUMERIC, "C");
MainWindow w;
w.show();
return a.exec();
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef QTEXAMPLE_H
#define QTEXAMPLE_H
#include <QMainWindow>
#include <mpv/client.h>
class QTextEdit;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
virtual bool event(QEvent *event);
private slots:
void on_file_open();
private:
QWidget *mpv_container;
mpv_handle *mpv;
QTextEdit *log;
void append_log(const QString &text);
void create_player();
void handle_mpv_event(mpv_event *event);
};
#endif // QTEXAMPLE_H
+12
View File
@@ -0,0 +1,12 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qtexample
TEMPLATE = app
CONFIG += link_pkgconfig debug
PKGCONFIG = mpv
SOURCES += qtexample.cpp
HEADERS += qtexample.h
+1
View File
@@ -21,6 +21,7 @@ int main(int argc, char *argv[])
// Enable default key bindings, so the user can actually interact with
// the player (and e.g. close the window).
check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes"));
mpv_set_option_string(ctx, "input-x11-keyboard", "yes");
int val = 1;
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
+9
View File
@@ -26,6 +26,15 @@ created scripts to help ease the process. These are the two recommended methods:
Note that MinGW environments included in Linux distributions are often broken,
outdated and useless, and usually don't use MinGW-w64.
Additional dependencies
-----------------------
You need a pthread wrapper. It must be interoperable with native Windows
threads. pthreads-win32 or MinGW pthreads might work.
If you want ``--input-file=...`` to work, you need libwaio. It's available
from: git://midipix.org/waio
Example with MXE
----------------
+4 -4
View File
@@ -27,13 +27,13 @@ The general simplified syntax is::
<filename>,<start in seconds>,<length in seconds>
If the start time is omitted, 0 is used. If the length is omitted, the
estimated duration of the source file is used.
estimated remaining duration of the source file is used.
Note::
mpv can't use ordered chapter files or libquvi-resolved URLs in EDL
entries. Usage of relative or absolute paths as well as any protocol
prefixes is prevented for security reasons.
mpv can't use ordered chapter files in EDL entries. Usage of relative or
absolute paths as well as any protocol prefixes is prevented for security
reasons.
Syntax of mpv EDL files
+1 -1
View File
@@ -25,7 +25,7 @@ from the input video. Note that not all codecs and not all formats support VFR
encoding, and some which do have bugs when a target bitrate is specified - use
-ofps or -oautofps to force CFR encoding in these cases.
Of course, the options can be stored in a profile, like this .mpv/config
Of course, the options can be stored in a profile, like this .config/mpv/mpv.conf
section::
[myencprofile]
+20 -19
View File
@@ -72,15 +72,17 @@ Available filters are:
``tospdif=<yes|no>``
Output raw AC-3 stream if ``no``, output to S/PDIF for
passthrough if ``yes`` (default).
pass-through if ``yes`` (default).
``bitrate=<rate>``
The bitrate use for the AC-3 stream. Set it to 384 to get 384 kbps.
The default is 640. Some receivers might not be able to handle this.
Valid values: 32, 40, 48, 56, 64, 80, 96, 112, 128,
160, 192, 224, 256, 320, 384, 448, 512, 576, 640.
The special value ``default`` selects a default bitrate based on the
The special value ``auto`` selects a default bitrate based on the
input channel number:
:1ch: 96
@@ -92,7 +94,7 @@ Available filters are:
``minchn=<n>``
If the input channel number is less than ``<minchn>``, the filter will
detach itself (default: 5).
detach itself (default: 3).
``sweep[=speed]``
Produces a sine sweep.
@@ -101,7 +103,7 @@ Available filters are:
Sine function delta, use very low values to hear the sweep.
``sinesuppress[=freq:decay]``
Remove a sine at the specified frequency. Useful to get rid of the 50/60Hz
Remove a sine at the specified frequency. Useful to get rid of the 50/60 Hz
noise on low quality audio equipment. It only works on mono input.
``<freq>``
@@ -182,7 +184,7 @@ Available filters are:
``mpv --af=equalizer=11:11:10:5:0:-12:0:5:12:12 media.avi``
Would amplify the sound in the upper and lower frequency region
while canceling it almost completely around 1kHz.
while canceling it almost completely around 1 kHz.
``channels=nch[:routes]``
Can be used for adding, removing, routing and copying audio channels. If
@@ -263,9 +265,8 @@ Available filters are:
Filter for internal use only. Converts between 24-bit and 32-bit sample
formats.
``convertsignendian``
Filter for internal use only. Converts between signed/unsigned formats
and formats with different endian.
``convertsign``
Filter for internal use only. Converts between signed/unsigned formats.
``volume[=<volumedb>[:...]]``
Implements software volume control. Use this filter with caution since it
@@ -277,8 +278,8 @@ Available filters are:
once for every audio stream.
``<volumedb>``
Sets the desired gain in dB for all channels in the stream from -200dB
to +60dB, where -200dB mutes the sound completely and +60dB equals a
Sets the desired gain in dB for all channels in the stream from -200 dB
to +60 dB, where -200 dB mutes the sound completely and +60 dB equals a
gain of 1000 (default: 0).
``replaygain-track``
Adjust volume gain according to the track-gain replaygain value stored
@@ -311,7 +312,7 @@ Available filters are:
.. admonition:: Example
``mpv --af=volume=10.1 media.avi``
Would amplify the sound by 10.1dB and hard-clip if the sound level
Would amplify the sound by 10.1 dB and hard-clip if the sound level
is too high.
``pan=n:[<matrix>]``
@@ -368,8 +369,8 @@ Available filters are:
to the subwoofer.
``<fc>``
cutoff frequency in Hz for the low-pass filter (20Hz to 300Hz)
(default: 60Hz) For the best result try setting the cutoff frequency
cutoff frequency in Hz for the low-pass filter (20 Hz to 300 Hz)
(default: 60 Hz) For the best result try setting the cutoff frequency
as low as possible. This will improve the stereo or surround sound
experience.
``<ch>``
@@ -381,7 +382,7 @@ Available filters are:
.. admonition:: Example
``mpv --af=sub=100:4 --audio-channels=5 media.avi``
Would add a subwoofer channel with a cutoff frequency of 100Hz to
Would add a subwoofer channel with a cutoff frequency of 100 Hz to
output channel 4.
``center``
@@ -409,7 +410,7 @@ Available filters are:
.. admonition:: Example
``mpv --af=surround=15 --audio-channels=4 media.avi``
Would add surround sound decoding with 15ms delay for the sound to
Would add surround sound decoding with 15 ms delay for the sound to
the rear speakers.
``delay[=[ch1,ch2,...]]``
@@ -437,8 +438,8 @@ Available filters are:
.. admonition:: Example
``mpv --af=delay=[10.5,10.5,0,0,7,0] media.avi``
Would delay front left and right by 10.5ms, the two rear channels
and the subwoofer by 0ms and the center channel by 7ms.
Would delay front left and right by 10.5 ms, the two rear channels
and the subwoofer by 0 ms and the center channel by 7 ms.
``export=mmapped_file:nsamples]``
Exports the incoming signal to other processes using memory mapping
@@ -588,7 +589,7 @@ Available filters are:
tempo.
``mpv --af=scaletempo=stride=30:overlap=.50:search=10 media.ogg``
Would tweak the quality and performace parameters.
Would tweak the quality and performance parameters.
``mpv --af=format=float,scaletempo media.ogg``
Would make scaletempo use float code. Maybe faster on some
@@ -600,7 +601,7 @@ Available filters are:
1.2x.
``lavfi=graph``
Filter audio using ffmpeg's libavfilter.
Filter audio using FFmpeg's libavfilter.
``<graph>``
Libavfilter graph. See ``lavfi`` video filter for details - the graph
+24 -6
View File
@@ -23,7 +23,7 @@ normal driver parameters.
where PulseAudio is used. On Windows, ``--ao=wasapi`` is preferred,
though it might cause trouble sometimes, in which case ``--ao=dsound``
should be used. On BSD systems, ``--ao=oss`` or `--ao=sndio`` may work
(the latter being experimental). On OSX systems, use ``--ao=coreaudio``.
(the latter being experimental). On OS X systems, use ``--ao=coreaudio``.
.. admonition:: Examples
@@ -53,6 +53,10 @@ Available audio output drivers are:
Set the index of the mixer channel (default: 0). Consider the output of
"``amixer scontrols``", then the index is the number that follows the
name of the element.
``non-interleaved``
Allow output of non-interleaved formats (if the audio decoder uses
this format). Currently disabled by default, because some popular
ALSA plugins are utterly broken with non-interleaved formats.
.. note::
@@ -110,12 +114,17 @@ Available audio output drivers are:
with fixed setups.
``coreaudio`` (Mac OS X only)
Native Mac OS X audio output driver
Native Mac OS X audio output driver using AudioUnits and the CoreAudio
sound server.
``device_id=<id>``
ID of output device to use (0 = default device)
``help``
List all available output devices with their IDs.
Automatically redirects to ``coreaudio_exclusive`` when playing compressed
formats.
``coreaudio_exclusive`` (Mac OS X only)
Native Mac OS X audio output driver using direct device access and
exclusive mode (bypasses the sound server).
Supports only compressed formats (AC3 and DTS).
``openal``
Experimental OpenAL audio output driver
@@ -137,6 +146,12 @@ Available audio output drivers are:
value makes the audio stream react faster, e.g. to playback speed
changes. Default: 250.
``latency-hacks=<yes|no>``
Enable hacks to workaround PulseAudio timing bugs (default: yes). If
enabled, mpv will do elaborate latency calculations on its own. If
disabled, it will use PulseAudio automatically updated timing
information. Disabling this might help with e.g. networked audio.
``portaudio``
PortAudio audio output driver. This works on all platforms, and has
extensive MS Windows support.
@@ -159,6 +174,9 @@ Available audio output drivers are:
Sets the device number to use. Playing a file with ``-v`` will show a
list of available devices.
``buffersize=<ms>``
DirectSound buffer size in milliseconds (default: 200).
``sdl``
SDL 1.2+ audio output driver. Should work on any platform supported by SDL
1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
+166 -99
View File
@@ -10,104 +10,159 @@ should generally be treated as a completely different program.
.. note::
These lists are incomplete.
General Changes for MPlayer to mpv
----------------------------------
General Changes from MPlayer to mpv
-----------------------------------
* Switch to GPLv2+. (Technically speaking, MPlayer as a whole seems to be
GPLv2-only, while mplayer2 is GPLv3+ - see ``Copyright`` file for details.)
* Removal of the internal GUI, MEncoder, OSD menu, video kernel drivers for
Linux 2.4 (including VIDIX)
* Large internal cleanups
* Removal of support for dead platforms
* New buildsystem
* No embedded copy of ffmpeg and other libraries
* Better pause handling (do not unpause on a command)
* Better MKV support (such as ordered chapters)
* vo_vdpau improvements
* Precise seeking support
* Native OpenGL backend for OSX
* General OSX improvements
* Improvements in audio/video sync handling
* Cleaned up terminal output
* Gapless audio support (``--gapless-audio``)
* Improved responsiveness on user input
* Support for modifier keys (alt, shift, ctrl) in input.conf
* OSS4 volume control
* More correct color reproduction (color matrix generation)
* Use libass for subtitle rendering by default (better quality)
* Generally preferring ffmpeg/libav over internal demuxers and decoders
* Improvements when playing multiple files (``--fixed-vo``)
* Screenshot improvements (instant screenshots without 1-frame delay, allow
taking screenshots even with hardware decoding)
* Improved support for PulseAudio
* Generally improved MS Windows support (dealing with unicode filenames,
improved ``--vo=direct3d``, improved window handling)
* Better OSD rendering (using libass). This has full unicode support, and
languages like Arabic should be better supported.
* Cleaned up terminal output (nicer status line, less useless noise)
* Support for playing URLs of popular streaming sites directly
(e.g. ``mpv https://www.youtube.com/watch?v=...``)
* Improved OpenGL output (``--vo=opengl-hq``)
* Make ``--softvol`` default (**mpv** is not a mixer control panel)
* Improved support for .cue files
* Screenshot improvements (can save screenshots as JPG or PNG, configurable
filenames, support for taking screenshots with or without subtitles - the
``screenshot`` video filter is not needed anymore, and should not be put
into the mpv config file)
* Removal of teletext support
* Removal of most builtin demuxers, using libavformat instead
* Removal of builtin network support, using libavformat instead (also,
support https via libavformat)
* Replace image VOs (``--vo=jpeg`` etc.) with ``--vo=image``
* Do not lose settings when playing a new file in the same player instance
* New location for config files, new name for the binary.
* Slave mode compatibility broken (see below)
* Encoding functionality (replacement for mencoder, see ``DOCS/encoding.rst``)
* Remove ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding can
handle these use cases. For yuv4mpeg, for example, use:
``mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop``.
* Image subtitles (DVDs etc.) are rendered in color and use more correct
positioning (color can be disabled with ``--sub-gray``)
* Wayland support
* Support for precise scrolling which scales the parameter of commands. If the
input doesn't support precise scrolling the scale factor stays 1.
* OSX: Cocoa event loop is independent from mplayer's event loop, so user
actions like accessing menus and live resizing do not block the playback.
* OSX: Apple Remote support.
* OSX: Media Keys support.
* Windows: Added WASAPI audio output.
* New OSD bar with chapter marks and not positioned in the middle of the video
(though this can be customized with the ``--osd-bar-align-y`` option).
* Allow customizing whether a key binding for seeking shows the video time, the
OSD bar, or nothing (see section `Input Command Prefixes`_).
* Display list of chapters and audio/subtitle tracks on OSD (see section
`Properties`_).
This listing is about changes introduced by mplayer2 and mpv relatively to
MPlayer.
Player
~~~~~~
* New name for the binary (``mpv``). New location for config files (either
``~/.config/mpv/mpv.conf``, or if you want, ``~/.mpv/config``).
* Encoding functionality (replacement for MEncoder, see the `ENCODING`_ section).
* Support for Lua scripting (see the `LUA SCRIPTING`_ section).
* Better pause handling (e.g. do not unpause on a command).
* Precise seeking support.
* Improvements in audio/video sync handling.
* Do not lose settings when playing a new file in the same player instance.
* Slave mode compatibility broken (see below).
* Re-enable screensaver while the player is paused.
* Allow resuming playback at a later point with ``Shift+q``, also see the
``quit_watch_later`` input command.
* ``--keep-open`` option to stop the player from closing the window and
exiting after playback ends.
* Re-enable screensaver while the player is paused.
* Matroska edition switching at runtime.
* A client API, that allows embedding **mpv** into applications
(see ``libmpv/client.h`` in the sources).
Input
~~~~~
* Improved default keybindings. MPlayer bindings are also available (see
``etc/mplayer-input.conf`` in the source tree).
* Improved responsiveness on user input.
* Support for modifier keys (alt, shift, ctrl) in input.conf.
* Allow customizing whether a key binding for seeking shows the video time, the
OSD bar, or nothing (see the `Input Command Prefixes`_ section).
* Support mapping multiple commands to one key.
Audio
~~~~~
* Support for gapless audio (see the ``--gapless-audio`` option).
* Support for OSS4 volume control.
* Improved support for PulseAudio.
* Make ``--softvol`` default (**mpv** is not a mixer control panel).
* By default, do pitch correction if playback speed is increased.
* Improved downmixing and output of surround audio:
- Instead of using hardcoded pan filters to do remixing, libavresample is used
- Channel maps are used to identify the channel layout, so e.g. ``3.0`` and
``2.1`` audio can be distinguished.
Video
~~~~~
* Wayland support.
* Native support for VAAPI and VDA. Improved VDPAU video output.
* Improved OpenGL output (see the ``opengl-hq`` video output).
* Make hardware decoding work with the ``opengl`` video output.
* Support for libavfilter (for video->video and audio->audio). This allows
using most of FFmpeg's filters, which improve greatly on the old MPlayer
filters in features, performance, and correctness.
* Improved downmixing and output of surround audio. Instead of using hardcoded
pan filters to do remixing, use libavresample. Channel maps are used to
identify the channel layout, so e.g. ``3.0`` and ``2.1`` audio can be
distinguished.
* Allow resuming playback at a later point with ``Shift+q``, also see
``quit_watch_later`` input command.
* Support mapping multiple commands to one key.
* More correct color reproduction (color matrix generation).
* Better subtitle rendering using libass by default.
* Improvements when playing multiple files (``--fixed-vo`` is default, do not
reset settings by default when playing a new file).
* Replace image video outputs (``--vo=jpeg`` etc.) with ``--vo=image``.
* Removal of ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding
can handle these use cases. For yuv4mpeg, for example, use::
mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop
* Image subtitles (DVDs etc.) are rendered in color and use more correct
positioning (color for image subs can be disabled with ``--sub-gray``).
OSD and terminal
~~~~~~~~~~~~~~~~
* Cleaned up terminal output: nicer status line, less useless noise.
* Improved OSD rendering using libass, with full Unicode support.
* New OSD bar with chapter marks. Not positioned in the middle of the video
(this can be customized with the ``--osd-bar-align-y`` option).
* Display list of chapters and audio/subtitle tracks on OSD (see the
`Properties`_ section).
Screenshots
~~~~~~~~~~~
* Instant screenshots without 1-frame delay.
* Support for taking screenshots even with hardware decoding.
* Support for saving screenshots as JPEG or PNG.
* Support for configurable file names.
* Support for taking screenshots with or without subtitles.
Note that the ``screenshot`` video filter is not needed anymore, and should not
be put into the mpv config file.
Miscellaneous
~~~~~~~~~~~~~
* Better MKV support (e.g. ordered chapters, 3D metadata).
* Matroska edition switching at runtime.
* Support for playing URLs of popular streaming sites directly.
(e.g. ``mpv https://www.youtube.com/watch?v=...``).
Requires a recent version of ``youtube-dl`` to be installed. Can be
disabled with ``ytdl=no`` in the mpv config file.
* Support for precise scrolling which scales the parameter of commands. If the
input doesn't support precise scrolling the scale factor stays 1.
* Allow changing/adjusting video filters at runtime. (This is also used to make
the ``D`` key insert vf_yadif if deinterlacing is not supported otherwise.)
* Native VAAPI support
* OSX: VDA support using libavcodec hwaccel API insted of FFmpeg's decoder. Up
the ``D`` key insert vf_yadif if deinterlacing is not supported otherwise).
* Improved support for .cue files.
Mac OS X
~~~~~~~~
* Native OpenGL backend.
* Cocoa event loop is independent from MPlayer's event loop, so user
actions like accessing menus and live resizing do not block the playback.
* Apple Remote support.
* Media Keys support.
* VDA support using libavcodec hwaccel API instead of FFmpeg's decoder with up
to 2-2.5x reduction in CPU usage.
* Make hardware decoding in general work with the ``opengl`` video output.
* Lua scripting (see `LUA SCRIPTING`_)
* A client API, that allows embedding **mpv** into applications
(see ``libmpv/client.h`` in the sources)
* General bug fixes and removal of long-standing issues
* General code cleanups (including refactoring or rewrites of many parts)
* Many more changes
Windows
~~~~~~~
* Improved support for Unicode file names.
* Improved window handling.
* Do not block playback when moving the window.
* Improved Direct3D video output.
* Added WASAPI audio output.
Internal changes
~~~~~~~~~~~~~~~~
* Switch to GPLv2+ (see ``Copyright`` file for details).
* Removal of lots of cruft:
- Internal GUI (replaced by the OSC, see the `ON SCREEN CONTROLLER`_ section).
- MEncoder (replaced by native encoding, see the `ENCODING`_ section).
- OSD menu.
- Kernel video drivers for Linux 2.4 (including VIDIX).
- Teletext support.
- Support for dead platforms.
- Most built-in demuxers have been replaced by their libavformat counterparts.
- Built-in network support has been replaced by libavformat's (which also
supports https URLs).
- Embedded copies of libraries (such as FFmpeg).
* General code cleanups (including refactoring or rewrites of many parts).
* New build system.
* Many bug fixes and removal of long-standing issues.
* Generally preferring FFmpeg/Libav over internal demuxers, decoders, and
filters.
Detailed Listing of User-visible Changes
----------------------------------------
@@ -308,28 +363,40 @@ input.conf and Slave Commands
Slave mode
~~~~~~~~~~
* Slave mode is broken. This mode is entirely insane in the ``old`` versions of
MPlayer. A proper slave mode application needed tons of code and hacks to get
* Slave mode was removed. A proper slave mode application needed tons of code
and hacks to get
it right. The main problem is that slave mode is a bad and incomplete
interface, and to get around that, applications parsed output messages
intended for users. It is hard to know which messages exactly are parsed by
slave mode applications. This makes it virtually impossible to improve
terminal output intended for users without possibly breaking something.
This is absolutely insane, and **mpv** will not try to keep slave mode
compatible. If you are a developer of a slave mode application, contact us,
and a new and better protocol can be developed.
This is absolutely insane, and since initial improvements to **mpv** quickly
made slave mode incompatible to most applications, it was removed as useless
cruft. The client API (see below) is provided instead.
``--identify`` was already removed (``TOOLS/mpv_identify.sh`` is provided
instead), and ``--slave-broken`` might be removed in the future.
``--identify`` was replaced by the ``TOOLS/mpv_identify.sh`` wrapper script.
* For some time (until including release 0.4.x), mpv supported a
``--slave-broken`` option. The following options are equivalent:
::
--input-file=/dev/stdin --input-terminal=no
Assuming the system supports ``/dev/stdin``.
(The option was readded in 0.5.1 and sets exactly these options.)
* A JSON RPC protocol giving access to the client API is also supported. See
`JSON IPC`_ for more information.
* **mpv** also provides a client API, which can be used to embed the player
by loading it as shared library. (See ``libmpv/client.h`` in the sources.)
It might also be possible to implement a custom slave mode-like protocol
using Lua scripting.
* A slave protocol is planned, but nothing has emerged yet.
Policy for Removed Features
---------------------------
+2 -2
View File
@@ -38,7 +38,7 @@ You can encode files from one format/codec to another using this facility.
``--oautofps``
Sets the output format time base to the guessed frame rate of the input
video (simulates mencoder behavior, useful for AVI; may cause frame drops).
video (simulates MEncoder behavior, useful for AVI; may cause frame drops).
Note that not all codecs and not all formats support VFR encoding, and some
which do have bugs when a target bitrate is specified - use ``--ofps`` or
``--oautofps`` to force CFR encoding in these cases.
@@ -74,7 +74,7 @@ You can encode files from one format/codec to another using this facility.
.. admonition:: Example
"``--oac=libmp3lame --oacopts=b=128000``"
selects 128kbps MP3 encoding.
selects 128 kbps MP3 encoding.
Options are managed in lists. There are a few commands to manage the
options list.
+324 -45
View File
@@ -4,12 +4,19 @@ INPUT.CONF
The input.conf file consists of a list of key bindings, for example::
s screenshot # take a screenshot with the s key
LEFT seek 15 # map the left-arrow key to seeking forward by 15 seconds
Each line maps a key to an input command. Keys are specified with their literal
value (upper case if combined with ``Shift``), or a name for special keys. For
example, ``a`` maps to the ``a`` key without shift, and ``A`` maps to ``a``
with shift.
The file is located in the mpv configuration directory (normally at
``~/.config/mpv/input.conf`` depending on platform). The default bindings are
defined here::
https://github.com/mpv-player/mpv/blob/master/etc/input.conf
A list of special keys can be obtained with
``mpv --input-keylist``
@@ -101,14 +108,14 @@ List of Input Commands
``revert_seek`` command itself.
``frame_step``
Play one frame, then pause.
Play one frame, then pause. Does nothing with audio-only playback.
``frame_back_step``
Go back by one frame, then pause. Note that this can be very slow (it tries
to be precise, not fast), and sometimes fails to behave as expected. How
well this works depends on whether precise seeking works correctly (e.g.
see the ``--hr-seek-demuxer-offset`` option). Video filters or other video
postprocessing that modifies timing of frames (e.g. deinterlacing) should
post-processing that modifies timing of frames (e.g. deinterlacing) should
usually work, but might make backstepping silently behave incorrectly in
corner cases. Using ``--hr-seek-framedrop=no`` should help, although it
might make precise seeking slower.
@@ -153,7 +160,9 @@ List of Input Commands
Take a single screenshot.
<each-frame>
Take a screenshot each frame. Issue this command again to stop taking
screenshots.
screenshots. Note that you should disable frame-dropping when using
this mode - or you might receive duplicate images in cases when a
frame was dropped.
``screenshot_to_file "<filename>" [subtitles|video|window]``
Take a screenshot and save it to a given file. The format of the file will
@@ -184,7 +193,7 @@ List of Input Commands
force
Terminate playback if the first file is being played.
``loadfile "<file>" [replace|append [options]]``
``loadfile "<file>" [replace|append|append-play [options]]``
Load the given file and play it.
Second argument:
@@ -193,6 +202,10 @@ List of Input Commands
Stop playback of the current file, and play the new file immediately.
<append>
Append the file to the playlist.
<append-play>
Append the file, and if nothing is currently playing, start playback.
(Always starts with the added file, even if the playlist was not empty
before running this command.)
The third argument is a list of options and values which should be set
while the file is playing. It is of the form ``opt1=value1,opt2=value2,..``.
@@ -249,16 +262,39 @@ List of Input Commands
will seek to the previous position on start. The (optional) argument is
exactly as in the ``quit`` command.
``sub_add "<file>"``
Load the given subtitle file. It is not selected as current subtitle after
``sub_add "<file>" [<flags> [<title> [<lang>]]]``
Load the given subtitle file. It is selected as current subtitle after
loading.
The ``flags`` args is one of the following values:
<select>
Select the subtitle immediately.
<auto>
Don't select the subtitle. (Or in some special situations, let the
default stream selection mechanism decide.)
<cached>
Select the subtitle. If a subtitle with the same filename was already
added, that one is selected, instead of loading a duplicate entry.
(In this case, title/language are ignored, and if the was changed since
it was loaded, these changes won't be reflected.)
The ``title`` argument sets the track title in the UI.
The ``lang`` argument sets the track language, and can also influence
stream selection with ``flags`` set to ``auto``.
``sub_remove [<id>]``
Remove the given subtitle track. If the ``id`` argument is missing, remove
the current track. (Works on external subtitle files only.)
``sub_reload [<id>]``
Reload the given subtitle tracks. If the ``id`` argument is missing, remove
Reload the given subtitle tracks. If the ``id`` argument is missing, reload
the current track. (Works on external subtitle files only.)
This works by unloading and re-adding the subtitle track.
@@ -317,6 +353,12 @@ List of Input Commands
Write the resume config file that the ``quit_watch_later`` command writes,
but continue playback normally.
``stop``
Stop playback and clear playlist. With default settings, this is
essentially like ``quit``. Useful for the client API: playback can be
stopped without terminating the player.
Input Commands that are Possibly Subject to Change
--------------------------------------------------
@@ -386,7 +428,7 @@ Input Commands that are Possibly Subject to Change
The special argument ``!reverse`` can be used to cycle the value list in
reverse. Compared with a command that just lists the value in reverse, this
command will actually share the internal counter with the forward-cycling
key binding.
key binding (as long as the rest of the arguments are the same).
Note that there is a static limit of (as of this writing) 10 arguments
(this limit could be raised on demand).
@@ -440,6 +482,16 @@ Input Commands that are Possibly Subject to Change
random points. Instead, call ``overlay_add`` again (preferably with a
different memory region to prevent tearing).
It is also possible to pass a raw memory address for use as bitmap memory
by passing a memory address as integer prefixed with a ``&`` character.
Passing the wrong thing here will crash the player. The ``offset`` parameter
is not used and must be 0. This mode might be useful for use with libmpv.
On Windows, currently only raw memory addresses work. File mapping is not
implemented because a ``mmap`` compatibility layer is missing, and because
this kind of shared memory method would perhaps not be overly useful on
Windows.
``offset`` is the offset of the first pixel in the source file. It is
passed directly to ``mmap`` and is subject to certain restrictions
(see ``man mmap`` for details). In particular, this value has to be a
@@ -489,12 +541,46 @@ Input Commands that are Possibly Subject to Change
``<target>``. Each client (scripts etc.) has a unique name. For example,
Lua scripts can get their name via ``mp.get_script_name()``.
(Scripts use this internally to dispatch key bindings, and this can also
be used in input.conf to reassign such bindings.)
``script_binding "<name>"``
Invoke a script-provided key binding. This can be used to remap key
bindings provided by external Lua scripts.
The argument is the name of the binding.
Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``stop`` (questionable
use), ``get_property`` (?), ``vo_cmdline`` (experimental).
It can optionally be prefixed with the name of the script, using ``/`` as
separator, e.g. ``script_binding scriptname/bindingname``.
For completeness, here is how this command works internally. The details
could change any time. On any matching key event, ``script_message_to``
or ``script_message`` is called (depending on whether the script name is
included), where the first argument is the string ``key-binding``, the
second argument is the name of the binding, and the third argument is the
key state as string. The key state consists of a number of letters. The
first letter is one of ``d`` (key was pressed down), ``u`` (was released),
``r`` (key is still down, and was repeated; only if key repeat is enabled
for this binding), ``p`` (key was pressed; happens if up/down can't be
tracked). The second letter whether the event originates from the mouse,
either ``m`` (mouse button) or ``-`` (something else).
``ab_loop``
Cycle through A-B loop states. The first command will set the ``A`` point
(the ``ab-loop-a`` property); the second the ``B`` point, and the third
will clear both points.
``vo_cmdline "<args>"``
Reset the sub-option of the current VO. Currently works with ``opengl``
(including ``opengl-hq``). The argument is the sub-option string usually
passed to the VO on the command line. Not all sub-options can be set, but
those which can will be reset even if they don't appear in the argument.
This command might be changed or removed in the future.
``drop_buffers``
Drop audio/video/demuxer buffers, and restart from fresh. Might help with
unseekable streams that are going out of sync.
This command might be changed or removed in the future.
Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``get_property`` (?),
``ao_reload`` (experimental/internal).
Input Command Prefixes
----------------------
@@ -519,7 +605,9 @@ prefixes can be specified. They are separated by whitespace.
Do not expand properties in string arguments. (Like ``"${property-name}"``.)
``expand-properties`` (default)
All string arguments are expanded as described in `Property Expansion`_.
``repeatable``
For some commands, keeping a key pressed doesn't run the command repeatedly.
This prefix forces enabling key repeat in any case.
All of the osd prefixes are still overridden by the global ``--osd-level``
settings.
@@ -564,7 +652,7 @@ Property list
See ``--osd-level``.
``osd-scale`` (RW)
OSD font size multiplicator, see ``--osd-scale``.
OSD font size multiplier, see ``--osd-scale``.
``loop`` (RW)
See ``--loop``.
@@ -586,14 +674,23 @@ Property list
``${stream-end}``. For ordered chapters and such, the
size of the currently played segment is returned.)
``estimated-frame-count``
Total number of frames in current file.
.. note:: This is only an estimate. (It's computed from two unreliable
quantities: fps and stream length.)
``estimated-frame-number``
Number of current frame in current stream.
.. note:: This is only an estimate. (It's computed from two unreliable
quantities: fps and possibly rounded timestamps.)
``path``
Full path of the currently played file.
``media-title``
If libquvi is used and libquvi returns a page title for the currently
played URL, return the page title.
Otherwise, if the currently played file has a ``title`` tag, use that.
If the currently played file has a ``title`` tag, use that.
Otherwise, if the media type is DVD, return the volume ID of DVD.
@@ -613,11 +710,6 @@ Property list
``stream-end``
Raw end position in bytes in source stream.
``stream-time-pos`` (RW)
Time position in source stream. This only works for DVD and Bluray. This
is probably never different from ``time-pos``, because ``time-pos`` is
forced to this value anyway.
``length``
Length of the current file in seconds. If the length is unknown, the
property is unavailable. Note that the file duration is not always exactly
@@ -632,8 +724,13 @@ Property list
disabled.
``drop-frame-count``
Frames dropped because they arrived to late. Unavailable if video
is disabled
Video frames dropped by decoder, because video is too far behind audio (when
using ``--framedrop=decoder``). Sometimes, this may be incremented in other
situations, e.g. when video packets are damaged, or the decoder doesn't
follow the usual rules. Unavailable if video is disabled.
``vo-drop-frame-count``
Frames dropped by VO (when using ``--framedrop=vo``).
``percent-pos`` (RW)
Position in current file (0-100). The advantage over using this instead of
@@ -641,9 +738,6 @@ Property list
estimating the playback position from the byte position, if the file
duration is not known.
``ratio-pos`` (RW)
Position in current file (0.0-1.0). higher precision that ``percent-pos``.
``time-pos`` (RW)
Position in current file in seconds.
@@ -658,6 +752,9 @@ Property list
``playtime-remaining``
``time-remaining`` scaled by the the current ``speed``.
``playback-time``
Return the playback time, which is the time difference between start PTS and current PTS.
``chapter`` (RW)
Current chapter number. The number of the first chapter is 0.
@@ -717,6 +814,10 @@ Property list
"title" MPV_FORMAT_STRING
"default" MPV_FORMAT_FLAG
``ab-loop-a``, ``ab-loop-b`` (TW)
Set/get A-B loop points. See corresponding options and ``ab_loop`` command.
The special value ``no`` on either of these properties disables looping.
``angle`` (RW)
Current DVD angle.
@@ -759,7 +860,7 @@ Property list
::
MPV_FORMAT_NODE_MAP
(key and string value for each metdata entry)
(key and string value for each metadata entry)
``chapter-metadata``
Metadata of current chapter. Works similar to ``metadata`` property. It
@@ -790,8 +891,12 @@ Property list
be different ``pause`` in special situations, such as when the player
pauses itself due to low network cache.
This also returns ``yes`` if playback is restarting or if nothing is
playing at all. In other words, it's only ``no`` if there's actually
video playing. (Behavior since mpv 0.7.0.)
``cache``
Network cache fill state (0-100).
Network cache fill state (0-100.0).
``cache-size`` (RW)
Total network cache size in KB. This is similar to ``--cache``. This allows
@@ -803,11 +908,34 @@ Property list
this easier, the cache resizing code will allocate the new cache while the
old cache is still allocated.
Don't use this when playing DVD or Bluray.
Don't use this when playing DVD or Blu-ray.
``cache-free`` (R)
Total free cache size in KB.
``cache-used`` (R)
Total used cache size in KB.
``cache-idle`` (R)
Returns ``yes`` if the cache is idle, which means the cache is filled as
much as possible, and is currently not reading more data.
``demuxer-cache-duration``
Approximate duration of video buffered in the demuxer, in seconds. The
guess is very unreliable, and often the property will not be available
at all, even if data is buffered.
``demuxer-cache-idle``
Returns ``yes`` if the demuxer is idle, which means the demuxer cache is
filled to the requested amount, and is currently not reading more data.
``paused-for-cache``
Returns ``yes`` when playback is paused because of waiting for the cache.
``cache-buffering-state``
Return the percentage (0-100) of the cache fill status until the player
will unpause (related to ``paused-for-cache``).
``eof-reached``
Returns ``yes`` if end of playback was reached, ``no`` otherwise. Note
that this is usually interesting only if ``--keep-open`` is enabled,
@@ -815,6 +943,12 @@ Property list
or enter idle mode), and in these cases the ``eof-reached`` property will
logically be cleared immediately after it's set.
``seeking``
Returns ``yes`` if the player is currently seeking, or otherwise trying
to restart playback. (It's possible that it returns ``yes`` while a file
is loaded, or when switching ordered chapter segments. This is because
the same underlying code is used for seeking and resyncing.)
``pts-association-mode`` (RW)
See ``--pts-association-mode``.
@@ -863,6 +997,9 @@ Property list
``deinterlace`` (RW)
See ``--deinterlace``.
``field-dominance`` (RW)
See ``--field-dominance``
``colormatrix`` (RW)
See ``--colormatrix``.
@@ -978,19 +1115,24 @@ Property list
"par" MPV_FORMAT_DOUBLE
"colormatrix" MPV_FORMAT_STRING
"colorlevels" MPV_FORMAT_STRING
"primaries" MPV_FORMAT_STRING
"chroma-location" MPV_FORMAT_STRING
"rotate" MPV_FORMAT_INT64
``dwidth``, ``dheight``
Video display size. This is the video size after filters and aspect scaling
have been applied. The actual video window size can still be different
from this.
from this, e.g. if the user resized the video window manually.
These have the same values as ``video-out-params/dw`` and
``video-out-params/dh``.
``video-out-params``
Same as ``video-params``, but after video filters have been applied. If
there are no video filters in use, this will contain the same values as
``video-params``. Note that this is still not necessarily what the video
window uses, since all real VOs do their own scaling.
window uses, since the user can change the window size, and all real VOs
do their own scaling independently from the filter chain.
Has the same sub-properties as ``video-params``.
@@ -1002,7 +1144,7 @@ Property list
Estimated/measured FPS of the video filter chain output. (If no filters
are used, this corresponds to decoder output.) This uses the average of
the 10 past frame durations to calculate the FPS. It will be inaccurate
if framedropping is involved (such as when framedrop is explicitly
if frame-dropping is involved (such as when framedrop is explicitly
enabled, or after precise seeking). Files with imprecise timestamps (such
as Matroska) might lead to unstable results.
@@ -1010,9 +1152,16 @@ Property list
Window size multiplier. Setting this will resize the video window to the
values contained in ``dwidth`` and ``dheight`` multiplied with the value
set with this property. Setting ``1`` will resize to original video size
(or to be exactly, the size the video filters output). ``2`` will set the
(or to be exact, the size the video filters output). ``2`` will set the
double size, ``0.5`` halves the size.
``window-minimized``
Return whether the video window is minimized or not.
``display-names``
Names of the displays that the mpv window covers. On X11, these
are the xrandr names (LVDS1, HDMI1, DP1, VGA1, etc.).
``video-aspect`` (RW)
Video aspect, see ``--video-aspect``.
@@ -1067,7 +1216,7 @@ Property list
See ``--sub-forced-only``.
``sub-scale`` (RW)
Subtitle font size multiplicator.
Subtitle font size multiplier.
``ass-use-margins`` (RW)
See ``--ass-use-margins``.
@@ -1079,8 +1228,8 @@ Property list
See ``--ass-style-override``.
``stream-capture`` (RW)
A filename, see ``--capture``. Setting this will start capture using the
given filename. Setting it to an empty string will stop it.
A filename, see ``--stream-capture``. Setting this will start capture using
the given filename. Setting it to an empty string will stop it.
``tv-brightness``, ``tv-contrast``, ``tv-saturation``, ``tv-hue`` (RW)
TV stuff.
@@ -1105,6 +1254,13 @@ Property list
``playlist/N/filename``
Filename of the Nth entry.
``playlist/N/current``, ``playlist/N/playing``
``yes`` if this entry is currently playing (or being loaded).
Unavailable or ``no`` otherwise. When changing files, ``current`` and
``playing`` can be different, because the currently playing file hasn't
been unloaded yet; in this case, ``current`` refers to the new
selection. (Since mpv 0.7.0.)
When querying the property with the client API using ``MPV_FORMAT_NODE``,
or with Lua ``mp.get_property_native``, this will return a mpv_node with
the following contents:
@@ -1114,6 +1270,8 @@ Property list
MPV_FORMAT_NODE_ARRAY
MPV_FORMAT_NODE_MAP (for each playlist entry)
"filename" MPV_FORMAT_STRING
"current" MPV_FORMAT_FLAG (might be missing; since mpv 0.7.0)
"playing" MPV_FORMAT_FLAG (same)
``track-list``
List of audio/video/sub tracks, current entry marked. Currently, the raw
@@ -1211,11 +1369,6 @@ Property list
"title" MPV_FORMAT_STRING
"time" MPV_FORMAT_DOUBLE
``quvi-format`` (RW)
See ``--quvi-format``. Cycling this property (``cycle``) will attempt to
cycle through known format, although currently this feature doesn't work
well at all.
``af`` (RW)
See ``--af`` and the ``af`` command.
@@ -1238,17 +1391,143 @@ Property list
It's also possible to write the property using this format.
``video-rotate`` (RW)
See ``--video-rotate`` option.
``seekable``
Return whether it's generally possible to seek in the current file.
``playback-abort``
Return whether playback is stopped or is to be stopped. (Useful in obscure
situations like during ``on_load`` hook processing, when the user can
stop playback, but the script has to explicitly end processing.)
``cursor-autohide`` (RW)
See ``--cursor-autohide``. Setting this to a new value will always update
the cursor, and reset the internal timer.
``osd-sym-cc``
Inserts the current OSD symbol as opaque OSD control code (cc). This makes
sense only with the ``show_text`` command or options which set OSD messages.
The control code is implementation specific and is useless for anything else.
``osd-ass-cc``
``${osd-ass-cc/0}`` disables escaping ASS sequences of text in OSD,
``${osd-ass-cc/1}`` enables it again. By default, ASS sequences are
escaped to avoid accidental formatting, and this property can disable
this behavior. Note that the properties return an opaque OSD control
code, which only makes sense for the ``show_text`` command or options
which set OSD messages.
.. admonition:: Example
--osd-status-msg='This is ${osd-ass-cc/0}{\\b1}bold text'
Any ASS override tags as understood by libass can be used.
Note that you need to escape the ``\`` character, because the string is
processed for C escape sequences before passing it to the OSD code.
``vo-configured``
Return whether the VO is configured right now. Usually this corresponds to
whether the video window is visible. If the ``--force-window`` option is
used, this is usually always returns ``yes``.
``audio-device-list``
Return the list of discovered audio devices. This is mostly for use with
the client API, and reflects what ``--audio-device=help`` with the command
line player returns.
When querying the property with the client API using ``MPV_FORMAT_NODE``,
or with Lua ``mp.get_property_native``, this will return a mpv_node with
the following contents:
::
MPV_FORMAT_NODE_ARRAY
MPV_FORMAT_NODE_MAP (for each device entry)
"name" MPV_FORMAT_STRING
"description" MPV_FORMAT_STRING
The ``name`` is what is to be passed to the ``--audio-device`` option (and
often a rather cryptic audio API-specific ID), while ``description`` is
human readable free form text. The description is an empty string if none
was received.
``audio-device`` (RW)
Set the audio device. This directly reads/writes the ``--audio-device``
option, but on write accesses, the audio output will be scheduled for
reloading.
Writing this property while no audio output is active will not automatically
enable audio. (This is also true in the case when audio was disabled due to
reinitialization failure after a previous write access to ``audio-device``.)
This property also doesn't tell you which audio device is actually in use.
How these details are handled may change in the future.
``mpv-version``
Return the mpv version/copyright string. Depending on how the binary was
built, it might contain either a release version, or just a git hash.
``mpv-configuration``
Return the configuration arguments which were passed to the build system
(typically the way ``./waf configure ...`` was invoked).
``options/<name>`` (RW)
Read-only access to value of option ``--<name>``. Most options can be
changed at runtime by writing to this property. Note that many options
require reloading the file for changes to take effect. If there is an
equivalent property, prefer setting the property instead.
``write_watch_later_config``
Saves current playback position.
``file-local-options/<name>``
Similar to ``options/<name>``, but when setting an option through this
property, the option is reset to its old value once the current file has
stopped playing. Trying to write an option while no file is playing (or
is being loaded) results in an error.
(Note that if an option is marked as file-local, even ``options/`` will
access the local value, and the ``old`` value, which will be restored on
end of playback, can not be read or written until end of playback.)
``option-info/<name>``
Additional per-option information.
This has a number of sub-properties. Replace ``<name>`` with the name of
a top-level option. No guarantee of stability is given to any of these
sub-properties - they may change radically in the feature.
``option-info/<name>/name``
Returns the name of the option.
``option-info/<name>/type``
Return the name of the option type, like ``String`` or ``Integer``.
For many complex types, this isn't very accurate.
``option-info/<name>/set-from-commandline``
Return ``yes`` if the option was set from the mpv command line,
``no`` otherwise. What this is set to if the option is e.g. changed
at runtime is left undefined (meaning it could change in the future).
``option-info/<name>/default-value``
The default value of the option. May not always be available.
``option-info/<name>/min``, ``option-info/<name>/max``
Integer minimum and maximum values allowed for the option. Only
available if the options are numeric, and the minimum/maximum has been
set internally. It's also possible that only one of these is set.
``option-info/<name>/choices``
If the option is a choice option, the possible choices. Choices that
are integers may or may not be included (they can be implied by ``min``
and ``max``). Note that options which behave like choice options, but
are not actual choice options internally, may not have this info
available.
``property-list``
Return the list of top-level properties.
Property Expansion
------------------
+183
View File
@@ -0,0 +1,183 @@
JSON IPC
========
mpv can be controlled by external programs using the JSON-based IPC protocol. It
can be enabled by specifying the path to a unix socket using the option
``--input-unix-socket``. Clients can connect to this socket and send commands to
the player or receive events from it. You can use the ``socat`` tool to send
commands (and receive reply) from the shell.
.. warning::
This is not intended to be a secure network protocol. It is explicitly
insecure: there is no authentication, no encryption, and the commands
themselves are insecure too. For example, the ``run`` command is exposed,
which can run arbitrary system commands. The use-case is controlling the
player locally. This is not different from the MPlayer slave protocol.
Protocol
--------
Clients can execute commands on the player by sending JSON messages of the
following form:
::
{ "command": ["command_name", "param1", "param2", ...] }
where ``command_name`` is the name of the command to be executed, followed by a
list of parameters. Parameters must be formatted as native JSON values
(integers, strings, booleans, ...). Every message **must** be terminated with
``\n``. Additionally, ``\n`` must not appear anywhere inside the message. In
practice this means that messages should be minified before being sent to mpv.
mpv will then send back a reply indicating whether the command was run
correctly, and an additional field holding the command-specific return data (it
can also be null).
::
{ "error": "success", "data": null }
mpv will also send events to clients with JSON messages of the following form:
::
{ "event": "event_name" }
where ``event_name`` is the name of the event. Additional event-specific fields
can also be present. See `List of events`_ for a list of all supported events.
If the first character (after skipping whitespace) is not ``{``, the command
will be interpreted as non-JSON text command, as they are used in input.conf
(or ``mpv_command_string()`` in the client API). Additionally, line starting
with ``#`` and empty lines are ignored.
Currently, embedded 0 bytes terminate the current line, but you should not
rely on this.
Commands
--------
Additionally to the commands described in `List of Input Commands`_, a few
extra commands can also be used as part of the protocol:
``client_name``
Return the name of the client as string. This is the string ``ipc-N`` with
N being an integer number.
``get_time_us``
Return the current mpv internal time in microseconds as a number. This is
basically the system time, with an arbitrary offset.
``get_property``
Return the value of the given property. The value will be sent in the data
field of the replay message.
Example:
::
{ "command": ["get_property", "volume"] }
{ "data": 50.0, "error": "success" }
``get_property_string``
Like ``get_property``, but the resulting data will always be a string.
Example:
::
{ "command": ["get_property_string", "volume"] }
{ "data": "50.000000", "error": "success" }
``set_property``
Set the given property to the given value. See `Properties`_ for more
information about properties.
Example:
::
{ "command": ["set_property", "pause", true] }
{ "error": "success" }
``set_property_string``
Like ``set_property``, but the argument value must be passed as string.
Example:
::
{ "command": ["set_property_string", "pause", "yes"] }
{ "error": "success" }
``observe_property``
Watch a property for changes. If the given property is changed, then an
event of type ``property-change`` will be generated
Example:
::
{ "command": ["observe_property", 1, "volume"] }
{ "error": "success" }
{ "event": "property-change", "id": 1, "data": 52.0, "name": "volume" }
``observe_property_string``
Like ``observe_property``, but the resulting data will always be a string.
Example:
::
{ "command": ["observe_property_string", 1, "volume"] }
{ "error": "success" }
{ "event": "property-change", "id": 1, "data": "52.000000", "name": "volume" }
``unobserve_property``
Undo ``observe_property`` or ``observe_property_string``. This requires the
numeric id passed to the observe command as argument.
Example:
::
{ "command": ["unobserve_property", 1] }
{ "error": "success" }
``request_log_messages``
Enable output of mpv log messages. They will be received as events. The
parameter to this command is the log-level (see ``mpv_request_log_messages``
C API function).
Log message output is meant for humans only (mostly for debugging).
Attempting to retrieve information by parsing these messages will just
lead to breakages with future mpv releases. Instead, make a feature request,
and ask for a proper event that returns the information you need.
``suspend``
Suspend the mpv main loop. There is a long-winded explanation of this in
the C API function ``mpv_suspend()``. In short, this prevents the player
from displaying the next video frame, so that you don't get blocked when
trying to access the player.
``resume``
Undo one ``suspend`` call. ``suspend`` increments an internal counter, and
``resume`` decrements it. When 0 is reached, the player is actually resumed.
``get_version``
Returns the client API version the C API of the remote mpv instance
provides. (Also see ``DOCS/client-api-changes.rst``.)
UTF-8
-----
Normally, all strings are in UTF-8. Sometimes it can happen that strings are
in some broken encoding (often happens with file tags and such, and filenames
on many Unixes are not required to be in UTF-8 either). This means that mpv
sometimes sends invalid JSON. If that is a problem for the client application's
parser, it should filter the raw data for invalid UTF-8 sequences and perform
the desired replacement, before feeding the data to its JSON parser.
mpv will not attempt to construct invalid UTF-8 with broken escape sequences.
+169 -43
View File
@@ -1,10 +1,16 @@
LUA SCRIPTING
=============
mpv can load Lua scripts. Scripts in ``~/.mpv/lua/`` will be loaded on program
start, or if passed to ``--lua``. mpv provides the builtin module ``mp``, which
provides functions to send commands to the mpv core and to retrieve information
about playback state, user settings, file information, and so on.
mpv can load Lua scripts. Scripts passed to the ``--lua`` option, or found in
the ``lua`` subdirectory of the mpv configuration directory (usually
``~/.config/mpv/lua/``) will be loaded on program start. mpv also appends the
``lua`` 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 provides the built-in module ``mp``, which provides functions to send
commands to the mpv core and to retrieve information about playback state, user
settings, file information, and so on.
These scripts can be used to control mpv in a similar way to slave mode.
Technically, the Lua code uses the client API internally.
@@ -27,12 +33,13 @@ allow users implement features which are not going to be added to the mpv core.
Mode of operation
-----------------
Your script will be loaded by the player at program start from ``~/.mpv/lua/``,
or ``--lua``, or in some cases, internally (like ``--osc``). Each script runs
in its own thread. Your script is first run "as is", and once that is done,
the event loop is entered. This event loop will dispatch events received by mpv
and call your own event handlers which you have registered with
``mp.register_event``, or timers added with ``mp.add_timeout`` or similar.
Your script will be loaded by the player at program start from the ``lua``
configuration subdirectory, from a path specified with the ``--lua`` option, or
in some cases, internally (like ``--osc``). Each script runs in its own
thread. Your script is first run "as is", and once that is done, the event loop
is entered. This event loop will dispatch events received by mpv and call your
own event handlers which you have registered with ``mp.register_event``, or
timers added with ``mp.add_timeout`` or similar.
When the player quits, all scripts will be asked to terminate. This happens via
a ``shutdown`` event, which by default will make the event loop return. If your
@@ -47,6 +54,15 @@ The event loop will wait for events and dispatch events registered with
``mp.register_event``. It will also handle timers added with ``mp.add_timeout``
and similar (by waiting with a timeout).
Since mpv 0.6.0, the player will wait until the script is fully loaded before
continuing normal operation. The player considers a script as fully loaded as
soon as it starts waiting for mpv events (or it exits). In practice this means
the player will more or less hang until the script returns from the main chunk
(and ``mp_event_loop`` is called), or the script calls ``mp_event_loop`` or
``mp.dispatch_events`` directly. This is done to make it possible for a script
to fully setup event handlers etc. before playback actually starts. In older
mpv versions, this happened asynchronously.
mp functions
------------
@@ -74,6 +90,19 @@ The ``mp`` module is preloaded, although it can be loaded manually with
These two commands are equivalent, except that the first version breaks
if the filename contains spaces or certain special characters.
Note that properties are *not* expanded. You can use either ``mp.command``,
the ``expand-properties`` prefix, or the ``mp.get_property`` family of
functions.
``mp.command_native(table [,def])``
Similar to ``mp.commandv``, but pass the argument list as table. This has
the advantage that in at least some cases, arguments can be passed as
native types.
Returns a result table on success (usually empty), or ``def, error`` on
error. ``def`` is the second parameter provided to the function, and is
nil if it's missing.
``mp.get_property(name [,def])``
Return the value of the given property as string. These are the same
properties as used in input.conf. See `Properties`_ for a list of
@@ -94,9 +123,9 @@ The ``mp`` module is preloaded, although it can be loaded manually with
will always result in a string.
``mp.get_property_bool(name [,def])``
Similar to ``mp.get_property``, but return the property value as boolean.
Similar to ``mp.get_property``, but return the property value as Boolean.
Returns a boolean on success, or ``def, error`` on error.
Returns a Boolean on success, or ``def, error`` on error.
``mp.get_property_number(name [,def])``
Similar to ``mp.get_property``, but return the property value as number.
@@ -109,7 +138,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``mp.get_property_native(name [,def])``
Similar to ``mp.get_property``, but return the property value using the best
Lua type for the property. Most time, this will return a string, boolean,
Lua type for the property. Most time, this will return a string, Boolean,
or number. Some properties (for example ``chapter-list``) are returned as
tables.
@@ -124,7 +153,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``mp.set_property_bool(name, value)``
Similar to ``mp.set_property``, but set the given property to the given
boolean value.
Boolean value.
``mp.set_property_number(name, value)``
Similar to ``mp.set_property``, but set the given property to the given
@@ -152,14 +181,14 @@ The ``mp`` module is preloaded, although it can be loaded manually with
Return the current mpv internal time in seconds as a number. This is
basically the system time, with an arbitrary offset.
``mp.add_key_binding(key, name|fn [,fn])``
``mp.add_key_binding(key, name|fn [,fn [,flags]])``
Register callback to be run on a key binding. The binding will be mapped to
the given ``key``, which is a string describing the physical key. This uses
the same key names as in input.conf, and also allows combinations
(e.g. ``ctrl+a``).
After calling this function, key presses will cause the function ``fn`` to
be called (unless the user overmapped the key with another binding).
be called (unless the user remapped the key with another binding).
The ``name`` argument should be a short symbolic string. It allows the user
to remap the key binding via input.conf using the ``script_message``
@@ -169,8 +198,23 @@ The ``mp`` module is preloaded, although it can be loaded manually with
overwritten. You can omit the name, in which case a random name is generated
internally.
Internally, key bindings are dispatched via the ``script_message_to`` input
command and ``mp.register_script_message``.
The last argument is used for optional flags. This is a table, which can
have the following entries:
``repeatable``
If set to ``true``, enables key repeat for this specific binding.
``complex``
If set to ``true``, then ``fn`` is called on both key up and down
events (as well as key repeat, if enabled), with the first
argument being a table. This table has an ``event`` entry, which
is set to one of the strings ``down``, ``repeat``, ``up`` or
``press`` (the latter if key up/down can't be tracked). It further
has an ``is_mouse`` entry, which tells whether the event was caused
by a mouse button.
Internally, key bindings are dispatched via the ``script_message_to`` or
``script_binding`` input commands and ``mp.register_script_message``.
Trying to map multiple commands to a key will essentially prefer a random
binding, while the other bindings are not called. It is guaranteed that
@@ -193,18 +237,18 @@ The ``mp`` module is preloaded, although it can be loaded manually with
::
y script_message something
y script_binding something
This will print the message when the key ``y`` is pressed. (``x`` will
still work, unless the user overmaps it.)
still work, unless the user remaps it.)
You can also explicitly send a message to a named script only. Assume the
above script was using the filename ``fooscript.lua``:
::
y script_message_to fooscript something
y script_binding fooscript.something
``mp.add_forced_key_binding(...)``
This works almost the same as ``mp.add_key_binding``, but registers the
@@ -299,6 +343,20 @@ The ``mp`` module is preloaded, although it can be loaded manually with
with ``add_timeout()``), this starts the timer from the beginning,
using the initially configured timeout.
``timeout`` (RW)
This field contains the current timeout period. This value is not
updated as time progresses. It's only used to calculate when the
timer should fire next when the timer expires.
If you write this, you can call ``t:kill() ; t:resume()`` to reset
the current timeout to the new one. (``t:stop()`` won't use the
new timeout.)
``oneshot`` (RW)
Whether the timer is periodic (``false``) or fires just once
(``true``). This value is used when the timer expires (but before
the timer callback function fn is run).
``mp.get_opt(key)``
Return a setting from the ``--lua-opts`` option. It's up to the user and
@@ -359,7 +417,7 @@ are useful only in special situations.
control what the Lua script does (instead of being called by the default
event loop), you can set the global variable ``mp_event_loop`` to your
own function running the event loop. From your event loop, you should call
``mp.dispatch_events()`` to unqueue and dispatch mpv events.
``mp.dispatch_events()`` to dequeue and dispatch mpv events.
If the ``allow_wait`` parameter is set to ``true``, the function will block
until the next event is received or the next timer expires. Otherwise (and
@@ -468,6 +526,13 @@ This built-in module provides generic helper functions for Lua, and have
strictly speaking nothing to do with mpv or video/audio playback. They are
provided for convenience. Most compensate for Lua's scarce standard library.
Be warned that any of these functions might disappear any time. They are not
strictly part of the guaranteed API.
``utils.getcwd()``
Returns the directory that mpv was launched from. On error, ``nil, error``
is returned.
``utils.readdir(path [, filter])``
Enumerate all entries at the given path on the filesystem, and return them
as array. Each entry is a directory entry (without the path).
@@ -504,6 +569,60 @@ provided for convenience. Most compensate for Lua's scarce standard library.
Return the concatenation of the 2 paths. Tries to be clever. For example,
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
and the captured output.
The parameter ``t`` is a table. The function reads the following entries:
``args``
Array of strings. The first array entry is the executable. This
can be either an absolute path, or a filename with no path
components, in which case the ``PATH`` environment variable is
used to resolve the executable. The other array elements are
passed as command line arguments.
``cancellable``
Optional. If set to ``true`` (default), then if the user stops
playback or goes to the next file while the process is running,
the process will be killed.
``max_size``
Optional. The maximum size in bytes of the data that can be captured
from stdout. (Default: 16 MB.)
The function returns a table as result with the following entries:
``status``
The raw exit status of the process. It will be negative on error.
``stdout``
Captured output stream as string, limited to ``max_size``.
``error``
``nil`` on success. The string ``killed`` if the process was
terminated in an unusual way. The string ``init`` if the process
could not be started.
On Windows, ``killed`` is only returned when the process has been
killed by mpv as a result of ``cancellable`` being set to ``true``.
In all cases, ``mp.resume_all()`` is implicitly called.
``utils.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
reading ``error``, because there is no fine-grained error reporting of any
kind.)
The returned value uses similar conventions as ``mp.get_property_native()``
to distinguish empty objects and arrays.
If the ``trail`` parameter is ``true`` (or any value equal to ``true``),
then trailing non-whitespace text is tolerated by the function, and the
trailing text is returned as 3rd return value. (The 3rd return value is
always there, but with ``trail`` set, no error is raised.)
Events
------
@@ -545,28 +664,11 @@ List of events
``playback-restart``
Start of playback after seek or after file was loaded.
``tracks-changed``
The list of video/audio/sub tracks was updated. (This happens on playback
start, and very rarely during playback.)
``track-switched``
A video/audio/subtitle track was switched on or off. This usually happens
when the user (or a script) changes the subtitle track and so on.
``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.
``pause``
Playback was paused. This also happens when for example the player is
paused on low network cache. Then the event type indicates the pause state
(like the property "pause" as opposed to the "core-idle" property), and you
might receive multiple ``pause`` events in a row.
``unpause``
Playback was unpaused. See above for details.
``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
@@ -626,8 +728,32 @@ List of events
``audio-reconfig``
Happens on audio output or filter reconfig.
``metadata-update``
Metadata (like file tags) was updated.
The following events also happen, but are deprecated: ``tracks-changed``,
``track-switched``, ``pause``, ``unpause``, ``metadata-update``,
``chapter-change``. Use ``mp.observe_property()`` instead.
``chapter-change``
The current chapter possibly changed.
Extras
------
This documents experimental features, or features that are "too special" and
we don't guarantee a stable interface to it.
``mp.add_hook(type, priority, fn)``
Add a hook callback for ``type`` (a string identifying a certain kind of
hook). These hooks allow the player to call script functions and wait for
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.
Currently existing hooks:
``on_load``
Called when a file is to be opened, before anything is actually done.
For example, you could read and write the ``stream-open-filename``
property to redirect an URL to something else (consider support for
streaming sites which rarely give the user a direct media URL), or
you could set per-file options with by setting the property
``file-local-options/<option name>``. The player will wait until all
hooks are run.
+150 -66
View File
@@ -2,7 +2,7 @@ mpv
###
##############
a movie player
a media player
##############
:Copyright: GPLv2+
@@ -12,14 +12,13 @@ a movie player
SYNOPSIS
========
| **mpv** [options] [file|URL|-]
| **mpv** [options] --playlist=PLAYLIST
| **mpv** [options] [file|URL|PLAYLIST|-]
| **mpv** [options] files
DESCRIPTION
===========
**mpv** is a movie player based on MPlayer and mplayer2. It supports a wide variety of video
**mpv** is a media player based on MPlayer and mplayer2. It supports a wide variety of video
file formats, audio and video codecs, and subtitle types. Special input URL
types are available to read input from a variety of sources other than disk
files. Depending on platform, a variety of different video and audio output
@@ -40,15 +39,16 @@ Keyboard Control
----------------
LEFT and RIGHT
Seek backward/forward 10 seconds. Shift+arrow does a 1 second exact seek
Seek backward/forward 5 seconds. Shift+arrow does a 1 second exact seek
(see ``--hr-seek``).
UP and DOWN
Seek forward/backward 1 minute. Shift+arrow does a 5 second exact seek (see
``--hr-seek``).
PGUP and PGDWN
Seek forward/backward 10 minutes.
Ctrl+LEFT and Ctrl+RIGHT
Seek to the previous/next subtitle. Subject to some restrictions and
might not work always; see ``sub_seek`` command.
[ and ]
Decrease/increase current playback speed by 10%.
@@ -63,41 +63,32 @@ BACKSPACE
Go backward/forward in the playlist.
ENTER
Go forward in the playlist, even over the end.
Go forward in the playlist.
p / SPACE
Pause (pressing again unpauses).
\.
Step forward. Pressing once will pause movie, every consecutive press will
Step forward. Pressing once will pause, every consecutive press will
play one frame and then go into pause mode again.
,
Step backward. Pressing once will pause movie, every consecutive press will
Step backward. Pressing once will pause, every consecutive press will
play one frame in reverse and then go into pause mode again.
q / ESC
q
Stop playing and quit.
Q
Like ``q``, but store the current playback position. Playing the same file
later will resume at the old playback position if possible.
U
Stop playing (and quit if ``--idle`` is not used).
\+ and -
Adjust audio delay by +/- 0.1 seconds.
/ and *
Decrease/increase volume.
9 and 0
Decrease/increase volume.
( and )
Adjust audio balance in favor of left/right channel.
m
Mute sound.
@@ -107,19 +98,22 @@ m
\#
Cycle through the available audio tracks.
TAB (MPEG-TS and libavformat only)
Cycle through the available programs.
f
Toggle fullscreen (see also ``--fs``).
ESC
Exit fullscreen mode.
T
Toggle stay-on-top (see also ``--ontop``).
w and e
Decrease/increase pan-and-scan range.
o
o (also P)
Show progression bar, elapsed time and total duration on the OSD.
O
Toggle OSD states: none / seek / seek + timer / seek + timer + total time.
d
@@ -132,12 +126,15 @@ v
j and J
Cycle through the available subtitles.
F
Toggle displaying "forced subtitles".
x and z
Adjust subtitle delay by +/- 0.1 seconds.
l
Set/clear A-B loop points. See ``ab_loop`` command for details.
Ctrl + and Ctrl -
Adjust audio delay by +/- 0.1 seconds.
V
Toggle subtitle VSFilter aspect compatibility mode. See
``--ass-vsfilter-aspect-compat`` for more info.
@@ -155,23 +152,18 @@ S
I
Show filename on the OSD.
P
Show progression bar, elapsed time and total duration on the OSD.
! and @
PGUP and PGDWN
Seek to the beginning of the previous/next chapter. In most cases,
"previous" will actually go to the beginning of the current chapter; see
``--chapter-seek-threshold``.
D (``--vo=vdpau``, ``--vf=yadif`` only)
Shift+PGUP and Shift+PGDWN
Seek backward or forward by 10 minutes. (This used to be mapped to
PGUP/PGDWN without Shift.)
D
Activate/deactivate deinterlacer.
A
Cycle through the available DVD angles.
c
Change YUV colorspace.
(The following keys are valid only when using a video output that supports the
corresponding adjustment, or the software equalizer (``--vf=eq``).)
@@ -187,24 +179,24 @@ corresponding adjustment, or the software equalizer (``--vf=eq``).)
7 and 8
Adjust saturation.
(The following keys are valid only on OSX.)
(The following keys are valid only on OS X.)
command + 0
Resize movie window to half its original size.
Resize video window to half its original size.
(On other platforms, you can bind keys to change the ``window-scale``
property.)
command + 1
Resize movie window to its original size.
Resize video window to its original size.
command + 2
Resize movie window to double its original size.
Resize video window to double its original size.
command + f
Toggle fullscreen (see also ``--fs``).
command + [ and command + ]
Set movie window alpha.
Set video window alpha.
(The following keys are valid if you have a keyboard with multimedia keys.)
@@ -223,12 +215,6 @@ support.)
h and k
Select previous/next channel.
n
Change norm.
u
Change channel list.
Mouse Control
-------------
@@ -285,7 +271,7 @@ need to escape special characters. To work this around, the path can be
additionally wrapped in the ``%n%string_of_length_n`` syntax (see above).
Some mpv options interpret paths starting with ``~``. Currently, the prefix
``~~/`` expands to the mpv configuration directory (usually ``~/.mpv/``).
``~~/`` expands to the mpv configuration directory (usually ``~/.config/mpv/``).
``~/`` expands to the user's home directory. (The trailing ``/`` is always
required.)
@@ -338,7 +324,7 @@ Location and Syntax
You can put all of the options in configuration files which will be read every
time mpv is run. The system-wide configuration file 'mpv.conf' is in your
configuration directory (e.g. ``/etc/mpv`` or ``/usr/local/etc/mpv``), the
user-specific one is ``~/.mpv/config``.
user-specific one is ``~/.config/mpv/mpv.conf``.
User-specific options override system-wide options and options given on the
command line override either. The syntax of the configuration files is
``option=<value>``; everything after a *#* is considered a comment. Options
@@ -373,13 +359,13 @@ File-specific Configuration Files
---------------------------------
You can also write file-specific configuration files. If you wish to have a
configuration file for a file called 'movie.avi', create a file named
'movie.avi.conf' with the file-specific options in it and put it in
``~/.mpv/``. You can also put the configuration file in the same directory
as the file to be played, as long as you give the ``--use-filedir-conf``
configuration file for a file called 'video.avi', create a file named
'video.avi.conf' with the file-specific options in it and put it in
``~/.config/mpv/``. You can also put the configuration file in the same directory
as the file to be played. Both require you to set the ``--use-filedir-conf``
option (either on the command line or in your global config file). If a
file-specific configuration file is found in the same directory, no
file-specific configuration is loaded from ``~/.mpv``. In addition, the
file-specific configuration is loaded from ``~/.config/mpv``. In addition, the
``--use-filedir-conf`` option enables directory-specific configuration files.
For this, mpv first tries to load a mpv.conf from the same directory
as the file played and then tries to load any file-specific configuration.
@@ -434,6 +420,52 @@ taking screenshots is handled by the VOs, and adding the screenshot filter will
break hardware decoding. (The filter may still be useful for taking screenshots
at a certain point within the video chain when using multiple video filters.)
TERMINAL STATUS LINE
====================
During playback, mpv shows the playback status on the terminal. It looks like
something like this:
``AV: 00:03:12 / 00:24:25 (13%) A-V: -0.000``
The status line can be overridden with the ``--term-status-msg`` option.
The following is a list of things that can show up in the status line. Input
properties, that can be used to get the same information manually, are also
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 (or ``00:00:00`` if unknown) (``length`` 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.)
- Playback percentage, e.g. ``(13%)``. How much of the file has been played.
Normally calculated out of playback position and duration, but can fallback
to other methods (like byte position) if these are not available.
(``percent-pos`` property.)
- The audio/video sync as ``A-V: 0.000``. This is the difference between
audio and video time. Normally it should be 0 or close to 0. If it's growing,
it might indicate a playback problem. (``avsync`` property.)
- Total A/V sync change, e.g. ``ct: -0.417``. Normally invisible. Can show up
if there is audio "missing", or not enough frames can be dropped. Usually
this will indicate a problem. (``total-avsync-change`` property.)
- Encoding state in ``{...}``, only shown in encoding mode.
- 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. Also can be incremented on "hiccups" and when the video
frame couldn't be displayed on time. (``vo-drop-frame-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 should almost never
happen, unless decoder-framedropping is enabled with one of the
``--framedrop`` options, the stream contains errors, or a weird codec is in
use. (``drop-frame-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 *additional* data buffered in the stream cache in
kilobytes. (``demuxer-cache-duration`` and ``cached-used`` properties.)
PROTOCOLS
=========
@@ -442,6 +474,10 @@ PROTOCOLS
be specified. mpv will never attempt to guess whether a filename is
actually a network address. A protocol prefix is always required.
Note that not all prefixes are documented here. Undocumented prefixes are
either aliases to documented protocols, or are just redirections to
protocols implemented and documented in FFmpeg.
``-``
Play data from stdin.
@@ -449,8 +485,8 @@ PROTOCOLS
Play a path from Samba share.
``bd://[title][/device]`` ``--bluray-device=PATH``
Play a Blu-Ray disc. Currently, this does not accept iso files. Instead,
you must mount the iso file as filesystem, and point ``--bluray-device``
Play a Blu-Ray disc. Currently, this does not accept ISO files. Instead,
you must mount the ISO file as filesystem, and point ``--bluray-device``
to the mounted directly.
``bdnav://[title][/device]``
@@ -531,6 +567,8 @@ PROTOCOLS
.. include:: lua.rst
.. include:: ipc.rst
.. include:: changes.rst
ENVIRONMENT VARIABLES
@@ -539,15 +577,23 @@ ENVIRONMENT VARIABLES
There are a number of environment variables that can be used to control the
behavior of mpv.
``HOME``
Used to determine mpv config directory: ``$HOME/.mpv``
``HOME``, ``XDG_CONFIG_HOME``
Used to determine mpv config directory. If ``XDG_CONFIG_HOME`` is not set,
``$HOME/.config/mpv`` is used.
``$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.
``TERM``
Used to determine terminal type.
``MPV_HOME``
Directory where mpv looks for user settings. Overrides ``HOME``, and mpv
will try to load the config file as ``$MPV_HOME/config``.
will try to load the config file as ``$MPV_HOME/mpv.conf``.
``MPV_VERBOSE`` (see also ``-v`` and ``--msg-level``)
Set the initial verbosity level across all message modules (default: 0).
@@ -660,18 +706,56 @@ FILES
``/usr/local/etc/mpv/mpv.conf``
mpv system-wide settings (depends on ``--prefix`` passed to configure)
``~/.mpv/config``
``~/.config/mpv/mpv.conf``
mpv user settings
``~/.mpv/input.conf``
input bindings (see ``--input-keylist`` for the full list)
``~/.config/mpv/input.conf``
key bindings (see `INPUT.CONF`_ section)
``~/.mpv/lua/``
``~/.config/mpv/lua/``
All files in this directly are loaded as if they were passed to the
``--lua`` 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.
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
================
On win32 (if compiled with MinGW, but not Cygwin), the default config file
locations are different:
``%APPDATA%/mpv/mpv.conf``
Preferred mpv config file. This maps to a system and user-specific path,
for example ``C:\users\USERNAME\Application Data\mpv\mpv.conf``. You can
find the exact path by running ``echo %APPDATA%\mpv\mpv.conf`` in cmd.exe.
``%APPDATA%/mpv/input.conf``
key bindings (see `INPUT.CONF`_ section)
``%APPDATA%/mpv/lua/``
equivalent of ``~/.config/mpv/lua/`` on Unix.
The environment variable ``$MPV_HOME`` completely overrides these, like on
UNIX.
Config files located in the same directory as ``mpv.exe`` are loaded with
lower priority. Some config files are loaded only once, which means that
e.g. of 2 ``input.conf`` files located in two config directories, only the
one from the directory with higher priority will be loaded.
A third config directory with lowest priority is the directory named ``mpv``
in the same directory as ``mpv.exe``. This used to be the directory with
highest priority, but is now discouraged to use and might be removed in the
future.
Note that mpv likes to mix ``/`` and ``\`` path separators for simplicity.
kernel32.dll accepts this, but cmd.exe does not.
EXAMPLES OF MPV USAGE
=====================
@@ -689,7 +773,7 @@ Play only chapters 5, 6, 7:
Play only titles 5, 6, 7:
``mpv dvd://5-7``
Play a multiangle DVD:
Play a multi-angle DVD:
``mpv dvd://1 --dvd-angle=2``
Play from a different DVD device:
+2116 -1713
View File
File diff suppressed because it is too large. Load diff
+9 -5
View File
@@ -122,11 +122,11 @@ time remaining
left-click toggle between total and remaining time
============= ================================================
Keybindings
~~~~~~~~~~~
Key Bindings
~~~~~~~~~~~~
These keybindings are active by default if nothing else is already bound to
these keys. In case of collosision, the function needs to be bound to a
These key bindings are active by default if nothing else is already bound to
these keys. In case of collision, the function needs to be bound to a
different key. See `Script Commands`_ section.
============= ================================================
@@ -161,7 +161,7 @@ To avoid collisions with other scripts, all options need to be prefixed with
Example::
--lua-opts=osc-optionA=value1:osc-optionB=value2
--lua-opts=osc-optionA=value1,osc-optionB=value2
Configurable Options
@@ -229,6 +229,10 @@ Configurable Options
| Default: yes
| Display a tooltip over the seekbar indicating time at mouse position.
``seekbarstyle``
| Default: slider
| Sets the style of the seekbar, slider (diamond marker) or bar (fill)
Script Commands
~~~~~~~~~~~~~~~
+61 -24
View File
@@ -47,7 +47,7 @@ Available filters are:
``crop[=w:h:x:y]``
Crops the given part of the image and discards the rest. Useful to remove
black bands from widescreen movies.
black bands from widescreen videos.
``<w>,<h>``
Cropped width and height, defaults to original width and height.
@@ -55,7 +55,7 @@ Available filters are:
Position of the cropped picture, defaults to center.
``expand[=w:h:x:y:aspect:round]``
Expands (not scales) movie resolution to the given value and places the
Expands (not scales) video resolution to the given value and places the
unscaled original at coordinates x, y.
``<w>,<h>``
@@ -93,7 +93,7 @@ Available filters are:
``scale[=w:h:param:param2:chr-drop:noup:arnd``
Scales the image with the software scaler (slow) and performs a YUV<->RGB
colorspace conversion (see also ``--sws``).
color space conversion (see also ``--sws``).
All parameters are optional.
@@ -120,9 +120,9 @@ Available filters are:
0.33:0.33 Mitchell-Netravali spline
1.00:0.00 cubic B-spline
--sws=7 (gaussian): sharpness (0 (soft) - 100 (sharp))
--sws=7 (Gaussian): sharpness (0 (soft) - 100 (sharp))
--sws=9 (lanczos): filter length (1-10)
--sws=9 (Lanczos): filter length (1-10)
``<chr-drop>``
chroma skipping
@@ -222,8 +222,8 @@ Available filters are:
====================== =====================
``noformat[=fmt]``
Restricts the colorspace for the next filter without doing any conversion.
Unlike the format filter, this will allow any colorspace except the one
Restricts the color space for the next filter without doing any conversion.
Unlike the format filter, this will allow any color space except the one
you specify.
.. note:: For a list of available formats, see ``noformat=fmt=help``.
@@ -231,12 +231,23 @@ Available filters are:
``<fmt>``
Format name, e.g. rgb15, bgr24, 420p, etc. (default: 420p).
``pp[=[filter1[:option1[:option2...]]/[-]filter2...]]``
Enables the specified chain of postprocessing subfilters. Subfilters must
``pp=[filter string]``
Enables the specified chain of post-processing subfilters. Subfilters must
be separated by '/' and can be disabled by prepending a '-'. Each
subfilter and some options have a short and a long name that can be used
interchangeably, i.e. ``dr``/``dering`` are the same. All subfilters share
common options to determine their scope:
interchangeably, i.e. ``dr``/``dering`` are the same.
.. note::
Unlike in MPlayer or in earlier versions, you must quote the pp string
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
.. admonition:: Warning
This filter is most likely useless on modern HD video. It might be
helpful with old low-resolution files.
All subfilters share common options to determine their scope:
``a/autoq``
Automatically switch the subfilter off if the CPU is too slow.
@@ -251,11 +262,6 @@ Available filters are:
``--vf=pp:help`` shows a list of available subfilters.
.. note::
Unlike in MPlayer or in earlier versions, you must quote the pp string
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
Available subfilters are:
``hb/hdeblock[:difference[:flatness]]``
@@ -336,7 +342,7 @@ Available filters are:
filtering every second line with a (-1 4 2 4 -1) filter.
``l5/lowpass5``
Vertically applied FIR lowpass deinterlacing filter that deinterlaces
Vertically applied FIR low-pass deinterlacing filter that deinterlaces
the given block by filtering all lines with a (-1 2 6 2 -1) filter.
``fq/forceQuant[:quantizer]``
@@ -356,7 +362,7 @@ Available filters are:
.. note::
This filter is only available if FFmpeg/libav has been compiled
This filter is only available if FFmpeg/Libav has been compiled
with libpostproc enabled.
.. admonition:: Examples
@@ -443,7 +449,7 @@ Available filters are:
temporal noise (noise pattern changes between frames)
``uniform``
uniform noise (gaussian otherwise)
uniform noise (Gaussian otherwise)
``hq``
high quality (slightly better looking, slightly slower) - not available
@@ -503,7 +509,7 @@ Available filters are:
:1: linear interpolation (default)
``unsharp[=lx:ly:la:cx:cy:ca]``
unsharp mask / gaussian blur
unsharp mask / Gaussian blur
``l`` is for the luma component, ``c`` for the chroma component. ``x``/``y``
is the filter size. ``a`` is the amount.
@@ -617,7 +623,7 @@ Available filters are:
``phase[=t|b|p|a|u|T|B|A|U][:v]``
Delay interlaced video by one field time so that the field order changes.
The intended use is to fix PAL movies that have been captured with the
The intended use is to fix PAL videos that have been captured with the
opposite field order to the film-to-video transfer. The options are:
``t``
@@ -769,8 +775,8 @@ Available filters are:
anaglyph red/cyan color (red filter on left eye, cyan filter on
right eye)
``arcd`` or ``anaglyph_red_cyan_dubois``
anaglyph red/cyan color optimized with the least squares
projection of dubois (red filter on left eye, cyan filter on right
anaglyph red/cyan color optimized with the least-squares
projection of Dubois (red filter on left eye, cyan filter on right
eye)
``agmg`` or ``anaglyph_green_magenta_gray``
anaglyph green/magenta gray (green filter on left eye, magenta
@@ -803,7 +809,7 @@ Available filters are:
``gradfun[=strength[:radius|:size=<size>]]``
Fix the banding artifacts that are sometimes introduced into nearly flat
regions by truncation to 8bit color depth. Interpolates the gradients that
regions by truncation to 8-bit color depth. Interpolates the gradients that
should go where the bands are, and dithers them.
``<strength>``
@@ -904,6 +910,31 @@ Available filters are:
making it higher than the number of cores can actually make it
slower.
``vapoursynth-lazy``
The same as ``vapoursynth``, but doesn't load Python scripts. Instead, a
custom backend using Lua and the raw VapourSynth API is used. The syntax
is completely different, and absolutely no conveniencve features are
provided. There's no type checking either, and you can trigger crashes.
.. admonition:: Example:
::
video_out = invoke("morpho", "Open", {clip = video_in})
The special variable ``video_in`` is the mpv video source, while the
special variable ``video_out`` is used to read video from. The 1st argument
is the plugin (queried with ``getPluginByNs``), the 2nd is the filter name,
and the 3rd argument is a table with the arguments. Positional arguments
are not supported. The types must match exactly. Since Lua is terrible and
can't distinguish integers and floats, integer arguments must be prefixed
with ``i_``, in which case the prefix is removed and the argument is cast
to an integer. Should the argument's name start with ``i_``, you're out of
luck.
Clips (VSNodeRef) are passed as light userdata, so trying to pass any
other userdata type will result in hard crashes.
``vavpp``
VA-AP-API video post processing. Works with ``--vo=vaapi`` and ``--vo=opengl``
only. Currently deinterlaces. This filter is automatically inserted if
@@ -969,3 +1000,9 @@ Available filters are:
Use default VDPAU scaling (default).
1-9
Apply high quality VDPAU scaling (needs capable hardware).
``buffer=<num>``
Buffer ``<num>`` frames in the filter chain. This filter is probably pretty
useless, except for debugging. (Note that this won't help smoothing out
latencies with decoding, because the filter will never output a frame if
the buffer isn't full, except on EOF.)
+88 -44
View File
@@ -38,36 +38,36 @@ Available video output drivers are:
.. note:: This driver is for compatibility with old systems.
``adaptor=<number>``
Select a specific XVideo adaptor (check xvinfo results).
Select a specific XVideo adapter (check xvinfo results).
``port=<number>``
Select a specific XVideo port.
``ck=<cur|use|set>``
Select the source from which the colorkey is taken (default: cur).
Select the source from which the color key is taken (default: cur).
cur
The default takes the colorkey currently set in Xv.
The default takes the color key currently set in Xv.
use
Use but do not set the colorkey from mpv (use the ``--colorkey``
Use but do not set the color key from mpv (use the ``--colorkey``
option to change it).
set
Same as use but also sets the supplied colorkey.
Same as use but also sets the supplied color key.
``ck-method=<man|bg|auto>``
Sets the colorkey drawing method (default: man).
Sets the color key drawing method (default: man).
man
Draw the colorkey manually (reduces flicker in some cases).
Draw the color key manually (reduces flicker in some cases).
bg
Set the colorkey as window background.
Set the color key as window background.
auto
Let Xv draw the colorkey.
Let Xv draw the color key.
``colorkey=<number>``
Changes the colorkey to an RGB value of your choice. ``0x000000`` is
Changes the color key to an RGB value of your choice. ``0x000000`` is
black and ``0xffffff`` is white.
``no-colorkey``
Disables colorkeying.
Disables color-keying.
``x11`` (X11 only)
Shared memory video output driver without hardware acceleration that works
@@ -82,7 +82,7 @@ Available video output drivers are:
.. note::
Earlier versions of mpv (and MPlayer, mplayer2) provided sub-options
to tune vdpau postprocessing, like ``deint``, ``sharpen``, ``denoise``,
to tune vdpau post-processing, like ``deint``, ``sharpen``, ``denoise``,
``chroma-deint``, ``pullup``, ``hqscaling``. These sub-options are
deprecated, and you should use the ``vdpaupp`` video filter instead.
@@ -173,7 +173,7 @@ Available video output drivers are:
to a YUV format before the VO. Sometimes useful to force availability
of certain YUV-only features, like video equalizer or deinterlacing.
Using the VDPAU frame queueing functionality controlled by the queuetime
Using the VDPAU frame queuing functionality controlled by the queuetime
options makes mpv's frame flip timing less sensitive to system CPU load and
allows mpv to start decoding the next frame(s) slightly earlier, which can
reduce jitter caused by individual slow-to-decode frames. However, the
@@ -233,18 +233,29 @@ Available video output drivers are:
Always force textures to power of 2, even if the device reports
non-power-of-2 texture sizes as supported.
``texture-memory=N``
``texture-memory=<mode>``
Only affects operation with shaders/texturing enabled, and (E)OSD.
Values for N:
Possible values:
0
default, will often use an additional shadow texture + copy
1
use ``D3DPOOL_MANAGED``
2
use ``D3DPOOL_DEFAULT``
3
use ``D3DPOOL_SYSTEMMEM``, but without shadow texture
``default`` (default)
Use ``D3DPOOL_DEFAULT``, with a ``D3DPOOL_SYSTEMMEM`` texture for
locking. If the driver supports ``D3DDEVCAPS_TEXTURESYSTEMMEMORY``,
``D3DPOOL_SYSTEMMEM`` is used directly.
``default-pool``
Use ``D3DPOOL_DEFAULT``. (Like ``default``, but never use a
shadow-texture.)
``default-pool-shadow``
Use ``D3DPOOL_DEFAULT``, with a ``D3DPOOL_SYSTEMMEM`` texture for
locking. (Like ``default``, but always force the shadow-texture.)
``managed``
Use ``D3DPOOL_MANAGED``.
``scratch``
Use ``D3DPOOL_SCRATCH``, with a ``D3DPOOL_SYSTEMMEM`` texture for
locking.
``swap-discard``
Use ``D3DSWAPEFFECT_DISCARD``, which might be faster.
@@ -259,13 +270,6 @@ Available video output drivers are:
.. note:: This driver is for compatibility with old systems.
``corevideo`` (Mac OS X 10.6 and later)
Mac OS X CoreVideo video output driver. Uses the CoreVideo APIs to fill
PixelBuffers and generate OpenGL textures from them (useful as a fallback
for ``opengl``).
.. note:: This driver is for compatibility with old systems.
``opengl``
OpenGL video output driver. It supports extended scaling methods, dithering
and color management.
@@ -282,7 +286,7 @@ Available video output drivers are:
Hardware decoding over OpenGL-interop is supported to some degree. Note
that in this mode, some corner case might not be gracefully handled, and
colorspace conversion and chroma upsampling is generally in the hand of
color space conversion and chroma upsampling is generally in the hand of
the hardware decoder APIs.
``lscale=<filter>``
@@ -297,6 +301,9 @@ Available video output drivers are:
``lanczos3``
Lanczos with radius=3.
``lanczos``
Generic Lanczos scaling filter. Set radius with ``lradius``.
``spline36``
This is the default when using ``opengl-hq``.
@@ -316,6 +323,14 @@ Available video output drivers are:
Mitchell-Netravali. The ``b`` and ``c`` parameters can be set with
``lparam1`` and ``lparam2``. Both are set to 1/3 by default.
``gaussian``
Gaussian filter with a parameter ``p`` for sharpness control.
``p`` can be set to float number between 1(blurry) and 100(sharp)
and has a default value of about 28.8 (see ``lparam1``).
Note that for extremely small value of ``p``, a large filter radius
might be required to avoid unintended artifacts (see ``lradius``).
There are some more filters. For a complete list, pass ``help`` as
value, e.g.::
@@ -329,6 +344,16 @@ Available video output drivers are:
``lparam2=<value>``
See ``lparam1``.
``lradius=<r>``
Set radius for filters listed below, must be a float number between 1.0
and 8.0. Defaults to be 2.0 if not specified.
``sinc``, ``lanczos``, ``blackman``, ``gaussian``
Note that depending on filter implementation details and video scaling
ratio, the radius that actually being used might be different
(most likely being increased a bit).
``scaler-resizes-only``
Disable the scaler if the video image is not resized. In that case,
``bilinear`` is used instead whatever is set with ``lscale``. Bilinear
@@ -349,7 +374,7 @@ Available video output drivers are:
green-magenta
Convert side by side input to full-color green-magenta stereo.
quadbuffer
Convert side by side input to quadbuffered stereo. Only supported
Convert side by side input to quad buffered stereo. Only supported
by very few OpenGL cards.
``srgb``
@@ -424,12 +449,22 @@ Available video output drivers are:
this options will make rendering a single operation.
Note that chroma scalers are always done as 1-pass filters.
``cscale=<n>``
``cscale=<filter>``
As ``lscale``, but for chroma (2x slower with little visible effect).
Note that with some scaling filters, upscaling is always done in
RGB. If chroma is not subsampled, this option is ignored, and the
luma scaler is used instead. Setting this option is often useless.
``lscale-down=<filter>``, ``cscale-down=<filter>``
Like ``lscale`` and ``cscale``, but apply these filters on downscaling
instead. If these options are unset, the filter implied by ``lscale``
(and ``cscale``, respectively) will be applied.
``cparam1``, ``cparam2``, ``cradius``
Set filter parameters and radius for ``cscale``.
See ``lparam1``, ``lparam2`` and ``lradius``.
``fancy-downscaling``
When using convolution based filters, extend the filter size
when downscaling. Trades quality for reduced downscaling performance.
@@ -439,7 +474,16 @@ Available video output drivers are:
Borders will be distorted due to filtering.
``glfinish``
Call ``glFinish()`` before swapping buffers
Call ``glFinish()`` before and after swapping buffers (default: disabled).
Slower, but might help getting better results when doing framedropping.
The details depend entirely on the OpenGL driver.
``waitvsync``
Call ``glXWaitVideoSyncSGI`` after each buffer swap (default: disabled).
This may or may not help with video timing accuracy and frame drop. It's
possible that this makes video output slower, or has no effect at all.
X11 only.
``sw``
Continue even if a software renderer is detected.
@@ -452,7 +496,7 @@ Available video output drivers are:
auto
auto-select (default)
cocoa
Cocoa/OSX
Cocoa/OS X
win
Win32/WGL
x11
@@ -479,7 +523,7 @@ Available video output drivers are:
``gamma=<0.0..10.0>``
Set a gamma value. If gamma is adjusted in other ways (like with
the ``--gamma`` option or keybindings and the ``gamma`` property), the
the ``--gamma`` option or key bindings and the ``gamma`` property), the
value is multiplied with the other gamma value.
Setting this value to 1.0 can be used to always enable gamma control.
@@ -487,7 +531,7 @@ Available video output drivers are:
``icc-profile=<file>``
Load an ICC profile and use it to transform linear RGB to screen output.
Needs LittleCMS2 support compiled in. This option overrides the ``srgb``
Needs LittleCMS 2 support compiled in. This option overrides the ``srgb``
property, as using both is somewhat redundant. It also enables linear
light scaling.
@@ -500,12 +544,12 @@ Available video output drivers are:
``icc-cache=<file>``
Store and load the 3D LUT created from the ICC profile in this file.
This can be used to speed up loading, since LittleCMS2 can take a while
This can be used to speed up loading, since LittleCMS 2 can take a while
to create the 3D LUT. Note that this file contains an uncompressed LUT.
Its size depends on the ``3dlut-size``, and can be very big.
``icc-intent=<value>``
Specifies the ICC Intent used for transformations between colorspaces.
Specifies the ICC Intent used for transformations between color spaces.
This affects the rendering when using ``icc-profile`` or ``srgb`` and
also affects the way DCP XYZ content gets converted to RGB.
@@ -524,7 +568,7 @@ Available video output drivers are:
for mastering instead of the true curve. Most notably, anything in the
Apple ecosystem uses this approximation - including all programs
compatible with it. It's a sound idea to try enabling this flag first
when watching movies and shows to see if things look better that way.
when watching videos and shows to see if things look better that way.
This only affects the output when using either ``icc-profile`` or ``srgb``.
@@ -562,7 +606,7 @@ Available video output drivers are:
This is equivalent to::
--vo=opengl:lscale=spline36:dither-depth=auto:fbo-format=rgb16
--vo=opengl:lscale=spline36:dither-depth=auto:fbo-format=rgba16
Note that some cheaper LCDs do dithering that gravely interferes with
``opengl``'s dithering. Disabling dithering with ``dither-depth=no`` helps.
@@ -571,7 +615,7 @@ Available video output drivers are:
can achieve better quality or performance by changing the ``fbo-format``
suboption to ``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include
Mesa/Intel not accepting ``rgb16``, Mesa sometimes not being compiled with
float texture support, and some OSX setups being very slow with ``rgb16``
float texture support, and some OS X setups being very slow with ``rgb16``
but fast with ``rgb32f``.
``opengl-old``
@@ -706,7 +750,7 @@ Available video output drivers are:
2
Convert side by side input to full-color green-magenta stereo.
3
Convert side by side input to quadbuffered stereo. Only supported
Convert side by side input to quad buffered stereo. Only supported
by very few OpenGL cards.
The following options are only useful if writing your own fragment programs.
@@ -748,7 +792,7 @@ Available video output drivers are:
auto
auto-select (default)
cocoa
Cocoa/OSX
Cocoa/OS X
win
Win32/WGL
x11
+15 -1
View File
@@ -24,11 +24,14 @@ Release procedure
- Create and/or update the ``VERSION`` file.
- Update ``DOCS/client-api-changes.rst`` (on major releases).
- Create tag v0.X.Y.
- Push branch and tag to GitHub.
- Create a new GitHub release using the content of ``RELEASE_NOTES``.
- Create a new GitHub release using the content of ``RELEASE_NOTES`` related to
the new version.
Release notes template
----------------------
@@ -36,6 +39,9 @@ Release notes template
Here is a template that can be used for writing the ``RELEASE_NOTES`` file.
```markdown
Release 0.X.Y
=============
Changes
-------
@@ -55,3 +61,11 @@ This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log <start>..<end>`` in
the git repository.
```
Note that the "Release 0.X.Y" title should be removed when creating a new GitHub
release.
When creating a new point release its changes should be added on top of the
``RELEASE_NOTES`` file (with the appropriate title) so that all the changes in
the current 0.X branch will be included. This way the ``RELEASE_NOTES`` file
can be used by distributors as changelog for point releases too.
+47 -29
View File
@@ -1,4 +1,4 @@
This file intends to give a big picture of how mpv is structured.
This file intends to give a big picture overview of how mpv is structured.
player/*.c:
Essentially makes up the player applications, including the main() function
@@ -17,12 +17,12 @@ player/*.c:
* check help options etc. (call handle_help_options()), possibly exit
* call play_files() function that works down the playlist:
* run idle loop (idle_loop()), until there are files in the
playlist or an exit command was given (slave mode only)
playlist or an exit command was given (only if --idle it set)
* actually load and play a file in play_current_file():
* run all the dozens of functions to load the file and
initialize playback
* run a small loop that does normal playback, until the file is
done or a slave command terminates playback
done or a command terminates playback
(on each iteration, run_playloop() is called, which is rather
big and complicated - it decodes some audio and video on
each frame, waits for input, etc.)
@@ -31,15 +31,28 @@ player/*.c:
* loop, or exit if no next file or quit is requested
(see enum stop_play_reason)
* call exit_player_with_rc()
* run_playloop():
* calls fill_audio_out_buffers()
This checks whether new audio needs to be decoded, and pushes it
to the AO.
* calls write_video()
Decode new video, and push it to the VO.
* determines whether playback of the current file has ended
* determines when to start playback after seeks
* and calls a whole lot of other stuff
(Really, this function does everything.)
Things worth saying about the playback core:
- the currently played tracks are in sh_video and sh_audio
- most state is in MPContext (core.h), which is not available to the
subsystems
- the currently played tracks are in mpctx->current_tracks, and decoder
state in d_video/d_audio/d_sub
- the timeline stuff is used only with MKV ordered chapters (and some other
minor features: cue, edl)
- most state is in MPContext (mp_core.h), which is not available to the
subsystems
- the other subsystems rarely call back into the frontend, and the frontend
polls them instead (probably a good thing)
- one exceptions are wakeup callbacks, which notify a "higher" component
of a changed situation in a subsystem
I like to call the player/*.c files the "frontend".
@@ -82,7 +95,7 @@ talloc.h & talloc.c:
(See ta/README for details.)
player/command.c:
This contains the implementation for slave commands and properties.
This contains the implementation for client API commands and properties.
Properties are essentially dynamic variables changed by certain commands.
This is basically responsible for all user commands, like initiating
seeking, switching tracks, etc. It calls into other player/*.c files,
@@ -92,9 +105,10 @@ player/core.h:
Data structures and function prototypes for most of player/*.c. They are
usually not accessed by other parts of mpv for the sake of modularization.
Note that there are lots of global variables floating around everywhere
else. This is an ongoing transition, and eventually there should be no
global variables anymore.
player/client.c:
This implements the client API (libmpv/client.h). For the most part, this
just calls into other parts of the player. This also manages a ringbuffer
of events from player to clients.
options/options.h, options/options.c
options.h contains the global option struct MPOpts. The option declarations
@@ -102,7 +116,7 @@ options/options.h, options/options.c
options.c. Most default values for options and MPOpts are in
mp_default_opts at the end of options.c.
MPOpts is unfortunarely quite monolithic, and virtually accessed by
MPOpts is unfortunately quite monolithic, and virtually accessed by
everything.But some components (like video outputs and video filters) have
their own sub-option tables separate from MPOpts.
@@ -110,19 +124,18 @@ options/options.h, options/options.c
parser-mpcmd.c, and uses the option table in options.c.
input/input.c:
This translates keyboard input comming from libvo and other sources (such
as remote control devices like Apple IR or slave mode commands) to the
This translates keyboard input comming from VOs and other sources (such
as remote control devices like Apple IR or client API commands) to the
key bindings listed in the user's (or the builtin) input.conf and turns
them into items of type struct mp_cmd. These commands are queued, and read
by playloop.c. They get pushed with run_command() to command.c.
Note that keyboard input and slave mode input are essentially the same
things. Just looking at input.conf should make this clear. (The other
direction of slave mode communication, mpv to application, consists of
random mp_msg() calls all over the code in all parts of the player.)
Note that keyboard input and commands used by the client API are the same.
The client API only uses the command parser though, and has its own queue
of input commands somewhere else.
common/msg.h:
All terminal output should go through mp_msg().
All terminal output must go through mp_msg().
stream/*:
File input is implemented here. stream.h/.c provides a simple stream based
@@ -181,7 +194,7 @@ video/out/:
vo_opengl can pick a windowing system at runtime, e.g. the same binary can
provide both X11 and Cocoa support on OSX.
VOs can be reconfigured at runtime. A config() call can change the video
VOs can be reconfigured at runtime. A vo_config() call can change the video
resolution and format, without destroying the window.
vo_vdpau and vo_opengl should be taken as reference.
@@ -203,9 +216,12 @@ audio/filter/:
audio/out/:
Audio outputs.
Unlike VOs, AOs can't be reconfigured on a format change. Without
--gapless-audio, even playing a new file will close and re-open the audio
device.
Unlike VOs, AOs can't be reconfigured on a format change. On audio format
changes, the AO will simply be closed and re-opened.
There are wrappers to support for two types of audio APIs: push.c and
pull.c. ao.c calls into one of these. They contain generic code to deal
with the data flow these APIs impose.
Note that mpv synchronizes the video to the audio. That's the reason
why buggy audio drivers can have a bad influence on playback quality.
@@ -213,17 +229,19 @@ audio/out/:
sub/:
Contains subtitle and OSD rendering.
sub.c/.h is actually the OSD code. It queries dec_sub.c to retrieve
osd.c/.h is actually the OSD code. It queries dec_sub.c to retrieve
decoded/rendered subtitles. osd_libass.c is the actual implementation of
the OSD text renderer (which uses libass, and takes care of all the tricky
fontconfig/freetype API usage and text layouting).
Subtitle loading is now in demux/ instead. demux_libass.c wraps loading
.ass subtitles via libass. demux_lavf.c loads most subtitle types via
FFmpeg. demux_subreader.c is the old MPlayer code. It's used as last
fallback, or to handle some text subtitle types on Libav. (It also can
load UTF-16 encoded subtitles without requiring the use of -sub-codepage.)
demux_subreader.c should eventually go away (maybe).
The VOs call osd.c to render OSD and subtitle (via e.g. osd_draw()). osd.c
in turn asks dec_sub.c for subtitle overlay bitmaps, which relays the
request to one of the sd_*.c subtitle decoders/renderers.
Subtitle loading is in demux/. The MPlayer subreader.c is mostly gone - parts
of it survive in demux_subreader.c. It's used as last fallback, or to handle
some text subtitle types on Libav. It should go away eventually. Normally,
subtitles are loaded via demux_lavf.c.
The subtitles are passed to dec_sub.c and the subtitle decoders in sd_*.c
as they are demuxed. All text subtitles are rendered by sd_ass.c. If text
+11 -9
View File
@@ -3,6 +3,8 @@ mpv
[![Build Status](https://api.travis-ci.org/mpv-player/mpv.png)](https://travis-ci.org/mpv-player/mpv)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/1232/badge.svg)](https://scan.coverity.com/projects/1232)
Overview
--------
@@ -48,7 +50,7 @@ Essential dependencies (incomplete list):
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavresample)
At least FFmpeg 2.1.4 or Libav 10 is required.
- libjpeg (for screenshots)
- libquvi if you want to play Youtube videos directly
- Lua (strictly speaking optional, but required for the OSC pseudo-GUI)
Libass dependencies:
@@ -117,17 +119,17 @@ make code review easier for both parties later on.
Contact
-------
These forms of contact are meant to ask questions about mpv usage, give
feedback on mpv and discuss it's development.
Most activity happens on the IRC channel and the github issue tracker. The
mailing lists are mostly unused.
If possible, please avoid posting bugs here and use the [issue tracker][issue-tracker]
instead.
- **Users IRC Channel**: `#mpv-player` on `irc.freenode.net`
- **Github issue tracker**: [issue tracker][issue-tracker] (report bugs here)
- **User IRC Channel**: `#mpv-player` on `irc.freenode.net`
- **Developer IRC Channel**: `#mpv-player-dev` on `irc.freenode.net`
- **Users Mailing List**: `mpv-users@googlegroups.com` ([Archive / Subscribe][mpv-users]).
- **Devel Mailing List**: `mpv-devel@googlegroups.com` ([Archive / Subscribe][mpv-devel])
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`.
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`. Use
only if discretion is required.
[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/changes.rst
[mpv-build]: https://github.com/mpv-player/mpv-build
@@ -136,4 +138,4 @@ To contact the `mpv` team in private write to `mpv-team@googlegroups.com`.
[mpv-users]: https://groups.google.com/forum/?hl=en#!forum/mpv-users
[mpv-devel]: https://groups.google.com/forum/?hl=en#!forum/mpv-devel
[ffmpeg_vs_libav]: https://github.com/mpv-player/mpv/wiki/FFmpeg-versus-Libav
[release-policy]: https://github.com/mpv-player/mpv/blob/master/release-policy.md
[release-policy]: https://github.com/mpv-player/mpv/blob/master/DOCS/release-policy.md
+135
View File
@@ -0,0 +1,135 @@
Release 0.7.2
=============
Changes
-------
- Give precedence to the DVD menu navigation keyboard bindings so that user
defined LEFT/RIGHT/... bindings don't break DVD menu navigation.
- Try to fallback to the "default" device if the selected device is busy in the
alsa AO.
- Don't create Dock icon for audio only files on OS X.
- Save screenshots to desktop when using the app bundle on OS X.
- Restore ab-loop settings with playback resume.
- Bump required youtube-dl version to 2014.11.26 and enable the ytdl_hook Lua
script by default (now playing videos from YouTube and the like will work
out of the box without any configuration change needed).
Bug fixes
---------
- Don't signal an error if --stream-dump is used.
- Fix removing key bindings from Lua scripts.
- Reject channel descriptions with too many channels in the coreaudio AO.
- Don't async redraw when waiting for VO redraw on OS X (this fixes the very
annoying glitch where the black bars disappear for a single frame when going
fullscreen).
- Fix mono playback with the also AO.
- Don't crash if framebuffers are not available in the opengl VO.
New features
------------
- Try to handle multi-arc videos in the ytdl_hook Lua script.
This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log 47ec404..c7d6b21`` in
the git repository.
Release 0.7.1
=============
Changes
-------
- Don't show the volume neutral marker on the OSD if softvol is disabled.
- Don't select a subtitle track when executing the sub_add input command in
"auto" mode.
Bug fixes
---------
- Fix busy loop when seeking while paused (this fixes a problem with pulseaudio
that caused mpv and the pulseaudio daemon to use 100% CPU).
- Fix Lua function utils.subprocess() in Windows versions older than Vista.
- Avoid creating a window bigger than the screen on Windows.
- Don't ignore the last line in m3u playlists.
- Don't crash if a codec could not be opened.
- Dynamically allocate audio channel map entries (this should fix a crash in
the alsa and coreaudio AOs with audio devices that support more than 20
channel maps).
- Ignore the "srgb" option in the opengl VO if hardware decoding is enabled.
- Linearize non-RGB sRGB files correctly (eg. JPEG).
- Fix opening reference URLs (.file/id=) on OS X.
This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log 8d8b36d..6583ad6`` in
the git repository.
Release 0.7.0
=============
Changes
-------
- Buffer partial log messages in the client API (the client API will now only
pass full log messages to clients).
- Remove ncurses/terminfo/termcap support (it was disabled by default and
replaced by new code since v0.6.0).
- Enable cdda:// support by default again (it was disabled since v0.6.0).
- Cascade-load input.conf (if there are several input.confs in the set of valid
config paths, load them all).
- Draw the OSD twice in 3D mode (this fixes subtitles display in 3D mode).
- Make wasapi the default AO on Windows again since many of its problems have
been solved.
- Use "site-functions" subdir to install the zsh completion script instead of
the Debian-specific "vendor-completions" (also provide the --zshdir waf
configure option for changing this value).
- Improve synchronization between the Cocoa GUI and the player (this fixes some
long standing deadlock issues on Mac OS X).
- Remove --fs-missioncontrol option (only relevant to Mac OS X).
New features
------------
- Enable pitch correction by default when playing at higher speeds (this can be
controlled with the --audio-pitch-correction option).
- Open stream and demuxer asynchronously (this should avoid having the player
get blocked on network streams).
- Add cache-buffering-state property for querying the cache fill status until
the player unpauses.
- Add support for listing and selecting the audio device (note that it is not
implemented for all AOs, see the --audio-device option for more information).
- Add support for a JSON-based IPC mechanism (note that this is not currently
supported on Windows, see the JSON IPC section in the manpage for more
information).
- Add Lua utility function for starting processes (see utils.subprocess() in the
manpage).
- Add Lua utility function for parsing JSON (see utils.parse_json() in the
manpage).
- Add field-dominance property (see --field-dominance option).
- Add video-rotate property (see --video-rotate option).
- Add playback-abort property for querying whether playback is stopped or is to
be stopped.
- Add cursor-autohide property (see --cursor-autohide option).
- Add vo-configured property for querying whether a window is created.
- Add support for dxva2 hardware acceleration on Windows.
- Drop libquvi support (this has been replaced by a built-in Lua script that
invokes the youtube-dl tool, which needs to be installed, see the --ytdl
option).
- Add support for loading chapters from an external file (see the
--chapters-file option).
- Add window-minimized property for querying whether the window is minimized
(works for X11 only).
- Make it possible to configure the OSC seekbar style (see the "seekbarstyle"
OSC option).
- Add support for libmpv on Mac OS X (it used to be broken, now it's fully
functional and also provides support for embedding the mpv window inside a
Cocoa/Qt application).
- Try to use the audio channel map reported by ALSA in the alsa AO.
- Add option to disable text OSD rendering completely (useful for working around
certain fontconfig issues, see the --use-text-osd option).
This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log 7759c18..9479daa`` in
the git repository.
+4 -4
View File
@@ -15,10 +15,10 @@ def is_user_lib(objfile, libname):
return not sys_re.match(libname) and \
not usr_re.match(libname) and \
not exe_re.match(libname) and \
not "libobjc" in libname and \
not "libSystem" in libname and \
not "libc" in libname and \
not "libgcc" in libname and \
not "libobjc." in libname and \
not "libSystem." in libname and \
not "libc." in libname and \
not "libgcc." in libname and \
not os.path.basename(objfile) in libname
def otool(objfile):
+2 -2
View File
@@ -5,8 +5,8 @@
conv() {
echo
identify -format "icon: %w %h" $1
convert $1 -depth 8 rgba:-
identify -format "icon: %w %h" "$1"
convert "$1" -depth 8 rgba:-
}
(echo "# File generated by gen-x11-icon.sh" ;
+55 -58
View File
@@ -1,23 +1,15 @@
#!/bin/sh
case "$0" in
*/*)
MYDIR=${0%/*}
;;
*)
MYDIR=.
;;
esac
: "${MPV:=mpv}"
: "${ILDETECT_MPV:=$MPV}"
: "${ILDETECT_MPVFLAGS:=--start=35% --length=35}"
: "${ILDETECT_DRY_RUN:=}"
: "${ILDETECT_QUIET:=}"
: "${ILDETECT_RUN_INTERLACED_ONLY:=}"
: "${ILDETECT_FORCE_RUN:=}"
: ${MPV:=mpv}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
: ${ILDETECT_DRY_RUN:=}
: ${ILDETECT_QUIET:=}
: ${ILDETECT_RUN_INTERLACED_ONLY:=}
: ${ILDETECT_FORCE_RUN:=}
: ${MAKE:=make}
# This script uses ffmpeg's "idet" filter for interlace detection. In the
# long run this should replace ildetect.sh+ildetect.so.
# exit status:
# 0 progressive
@@ -30,126 +22,131 @@ esac
testfun()
{
$ILDETECT_MPV "$@" \
--vf=lavfi="[idet]" --msg-level ffmpeg=v \
--vf-add=lavfi="[idet]" --msg-level ffmpeg=v \
--o= --vo=null --no-audio --untimed \
$ILDETECT_MPVFLAGS \
| { if [ -n "$ILDETECT_QUIET" ]; then cat; else tee /dev/stderr; fi } \
| grep "Parsed_idet_0: Multi frame detection: " | tail -n 1
| grep "Parsed_idet_0: Multi frame detection: "
}
judge()
{
out=`testfun "$@"`
tff=${out##* TFF:}; tff=${tff%% *}
bff=${out##* BFF:}; bff=${bff%% *}
progressive=${out##* Progressive:}; progressive=${progressive%% *}
undetermined=${out##* Undetermined:}; undetermined=${undetermined%% *}
case "$tff$bff$progressive$undetermined" in
*[!0-9]*)
echo >&2 "ERROR: Unrecognized idet output: $out"
exit 16
;;
esac
tff=0
bff=0
progressive=0
undetermined=0
while read -r _ _ _ _ _ _ tff1 _ bff1 _ progressive1 _ undetermined1 _; do
case "$tff1$bff1$progressive1$undetermined1" in
*[!0-9]*)
printf >&2 'ERROR: Unrecognized idet output: %s\n' "$out"
exit 16
;;
esac
tff=$((tff + tff1))
bff=$((bff + bff1))
progressive=$((progressive + progressive1))
undetermined=$((undetermined + undetermined1))
done <<EOF
$(testfun "$@")
EOF
interlaced=$((bff + tff))
determined=$((interlaced + progressive))
if [ $undetermined -gt $determined ] || [ $determined -lt 250 ]; then
if [ "$undetermined" -gt "$determined" ] || [ "$determined" -lt 250 ]; then
echo >&2 "ERROR: Less than 50% or 250 frames are determined."
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
echo >&2 "Assuming interlacing."
if [ $tff -gt $((bff * 10)) ]; then
verdict=interlaced-tff
elif [ $bff -gt $((tff * 10)) ]; then
verdict=interlaced-bff
if [ "$tff" -gt $((bff * 10)) ]; then
verdict="interlaced-tff"
elif [ "$bff" -gt $((tff * 10)) ]; then
verdict="interlaced-bff"
else
verdict=interlaced
verdict="interlaced"
fi
elif [ $((interlaced * 20)) -gt $progressive ]; then
elif [ $((interlaced * 20)) -gt "$progressive" ]; then
# At least 5% of the frames are interlaced!
if [ $tff -gt $((bff * 10)) ]; then
verdict=interlaced-tff
elif [ $bff -gt $((tff * 10)) ]; then
verdict=interlaced-bff
if [ "$tff" -gt $((bff * 10)) ]; then
verdict="interlaced-tff"
elif [ "$bff" -gt $((tff * 10)) ]; then
verdict="interlaced-bff"
else
echo >&2 "ERROR: Content is interlaced, but can't determine field order."
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
echo >&2 "Assuming interlacing with default field order."
verdict=interlaced
verdict="interlaced"
fi
else
# Likely progrssive.
verdict=progressive
# Likely progressive
verdict="progressive"
fi
echo "$verdict"
printf '%s\n' "$verdict"
}
judge "$@"
judge "$@" --vf-clr
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
[ -n "$ILDETECT_RUN_INTERLACED_ONLY" ] || \
$ILDETECT_MPV "$@"
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 0
;;
interlaced-tff)
judge "$@" --vf-pre=pullup --field-dominance=top
judge "$@" --vf-clr --vf-pre=pullup --field-dominance=top
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 2
;;
esac
;;
interlaced-bff)
judge "$@" --vf-pre=pullup --field-dominance=bottom
judge "$@" --vf-clr --vf-pre=pullup --field-dominance=bottom
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 2
;;
esac
;;
interlaced)
judge "$@" --vf-pre=pullup
judge "$@" --vf-clr --vf-pre=pullup
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif
r=$?
[ $r -eq 0 ] || exit $(($r | 16))
[ $r -eq 0 ] || exit $((r | 16))
exit 2
;;
esac
+6
View File
@@ -232,6 +232,7 @@ sub define_matroska {
elem('Block', 'a1', 'binary'),
elem('BlockDuration', '9b', 'uint'),
elem('ReferenceBlock*', 'fb', 'sint'),
elem('DiscardPadding', '75A2', 'sint'),
}),
elem('SimpleBlock*', 'a3', 'binary'),
}),
@@ -256,6 +257,8 @@ sub define_matroska {
elem('CodecPrivate', '63a2', 'binary'),
elem('CodecName', '258688', 'str'),
elem('CodecDecodeAll', 'aa', 'uint'),
elem('CodecDelay', '56AA', 'uint'),
elem('SeekPreRoll', '56BB', 'uint'),
elem('Video', 'e0', {
elem('FlagInterlaced', '9a', 'uint'),
elem('PixelWidth', 'b0', 'uint'),
@@ -265,6 +268,7 @@ sub define_matroska {
elem('DisplayUnit', '54b2', 'uint'),
elem('FrameRate', '2383e3', 'float'),
elem('ColourSpace', '2eb524', 'binary'),
elem('StereoMode', '53b8', 'uint'),
}),
elem('Audio', 'e1', {
elem('SamplingFrequency', 'b5', 'float'),
@@ -292,6 +296,8 @@ sub define_matroska {
elem('CueTrackPositions*', 'b7', {
elem('CueTrack', 'f7', 'uint'),
elem('CueClusterPosition', 'f1', 'uint'),
elem('CueRelativePosition','f0', 'uint'),
elem('CueDuration', 'b2', 'uint'),
}),
}),
}),
+2 -9
View File
@@ -8,12 +8,5 @@ adding the option
to mpv's command line.
Unless otherwise specified, they are also suitable for inclusion in
the `~/.mpv/lua` directory where they will be loaded every time mpv
starts, obviating the need to load them with the above `--lua=...`
argument. This is acceptable as they do only basic argument parsing
and key-binding registration, until those bound keys are actually
pressed. They should therefore not interfere with normal playback
(unless you have a conflicting user-defined key-binding, in which
case, you may want to modify either the `mp.add_key_binding()` calls
in the scripts, or your keybinding).
Where appropriate, they may also be placed in ~/.config/mpv/lua from where
they will be automatically loaded when mpv starts.
+18 -18
View File
@@ -42,11 +42,11 @@ function del_filter_if_present(label)
-- 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)
return true
end
if vf["label"] == label then
table.remove(vfs, i)
mp.set_property_native("vf", vfs)
return true
end
end
return false
end
@@ -65,10 +65,10 @@ function autocrop_start()
-- insert the cropdetect filter
ret=mp.command(
string.format(
'vf add @%s:lavfi=graph="cropdetect=limit=24:round=2:reset=0"',
cropdetect_label
)
string.format(
'vf add @%s:lavfi=graph="cropdetect=limit=24:round=2:reset=0"',
cropdetect_label
)
)
-- wait to gather data
timer=mp.add_timeout(detect_seconds, do_crop)
@@ -77,15 +77,15 @@ end
function do_crop()
-- get the metadata
local cropdetect_metadata = mp.get_property_native(
string.format("vf-metadata/%s", cropdetect_label)
string.format("vf-metadata/%s", cropdetect_label)
)
-- 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
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:crop=%s:%s:%s:%s",
crop_label,
cropdetect_metadata["lavfi.cropdetect.w"],
@@ -94,9 +94,9 @@ function do_crop()
cropdetect_metadata["lavfi.cropdetect.y"]))
else
mp.msg.error(
"Got empty crop data. You might need to increase detect_seconds."
)
end
"Got empty crop data. You might need to increase detect_seconds."
)
end
else
mp.msg.error(
"No crop data. Was the cropdetect filter successfully inserted?"
+164
View File
@@ -0,0 +1,164 @@
-- This script uses the lavfi idet filter to automatically insert the
-- appropriate deinterlacing filter based on a short section of the
-- currently playing video.
--
-- It registers the key-binding ctrl+d, which when pressed, inserts
-- the filter vf=lavfi=idet. After 4 second, it examines the results
-- to determine whether the content progressive or interlaced and the
-- interlacing field dominance. It immediately sets the latter within
-- mpv.
--
-- If the content is judged not to be progressive, it may be either
-- interlaced or telecined. To determine which one, the video is
-- seeked back to the detection starting point with the "pullup"
-- filter inserted. After another four seconds, if idet thinks that
-- the pulled up viedo is "progressive", then pullup is the correct
-- filter and this script leaves it in places while removing the idet
-- filter. Otherwise, the content plain interlaced and mpv's deinterlace
-- property is set. This will usually insert the yadif deinterlacing filter.
--
-- The default detection time may be overridden by adding
--
-- --lua-opts=autodeint.detect_seconds=<number of seconds>
--
-- to mpv's arguments. This may be desirable to allow idet more
-- time to collect data.
--
-- To see counts of the various types of frames for each detection phase,
-- the verbosity can be increased with
--
-- --msg-level autodeint=v
--
-- This script requires a recent version of ffmpeg for which the idet
-- filter adds the required metadata.
require "mp.msg"
script_name = mp.get_script_name()
detect_label = string.format("%s-detect", script_name)
pullup_label = string.format("%s", 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
detect_seconds = 4
end
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)
return true
end
end
return false
end
function start_detect()
-- exit if detection is already in progress
if timer then
mp.msg.warn("already detecting!")
return
end
mp.set_property("deinterlace","no")
del_filter_if_present(pullup_label)
percent_pos = mp.get_property("percent-pos")
-- insert the detection filter
local cmd = string.format('vf add @%s:lavfi=graph="idet"', detect_label)
if not mp.command(cmd) then
mp.msg.error("failed to insert detection filter")
return
end
-- wait to gather data
timer = mp.add_timeout(detect_seconds, judge_field_dominance)
end
function stop_detect()
del_filter_if_present(detect_label)
timer = nil
mp.set_property("playback-pos", percent_pos)
end
progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3, 4
function judge()
-- get the metadata
local result = mp.get_property_native(string.format("vf-metadata/%s", detect_label))
num_tff = tonumber(result["lavfi.idet.multiple.tff"])
num_bff = tonumber(result["lavfi.idet.multiple.bff"])
num_progressive = tonumber(result["lavfi.idet.multiple.progressive"])
num_undetermined = tonumber(result["lavfi.idet.multiple.undetermined"])
num_interlaced = num_tff + num_bff
num_determined = num_interlaced + num_progressive
mp.msg.verbose("progressive = "..num_progressive)
mp.msg.verbose("interlaced-tff = "..num_tff)
mp.msg.verbose("interlaced-bff = "..num_bff)
mp.msg.verbose("undetermined = "..num_undetermined)
if num_determined < num_undetermined then
mp.msg.warn("majority undetermined frames")
end
if num_progressive > 20*num_interlaced then
return progressive
elseif num_tff > 10*num_bff then
return interlaced_tff
elseif num_bff > 10*num_tff then
return interlaced_bff
else
return interlaced
end
end
function judge_field_dominance()
verdict = judge()
if verdict == progressive then
stop_detect()
mp.msg.info("progressive: doing nothing")
return
elseif verdict == interlaced_tff then
mp.set_property("field-dominance", "top")
elseif verdict == interlaced_bff then
mp.set_property("field-dominance", "bottom")
elseif verdict == interlaced then
mp.set_property("field-dominance", "auto")
end
local cmd = string.format("vf pre @%s:pullup", pullup_label)
if not mp.command(cmd) then
mp.msg.error("failed to insert pullup filter")
stop_detect()
return
end
-- redo the detection with the pullup filter to see if it's telecined
mp.set_property("percent-pos", percent_pos)
timer = mp.add_timeout(detect_seconds, judge_ivtc)
end
function judge_ivtc()
verdict = judge()
if verdict == progressive then
mp.msg.info(string.format("telecinied with %s field dominance: using pullup", mp.get_property("field-dominance")))
stop_detect()
else
mp.msg.info(string.format("interlaced with %s field dominance: setting deinterlace property", mp.get_property("field-dominance")))
del_filter_if_present(pullup_label)
mp.set_property("deinterlace","yes")
stop_detect()
end
return
end
mp.add_key_binding("ctrl+d", script_name, start_detect)
+11 -7
View File
@@ -26,6 +26,9 @@ function find_and_add_entries()
end
local files = mputils.readdir(dir, "files")
table.sort(files)
if dir == "." then
dir = ""
end
local pl = mp.get_property_native("playlist", {})
local pl_current = mp.get_property_number("playlist-pos", 0) + 1
-- Find the current pl entry (dir+"/"+filename) in the sorted dir list
@@ -40,27 +43,28 @@ function find_and_add_entries()
return
end
local append = {[-1] = {}, [1] = {}}
for dir = -1, 1, 2 do -- 2 iterations, with dir = -1 and +1
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
for i = 1, MAXENTRIES do
local file = files[current + i * dir]
local pl_e = pl[pl_current + i * dir]
local file = files[current + i * direction]
local pl_e = pl[pl_current + i * direction]
if file == nil or file[1] == "." then
break
end
local filepath = dir .. file
if pl_e then
-- If there's a playlist entry, and it's the same file, stop.
if pl_e.filename == file then
if pl_e.filename == filepath then
break
end
end
if dir == -1 then
if direction == -1 then
if pl_current == 1 then -- never add additional entries in the middle
mp.msg.info("Prepending " .. file)
table.insert(append[-1], 1, file)
table.insert(append[-1], 1, filepath)
end
else
mp.msg.info("Adding " .. file)
table.insert(append[1], file)
table.insert(append[1], filepath)
end
end
end
+3 -3
View File
@@ -20,9 +20,9 @@ pullup_label = string.format("%s-pullup", script_name)
function pullup_on()
for i,vf in pairs(mp.get_property_native('vf')) do
if vf['label'] == pullup_label then
return "yes"
end
if vf['label'] == pullup_label then
return "yes"
end
end
return "no"
end
+29 -29
View File
@@ -21,30 +21,30 @@ script_name = mp.get_script_name()
function print_state(params)
if params then
mp.osd_message(script_name..":\n"
.."method = "..params["method"].."\n"
.."target = "..params["target"])
mp.osd_message(script_name..":\n"
.."method = "..params["method"].."\n"
.."target = "..params["target"])
else
mp.osd_message(script_name..":\noff")
mp.osd_message(script_name..":\noff")
end
end
function get_index_of_drc(afs)
for i,af in pairs(afs) do
if af["label"] == script_name then
return i
end
if af["label"] == script_name then
return i
end
end
end
function append_drc(afs)
afs[#afs+1] = {
name = "drc",
label = script_name,
params = {
method = "1",
target = "0.25"
}
name = "drc",
label = script_name,
params = {
method = "1",
target = "0.25"
}
}
print_state(afs[#afs]["params"])
end
@@ -53,34 +53,34 @@ function modify_or_create_af(fun)
afs = mp.get_property_native("af")
i = get_index_of_drc(afs)
if not i then
append_drc(afs)
append_drc(afs)
else
fun(afs, i)
fun(afs, i)
end
mp.set_property_native("af", afs)
end
function drc_toggle_method_handler()
modify_or_create_af(
function (afs, i)
new_method=(afs[i]["params"]["method"]+1)%3
if new_method == 0 then
table.remove(afs, i)
print_state(nil)
else
afs[i]["params"]["method"] = tostring((afs[i]["params"]["method"])%2+1)
print_state(afs[i]["params"])
end
end
function (afs, i)
new_method=(afs[i]["params"]["method"]+1)%3
if new_method == 0 then
table.remove(afs, i)
print_state(nil)
else
afs[i]["params"]["method"] = tostring((afs[i]["params"]["method"])%2+1)
print_state(afs[i]["params"])
end
end
)
end
function drc_scale_target(factor)
modify_or_create_af(
function (afs)
afs[i]["params"]["target"] = tostring(afs[i]["params"]["target"]*factor)
print_state(afs[i]["params"])
end
function (afs)
afs[i]["params"]["target"] = tostring(afs[i]["params"]["target"]*factor)
print_state(afs[i]["params"])
end
)
end
+16
View File
@@ -0,0 +1,16 @@
-- Test script for property change notification mechanism.
function format_property_val(v)
if type(v) == "table" then
return mp.format_table(v) -- undocumented function; might be removed
else
return tostring(v)
end
end
for i,name in ipairs(mp.get_property_native("property-list")) do
mp.observe_property(name, "native", function(name, val)
print("property '" .. name .. "' changed to '" ..
format_property_val(val) .. "'")
end)
end
@@ -1,4 +1,4 @@
-- Rebuild the status line as a lua script
-- Rebuild the terminal status line as a lua script
-- Be aware that this will require more cpu power!
-- Add a string to the status line
+127 -150
View File
@@ -17,157 +17,134 @@
# When multiple files were specified, their info will be put into FOO_* for the
# first file, FOO_1_* for the second file, FOO_2_* for the third file, etc.
case "$0" in
mpv_identify.sh|*/mpv_identify.sh)
# we are NOT being sourced
case "$1" in
'')
__midentify__main() {
case "$0" in
mpv_identify.sh|*/mpv_identify.sh)
# we are NOT being sourced
[ -n "$1" ] && set -- '' "$@"
;;
esac
if [ "$#" -lt 2 ]; then
cat >&2 <<EOF
Usage 1 (for humans only): $0 filename.mkv
will print all property values.
Note that this output really shouldn't be parsed, as the
format is subject to change.
Usage 2 (for use by scripts): see top of this file
NOTE: for mkv with ordered chapters, this may
not always identify the specified file, but the
file providing the first chapter. Specify
--no-ordered-chapters to prevent this.
EOF
return 2
fi
local LF="
"
local nextprefix="$1"
shift
if [ -n "$nextprefix" ]; then
# in case of error, we always want this unset
unset "${nextprefix}path"
fi
local allprops="
filename
path
stream-start
stream-end
stream-length
demuxer
length
chapters
editions
titles
audio
audio-bitrate
audio-codec
audio-format
channels
samplerate
video
angle
video-bitrate
video-codec
video-format
video-aspect
fps
width
height
dwidth
dheight
sub
"
# TODO add metadata support once mpv can do it
local propstr="X-MIDENTIFY-START:$LF"
local key
for key in $allprops; do
propstr="${propstr}X-MIDENTIFY: $key \${=$key}$LF"
key="$(printf '%s\n' "$key" | tr - _)"
unset "$nextprefix$key"
done
local fileindex=0
local prefix=
local line
while IFS= read -r line; do
case "$line" in
X-MIDENTIFY-START:)
if [ -n "$nextprefix" ]; then
prefix="$nextprefix"
if [ "$fileindex" -gt 0 ]; then
nextprefix="${prefix%${fileindex}_}"
fi
fileindex="$((fileindex+1))"
nextprefix="${nextprefix}${fileindex}_"
for key in $allprops; do
key="$(printf '%s\n' "$key" | tr - _)"
unset "$nextprefix$key"
done
else
if [ "$fileindex" -gt 0 ]; then
printf '\n'
fi
fileindex="$((fileindex+1))"
fi
;;
*)
set -- '' "$@"
X-MIDENTIFY:\ *)
local key="${line#X-MIDENTIFY: }"
local value="${key#* }"
key="${key%% *}"
key="$(printf '%s\n' "$key" | tr - _)"
if [ -n "$nextprefix" ]; then
if [ -z "$prefix" ]; then
echo >&2 "Got X-MIDENTIFY: without X-MIDENTIFY-START:"
elif [ -n "$value" ]; then
eval "$prefix$key"='"$value"'
fi
else
if [ -n "$value" ]; then
printf '%s=%s\n' "$key" "$value"
fi
fi
;;
esac
;;
esac
done <<EOF
$(${MPV:-mpv} --term-playing-msg="$propstr" --vo=null --ao=null \
--frames=1 --quiet --no-cache --no-config -- "$@")
EOF
}
if [ $# -lt 2 ]; then
echo >&2 "Usage 1 (for humans only): $0 filename.mkv"
echo >&2 "will print all property values."
echo >&2 "Note that this output really shouldn't be parsed, as the"
echo >&2 "format is subject to change."
echo >&2
echo >&2 "Usage 2 (for use by scripts): see top of this file"
echo >&2
echo >&2 "NOTE: for mkv with ordered chapters, this may"
echo >&2 "not always identify the specified file, but the"
echo >&2 "file providing the first chapter. Specify"
echo >&2 "--no-ordered-chapters to prevent this."
exit 1
fi
if [ -z "$MPV" ]; then
MPV="mpv"
fi
__midentify__LF="
"
__midentify__nextprefix=$1
shift
if [ -n "$__midentify__nextprefix" ]; then
# in case of error, we always want this unset
eval unset $__midentify__nextprefix'path'
fi
__midentify__allprops="
filename
path
stream-start
stream-end
stream-length
demuxer
length
chapters
editions
titles
audio
audio-bitrate
audio-codec
audio-format
channels
samplerate
video
angle
video-bitrate
video-codec
video-format
video-aspect
fps
width
height
dwidth
dheight
sub
"
# TODO add metadata support once mpv can do it
__midentify__propstr="X-MIDENTIFY-START:$__midentify__LF"
for __midentify__key in $__midentify__allprops; do
__midentify__propstr=$__midentify__propstr"X-MIDENTIFY: $__midentify__key \${=$__midentify__key}$__midentify__LF"
__midentify__key=`echo "$__midentify__key" | tr - _`
eval unset $__midentify__nextprefix$__midentify__key
done
__midentify__output=`$MPV --term-playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet --no-cache --no-config "$@"`
__midentify__fileindex=0
__midentify__prefix=
while :; do
case "$__midentify__output" in
'')
break
;;
*$__midentify__LF*)
__midentify__line=${__midentify__output%%$__midentify__LF*}
__midentify__output=${__midentify__output#*$__midentify__LF}
;;
*)
__midentify__line=$__midentify__output
__midentify__output=
;;
esac
case "$__midentify__line" in
X-MIDENTIFY-START:)
if [ -n "$__midentify__nextprefix" ]; then
__midentify__prefix=$__midentify__nextprefix
if [ $__midentify__fileindex -gt 0 ]; then
__midentify__nextprefix=${__midentify__prefix%$__midentify__fileindex\_}
fi
__midentify__fileindex=$(($__midentify__fileindex+1))
__midentify__nextprefix=$__midentify__nextprefix$__midentify__fileindex\_
for __midentify__key in $__midentify__allprops; do
__midentify__key=`echo "$__midentify__key" | tr - _`
eval unset $__midentify__nextprefix$__midentify__key
done
else
if [ $__midentify__fileindex -gt 0 ]; then
echo
fi
__midentify__fileindex=$(($__midentify__fileindex+1))
fi
;;
X-MIDENTIFY:\ *)
__midentify__key=${__midentify__line#X-MIDENTIFY:\ }
__midentify__value=${__midentify__key#* }
__midentify__key=${__midentify__key%% *}
__midentify__key=`echo "$__midentify__key" | tr - _`
if [ -n "$__midentify__nextprefix" ]; then
if [ -z "$__midentify__prefix" ]; then
echo >&2 "Got X-MIDENTIFY: without X-MIDENTIFY-START:"
elif [ -n "$__midentify__value" ]; then
eval $__midentify__prefix$__midentify__key=\$__midentify__value
fi
else
if [ -n "$__midentify__value" ]; then
echo "$__midentify__key=$__midentify__value"
fi
fi
;;
esac
done
unset __midentify__fileindex
unset __midentify__allprops
unset __midentify__key
unset __midentify__LF
unset __midentify__line
unset __midentify__output
unset __midentify__nextprefix
unset __midentify__prefix
unset __midentify__propstr
unset __midentify__value
__midentify__main "$@"
@@ -624,6 +624,90 @@
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>AVC raw stream</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.h264</string>
<key>UTTypeReferenceURL</key>
<string>http://www.itu.int/rec/T-REC-H.264</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>264</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>HEVC raw stream</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.hevc</string>
<key>UTTypeReferenceURL</key>
<string>http://hevc.info</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>hevc</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>YUV stream</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.yuv</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/YUV</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>yuv</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>YUV4MPEG2 stream</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.y4m</string>
<key>UTTypeReferenceURL</key>
<string>http://wiki.multimedia.cx/index.php?title=YUV4MPEG2</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>y4m</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
@@ -0,0 +1 @@
screenshot-template=~/Desktop/shot%n
+31 -18
View File
@@ -18,10 +18,11 @@ e.g.:
Currently, the following event types are supported:
'start' <name> start of the named event
'end' <name> end of the named event
'value' <float> <name> a normal value (as opposed to event)
<event> singular event
'start' <name> start of the named event
'end' <name> end of the named event
'value' <float> <name> a normal value (as opposed to event)
'event-timed' <ts> <name> singular event at the given timestamp
<name> singular event
"""
@@ -29,19 +30,32 @@ class G:
events = {}
sevents = [] # events, deterministically sorted
start = None
# http://matplotlib.org/api/markers_api.html#module-matplotlib.markers
markers = ["o", "8", "s", "p", "*", "h", "+", "x", "D"]
def find_marker():
if len(G.markers) == 0:
return "o"
m = G.markers[0]
G.markers = G.markers[1:]
return m
class Event:
pass
def get_event(event):
def get_event(event, evtype):
if event not in G.events:
e = Event()
G.events[event] = e
e.name = event
e.vals = []
e.type = "unknown"
e.type = evtype
e.marker = "o"
e.numid = len(G.events)
G.sevents = list(G.events.values())
G.sevents.sort(key=lambda x: x.name)
if e.type == "event-signal":
e.marker = find_marker()
return G.events[event]
for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
@@ -54,30 +68,29 @@ for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
G.start = ts
ts = ts - G.start
if event.startswith("start "):
e = get_event(event[6:])
e.type = "event"
e = get_event(event[6:], "event")
e.vals.append((ts, 0))
e.vals.append((ts, 1))
elif event.startswith("end "):
e = get_event(event[4:])
e.type = "event"
e = get_event(event[4:], "event")
e.vals.append((ts, 1))
e.vals.append((ts, 0))
elif event.startswith("value "):
_, val, name = event.split(" ", 2)
val = float(val)
e = get_event(name)
e.type = "value"
e = get_event(name, "value")
e.vals.append((ts, val))
elif event.startswith("event-timed "):
_, val, name = event.split(" ", 2)
val = int(val) / 1000 - G.start
e = get_event(name, "event-signal")
e.vals.append((val, 1))
else:
e = get_event(event)
e.type = "event-signal"
e = get_event(event, "event-signal")
e.vals.append((ts, 1))
ao_events = ["ao fill", "audio wait"]
for e in G.sevents:
if e.name in ao_events:
e.vals = [(x, y * 0.5) for (x, y) in e.vals]
e.vals = [(x, y * e.numid / len(G.events)) for (x, y) in e.vals]
plot.hold(True)
mainpl = plot.subplot(2, 1, 1)
@@ -89,7 +102,7 @@ for e in G.sevents:
plot.subplot(2, 1, 1)
pl, = plot.plot([x for x,y in e.vals], [y for x,y in e.vals], label=e.name)
if e.type == "event-signal":
plot.setp(pl, marker = "o", linestyle = "None")
plot.setp(pl, marker = e.marker, linestyle = "None")
legend.append(pl)
plot.subplot(2, 1, 1)
plot.legend(legend, [pl.get_label() for pl in legend])
+16 -41
View File
@@ -21,20 +21,13 @@ 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" > /tmp/umpv-fifo-*
echo "cycle fullscreen" > ~/.umpv-fifo
Note: you can supply custom options with the UMPV_OPTIONS environment variable.
The environment variable will be split on whitespace, and each item is
passed as option to mpv _if_ the script starts mpv. If mpv is not started
by the script (i.e. mpv is already running), the options will be ignored.
Warning:
The script attempts to make sure the FIFO is safely created (i.e. not world-
writable), and checks that it's really a FIFO. This is important for security,
because the FIFO allows anyone with write access to run arbitrary commands
in mpv's context using the "run" input command. If you are worried about
security, you should verify that the code handles these concerns correctly.
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
_if_ the script starts mpv. If mpv is not started by the script (i.e. mpv
is already running), this will be ignored.
"""
import sys
@@ -45,21 +38,17 @@ import fcntl
import stat
import string
if len(sys.argv) < 1:
sys.exit(1)
files = sys.argv[1:]
# this is about the same method mpv uses to decide this
# this is the same method mpv uses to decide this
def is_url(filename):
parts = filename.split(":", 1)
parts = filename.split("://", 1)
if len(parts) < 2:
return False
# protocol prefix has no special characters => it's an URL
allowed_symbols = string.ascii_letters + string.digits + '_'
prefix = parts[0]
for c in prefix:
if string.ascii_letters.find(c) < 0:
return False
return True
return all(map(lambda c: c in allowed_symbols, prefix))
# make them absolute; also makes them safe against interpretation as options
def make_abs(filename):
@@ -68,10 +57,7 @@ def make_abs(filename):
return filename
files = [make_abs(f) for f in files]
opts_env = os.getenv("UMPV_OPTIONS")
opts_env = opts_env.split() if opts_env else []
FIFO = "/tmp/umpv-fifo-" + os.getenv("USER")
FIFO = os.path.join(os.getenv("HOME"), ".umpv_fifo")
fifo_fd = -1
try:
@@ -84,14 +70,6 @@ except OSError as e:
else:
raise e
if fifo_fd >= 0:
st = os.fstat(fifo_fd)
if (((st.st_mode & (stat.S_IRWXG | stat.S_IRWXO)) != 0) or
(not stat.S_ISFIFO(st.st_mode)) or
(st.st_uid != os.getuid())):
print("error: command FIFO is not a FIFO or has bogus permissions")
sys.exit(1)
if fifo_fd >= 0:
# Unhandled race condition: what if mpv is terminating right now?
fcntl.fcntl(fifo_fd, fcntl.F_SETFL, 0) # set blocking mode
@@ -108,15 +86,12 @@ else:
try:
os.unlink(FIFO)
except OSError as e:
if e.errno == errno.ENOENT:
pass
else:
raise e
os.mkfifo(FIFO, int("0600", 8))
pass
os.mkfifo(FIFO, 0o600)
opts = ["mpv", "--no-terminal", "--force-window", "--input-file=" + FIFO]
opts.extend(opts_env)
opts.append("--")
opts = (os.getenv("MPV") or "mpv").split()
opts.extend(["--no-terminal", "--force-window", "--input-file=" + FIFO,
"--"])
opts.extend(files)
subprocess.check_call(opts)
+1 -2
View File
@@ -90,8 +90,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
if (argc != 1 && argc != 2)
return -1;
framestep_data_t *framestep = malloc(sizeof(framestep_data_t));
memset(framestep, 0, sizeof(*framestep));
framestep_data_t *framestep = calloc(1,sizeof(framestep_data_t));
framestep->step = atoi(argv[0]);
framestep->pos = (argc >= 2) ? atoi(argv[1]) : 0;
+1 -2
View File
@@ -267,8 +267,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
(void) argc;
(void) argv;
ildetect_data_t *il = malloc(sizeof(ildetect_data_t));
memset(il, 0, sizeof(*il));
ildetect_data_t *il = calloc(1,sizeof(ildetect_data_t));
#define A(i,d) ((argc>(i) && *argv[i]) ? atof(argv[i]) : (d))
il->method = A(0, 0);
-1
View File
@@ -11,7 +11,6 @@ esac
: ${MPV:=mpv}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
: ${ILDETECT_DRY_RUN:=}
: ${ILDETECT_QUIET:=}
+1 -2
View File
@@ -348,8 +348,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
{ "yuv420p", "yuv420p" },
{ NULL, NULL }
};
privdata *priv = malloc(sizeof(privdata));
memset(priv, 0, sizeof(*priv));
privdata *priv = calloc(1,sizeof(privdata));
priv->step = 8;
if(argc >= 1)
priv->w = atoi(argv[0]);
+1 -2
View File
@@ -237,8 +237,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
if (!a0[0] || a0[1] || !a1[0] || argc > 2)
return -1;
tc_data_t *tc = malloc(sizeof(tc_data_t));
memset(tc, 0, sizeof(*tc));
tc_data_t *tc = calloc(1,sizeof(tc_data_t));
if (a0[0] == 't')
tc->firstfield = 0;
+1 -2
View File
@@ -150,8 +150,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
if (argc != 2)
return -1;
tile_data_t *tile = malloc(sizeof(tile_data_t));
memset(tile, 0, sizeof(*tile));
tile_data_t *tile = calloc(1,sizeof(tile_data_t));
tile->cols = atoi(argv[0]);
tile->rows = atoi(argv[1]);
+4 -5
View File
@@ -10,14 +10,13 @@ video_url="$(youtube-dl \
--user-agent="$user_agent" \
--cookies="$cookies_file" \
--get-url \
"$1")"
"$@")"
shift
mpv \
set -f
${MPV:-mpv} \
--cookies \
--cookies-file="$cookies_file" \
--user-agent="$user_agent" \
"$@" -- $video_url
-- $video_url
rm -rf "$cookies_dir"
+106 -33
View File
@@ -7,7 +7,7 @@ use warnings;
my $mpv = $ARGV[0] || 'mpv';
my @opts = parse_opts("$mpv --list-options", '^ (\-\-[^\s\*]*)\*?\s*(.*)');
my @opts = parse_opts("$mpv --list-options", '^ (\-\-[^\s\*]*)\*?\s*(.*)', 1);
my @ao = parse_opts("$mpv --ao=help", '^ ([^\s\:]*)\s*: (.*)');
my @vo = parse_opts("$mpv --vo=help", '^ ([^\s\:]*)\s*: (.*)');
@@ -15,9 +15,11 @@ my @vo = parse_opts("$mpv --vo=help", '^ ([^\s\:]*)\s*: (.*)');
my @af = parse_opts("$mpv --af=help", '^ ([^\s\:]*)\s*: (.*)');
my @vf = parse_opts("$mpv --vf=help", '^ ([^\s\:]*)\s*: (.*)');
my ($opts_str, $ao_str, $vo_str, $af_str, $vf_str);
my @protos = parse_opts("$mpv --list-protocols", '^ ([^\s]*)');
$opts_str .= qq{ '$_': \\\n} foreach (@opts);
my ($opts_str, $ao_str, $vo_str, $af_str, $vf_str, $protos_str);
$opts_str .= qq{ '$_' \\\n} foreach (@opts);
chomp $opts_str;
$ao_str .= qq{ '$_' \\\n} foreach (@ao);
@@ -32,14 +34,52 @@ chomp $af_str;
$vf_str .= qq{ '$_' \\\n} foreach (@vf);
chomp $vf_str;
$protos_str .= qq{$_ } foreach (@protos);
chomp $protos_str;
my $profile_comp = <<'EOS';
local -a profiles
local current
for current in "${(@f)$($words[1] --profile=help)}"; do
current=${current//\*/\\\*}
current=${current//\:/\\\:}
current=${current//\[/\\\[}
current=${current//\]/\\\]}
if [[ $current =~ $'\t'([^$'\t']*)$'\t'(.*) ]]; then
if [[ -n $match[2] ]]; then
current="$match[1][$match[2]]"
else
current="$match[1]"
fi
profiles=($profiles $current)
fi
done
if [[ $state == profile ]]; then
# For --show-profile, only one allowed
if (( ${#profiles} > 0 )); then
_values 'profile' $profiles && rc=0
fi
else
# For --profile, multiple allowed
profiles=($profiles 'help[list profiles]')
_values -s , 'profile(s)' $profiles && rc=0
fi
EOS
chomp $profile_comp;
my $tmpl = <<"EOS";
#compdef mpv
# mpv zsh completion
_x_arguments -C -s \\
local curcontext="\$curcontext" state state_descr line
typeset -A opt_args
local rc=1
_arguments -C -S \\
$opts_str
'*:files:->mfiles'
'*:files:->mfiles' && rc=0
case \$state in
ao)
@@ -48,7 +88,7 @@ case \$state in
$ao_str
)
_describe -t values 'audio outputs' values
_describe -t values 'audio outputs' values && rc=0
;;
vo)
@@ -57,7 +97,7 @@ $ao_str
$vo_str
)
_describe -t values 'video outputs' values
_describe -t values 'video outputs' values && rc=0
;;
af)
@@ -66,7 +106,7 @@ $vo_str
$af_str
)
_describe -t values 'audio filters' values
_describe -t values 'audio filters' values && rc=0
;;
vf)
@@ -75,55 +115,88 @@ $af_str
$vf_str
)
_describe -t values 'video filters' values
_describe -t values 'video filters' values && rc=0
;;
profile|profiles)
$profile_comp
;;
files)
compset -P '*,'
compset -S ',*'
_files -r ',/ \\t\\n\\-' && rc=0
;;
mfiles)
local expl
_tags files urls
while _tags; do
_requested files expl 'media file' _files -g \\
"*.(#i)(asf|asx|avi|flac|flv|m1v|m2p|m2v|m4v|mjpg|mka|mkv|mov|mp3|mp4|mpe|mpeg|mpg|ogg|ogm|ogv|qt|rm|ts|vob|wav|webm|wma|wmv)(-.)" && ret=0
"*.(#i)(asf|asx|avi|flac|flv|m1v|m2p|m2v|m4v|mjpg|mka|mkv|mov|mp3|mp4|mpe|mpeg|mpg|ogg|ogm|ogv|qt|rm|ts|vob|wav|webm|wma|wmv)(-.)" && rc=0
if _requested urls; then
while _next_label urls expl URL; do
_urls "\$expl[@]" && ret=0
compadd -S '' "\$expl[@]" \{dvd,vcd,cdda,cddb,tv\}:// && ret=0
_urls "\$expl[@]" && rc=0
compadd -S '' "\$expl[@]" $protos_str && rc=0
done
fi
(( ret )) || return 0
(( rc )) || return 0
done
;;
esac
return rc
EOS
print $tmpl;
sub parse_opts {
my ($cmd, $regex) = @_;
my ($cmd, $regex, $parsing_main_options) = @_;
my @list;
my @lines = split /\n/, `$cmd`;
my @list;
my @lines = split /\n/, `$cmd`;
foreach my $line (@lines) {
if ($line !~ /^$regex/) {
next;
}
foreach my $line (@lines) {
if ($line !~ /^$regex/) {
next;
}
my $entry = "$1:";
my $entry = $1;
if (defined $2) {
my $desc = $2;
$desc =~ s/\:/\\:/;
if ($parsing_main_options) {
$entry .= '=-';
}
$entry .= $desc;
}
if (defined $2) {
my $desc = $2;
$desc =~ s/\:/\\:/g;
$entry .= ':->ao' if ($1 eq '--ao');
$entry .= ':->vo' if ($1 eq '--vo');
$entry .= ':->af' if ($1 eq '--af');
$entry .= ':->vf' if ($1 eq '--vf');
$entry .= ':' . $desc;
}
push @list, $entry if ($line =~ /^$regex/)
}
if ($parsing_main_options) {
$entry .= ':';
return @list;
$entry .= '->ao' if ($1 eq '--ao');
$entry .= '->vo' if ($1 eq '--vo');
$entry .= '->af' if ($1 eq '--af');
$entry .= '->vf' if ($1 eq '--vf');
$entry .= '->profiles' if ($1 eq '--profile');
$entry .= '->profile' if ($1 eq '--show-profile');
$entry .= '->files' if ($line =~ /\[file\]/);
}
push @list, $entry
}
if ($parsing_main_options) {
@list = sort {
$a =~ /(.*?)\:/; my $ma = $1;
$b =~ /(.*?)\:/; my $mb = $1;
length($mb) <=> length($ma)
} @list;
}
return @list;
}
+1
View File
@@ -0,0 +1 @@
0.7.2
+165 -35
View File
@@ -20,10 +20,13 @@
#include <stdlib.h>
#include <assert.h>
#include <libavutil/mem.h>
#include <libavutil/buffer.h>
#include <libavutil/frame.h>
#include <libavutil/version.h>
#include "talloc.h"
#include "common/common.h"
#include "fmt-conversion.h"
#include "audio.h"
static void update_redundant_info(struct mp_audio *mpa)
@@ -88,18 +91,12 @@ bool mp_audio_config_valid(const struct mp_audio *mpa)
&& mpa->rate >= 1 && mpa->rate < 10000000;
}
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format)
char *mp_audio_config_to_str_buf(char *buf, size_t buf_sz, struct mp_audio *mpa)
{
char *chstr = mp_chmap_to_str(chmap);
char *res = talloc_asprintf(NULL, "%dHz %s %dch %s", srate, chstr,
chmap->num, af_fmt_to_str(format));
talloc_free(chstr);
return res;
}
char *mp_audio_config_to_str(struct mp_audio *mpa)
{
return mp_audio_fmt_to_str(mpa->rate, &mpa->channels, mpa->format);
snprintf(buf, buf_sz, "%dHz %s %dch %s", mpa->rate,
mp_chmap_to_str(&mpa->channels), mpa->channels.num,
af_fmt_to_str(mpa->format));
return buf;
}
void mp_audio_force_interleaved_format(struct mp_audio *mpa)
@@ -116,19 +113,27 @@ int mp_audio_psize(struct mp_audio *mpa)
void mp_audio_set_null_data(struct mp_audio *mpa)
{
for (int n = 0; n < MP_NUM_CHANNELS; n++)
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
mpa->planes[n] = NULL;
mpa->allocated[n] = NULL;
}
mpa->samples = 0;
}
static int get_plane_size(const struct mp_audio *mpa, int samples)
{
if (samples < 0 || !mp_audio_config_valid(mpa))
return -1;
if (samples >= INT_MAX / mpa->sstride)
return -1;
return MPMAX(samples * mpa->sstride, 1);
}
static void mp_audio_destructor(void *ptr)
{
struct mp_audio *mpa = ptr;
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
// Note: don't free if not allocated by mp_audio_realloc
if (mpa->allocated[n])
av_free(mpa->planes[n]);
}
for (int n = 0; n < MP_NUM_CHANNELS; n++)
av_buffer_unref(&mpa->allocated[n]);
}
/* Reallocate the data stored in mpa->planes[n] so that enough samples are
@@ -147,27 +152,19 @@ static void mp_audio_destructor(void *ptr)
*/
void mp_audio_realloc(struct mp_audio *mpa, int samples)
{
assert(samples >= 0);
if (samples >= INT_MAX / mpa->sstride)
abort(); // oom
int size = MPMAX(samples * mpa->sstride, 1);
int size = get_plane_size(mpa, samples);
if (size < 0)
abort(); // oom or invalid parameters
for (int n = 0; n < mpa->num_planes; n++) {
if (size != mpa->allocated[n]) {
// Note: av_realloc() can't be used (see libavutil doxygen)
void *new = av_malloc(size);
if (!new)
abort();
if (mpa->allocated[n])
memcpy(new, mpa->planes[n], MPMIN(mpa->allocated[n], size));
av_free(mpa->planes[n]);
mpa->planes[n] = new;
mpa->allocated[n] = size;
if (!mpa->allocated[n] || size != mpa->allocated[n]->size) {
if (av_buffer_realloc(&mpa->allocated[n], size) < 0)
abort(); // OOM
mpa->planes[n] = mpa->allocated[n]->data;
}
}
for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) {
av_free(mpa->planes[n]);
av_buffer_unref(&mpa->allocated[n]);
mpa->planes[n] = NULL;
mpa->allocated[n] = 0;
}
talloc_set_destructor(mpa, mp_audio_destructor);
}
@@ -194,7 +191,7 @@ int mp_audio_get_allocated_size(struct mp_audio *mpa)
{
int size = 0;
for (int n = 0; n < mpa->num_planes; n++) {
int s = mpa->allocated[n] / mpa->sstride;
int s = mpa->allocated[n] ? mpa->allocated[n]->size / mpa->sstride : 0;
size = n == 0 ? s : MPMIN(size, s);
}
return size;
@@ -240,3 +237,136 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
data->samples -= samples;
}
// Make sure the frame owns the audio data, and if not, copy the data.
// Return negative value on failure (which means it can't be made writeable).
// Non-refcounted frames are always considered writeable.
int mp_audio_make_writeable(struct mp_audio *data)
{
bool ok = true;
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
if (data->allocated[n])
ok &= av_buffer_is_writable(data->allocated[n]);
}
if (!ok) {
struct mp_audio *new = talloc(NULL, struct mp_audio);
*new = *data;
mp_audio_set_null_data(new); // use format only
mp_audio_realloc(new, data->samples);
new->samples = data->samples;
mp_audio_copy(new, 0, data, 0, data->samples);
// "Transfer" the reference.
mp_audio_destructor(data);
*data = *new;
talloc_set_destructor(new, NULL);
talloc_free(new);
}
return 0;
}
struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe)
{
AVFrame *tmp = NULL;
struct mp_audio *new = talloc_zero(NULL, struct mp_audio);
talloc_set_destructor(new, mp_audio_destructor);
mp_audio_set_format(new, af_from_avformat(avframe->format));
struct mp_chmap lavc_chmap;
mp_chmap_from_lavc(&lavc_chmap, avframe->channel_layout);
#if LIBAVUTIL_VERSION_MICRO >= 100
// FFmpeg being special again
if (lavc_chmap.num != avframe->channels)
mp_chmap_from_channels(&lavc_chmap, avframe->channels);
#endif
new->rate = avframe->sample_rate;
mp_audio_set_channels(new, &lavc_chmap);
// Force refcounted frame.
if (!avframe->buf[0]) {
tmp = av_frame_alloc();
if (!tmp)
goto fail;
if (av_frame_ref(tmp, avframe) < 0)
goto fail;
avframe = tmp;
}
// If we can't handle the format (e.g. too many channels), bail out.
if (!mp_audio_config_valid(new) || avframe->nb_extended_buf)
goto fail;
for (int n = 0; n < AV_NUM_DATA_POINTERS; n++) {
if (!avframe->buf[n])
break;
if (n >= MP_NUM_CHANNELS)
goto fail;
new->allocated[n] = av_buffer_ref(avframe->buf[n]);
if (!new->allocated[n])
goto fail;
}
for (int n = 0; n < new->num_planes; n++)
new->planes[n] = avframe->data[n];
new->samples = avframe->nb_samples;
return new;
fail:
talloc_free(new);
av_frame_free(&tmp);
return NULL;
}
struct mp_audio_pool {
AVBufferPool *avpool;
int element_size;
};
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent)
{
return talloc_zero(ta_parent, struct mp_audio_pool);
}
static void mp_audio_pool_destructor(void *p)
{
struct mp_audio_pool *pool = p;
av_buffer_pool_uninit(&pool->avpool);
}
// Allocate data using the given format and number of samples.
// Returns NULL on error.
struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
const struct mp_audio *fmt, int samples)
{
int size = get_plane_size(fmt, samples);
if (size < 0)
return NULL;
if (!pool->avpool || size > pool->element_size) {
size_t alloc = ta_calc_prealloc_elems(size);
if (alloc >= INT_MAX)
return NULL;
av_buffer_pool_uninit(&pool->avpool);
pool->avpool = av_buffer_pool_init(alloc, NULL);
if (!pool->avpool)
return NULL;
talloc_set_destructor(pool, mp_audio_pool_destructor);
}
struct mp_audio *new = talloc_ptrtype(NULL, new);
talloc_set_destructor(new, mp_audio_destructor);
*new = *fmt;
mp_audio_set_null_data(new);
new->samples = samples;
for (int n = 0; n < new->num_planes; n++) {
new->allocated[n] = av_buffer_pool_get(pool->avpool);
if (!new->allocated[n]) {
talloc_free(new);
return NULL;
}
new->planes[n] = new->allocated[n]->data;
}
return new;
}
+12 -3
View File
@@ -38,7 +38,7 @@ struct mp_audio {
int bps; // size of sub-samples (af_fmt2bps(format))
// private
int allocated[MP_NUM_CHANNELS]; // use mp_audio_get_allocated_size()
struct AVBufferRef *allocated[MP_NUM_CHANNELS];
};
void mp_audio_set_format(struct mp_audio *mpa, int format);
@@ -49,8 +49,8 @@ void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src);
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b);
bool mp_audio_config_valid(const struct mp_audio *mpa);
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format);
char *mp_audio_config_to_str(struct mp_audio *mpa);
char *mp_audio_config_to_str_buf(char *buf, size_t buf_sz, struct mp_audio *mpa);
#define mp_audio_config_to_str(m) mp_audio_config_to_str_buf((char[64]){0}, 64, (m))
void mp_audio_force_interleaved_format(struct mp_audio *mpa);
@@ -68,4 +68,13 @@ void mp_audio_copy(struct mp_audio *dst, int dst_offset,
struct mp_audio *src, int src_offset, int length);
void mp_audio_skip_samples(struct mp_audio *data, int samples);
int mp_audio_make_writeable(struct mp_audio *data);
struct AVFrame;
struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe);
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent);
struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
const struct mp_audio *fmt, int samples);
#endif
+15 -12
View File
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <assert.h>
#include "common/common.h"
#include "common/msg.h"
#include "chmap.h"
@@ -86,6 +87,7 @@ static const char *const std_layout_names[][2] = {
{"7.1(wide-side)", "fl-fr-fc-lfe-flc-frc-sl-sr"},
{"octagonal", "fl-fr-fc-bl-br-bc-sl-sr"},
{"downmix", "dl-dr"},
{"auto", ""}, // not in lavc
{0}
};
@@ -375,34 +377,35 @@ void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
// Returns something like "fl-fr-fc". If there's a standard layout in lavc
// order, return that, e.g. "3.0" instead of "fl-fr-fc".
// Unassigned but valid speakers get names like "sp28".
char *mp_chmap_to_str(const struct mp_chmap *src)
char *mp_chmap_to_str_buf(char *buf, size_t buf_size, const struct mp_chmap *src)
{
char *res = talloc_strdup(NULL, "");
buf[0] = '\0';
if (mp_chmap_is_unknown(src))
return talloc_asprintf_append_buffer(res, "unknown%d", src->num);
if (mp_chmap_is_unknown(src)) {
snprintf(buf, buf_size, "unknown%d", src->num);
return buf;
}
for (int n = 0; n < src->num; n++) {
int sp = src->speaker[n];
const char *s = sp < MP_SPEAKER_ID_COUNT ? speaker_names[sp][0] : NULL;
char buf[10];
char sp_buf[10];
if (!s) {
snprintf(buf, sizeof(buf), "sp%d", sp);
s = buf;
snprintf(sp_buf, sizeof(sp_buf), "sp%d", sp);
s = sp_buf;
}
res = talloc_asprintf_append_buffer(res, "%s%s", n > 0 ? "-" : "", s);
mp_snprintf_cat(buf, buf_size, "%s%s", n > 0 ? "-" : "", s);
}
// To standard layout name
for (int n = 0; std_layout_names[n][0]; n++) {
if (res && strcmp(res, std_layout_names[n][1]) == 0) {
talloc_free(res);
res = talloc_strdup(NULL, std_layout_names[n][0]);
if (strcmp(buf, std_layout_names[n][1]) == 0) {
snprintf(buf, buf_size, "%s", std_layout_names[n][0]);
break;
}
}
return res;
return buf;
}
// If src can be parsed as channel map (as produced by mp_chmap_to_str()),
+6 -3
View File
@@ -20,7 +20,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include "bstr/bstr.h"
#include "misc/bstr.h"
#define MP_NUM_CHANNELS 8
@@ -61,7 +61,8 @@ enum mp_speaker_id {
MP_SPEAKER_ID_UNKNOWN0 = 64,
MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1,
// Including the unassigned IDs in between. This is not a valid ID anymore.
// Including the unassigned IDs in between. This is not a valid ID anymore,
// but is still within uint8_t.
MP_SPEAKER_ID_COUNT,
};
@@ -119,7 +120,9 @@ void mp_chmap_reorder_to_lavc(struct mp_chmap *map);
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
const struct mp_chmap *to);
char *mp_chmap_to_str(const struct mp_chmap *src);
char *mp_chmap_to_str_buf(char *buf, size_t buf_size, const struct mp_chmap *src);
#define mp_chmap_to_str(m) mp_chmap_to_str_buf((char[64]){0}, 64, (m))
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
struct mp_log;
+12 -5
View File
@@ -81,14 +81,21 @@ void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s)
}
}
#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
// Add a channel map that should be allowed.
void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map)
{
assert(s->num_chmaps < ARRAY_LEN(s->chmaps));
if (mp_chmap_is_valid(map))
s->chmaps[s->num_chmaps++] = *map;
if (!mp_chmap_is_valid(map))
return;
if (!s->chmaps)
s->chmaps = s->chmaps_storage;
if (s->num_chmaps == MP_ARRAY_SIZE(s->chmaps_storage)) {
if (!s->tmp)
return;
s->chmaps = talloc_memdup(s->tmp, s->chmaps, sizeof(s->chmaps_storage));
}
if (s->chmaps != s->chmaps_storage)
MP_TARRAY_GROW(s->tmp, s->chmaps, s->num_chmaps);
s->chmaps[s->num_chmaps++] = *map;
}
// Allow all waveext formats in default order.
+5 -1
View File
@@ -26,8 +26,12 @@ struct mp_chmap_sel {
// should be considered opaque
bool allow_any, allow_waveext;
bool speakers[MP_SPEAKER_ID_COUNT];
struct mp_chmap chmaps[20];
struct mp_chmap *chmaps;
int num_chmaps;
struct mp_chmap chmaps_storage[20];
void *tmp; // set to any talloc context to allow more chmaps entries
};
void mp_chmap_sel_add_any(struct mp_chmap_sel *s);
+1 -1
View File
@@ -36,7 +36,7 @@ struct ad_functions {
int (*init)(struct dec_audio *da, const char *decoder);
void (*uninit)(struct dec_audio *da);
int (*control)(struct dec_audio *da, int cmd, void *arg);
int (*decode_audio)(struct dec_audio *da, struct mp_audio *buffer, int maxlen);
int (*decode_packet)(struct dec_audio *da, struct mp_audio **out);
};
enum ad_ctrl {
+61 -196
View File
@@ -25,6 +25,7 @@
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/common.h>
#include <libavutil/intreadwrite.h>
#include "talloc.h"
@@ -33,30 +34,27 @@
#include "common/codecs.h"
#include "common/msg.h"
#include "options/options.h"
#include "common/av_opts.h"
#include "ad.h"
#include "audio/fmt-conversion.h"
#include "compat/libav.h"
struct priv {
AVCodecContext *avctx;
AVFrame *avframe;
struct mp_audio frame;
bool force_channel_map;
struct demux_packet *packet;
uint32_t skip_samples;
};
static void uninit(struct dec_audio *da);
static int decode_new_packet(struct dec_audio *da);
#define OPT_BASE_STRUCT struct ad_lavc_params
struct ad_lavc_params {
float ac3drc;
int downmix;
int threads;
char *avopt;
char **avopts;
};
const struct m_sub_options ad_lavc_conf = {
@@ -64,7 +62,7 @@ const struct m_sub_options ad_lavc_conf = {
OPT_FLOATRANGE("ac3drc", ac3drc, 0, 0, 2),
OPT_FLAG("downmix", downmix, 0),
OPT_INTRANGE("threads", threads, 0, 1, 16),
OPT_STRING("o", avopt, 0),
OPT_KEYVALUELIST("o", avopts, 0),
{0}
},
.size = sizeof(struct ad_lavc_params),
@@ -75,121 +73,6 @@ const struct m_sub_options ad_lavc_conf = {
},
};
struct pcm_map
{
int tag;
const char *codecs[6]; // {any, 1byte, 2bytes, 3bytes, 4bytes, 8bytes}
};
// NOTE: these are needed to make rawaudio with demux_mkv work.
static const struct pcm_map tag_map[] = {
// Microsoft PCM
{0x0, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
{0x1, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
// MS PCM, Extended
{0xfffe, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
// IEEE float
{0x3, {"pcm_f32le", [5] = "pcm_f64le"}},
// 'raw '
{0x20776172, {"pcm_s16be", [1] = "pcm_u8"}},
// 'twos', used by demux_mkv.c internally
{MKTAG('t', 'w', 'o', 's'),
{NULL, "pcm_s8", "pcm_s16be", "pcm_s24be", "pcm_s32be"}},
{-1},
};
// For demux_rawaudio.c; needed because ffmpeg doesn't have these sample
// formats natively.
static const struct pcm_map af_map[] = {
{AF_FORMAT_U8, {"pcm_u8"}},
{AF_FORMAT_S8, {"pcm_u8"}},
{AF_FORMAT_U16_LE, {"pcm_u16le"}},
{AF_FORMAT_U16_BE, {"pcm_u16be"}},
{AF_FORMAT_S16_LE, {"pcm_s16le"}},
{AF_FORMAT_S16_BE, {"pcm_s16be"}},
{AF_FORMAT_U24_LE, {"pcm_u24le"}},
{AF_FORMAT_U24_BE, {"pcm_u24be"}},
{AF_FORMAT_S24_LE, {"pcm_s24le"}},
{AF_FORMAT_S24_BE, {"pcm_s24be"}},
{AF_FORMAT_U32_LE, {"pcm_u32le"}},
{AF_FORMAT_U32_BE, {"pcm_u32be"}},
{AF_FORMAT_S32_LE, {"pcm_s32le"}},
{AF_FORMAT_S32_BE, {"pcm_s32be"}},
{AF_FORMAT_FLOAT_LE, {"pcm_f32le"}},
{AF_FORMAT_FLOAT_BE, {"pcm_f32be"}},
{AF_FORMAT_DOUBLE_LE, {"pcm_f64le"}},
{AF_FORMAT_DOUBLE_BE, {"pcm_f64be"}},
{-1},
};
static const char *find_pcm_decoder(const struct pcm_map *map, int format,
int bits_per_sample)
{
int bytes = (bits_per_sample + 7) / 8;
if (bytes == 8)
bytes = 5; // 64 bit entry
for (int n = 0; map[n].tag != -1; n++) {
const struct pcm_map *entry = &map[n];
if (entry->tag == format) {
const char *dec = NULL;
if (bytes >= 1 && bytes <= 5)
dec = entry->codecs[bytes];
if (!dec)
dec = entry->codecs[0];
if (dec)
return dec;
}
}
return NULL;
}
static int setup_format(struct dec_audio *da)
{
struct priv *priv = da->priv;
AVCodecContext *lavc_context = priv->avctx;
struct sh_audio *sh_audio = da->header->audio;
// Note: invalid parameters are rejected by dec_audio.c
int fmt = lavc_context->sample_fmt;
mp_audio_set_format(&da->decoded, af_from_avformat(fmt));
if (!da->decoded.format)
MP_FATAL(da, "unsupported lavc format %s", av_get_sample_fmt_name(fmt));
da->decoded.rate = lavc_context->sample_rate;
if (!da->decoded.rate && sh_audio->wf) {
// If not set, try container samplerate.
// (Maybe this can't happen, and it's an artifact from the past.)
da->decoded.rate = sh_audio->wf->nSamplesPerSec;
MP_WARN(da, "using container rate.\n");
}
struct mp_chmap lavc_chmap;
mp_chmap_from_lavc(&lavc_chmap, lavc_context->channel_layout);
// No channel layout or layout disagrees with channel count
if (lavc_chmap.num != lavc_context->channels)
mp_chmap_from_channels(&lavc_chmap, lavc_context->channels);
if (priv->force_channel_map) {
if (lavc_chmap.num == sh_audio->channels.num)
lavc_chmap = sh_audio->channels;
}
mp_audio_set_channels(&da->decoded, &lavc_chmap);
return 0;
}
static void set_from_wf(AVCodecContext *avctx, MP_WAVEFORMATEX *wf)
{
avctx->channels = wf->nChannels;
avctx->sample_rate = wf->nSamplesPerSec;
avctx->bit_rate = wf->nAvgBytesPerSec * 8;
avctx->block_align = wf->nBlockAlign;
avctx->bits_per_coded_sample = wf->wBitsPerSample;
if (wf->cbSize > 0)
mp_lavc_set_extradata(avctx, wf + 1, wf->cbSize);
}
static int init(struct dec_audio *da, const char *decoder)
{
struct MPOpts *mpopts = da->opts;
@@ -202,13 +85,7 @@ static int init(struct dec_audio *da, const char *decoder)
struct priv *ctx = talloc_zero(NULL, struct priv);
da->priv = ctx;
if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
decoder = find_pcm_decoder(tag_map, sh->format,
sh_audio->wf->wBitsPerSample);
} else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
decoder = find_pcm_decoder(af_map, sh->format, 0);
ctx->force_channel_map = true;
}
ctx->force_channel_map = sh_audio->force_channels;
lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec) {
@@ -233,23 +110,23 @@ static int init(struct dec_audio *da, const char *decoder)
av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc,
AV_OPT_SEARCH_CHILDREN);
if (opts->avopt) {
if (parse_avopts(lavc_context, opts->avopt) < 0) {
MP_ERR(da, "setting AVOptions '%s' failed.\n", opts->avopt);
uninit(da);
return 0;
}
}
#if HAVE_AVFRAME_SKIP_SAMPLES
// 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);
lavc_context->codec_tag = sh->format;
lavc_context->sample_rate = sh_audio->samplerate;
lavc_context->bit_rate = sh_audio->bitrate;
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
lavc_context->block_align = sh_audio->block_align;
lavc_context->bits_per_coded_sample = sh_audio->bits_per_coded_sample;
lavc_context->channels = sh_audio->channels.num;
if (!mp_chmap_is_unknown(&sh_audio->channels))
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
if (sh_audio->wf)
set_from_wf(lavc_context, sh_audio->wf);
// demux_mkv, demux_mpg
// demux_mkv
if (sh_audio->codecdata_len && sh_audio->codecdata &&
!lavc_context->extradata) {
mp_lavc_set_extradata(lavc_context, sh_audio->codecdata,
@@ -267,27 +144,9 @@ static int init(struct dec_audio *da, const char *decoder)
uninit(da);
return 0;
}
MP_VERBOSE(da, "INFO: libavcodec \"%s\" init OK!\n",
lavc_codec->name);
// Decode at least 1 sample: (to get header filled)
for (int tries = 1; ; tries++) {
int x = decode_new_packet(da);
if (x >= 0 && ctx->frame.samples > 0) {
MP_VERBOSE(da, "Initial decode succeeded after %d packets.\n", tries);
break;
}
if (tries >= 50) {
MP_ERR(da, "initial decode failed\n");
uninit(da);
return 0;
}
}
if (lavc_context->bit_rate != 0)
da->bitrate = lavc_context->bit_rate;
else if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
da->bitrate = sh_audio->wf->nAvgBytesPerSec * 8;
return 1;
}
@@ -314,24 +173,24 @@ static int control(struct dec_audio *da, int cmd, void *arg)
switch (cmd) {
case ADCTRL_RESET:
avcodec_flush_buffers(ctx->avctx);
ctx->frame.samples = 0;
talloc_free(ctx->packet);
ctx->packet = NULL;
ctx->skip_samples = 0;
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
static int decode_new_packet(struct dec_audio *da)
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
priv->frame.samples = 0;
struct demux_packet *mpkt = priv->packet;
if (!mpkt)
mpkt = demux_read_packet(da->header);
if (!mpkt) {
if (demux_read_packet_async(da->header, &mpkt) == 0)
return AD_WAIT;
}
priv->packet = talloc_steal(priv, mpkt);
@@ -364,22 +223,14 @@ static int decode_new_packet(struct dec_audio *da)
}
// LATM may need many packets to find mux info
if (ret == AVERROR(EAGAIN))
return 0;
return AD_OK;
}
if (ret < 0) {
MP_VERBOSE(da, "lavc_audio: error\n");
return -1;
MP_ERR(da, "Error decoding audio.\n");
return AD_ERR;
}
if (!got_frame)
return mpkt ? 0 : -1; // -1: eof
if (setup_format(da) < 0)
return -1;
priv->frame.samples = priv->avframe->nb_samples;
mp_audio_copy_config(&priv->frame, &da->decoded);
for (int n = 0; n < priv->frame.num_planes; n++)
priv->frame.planes[n] = priv->avframe->data[n];
return mpkt ? AD_OK : AD_EOF;
double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, NULL);
if (out_pts != MP_NOPTS_VALUE) {
@@ -387,35 +238,49 @@ static int decode_new_packet(struct dec_audio *da)
da->pts_offset = 0;
}
MP_DBG(da, "Decoded %d -> %d samples\n", in_len,
priv->frame.samples);
return 0;
}
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
if (!mpframe)
return AD_ERR;
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
{
struct priv *priv = da->priv;
if (!priv->frame.samples) {
if (decode_new_packet(da) < 0)
return -1;
struct mp_chmap lavc_chmap = mpframe->channels;
if (lavc_chmap.num != avctx->channels)
mp_chmap_from_channels(&lavc_chmap, avctx->channels);
if (priv->force_channel_map) {
struct sh_audio *sh_audio = da->header->audio;
if (lavc_chmap.num == sh_audio->channels.num)
lavc_chmap = sh_audio->channels;
}
mp_audio_set_channels(mpframe, &lavc_chmap);
if (!mp_audio_config_equals(buffer, &priv->frame))
return 0;
#if HAVE_AVFRAME_SKIP_SAMPLES
AVFrameSideData *sd =
av_frame_get_side_data(priv->avframe, AV_FRAME_DATA_SKIP_SAMPLES);
if (sd && sd->size >= 10) {
char *d = sd->data;
priv->skip_samples += AV_RL32(d + 0);
uint32_t pad = AV_RL32(d + 4);
uint32_t skip = MPMIN(priv->skip_samples, mpframe->samples);
if (skip) {
mp_audio_skip_samples(mpframe, skip);
da->pts_offset += skip;
priv->skip_samples -= skip;
}
if (pad <= mpframe->samples)
mpframe->samples -= pad;
}
#endif
buffer->samples = MPMIN(priv->frame.samples, maxlen);
mp_audio_copy(buffer, 0, &priv->frame, 0, buffer->samples);
mp_audio_skip_samples(&priv->frame, buffer->samples);
da->pts_offset += buffer->samples;
*out = mpframe;
av_frame_unref(priv->avframe);
MP_DBG(da, "Decoded %d -> %d samples\n", in_len, mpframe->samples);
return 0;
}
static void add_decoders(struct mp_decoder_list *list)
{
mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
mp_add_decoder(list, "lavc", "pcm", "pcm", "Raw PCM");
mp_add_decoder(list, "lavc", "mp-pcm", "mp-pcm", "Raw PCM");
}
const struct ad_functions ad_lavc = {
@@ -424,5 +289,5 @@ const struct ad_functions ad_lavc = {
.init = init,
.uninit = uninit,
.control = control,
.decode_audio = decode_audio,
.decode_packet = decode_packet,
};
+74 -147
View File
@@ -35,9 +35,7 @@
struct ad_mpg123_context {
mpg123_handle *handle;
bool new_format;
int sample_size;
bool need_data;
/* Running mean for bit rate, stream length estimation. */
float mean_rate;
unsigned int mean_count;
@@ -45,6 +43,7 @@ struct ad_mpg123_context {
short delay;
/* If the stream is actually VBR. */
char vbr;
struct mp_audio frame;
};
static void uninit(struct dec_audio *da)
@@ -58,7 +57,7 @@ static void uninit(struct dec_audio *da)
/* This initializes libmpg123 and prepares the handle, including funky
* parameters. */
static int preinit(struct dec_audio *da)
static int init(struct dec_audio *da, const char *decoder)
{
int err;
struct ad_mpg123_context *con;
@@ -111,15 +110,18 @@ static int preinit(struct dec_audio *da)
* We need at least 1152 samples. dec_audio.c normally guarantees this. */
mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.);
err = mpg123_open_feed(con->handle);
if (err != MPG123_OK)
goto bad_end;
return 1;
bad_end:
if (!con->handle)
MP_ERR(da, "mpg123 preinit error: %s\n",
mpg123_plain_strerror(err));
else
MP_ERR(da, "mpg123 preinit error: %s\n",
mpg123_strerror(con->handle));
if (!con->handle) {
MP_ERR(da, "mpg123 preinit error: %s\n", mpg123_plain_strerror(err));
} else {
MP_ERR(da, "mpg123 preinit error: %s\n", mpg123_strerror(con->handle));
}
uninit(da);
return 0;
@@ -140,111 +142,6 @@ static int mpg123_format_to_af(int mpg123_encoding)
return 0;
}
/* libmpg123 has a new format ready; query and store, return return value
of mpg123_getformat() */
static int set_format(struct dec_audio *da)
{
struct ad_mpg123_context *con = da->priv;
int ret;
long rate;
int channels;
int encoding;
ret = mpg123_getformat(con->handle, &rate, &channels, &encoding);
if (ret == MPG123_OK) {
mp_audio_set_num_channels(&da->decoded, channels);
da->decoded.rate = rate;
int af = mpg123_format_to_af(encoding);
if (!af) {
/* This means we got a funny custom build of libmpg123 that only supports an unknown format. */
MP_ERR(da, "Bad encoding from mpg123: %i.\n", encoding);
return MPG123_ERR;
}
mp_audio_set_format(&da->decoded, af);
con->sample_size = channels * af_fmt2bps(af);
con->new_format = 0;
}
return ret;
}
static int feed_new_packet(struct dec_audio *da)
{
struct ad_mpg123_context *con = da->priv;
int ret;
struct demux_packet *pkt = demux_read_packet(da->header);
if (!pkt)
return -1; /* EOF. */
/* Next bytes from that presentation time. */
if (pkt->pts != MP_NOPTS_VALUE) {
da->pts = pkt->pts;
da->pts_offset = 0;
}
/* Have to use mpg123_feed() to avoid decoding here. */
ret = mpg123_feed(con->handle, pkt->buffer, pkt->len);
talloc_free(pkt);
if (ret == MPG123_ERR)
return -1;
if (ret == MPG123_NEW_FORMAT)
con->new_format = 1;
return 0;
}
/* Now we really start accessing some data and determining file format.
* Format now is allowed to change on-the-fly. Here is the only point
* that has MPlayer react to errors. We have to pray that exceptional
* erros in other places simply cannot occur. */
static int init(struct dec_audio *da, const char *decoder)
{
if (!preinit(da))
return 0;
struct ad_mpg123_context *con = da->priv;
int ret;
ret = mpg123_open_feed(con->handle);
if (ret != MPG123_OK)
goto fail;
for (int n = 0; ; n++) {
if (feed_new_packet(da) < 0) {
ret = MPG123_NEED_MORE;
goto fail;
}
size_t got_now = 0;
ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);
if (ret == MPG123_OK || ret == MPG123_NEW_FORMAT) {
ret = set_format(da);
if (ret == MPG123_OK)
break;
}
if (ret != MPG123_NEED_MORE)
goto fail;
// max. 16 retries (randomly chosen number)
if (n > 16) {
ret = MPG123_NEED_MORE;
goto fail;
}
}
return 1;
fail:
if (ret == MPG123_NEED_MORE) {
MP_ERR(da, "Could not find mp3 stream.\n");
} else {
MP_ERR(da, "mpg123 init error: %s\n",
mpg123_strerror(con->handle));
}
uninit(da);
return 0;
}
/* Compute bitrate from frame size. */
static int compute_bitrate(struct mpg123_frameinfo *i)
{
@@ -290,57 +187,87 @@ static void update_info(struct dec_audio *da)
}
}
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
/* libmpg123 has a new format ready; query and store, return return value
of mpg123_getformat() */
static int set_format(struct dec_audio *da)
{
struct ad_mpg123_context *con = da->priv;
int ret;
long rate;
int channels;
int encoding;
ret = mpg123_getformat(con->handle, &rate, &channels, &encoding);
if (ret == MPG123_OK) {
mp_audio_set_num_channels(&con->frame, channels);
con->frame.rate = rate;
int af = mpg123_format_to_af(encoding);
if (!af) {
/* This means we got a funny custom build of libmpg123 that only supports an unknown format. */
MP_ERR(da, "Bad encoding from mpg123: %i.\n", encoding);
return MPG123_ERR;
}
mp_audio_set_format(&con->frame, af);
con->sample_size = channels * af_fmt2bps(af);
}
return ret;
}
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct ad_mpg123_context *con = da->priv;
void *buf = buffer->planes[0];
int ret;
if (con->new_format) {
ret = set_format(da);
if (ret == MPG123_OK) {
return 0; // let caller handle format change
} else if (ret == MPG123_NEED_MORE) {
con->need_data = true;
} else {
goto mpg123_fail;
}
struct demux_packet *pkt;
if (demux_read_packet_async(da->header, &pkt) == 0)
return AD_WAIT;
if (!pkt)
return AD_EOF;
/* Next bytes from that presentation time. */
if (pkt->pts != MP_NOPTS_VALUE) {
da->pts = pkt->pts;
da->pts_offset = 0;
}
if (con->need_data) {
if (feed_new_packet(da) < 0)
return -1;
}
/* Have to use mpg123_feed() to avoid decoding here. */
ret = mpg123_feed(con->handle, pkt->buffer, pkt->len);
talloc_free(pkt);
if (!mp_audio_config_equals(&da->decoded, buffer))
return 0;
size_t got_now = 0;
ret = mpg123_replace_buffer(con->handle, buf, maxlen * con->sample_size);
if (ret != MPG123_OK)
goto mpg123_fail;
ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);
unsigned char *audio = NULL;
size_t bytes = 0;
ret = mpg123_decode_frame(con->handle, NULL, &audio, &bytes);
int got_samples = got_now / con->sample_size;
buffer->samples += got_samples;
da->pts_offset += got_samples;
if (ret == MPG123_NEED_MORE)
return 0;
if (ret == MPG123_NEW_FORMAT) {
con->new_format = true;
} else if (ret == MPG123_NEED_MORE) {
con->need_data = true;
} else if (ret != MPG123_OK && ret != MPG123_DONE) {
if (ret != MPG123_OK && ret != MPG123_DONE && ret != MPG123_NEW_FORMAT)
goto mpg123_fail;
ret = set_format(da);
if (ret != MPG123_OK)
goto mpg123_fail;
if (con->sample_size < 1) {
MP_ERR(da, "no sample size\n");
return AD_ERR;
}
int got_samples = bytes / con->sample_size;
*out = mp_audio_pool_get(da->pool, &con->frame, got_samples);
if (!*out)
return AD_ERR;
memcpy((*out)->planes[0], audio, bytes);
update_info(da);
return 0;
mpg123_fail:
MP_ERR(da, "mpg123 decoding error: %s\n",
mpg123_strerror(con->handle));
return -1;
MP_ERR(da, "mpg123 decoding error: %s\n", mpg123_strerror(con->handle));
return AD_ERR;
}
static int control(struct dec_audio *da, int cmd, void *arg)
@@ -373,5 +300,5 @@ const struct ad_functions ad_mpg123 = {
.init = init,
.uninit = uninit,
.control = control,
.decode_audio = decode_audio,
.decode_packet = decode_packet,
};
+29 -29
View File
@@ -38,16 +38,16 @@ struct spdifContext {
AVFormatContext *lavf_ctx;
int iec61937_packet_size;
int out_buffer_len;
int out_buffer_size;
uint8_t *out_buffer;
uint8_t out_buffer[OUTBUF_SIZE];
bool need_close;
struct mp_audio fmt;
};
static int write_packet(void *p, uint8_t *buf, int buf_size)
{
struct spdifContext *ctx = p;
int buffer_left = ctx->out_buffer_size - ctx->out_buffer_len;
int buffer_left = OUTBUF_SIZE - ctx->out_buffer_len;
if (buf_size > buffer_left) {
MP_ERR(ctx, "spdif packet too large.\n");
buf_size = buffer_left;
@@ -118,13 +118,13 @@ static int init(struct dec_audio *da, const char *decoder)
switch (stream->codec->codec_id) {
case AV_CODEC_ID_AAC:
spdif_ctx->iec61937_packet_size = 16384;
sample_format = AF_FORMAT_IEC61937_LE;
sample_format = AF_FORMAT_S_AAC;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_AC3:
spdif_ctx->iec61937_packet_size = 6144;
sample_format = AF_FORMAT_AC3_LE;
sample_format = AF_FORMAT_S_AC3;
samplerate = 48000;
num_channels = 2;
break;
@@ -132,40 +132,40 @@ static int init(struct dec_audio *da, const char *decoder)
if (da->opts->dtshd) {
av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_IEC61937_LE;
sample_format = AF_FORMAT_S_DTSHD;
samplerate = 192000;
num_channels = 2*4;
} else {
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_AC3_LE;
sample_format = AF_FORMAT_S_DTS;
samplerate = 48000;
num_channels = 2;
}
break;
case AV_CODEC_ID_EAC3:
spdif_ctx->iec61937_packet_size = 24576;
sample_format = AF_FORMAT_IEC61937_LE;
sample_format = AF_FORMAT_S_EAC3;
samplerate = 192000;
num_channels = 2;
break;
case AV_CODEC_ID_MP3:
spdif_ctx->iec61937_packet_size = 4608;
sample_format = AF_FORMAT_MPEG2;
sample_format = AF_FORMAT_S_MP3;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_TRUEHD:
spdif_ctx->iec61937_packet_size = 61440;
sample_format = AF_FORMAT_IEC61937_LE;
sample_format = AF_FORMAT_S_TRUEHD;
samplerate = 192000;
num_channels = 8;
break;
default:
abort();
}
mp_audio_set_num_channels(&da->decoded, num_channels);
mp_audio_set_format(&da->decoded, sample_format);
da->decoded.rate = samplerate;
mp_audio_set_num_channels(&spdif_ctx->fmt, num_channels);
mp_audio_set_format(&spdif_ctx->fmt, sample_format);
spdif_ctx->fmt.rate = samplerate;
if (avformat_write_header(lavf_ctx, &format_opts) < 0) {
MP_FATAL(da, "libavformat spdif initialization failed.\n");
@@ -183,24 +183,19 @@ fail:
return 0;
}
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct spdifContext *spdif_ctx = da->priv;
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
int sstride = 2 * da->decoded.channels.num;
assert(sstride == buffer->sstride);
if (maxlen * sstride < spdif_ctx->iec61937_packet_size)
return 0;
spdif_ctx->out_buffer_len = 0;
spdif_ctx->out_buffer_size = maxlen * sstride;
spdif_ctx->out_buffer = buffer->planes[0];
struct demux_packet *mpkt = demux_read_packet(da->header);
struct demux_packet *mpkt;
if (demux_read_packet_async(da->header, &mpkt) == 0)
return AD_WAIT;
if (!mpkt)
return -1;
return AD_EOF;
AVPacket pkt;
mp_set_av_packet(&pkt, mpkt, NULL);
@@ -211,12 +206,17 @@ static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxle
da->pts_offset = 0;
}
int ret = av_write_frame(lavf_ctx, &pkt);
avio_flush(lavf_ctx->pb);
buffer->samples = spdif_ctx->out_buffer_len / sstride;
da->pts_offset += buffer->samples;
talloc_free(mpkt);
avio_flush(lavf_ctx->pb);
if (ret < 0)
return -1;
return AD_ERR;
int samples = spdif_ctx->out_buffer_len / spdif_ctx->fmt.sstride;
*out = mp_audio_pool_get(da->pool, &spdif_ctx->fmt, samples);
if (!*out)
return AD_ERR;
memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
return 0;
}
@@ -253,5 +253,5 @@ const struct ad_functions ad_spdif = {
.init = init,
.uninit = uninit,
.control = control,
.decode_audio = decode_audio,
.decode_packet = decode_packet,
};
+57 -174
View File
@@ -28,7 +28,7 @@
#include "config.h"
#include "common/codecs.h"
#include "common/msg.h"
#include "bstr/bstr.h"
#include "misc/bstr.h"
#include "stream/stream.h"
#include "demux/demux.h"
@@ -48,35 +48,14 @@ extern const struct ad_functions ad_lavc;
extern const struct ad_functions ad_spdif;
static const struct ad_functions * const ad_drivers[] = {
&ad_lavc,
#if HAVE_MPG123
&ad_mpg123,
#endif
&ad_lavc,
&ad_spdif,
NULL
};
// ad_mpg123 needs to be able to decode 1152 samples at once
// ad_spdif needs up to 8192
#define DECODE_MAX_UNIT MPMAX(8192, 1152)
// At least 8192 samples, plus hack for ad_mpg123 and ad_spdif
#define DECODE_BUFFER_SAMPLES (8192 + DECODE_MAX_UNIT)
// Drop audio buffer and reinit it (after format change)
// Returns whether the format was valid at all.
static bool reinit_audio_buffer(struct dec_audio *da)
{
if (!mp_audio_config_valid(&da->decoded)) {
MP_ERR(da, "Audio decoder did not specify audio "
"format, or requested an unsupported configuration!\n");
return false;
}
mp_audio_buffer_reinit(da->decode_buffer, &da->decoded);
mp_audio_buffer_preallocate_min(da->decode_buffer, DECODE_BUFFER_SAMPLES);
return true;
}
static void uninit_decoder(struct dec_audio *d_audio)
{
if (d_audio->ad_driver) {
@@ -97,12 +76,6 @@ static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
return 0;
}
d_audio->decode_buffer = mp_audio_buffer_create(NULL);
if (!reinit_audio_buffer(d_audio)) {
uninit_decoder(d_audio);
return 0;
}
return 1;
}
@@ -164,9 +137,6 @@ int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
decoder->decoder);
MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
MP_VERBOSE(d_audio, "AUDIO: %d Hz, %d ch, %s\n",
d_audio->decoded.rate, d_audio->decoded.channels.num,
af_fmt_to_str(d_audio->decoded.format));
} else {
MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
d_audio->header->codec ? d_audio->header->codec : "<unknown>");
@@ -180,170 +150,82 @@ void audio_uninit(struct dec_audio *d_audio)
{
if (!d_audio)
return;
if (d_audio->afilter) {
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
af_destroy(d_audio->afilter);
d_audio->afilter = NULL;
}
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
af_destroy(d_audio->afilter);
uninit_decoder(d_audio);
talloc_free(d_audio->decode_buffer);
talloc_free(d_audio);
}
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format)
/* Decode packets until we know the audio format. Then reinit the buffer.
* Returns AD_OK on success, negative AD_* code otherwise.
* Also returns AD_OK if already initialized (and does nothing).
*/
int initial_audio_decode(struct dec_audio *da)
{
if (!d_audio->afilter)
d_audio->afilter = af_new(d_audio->global);
struct af_stream *afs = d_audio->afilter;
// input format: same as codec's output format:
mp_audio_buffer_get_format(d_audio->decode_buffer, &afs->input);
// Sample rate can be different when adjusting playback speed
afs->input.rate = in_samplerate;
// output format: same as ao driver's input format (if missing, fallback to input)
afs->output.rate = *out_samplerate;
mp_audio_set_channels(&afs->output, out_channels);
mp_audio_set_format(&afs->output, *out_format);
afs->metadata = d_audio->metadata;
afs->replaygain_data = d_audio->replaygain_data;
char *s_from = mp_audio_config_to_str(&afs->input);
char *s_to = mp_audio_config_to_str(&afs->output);
MP_VERBOSE(d_audio, "Building audio filter chain for %s -> %s...\n", s_from, s_to);
talloc_free(s_from);
talloc_free(s_to);
// let's autoprobe it!
if (af_init(afs) != 0) {
af_destroy(afs);
d_audio->afilter = NULL;
return 0; // failed :(
while (!da->waiting) {
int ret = da->ad_driver->decode_packet(da, &da->waiting);
if (ret < 0)
return ret;
}
*out_samplerate = afs->output.rate;
*out_channels = afs->output.channels;
*out_format = afs->output.format;
return 1;
}
// Filter len bytes of input, put result into outbuf.
static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
int len)
{
int error = 0;
struct mp_audio config;
mp_audio_buffer_get_format(da->decode_buffer, &config);
while (mp_audio_buffer_samples(da->decode_buffer) < len) {
int maxlen = mp_audio_buffer_get_write_available(da->decode_buffer);
if (maxlen < DECODE_MAX_UNIT)
break;
struct mp_audio buffer;
mp_audio_buffer_get_write_buffer(da->decode_buffer, maxlen, &buffer);
buffer.samples = 0;
error = da->ad_driver->decode_audio(da, &buffer, maxlen);
if (error < 0)
break;
// Commit the data just read as valid data
mp_audio_buffer_finish_write(da->decode_buffer, buffer.samples);
// Format change
if (!mp_audio_config_equals(&da->decoded, &config)) {
// If there are still samples left in the buffer, let them drain
// first, and don't signal a format change to the caller yet.
if (mp_audio_buffer_samples(da->decode_buffer) > 0)
break;
error = -2;
break;
}
}
// Filter
struct mp_audio filter_data;
mp_audio_buffer_peek(da->decode_buffer, &filter_data);
filter_data.rate = da->afilter->input.rate; // due to playback speed change
len = MPMIN(filter_data.samples, len);
filter_data.samples = len;
bool eof = filter_data.samples == 0 && error < 0;
if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0)
return -1;
mp_audio_buffer_append(outbuf, &filter_data);
if (eof && filter_data.samples > 0)
error = 0; // don't end playback yet
// remove processed data from decoder buffer:
mp_audio_buffer_skip(da->decode_buffer, len);
// Assume the filter chain is drained from old data at this point.
// (If not, the remaining old data is discarded.)
if (error == -2) {
if (!reinit_audio_buffer(da))
error = -1; // switch to invalid format
}
return error;
talloc_steal(da, da->waiting);
da->decode_format = *da->waiting;
return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR;
}
/* Try to get at least minsamples decoded+filtered samples in outbuf
* (total length including possible existing data).
* Return 0 on success, -1 on error/EOF (not distinguidaed).
* Return 0 on success, or negative AD_* error code.
* In the former case outbuf has at least minsamples buffered on return.
* In case of EOF/error it might or might not be. */
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
int audio_decode(struct dec_audio *da, struct mp_audio_buffer *outbuf,
int minsamples)
{
// Indicates that a filter seems to be buffering large amounts of data
int huge_filter_buffer = 0;
// Decoded audio must be cut at boundaries of this many samples
// (Note: the reason for this is unknown, possibly a refactoring artifact)
int unitsize = 16;
struct af_stream *afs = da->afilter;
if (afs->initialized < 1)
return AD_ERR;
/* Filter output size will be about filter_multiplier times input size.
* If some filter buffers audio in big blocks this might only hold
* as average over time. */
double filter_multiplier = af_calc_filter_multiplier(d_audio->afilter);
MP_STATS(da, "start audio");
int prev_buffered = -1;
int res = 0;
MP_STATS(d_audio, "start audio");
while (res >= 0 && minsamples >= 0) {
int buffered = mp_audio_buffer_samples(outbuf);
if (minsamples < buffered || buffered == prev_buffered)
if (minsamples < buffered)
break;
prev_buffered = buffered;
int decsamples = (minsamples - buffered) / filter_multiplier;
// + some extra for possible filter buffering
decsamples += unitsize << 5;
res = 0;
if (huge_filter_buffer) {
/* Some filter must be doing significant buffering if the estimated
* input length didn't produce enough output from filters.
* Feed the filters 250 samples at a time until we have enough
* output. Very small amounts could make filtering inefficient while
* large amounts can make mpv demux the file unnecessarily far ahead
* to get audio data and buffer video frames in memory while doing
* so. However the performance impact of either is probably not too
* significant as long as the value is not completely insane. */
decsamples = 250;
struct mp_audio *mpa = da->waiting;
if (!mpa)
res = da->ad_driver->decode_packet(da, &mpa);
if (res != AD_EOF) {
if (res < 0)
break;
if (!mpa )
continue;
}
/* if this iteration does not fill buffer, we must have lots
* of buffering in filters */
huge_filter_buffer = 1;
if (mpa) {
da->pts_offset += mpa->samples;
da->decode_format = *mpa;
mp_audio_set_null_data(&da->decode_format);
// On format change, make sure to drain the filter chain.
if (!mp_audio_config_equals(&afs->input, mpa)) {
res = AD_NEW_FMT;
da->waiting = talloc_steal(da, mpa);
mpa = NULL;
}
}
res = filter_n_bytes(d_audio, outbuf, decsamples);
if (mpa)
da->waiting = NULL;
if (af_filter(afs, mpa, outbuf) < 0)
return AD_ERR;
}
MP_STATS(d_audio, "end audio");
MP_STATS(da, "end audio");
return res;
}
@@ -351,10 +233,11 @@ void audio_reset_decoding(struct dec_audio *d_audio)
{
if (d_audio->ad_driver)
d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
if (d_audio->afilter)
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
d_audio->pts = MP_NOPTS_VALUE;
d_audio->pts_offset = 0;
if (d_audio->decode_buffer)
mp_audio_buffer_clear(d_audio->decode_buffer);
if (d_audio->waiting) {
talloc_free(d_audio->waiting);
d_audio->waiting = NULL;
}
}
+13 -10
View File
@@ -33,15 +33,13 @@ struct dec_audio {
struct mpv_global *global;
const struct ad_functions *ad_driver;
struct sh_stream *header;
struct mp_audio_buffer *decode_buffer;
struct af_stream *afilter;
char *decoder_desc;
struct mp_tags *metadata;
struct replaygain_data *replaygain_data;
int init_retries;
struct mp_audio_pool *pool;
struct mp_audio decode_format;
struct mp_audio *waiting; // used on format-change
// set by decoder
struct mp_audio decoded; // format of decoded audio (no data, temporarily
// different from decode_buffer during format
// changes)
int bitrate; // input bitrate, can change with VBR sources
// last known pts value in output from decoder
double pts;
@@ -51,15 +49,20 @@ struct dec_audio {
void *priv;
};
enum {
AD_OK = 0,
AD_ERR = -1,
AD_EOF = -2,
AD_NEW_FMT = -3,
AD_WAIT = -4,
};
struct mp_decoder_list *audio_decoder_list(void);
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders);
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
int minsamples);
int initial_audio_decode(struct dec_audio *d_audio);
void audio_reset_decoding(struct dec_audio *d_audio);
void audio_uninit(struct dec_audio *d_audio);
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format);
#endif /* MPLAYER_DEC_AUDIO_H */
+98 -46
View File
@@ -28,6 +28,7 @@
#include "options/m_option.h"
#include "options/m_config.h"
#include "audio/audio_buffer.h"
#include "af.h"
// Static list of filters
@@ -53,6 +54,7 @@ extern const struct af_info af_info_center;
extern const struct af_info af_info_sinesuppress;
extern const struct af_info af_info_karaoke;
extern const struct af_info af_info_scaletempo;
extern const struct af_info af_info_forcespeed;
extern const struct af_info af_info_bs2b;
extern const struct af_info af_info_lavfi;
extern const struct af_info af_info_convert24;
@@ -83,6 +85,7 @@ static const struct af_info *const filter_list[] = {
&af_info_center,
&af_info_sinesuppress,
&af_info_karaoke,
&af_info_forcespeed,
&af_info_scaletempo,
#if HAVE_LIBBS2B
&af_info_bs2b,
@@ -121,13 +124,6 @@ const struct m_obj_list af_obj_list = {
},
};
static bool af_config_equals(struct mp_audio *a, struct mp_audio *b)
{
return a->format == b->format
&& mp_chmap_equals(&a->channels, &b->channels)
&& a->rate == b->rate;
}
static void af_copy_unset_fields(struct mp_audio *dst, struct mp_audio *src)
{
if (dst->format == AF_FORMAT_UNKNOWN)
@@ -162,7 +158,7 @@ static int output_control(struct af_instance* af, int cmd, void* arg)
*filter_output = *output;
af_copy_unset_fields(filter_output, in);
*in = *filter_output;
return af_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
}
}
return AF_UNKNOWN;
@@ -204,7 +200,6 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
.mul = 1,
.data = talloc_zero(af, struct mp_audio),
.log = mp_log_new(af, s->log, name),
.metadata = s->metadata,
.replaygain_data = s->replaygain_data,
};
struct m_config *config = m_config_from_obj_desc(af, s->log, &desc);
@@ -311,23 +306,18 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
struct af_instance *af = s->first;
while (af) {
MP_MSG(s, msg_level, " [%s] ", af->info->name);
if (af->data) {
char *info = mp_audio_config_to_str(af->data);
MP_MSG(s, msg_level, "%s", info);
talloc_free(info);
}
char b[128] = {0};
mp_snprintf_cat(b, sizeof(b), " [%s] ", af->info->name);
if (af->data)
mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data));
if (af == at)
MP_MSG(s, msg_level, " <-");
MP_MSG(s, msg_level, "\n");
mp_snprintf_cat(b, sizeof(b), " <-");
MP_MSG(s, msg_level, "%s\n", b);
af = af->next;
}
MP_MSG(s, msg_level, " [ao] ");
char *info = mp_audio_config_to_str(&s->output);
MP_MSG(s, msg_level, "%s\n", info);
talloc_free(info);
MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output));
}
static int af_count_filters(struct af_stream *s)
@@ -524,11 +514,16 @@ static int af_reinit(struct af_stream *s)
// Reset just in case...
mp_audio_set_null_data(&in);
if (!mp_audio_config_valid(&in))
goto error;
int rv = af->control(af, AF_CONTROL_REINIT, &in);
if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data))
rv = AF_FALSE; // conversion filter needed
switch (rv) {
case AF_OK:
if (!mp_audio_config_valid(af->data))
goto error;
af = af->next;
break;
case AF_FALSE: { // Configuration filter is needed
@@ -559,22 +554,27 @@ static int af_reinit(struct af_stream *s)
MP_ERR(s, "Reinitialization did not work, "
"audio filter '%s' returned error code %i\n",
af->info->name, rv);
af_print_filter_chain(s, af, MSGL_ERR);
return AF_ERROR;
goto error;
}
}
af_print_filter_chain(s, NULL, MSGL_V);
/* Set previously unset fields in s->output to those of the filter chain
* output. This is used to make the output format fixed, and even if you
* insert new filters or change the input format, the output format won't
* change. (Audio outputs generally can't change format at runtime.) */
af_copy_unset_fields(&s->output, &s->filter_output);
return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
if (mp_audio_config_equals(&s->output, &s->filter_output)) {
s->initialized = 1;
af_print_filter_chain(s, NULL, MSGL_V);
return AF_OK;
}
goto error;
negotiate_error:
MP_ERR(s, "Unable to convert audio input format to output format.\n");
error:
s->initialized = -1;
af_print_filter_chain(s, af, MSGL_ERR);
return AF_ERROR;
}
@@ -584,6 +584,7 @@ void af_uninit(struct af_stream *s)
{
while (s->first->next && s->first->next != s->last)
af_remove(s, s->first->next);
s->initialized = 0;
}
struct af_stream *af_new(struct mpv_global *global)
@@ -633,10 +634,6 @@ void af_destroy(struct af_stream *s)
The return value is 0 if success and -1 if failure */
int af_init(struct af_stream *s)
{
// Sanity check
if (!s)
return -1;
// Precaution in case caller is misbehaving
mp_audio_set_null_data(&s->input);
mp_audio_set_null_data(&s->output);
@@ -646,17 +643,20 @@ int af_init(struct af_stream *s)
// Add all filters in the list (if there are any)
struct m_obj_settings *list = s->opts->af_settings;
for (int i = 0; list && list[i].name; i++) {
if (!af_prepend(s, s->last, list[i].name, list[i].attribs)) {
struct af_instance *af =
af_prepend(s, s->last, list[i].name, list[i].attribs);
if (!af) {
af_uninit(s);
s->initialized = -1;
return -1;
}
af->label = talloc_strdup(af, list[i].label);
}
}
if (af_reinit(s) != AF_OK) {
// Something is stuffed audio out will not work
MP_ERR(s, "Could not create audio filter chain.\n");
af_uninit(s);
return -1;
}
return 0;
@@ -669,9 +669,6 @@ int af_init(struct af_stream *s)
struct af_instance *af_add(struct af_stream *s, char *name, char **args)
{
struct af_instance *new;
// Sanity check
if (!s || !s->first || !name)
return NULL;
// Insert the filter somewhere nice
if (af_is_conversion_filter(s->first->next))
new = af_append(s, s->first->next, name, args);
@@ -682,30 +679,85 @@ struct af_instance *af_add(struct af_stream *s, char *name, char **args)
// Reinitalize the filter list
if (af_reinit(s) != AF_OK) {
af_uninit(s);
af_init(s);
af_remove(s, new);
if (af_reinit(s) != AF_OK) {
af_uninit(s);
af_init(s);
}
return NULL;
}
return new;
}
/* Filter data chunk through the filters in the list.
* On success, *data is set to the filtered data/format.
* Warning: input audio data will be overwritten.
struct af_instance *af_find_by_label(struct af_stream *s, char *label)
{
for (struct af_instance *af = s->first; af; af = af->next) {
if (af->label && strcmp(af->label, label) == 0)
return af;
}
return NULL;
}
/* Remove the first filter that matches this name. Return number of filters
* removed (0, 1), or a negative error code if reinit after removing failed.
*/
int af_filter(struct af_stream *s, struct mp_audio *data, int flags)
int af_remove_by_label(struct af_stream *s, char *label)
{
struct af_instance *af = af_find_by_label(s, label);
if (!af)
return 0;
af_remove(s, af);
if (af_reinit(s) != AF_OK) {
af_uninit(s);
af_init(s);
return -1;
}
return 1;
}
/* Feed "data" to the chain, and write results to output. "data" needs to be
* a refcounted frame, although refcounting is not used yet.
* data==NULL means EOF.
*/
int af_filter(struct af_stream *s, struct mp_audio *data,
struct mp_audio_buffer *output)
{
struct af_instance *af = s->first;
assert(mp_audio_config_equals(af->data, data));
assert(s->initialized > 0);
int flags = 0;
int r = 0;
struct mp_audio tmp;
char dummy[MP_NUM_CHANNELS];
if (data) {
assert(mp_audio_config_equals(af->data, data));
r = mp_audio_make_writeable(data);
} else {
data = &tmp;
*data = *(af->data);
mp_audio_set_null_data(data);
flags = AF_FILTER_FLAG_EOF;
for (int n = 0; n < MP_NUM_CHANNELS; n++)
data->planes[n] = &dummy[n];
}
if (r < 0)
goto done;
struct mp_audio frame = *data;
for (int n = 0; n < MP_NUM_CHANNELS; n++)
frame.allocated[n] = NULL;
// Iterate through all filters
while (af) {
int r = af->filter(af, data, flags);
r = af->filter(af, &frame, flags);
if (r < 0)
return r;
assert(mp_audio_config_equals(af->data, data));
goto done;
assert(mp_audio_config_equals(af->data, &frame));
af = af->next;
}
return 0;
mp_audio_buffer_append(output, &frame);
done:
if (data != &tmp)
talloc_free(data);
return r;
}
// Calculate average ratio of filter output samples to input samples.
+9 -3
View File
@@ -59,7 +59,6 @@ struct af_info {
struct af_instance {
const struct af_info *info;
struct mp_log *log;
struct mp_tags *metadata;
struct replaygain_data *replaygain_data;
int (*control)(struct af_instance *af, int cmd, void *arg);
void (*uninit)(struct af_instance *af);
@@ -77,10 +76,13 @@ struct af_instance {
* the number of samples passed though. (Ratio of input
* and output, e.g. mul=4 => 1 sample becomes 4 samples) .*/
bool auto_inserted; // inserted by af.c, such as conversion filters
char *label;
};
// Current audio stream
struct af_stream {
int initialized; // 0: no, 1: yes, -1: attempted to, but failed
// The first and last filter in the list
struct af_instance *first;
struct af_instance *last;
@@ -92,7 +94,6 @@ struct af_stream {
struct mp_log *log;
struct MPOpts *opts;
struct mp_tags *metadata;
struct replaygain_data *replaygain_data;
};
@@ -119,6 +120,7 @@ enum af_control {
AF_CONTROL_SET_PAN_BALANCE,
AF_CONTROL_GET_PAN_BALANCE,
AF_CONTROL_SET_PLAYBACK_SPEED,
AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE,
};
// Argument for AF_CONTROL_SET_PAN_LEVEL
@@ -132,7 +134,11 @@ void af_destroy(struct af_stream *s);
int af_init(struct af_stream *s);
void af_uninit(struct af_stream *s);
struct af_instance *af_add(struct af_stream *s, char *name, char **args);
int af_filter(struct af_stream *s, struct mp_audio *data, int flags);
int af_remove_by_label(struct af_stream *s, char *label);
struct af_instance *af_find_by_label(struct af_stream *s, char *label);
struct mp_audio_buffer;
int af_filter(struct af_stream *s, struct mp_audio *data,
struct mp_audio_buffer *output);
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
void af_control_all(struct af_stream *s, int cmd, void *arg);
+20 -49
View File
@@ -48,20 +48,12 @@ static int filter_##name(struct af_instance *af, struct mp_audio *data, int f) \
}
FILTER(f, float)
FILTER(fbe, float)
FILTER(fle, float)
FILTER(s32be, int32_t)
FILTER(u32be, uint32_t)
FILTER(s32le, int32_t)
FILTER(u32le, uint32_t)
FILTER(s24be, bs2b_int24_t)
FILTER(u24be, bs2b_uint24_t)
FILTER(s24le, bs2b_int24_t)
FILTER(u24le, bs2b_uint24_t)
FILTER(s16be, int16_t)
FILTER(u16be, uint16_t)
FILTER(s16le, int16_t)
FILTER(u16le, uint16_t)
FILTER(s32, int32_t)
FILTER(u32, uint32_t)
FILTER(s24, bs2b_int24_t)
FILTER(u24, bs2b_uint24_t)
FILTER(s16, int16_t)
FILTER(u16, uint16_t)
FILTER(s8, int8_t)
FILTER(u8, uint8_t)
@@ -85,47 +77,26 @@ static int control(struct af_instance *af, int cmd, void *arg)
/* check for formats supported by libbs2b
and assign corresponding handlers */
switch (format) {
case AF_FORMAT_FLOAT_BE:
af->filter = filter_fbe;
case AF_FORMAT_FLOAT:
af->filter = filter_f;
break;
case AF_FORMAT_FLOAT_LE:
af->filter = filter_fle;
case AF_FORMAT_S32:
af->filter = filter_s32;
break;
case AF_FORMAT_S32_BE:
af->filter = filter_s32be;
case AF_FORMAT_U32:
af->filter = filter_u32;
break;
case AF_FORMAT_U32_BE:
af->filter = filter_u32be;
case AF_FORMAT_S24:
af->filter = filter_s24;
break;
case AF_FORMAT_S32_LE:
af->filter = filter_s32le;
case AF_FORMAT_U24:
af->filter = filter_u24;
break;
case AF_FORMAT_U32_LE:
af->filter = filter_u32le;
case AF_FORMAT_S16:
af->filter = filter_s16;
break;
case AF_FORMAT_S24_BE:
af->filter = filter_s24be;
break;
case AF_FORMAT_U24_BE:
af->filter = filter_u24be;
break;
case AF_FORMAT_S24_LE:
af->filter = filter_s24le;
break;
case AF_FORMAT_U24_LE:
af->filter = filter_u24le;
break;
case AF_FORMAT_S16_BE:
af->filter = filter_s16be;
break;
case AF_FORMAT_U16_BE:
af->filter = filter_u16be;
break;
case AF_FORMAT_S16_LE:
af->filter = filter_s16le;
break;
case AF_FORMAT_U16_LE:
af->filter = filter_u16le;
case AF_FORMAT_U16:
af->filter = filter_u16;
break;
case AF_FORMAT_S8:
af->filter = filter_s8;
+1
View File
@@ -20,6 +20,7 @@
#include "audio/format.h"
#include "af.h"
#include "osdep/endian.h"
static bool test_conversion(int src_format, int dst_format)
{
+9 -41
View File
@@ -20,21 +20,16 @@
#include "af.h"
#include "audio/format.h"
#include "compat/mpbswap.h"
#include "osdep/endian.h"
static bool test_conversion(int src_format, int dst_format)
{
if ((src_format & AF_FORMAT_PLANAR) ||
(dst_format & AF_FORMAT_PLANAR))
return false;
int src_noend = src_format & ~AF_FORMAT_END_MASK;
int dst_noend = dst_format & ~AF_FORMAT_END_MASK;
// We can swap endian for all formats, but sign only for integer formats.
if (src_noend == dst_noend)
return true;
if (((src_noend & ~AF_FORMAT_SIGN_MASK) ==
(dst_noend & ~AF_FORMAT_SIGN_MASK)) &&
((src_noend & AF_FORMAT_POINT_MASK) == AF_FORMAT_I))
if (((src_format & ~AF_FORMAT_SIGN_MASK) ==
(dst_format & ~AF_FORMAT_SIGN_MASK)) &&
((src_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_I))
return true;
return false;
}
@@ -63,34 +58,11 @@ static int control(struct af_instance *af, int cmd, void *arg)
return AF_UNKNOWN;
}
static void endian(void *data, int len, int bps)
{
switch (bps) {
case 2:
for (int i = 0; i < len; i++) {
((uint16_t*)data)[i] = bswap_16(((uint16_t *)data)[i]);
}
break;
case 3:
for(int i = 0; i < len; i++) {
uint8_t s = ((uint8_t *)data)[3 * i];
((uint8_t *)data)[3 * i] = ((uint8_t *)data)[3 * i + 2];
((uint8_t *)data)[3 * i + 2] = s;
}
break;
case 4:
for(int i = 0; i < len; i++) {
((uint32_t*)data)[i] = bswap_32(((uint32_t *)data)[i]);
}
break;
}
}
static void si2us(void *data, int len, int bps, bool le)
static void si2us(void *data, int len, int bps)
{
ptrdiff_t i = -(len * bps);
uint8_t *p = &((uint8_t *)data)[len * bps];
if (le && bps > 1)
if (BYTE_ORDER == LITTLE_ENDIAN && bps > 1)
p += bps - 1;
if (len <= 0)
return;
@@ -105,12 +77,8 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
int outfmt = af->data->format;
size_t len = data->samples * data->nch;
if ((infmt & AF_FORMAT_END_MASK) != (outfmt & AF_FORMAT_END_MASK))
endian(data->planes[0], len, data->bps);
if ((infmt & AF_FORMAT_SIGN_MASK) != (outfmt & AF_FORMAT_SIGN_MASK))
si2us(data->planes[0], len, data->bps,
(outfmt & AF_FORMAT_END_MASK) == AF_FORMAT_LE);
si2us(data->planes[0], len, data->bps);
mp_audio_set_format(data, outfmt);
return 0;
@@ -124,8 +92,8 @@ static int af_open(struct af_instance *af)
}
const struct af_info af_info_convertsignendian = {
.info = "Convert between sample format sign/endian",
.name = "convertsignendian",
.info = "Convert between sample format sign",
.name = "convertsign",
.open = af_open,
.test_conversion = test_conversion,
};
+6 -5
View File
@@ -78,8 +78,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
int mapsize;
// Free previous buffers
if (s->buf)
free(s->buf[0]);
free(s->buf[0]);
// unmap previous area
if(s->mmap_area)
@@ -94,8 +93,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Allocate new buffers (as one continuous block)
s->buf[0] = calloc(s->sz*af->data->nch, af->data->bps);
if(NULL == s->buf[0])
if(NULL == s->buf[0]) {
MP_FATAL(af, "Out of memory\n");
return AF_ERROR;
}
for(i = 1; i < af->data->nch; i++)
s->buf[i] = (uint8_t *)s->buf[0] + i*s->sz*af->data->bps;
@@ -147,8 +148,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
static void uninit( struct af_instance* af )
{
af_export_t* s = af->priv;
if (s->buf)
free(s->buf[0]);
free(s->buf[0]);
// Free mmaped area
if(s->mmap_area)
+69
View File
@@ -0,0 +1,69 @@
/*
* 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 "af.h"
struct priv {
double speed;
};
static int control(struct af_instance *af, int cmd, void *arg)
{
struct priv *priv = af->priv;
switch (cmd) {
case AF_CONTROL_REINIT: {
struct mp_audio *in = arg;
struct mp_audio orig_in = *in;
struct mp_audio *out = af->data;
mp_audio_copy_config(out, in);
out->rate = in->rate * priv->speed;
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
}
case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
priv->speed = *(double *)arg;
return AF_OK;
}
}
return AF_UNKNOWN;
}
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
{
mp_audio_copy_config(data, af->data);
return 0;
}
static int af_open(struct af_instance *af)
{
struct priv *priv = af->priv;
af->control = control;
af->filter = filter;
priv->speed = 1.0;
return AF_OK;
}
#define OPT_BASE_STRUCT struct priv
const struct af_info af_info_forcespeed = {
.info = "Force audio speed",
.name = "forcespeed",
.open = af_open,
.priv_size = sizeof(struct priv),
};
+2 -2
View File
@@ -80,12 +80,12 @@ static int control(struct af_instance *af, int cmd, void *arg)
force_out_params(af, out);
if (in->nch != out->nch || in->bps != out->bps) {
MP_ERR(af, "[af_format] Forced input/output formats are incompatible.\n");
MP_ERR(af, "Forced input/output formats are incompatible.\n");
return AF_ERROR;
}
if (priv->fail) {
MP_ERR(af, "[af_format] Failing on purpose.\n");
MP_ERR(af, "Failing on purpose.\n");
return AF_ERROR;
}
+41 -18
View File
@@ -280,8 +280,34 @@ static inline void update_ch(af_hrtf_t *s, short *in, const int k)
}
/* We need to update the bass compensation delay line, too. */
s->ba_l[k] = in[0] + in[4] + in[2];
s->ba_r[k] = in[4] + in[1] + in[3];
// TODO: should this use lf/cf/rf etc. instead?
s->ba_l[k] = in[0];
s->ba_r[k] = in[1];
if (s->decode_mode == HRTF_MIX_51) {
s->ba_l[k] += in[4] + in[2];
s->ba_r[k] += in[4] + in[3];
}
}
static void clear_coeff(af_hrtf_t *s, float *c)
{
memset(c, 0, s->dlbuflen * sizeof(float));
}
static void reset(af_hrtf_t *s)
{
clear_coeff(s, s->lf);
clear_coeff(s, s->rf);
clear_coeff(s, s->lr);
clear_coeff(s, s->rr);
clear_coeff(s, s->cf);
clear_coeff(s, s->cr);
clear_coeff(s, s->ba_l);
clear_coeff(s, s->ba_r);
clear_coeff(s, s->fwrbuf_l);
clear_coeff(s, s->fwrbuf_r);
clear_coeff(s, s->fwrbuf_lr);
clear_coeff(s, s->fwrbuf_rr);
}
/* Initialization and runtime control */
@@ -292,30 +318,27 @@ static int control(struct af_instance *af, int cmd, void* arg)
switch(cmd) {
case AF_CONTROL_REINIT:
af->data->rate = ((struct mp_audio*)arg)->rate;
if(af->data->rate != 48000) {
// automatic samplerate adjustment in the filter chain
// is not yet supported.
MP_ERR(af, "ERROR: Sampling rate is not 48000 Hz (%d)!\n",
af->data->rate);
return AF_ERROR;
}
reset(s);
af->data->rate = 48000;
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
/* Default behavior is stereo mixing. */
s->decode_mode = HRTF_MIX_STEREO;
}
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
/* Default behavior is stereo mixing. */
s->decode_mode = HRTF_MIX_STEREO;
}
else if (af->data->nch < 5)
mp_audio_set_channels_old(af->data, 5);
} else if (af->data->nch < 5) {
mp_audio_set_channels_old(af->data, 5);
}
mp_audio_set_format(af->data, AF_FORMAT_S16);
test_output_res = af_test_output(af, (struct mp_audio*)arg);
// after testing input set the real output format
mp_audio_set_num_channels(af->data, 2);
s->print_flag = 1;
return test_output_res;
case AF_CONTROL_RESET:
reset(s);
return AF_OK;
}
return AF_UNKNOWN;
+17 -8
View File
@@ -30,6 +30,7 @@
#include <libavutil/audioconvert.h>
#include <libavutil/intreadwrite.h>
#include <libavutil/common.h>
#include <libavutil/bswap.h>
#include <libavutil/mem.h>
#include "common/common.h"
@@ -87,7 +88,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (in->nch > AC3_MAX_CHANNELS)
mp_audio_set_num_channels(in, AC3_MAX_CHANNELS);
mp_audio_set_format(af->data, AF_FORMAT_AC3_BE);
mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
mp_audio_set_num_channels(af->data, 2);
if (!mp_audio_config_equals(in, &orig_in))
@@ -150,6 +151,12 @@ static void uninit(struct af_instance* af)
}
}
static void swap_16(uint16_t *ptr, size_t size)
{
for (size_t n = 0; n < size; n++)
ptr[n] = av_bswap16(ptr[n]);
}
// Filter data through filter
static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
{
@@ -223,11 +230,11 @@ static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
frame_size = AC3_FRAME_SIZE * 2 * 2;
header_len = 8;
AV_WB16(hdr, 0xF872); // iec 61937 syncword 1
AV_WB16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
hdr[4] = bsmod; // bsmod
hdr[5] = 0x01; // data-type ac3
AV_WB16(hdr + 6, len << 3); // number of bits in payload
AV_WL16(hdr, 0xF872); // iec 61937 syncword 1
AV_WL16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
hdr[5] = bsmod; // bsmod
hdr[4] = 0x01; // data-type ac3
AV_WL16(hdr + 6, len << 3); // number of bits in payload
}
size_t max_size = (max_out_samples - out->samples) * out->sstride;
@@ -239,6 +246,7 @@ static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
memcpy(buf + header_len, s->pkt.data, s->pkt.size);
memset(buf + header_len + s->pkt.size, 0,
frame_size - (header_len + s->pkt.size));
swap_16((uint16_t *)(buf + header_len), s->pkt.size / 2);
out->samples += frame_size / out->sstride;
}
@@ -312,12 +320,13 @@ const struct af_info af_info_lavcac3enc = {
.priv_size = sizeof(struct af_ac3enc_s),
.priv_defaults = &(const struct af_ac3enc_s){
.cfg_add_iec61937_header = 1,
.cfg_min_channel_num = 5,
.cfg_bit_rate = 640,
.cfg_min_channel_num = 3,
},
.options = (const struct m_option[]) {
OPT_FLAG("tospdif", cfg_add_iec61937_header, 0),
OPT_CHOICE_OR_INT("bitrate", cfg_bit_rate, 0, 32, 640,
({"default", 0})),
({"auto", 0}, {"default", 0})),
OPT_INTRANGE("minch", cfg_min_channel_num, 0, 2, 6),
{0}
},
+5 -7
View File
@@ -38,8 +38,9 @@
#include "audio/fmt-conversion.h"
#include "af.h"
#include "common/av_common.h"
#include "options/m_option.h"
#include "common/av_opts.h"
// FFmpeg and Libav have slightly different APIs, just enough to cause us
// unnecessary pain. <Expletive deleted.>
@@ -62,7 +63,7 @@ struct priv {
// options
char *cfg_graph;
char *cfg_avopts;
char **cfg_avopts;
};
static void destroy_graph(struct af_instance *af)
@@ -90,11 +91,8 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config)
if (!graph)
goto error;
if (parse_avopts(graph, p->cfg_avopts) < 0) {
MP_FATAL(af, "lavfi: could not set opts: '%s'\n",
p->cfg_avopts);
if (mp_set_avopts(af->log, graph, p->cfg_avopts) < 0)
goto error;
}
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
@@ -306,7 +304,7 @@ const struct af_info af_info_lavfi = {
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_STRING("graph", cfg_graph, 0),
OPT_STRING("o", cfg_avopts, 0),
OPT_KEYVALUELIST("o", cfg_avopts, 0),
{0}
},
};
+9 -12
View File
@@ -52,9 +52,9 @@
#error "config.h broken or no resampler found"
#endif
#include "common/av_common.h"
#include "common/msg.h"
#include "options/m_option.h"
#include "common/av_opts.h"
#include "audio/filter/af.h"
#include "audio/fmt-conversion.h"
@@ -74,7 +74,7 @@ struct af_resample_opts {
struct af_resample {
int allow_detach;
char *avopts;
char **avopts;
struct AVAudioResampleContext *avrctx;
struct AVAudioResampleContext *avrctx_out; // for output channel reordering
struct af_resample_opts ctx; // opts in the context
@@ -164,10 +164,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
av_opt_set_double(s->avrctx, "cutoff", s->ctx.cutoff, 0);
if (parse_avopts(s->avrctx, s->avopts) < 0) {
MP_FATAL(af, "af_lavrresample: could not set opts: '%s'\n", s->avopts);
if (mp_set_avopts(af->log, s->avrctx, s->avopts) < 0)
return AF_ERROR;
}
struct mp_chmap map_in = in->channels;
struct mp_chmap map_out = out->channels;
@@ -216,8 +214,7 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
if (avresample_open(s->avrctx) < 0 ||
avresample_open(s->avrctx_out) < 0)
{
MP_ERR(af, "Cannot open "
"Libavresample Context. \n");
MP_ERR(af, "Cannot open Libavresample Context. \n");
return AF_ERROR;
}
return AF_OK;
@@ -341,7 +338,7 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
if (needs_reorder(s->reorder_out, out->nch)) {
if (af_fmt_is_planar(out->format)) {
reorder_planes(data, s->reorder_out);
} else {
} else if (out->samples) {
int out_size = out->samples * out->sstride;
if (talloc_get_size(s->reorder_buffer) < out_size)
s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
@@ -349,7 +346,8 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
int out_samples = avresample_convert(s->avrctx_out,
(uint8_t **) data->planes, out_size, out->samples,
(uint8_t **) out->planes, out_size, out->samples);
assert(out_samples == data->samples);
if (out_samples < 0)
MP_ERR(af, "Reordering failed.\n");
}
}
@@ -373,8 +371,7 @@ static int af_open(struct af_instance *af)
if (s->avrctx && s->avrctx_out) {
return AF_OK;
} else {
MP_ERR(af, "Cannot initialize "
"Libavresample Context. \n");
MP_ERR(af, "Cannot initialize Libavresample Context. \n");
uninit(af);
return AF_ERROR;
}
@@ -402,7 +399,7 @@ const struct af_info af_info_lavrresample = {
OPT_FLAG("linear", opts.linear, 0),
OPT_DOUBLE("cutoff", opts.cutoff, M_OPT_RANGE, .min = 0, .max = 1),
OPT_FLAG("detach", allow_detach, 0),
OPT_STRING("o", avopts, 0),
OPT_KEYVALUELIST("o", avopts, 0),
{0}
},
};
+1 -1
View File
@@ -271,7 +271,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
switch (cmd) {
case AF_CONTROL_REINIT: {
struct mp_audio *data = (struct mp_audio *)arg;
float srate = data->rate / 1000;
float srate = data->rate / 1000.0;
int nch = data->nch;
int use_int = 0;
+2 -2
View File
@@ -79,7 +79,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (!s->rgain_clip) // clipping prevention
s->rgain = MPMIN(s->rgain, 1.0 / peak);
}
if (s->detach && fabs(s->level + s->rgain - 2.0) < 0.00001)
if (s->detach && fabs(s->level * s->rgain - 1.0) < 0.00001)
return AF_DETACH;
return af_test_output(af, in);
}
@@ -97,7 +97,7 @@ static void filter_plane(struct af_instance *af, void *ptr, int num_samples)
{
struct priv *s = af->priv;
float level = s->level + s->rgain - 1.0;
float level = s->level * s->rgain;
if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16) {
int16_t *a = ptr;
+26 -38
View File
@@ -30,9 +30,6 @@
int af_fmt2bps(int format)
{
if (AF_FORMAT_IS_AC3(format)) return 2;
if (format == AF_FORMAT_UNKNOWN)
return 0;
switch (format & AF_FORMAT_BITS_MASK) {
case AF_FORMAT_8BIT: return 1;
case AF_FORMAT_16BIT: return 2;
@@ -62,7 +59,7 @@ static int bits_to_mask(int bits)
int af_fmt_change_bits(int format, int bits)
{
if (!af_fmt_is_valid(format) || (format & AF_FORMAT_SPECIAL_MASK))
if (!af_fmt_is_valid(format))
return 0;
int mask = bits_to_mask(bits);
format = (format & ~AF_FORMAT_BITS_MASK) | mask;
@@ -109,35 +106,31 @@ bool af_fmt_is_planar(int format)
return !!(format & AF_FORMAT_PLANAR);
}
#define FMT(string, id) \
{string, id},
#define FMT_ENDIAN(string, id) \
{string, id}, \
{string "le", MP_CONCAT(id, _LE)}, \
{string "be", MP_CONCAT(id, _BE)}, \
const struct af_fmt_entry af_fmtstr_table[] = {
FMT("mpeg2", AF_FORMAT_MPEG2)
FMT_ENDIAN("ac3", AF_FORMAT_AC3)
FMT_ENDIAN("iec61937", AF_FORMAT_IEC61937)
{"u8", AF_FORMAT_U8},
{"s8", AF_FORMAT_S8},
{"u16", AF_FORMAT_U16},
{"s16", AF_FORMAT_S16},
{"u24", AF_FORMAT_U24},
{"s24", AF_FORMAT_S24},
{"u32", AF_FORMAT_U32},
{"s32", AF_FORMAT_S32},
{"float", AF_FORMAT_FLOAT},
{"double", AF_FORMAT_DOUBLE},
FMT("u8", AF_FORMAT_U8)
FMT("s8", AF_FORMAT_S8)
FMT_ENDIAN("u16", AF_FORMAT_U16)
FMT_ENDIAN("s16", AF_FORMAT_S16)
FMT_ENDIAN("u24", AF_FORMAT_U24)
FMT_ENDIAN("s24", AF_FORMAT_S24)
FMT_ENDIAN("u32", AF_FORMAT_U32)
FMT_ENDIAN("s32", AF_FORMAT_S32)
FMT_ENDIAN("float", AF_FORMAT_FLOAT)
FMT_ENDIAN("double", AF_FORMAT_DOUBLE)
{"u8p", AF_FORMAT_U8P},
{"s16p", AF_FORMAT_S16P},
{"s32p", AF_FORMAT_S32P},
{"floatp", AF_FORMAT_FLOATP},
{"doublep", AF_FORMAT_DOUBLEP},
FMT("u8p", AF_FORMAT_U8P)
FMT("s16p", AF_FORMAT_S16P)
FMT("s32p", AF_FORMAT_S32P)
FMT("floatp", AF_FORMAT_FLOATP)
FMT("doublep", AF_FORMAT_DOUBLEP)
{"spdif-aac", AF_FORMAT_S_AAC},
{"spdif-ac3", AF_FORMAT_S_AC3},
{"spdif-dts", AF_FORMAT_S_DTS},
{"spdif-dtshd", AF_FORMAT_S_DTSHD},
{"spdif-eac3", AF_FORMAT_S_EAC3},
{"spdif-mp3", AF_FORMAT_S_MP3},
{"spdif-truehd",AF_FORMAT_S_TRUEHD},
{0}
};
@@ -199,22 +192,17 @@ int af_format_conversion_score(int dst_format, int src_format)
return INT_MIN;
if (dst_format == src_format)
return 1024;
// Just endian swapping (separate because it works for special formats)
if ((dst_format & ~AF_FORMAT_END_MASK) == (src_format & ~AF_FORMAT_END_MASK))
return 1024 - 2;
// Can't be normally converted
if (AF_FORMAT_IS_SPECIAL(dst_format) || AF_FORMAT_IS_SPECIAL(src_format))
return INT_MIN;
int score = 1024;
if (FMT_DIFF(AF_FORMAT_INTERLEAVING_MASK, dst_format, src_format))
score -= 1; // has to (de-)planarize
if (FMT_DIFF(AF_FORMAT_END_MASK, dst_format, src_format))
score -= 2; // has to swap endian
if (FMT_DIFF(AF_FORMAT_SIGN_MASK, dst_format, src_format))
score -= 4; // has to swap sign
if (FMT_DIFF(AF_FORMAT_POINT_MASK, dst_format, src_format)) {
if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) {
int dst_bits = dst_format & AF_FORMAT_BITS_MASK;
if ((dst_format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F) {
if ((dst_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F) {
// For int->float, always prefer 32 bit float.
score -= dst_bits == AF_FORMAT_32BIT ? 8 : 0;
} else {
@@ -230,7 +218,7 @@ int af_format_conversion_score(int dst_format, int src_format)
}
}
// Consider this the worst case.
if (FMT_DIFF(AF_FORMAT_POINT_MASK, dst_format, src_format))
if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format))
score -= 2048; // has to convert float<->int
return score;
}
+47 -91
View File
@@ -24,122 +24,78 @@
#define MPLAYER_AF_FORMAT_H
#include <stdbool.h>
#include <sys/types.h>
#include "bstr/bstr.h"
#if BYTE_ORDER == BIG_ENDIAN
#define AF_SELECT_LE_BE(LE, BE) BE
#else
#define AF_SELECT_LE_BE(LE, BE) LE
#endif
// Endianness
#define AF_FORMAT_BE (0<<0) // Big Endian
#define AF_FORMAT_LE (1<<0) // Little Endian
#define AF_FORMAT_END_MASK (1<<0)
#define AF_FORMAT_NE AF_SELECT_LE_BE(AF_FORMAT_LE, AF_FORMAT_BE)
#include "misc/bstr.h"
// Signed/unsigned
#define AF_FORMAT_SI (0<<1) // Signed
#define AF_FORMAT_US (1<<1) // Unsigned
#define AF_FORMAT_SIGN_MASK (1<<1)
#define AF_FORMAT_SI (0<<0) // Signed
#define AF_FORMAT_US (1<<0) // Unsigned
#define AF_FORMAT_SIGN_MASK (1<<0)
// Bits used
// Some code assumes they're sorted by size.
#define AF_FORMAT_8BIT (0<<3)
#define AF_FORMAT_16BIT (1<<3)
#define AF_FORMAT_24BIT (2<<3)
#define AF_FORMAT_32BIT (3<<3)
#define AF_FORMAT_64BIT (4<<3)
#define AF_FORMAT_BITS_MASK (7<<3)
#define AF_FORMAT_8BIT (0<<1)
#define AF_FORMAT_16BIT (1<<1)
#define AF_FORMAT_24BIT (2<<1)
#define AF_FORMAT_32BIT (3<<1)
#define AF_FORMAT_64BIT (4<<1)
#define AF_FORMAT_BITS_MASK (7<<1)
// Special flags refering to non pcm data (note: 1<<6, 2<<6, 5<<6 unused)
#define AF_FORMAT_S_MPEG2 (3<<6) // MPEG(2) audio
#define AF_FORMAT_S_AC3 (4<<6) // Dolby Digital AC3
#define AF_FORMAT_S_IEC61937 (6<<6)
#define AF_FORMAT_SPECIAL_MASK (7<<6)
// Fixed or floating point
#define AF_FORMAT_I (1<<9) // Int
#define AF_FORMAT_F (2<<9) // Foating point
#define AF_FORMAT_POINT_MASK (3<<9)
// Fixed/floating point/special
#define AF_FORMAT_I (1<<4) // Int
#define AF_FORMAT_F (2<<4) // Foating point
#define AF_FORMAT_S (4<<4) // special (IEC61937)
#define AF_FORMAT_TYPE_MASK (7<<4)
// Interleaving (planar formats have data for each channel in separate planes)
#define AF_FORMAT_INTERLEAVED (0<<11) // must be 0
#define AF_FORMAT_PLANAR (1<<11)
#define AF_FORMAT_INTERLEAVING_MASK (1<<11)
#define AF_FORMAT_INTERLEAVED (0<<7) // must be 0
#define AF_FORMAT_PLANAR (1<<7)
#define AF_FORMAT_INTERLEAVING_MASK (1<<7)
#define AF_FORMAT_S_CODEC(n) ((n)<<8)
#define AF_FORMAT_S_CODEC_MASK (15 <<8) // 16 codecs max.
#define AF_FORMAT_MASK ((1<<12)-1)
#define AF_INTP (AF_FORMAT_I|AF_FORMAT_PLANAR)
#define AF_FLTP (AF_FORMAT_F|AF_FORMAT_PLANAR)
#define AF_FORMAT_S_(n) (AF_FORMAT_S_CODEC(n)|AF_FORMAT_S|AF_FORMAT_16BIT)
// actual sample formats
enum af_format {
AF_FORMAT_UNKNOWN = 0,
AF_FORMAT_U8 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_8BIT|AF_FORMAT_NE),
AF_FORMAT_S8 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_8BIT|AF_FORMAT_NE),
AF_FORMAT_U16_LE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_U16_BE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_S16_LE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_S16_BE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_U24_LE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_24BIT|AF_FORMAT_LE),
AF_FORMAT_U24_BE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_24BIT|AF_FORMAT_BE),
AF_FORMAT_S24_LE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_24BIT|AF_FORMAT_LE),
AF_FORMAT_S24_BE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_24BIT|AF_FORMAT_BE),
AF_FORMAT_U32_LE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_32BIT|AF_FORMAT_LE),
AF_FORMAT_U32_BE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_32BIT|AF_FORMAT_BE),
AF_FORMAT_S32_LE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_LE),
AF_FORMAT_S32_BE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_BE),
AF_FORMAT_U8 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_8BIT),
AF_FORMAT_S8 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_8BIT),
AF_FORMAT_U16 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_16BIT),
AF_FORMAT_S16 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_16BIT),
AF_FORMAT_U24 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_24BIT),
AF_FORMAT_S24 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_24BIT),
AF_FORMAT_U32 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_32BIT),
AF_FORMAT_S32 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_32BIT),
AF_FORMAT_FLOAT_LE = (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_LE),
AF_FORMAT_FLOAT_BE = (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_BE),
AF_FORMAT_DOUBLE_LE = (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_LE),
AF_FORMAT_DOUBLE_BE = (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_BE),
AF_FORMAT_AC3_LE = (AF_FORMAT_S_AC3|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_AC3_BE = (AF_FORMAT_S_AC3|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_IEC61937_LE = (AF_FORMAT_S_IEC61937|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_IEC61937_BE = (AF_FORMAT_S_IEC61937|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_MPEG2 = (AF_FORMAT_S_MPEG2),
AF_FORMAT_FLOAT = (AF_FORMAT_F|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLE = (AF_FORMAT_F|AF_FORMAT_64BIT),
// Planar variants
AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT|AF_FORMAT_NE),
AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_NE),
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_NE),
AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT|AF_FORMAT_NE),
AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_64BIT|AF_FORMAT_NE),
AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT),
AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT),
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_32BIT),
AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_64BIT),
// Native endian variants
AF_FORMAT_U16 = AF_SELECT_LE_BE(AF_FORMAT_U16_LE, AF_FORMAT_U16_BE),
AF_FORMAT_S16 = AF_SELECT_LE_BE(AF_FORMAT_S16_LE, AF_FORMAT_S16_BE),
AF_FORMAT_U24 = AF_SELECT_LE_BE(AF_FORMAT_U24_LE, AF_FORMAT_U24_BE),
AF_FORMAT_S24 = AF_SELECT_LE_BE(AF_FORMAT_S24_LE, AF_FORMAT_S24_BE),
AF_FORMAT_U32 = AF_SELECT_LE_BE(AF_FORMAT_U32_LE, AF_FORMAT_U32_BE),
AF_FORMAT_S32 = AF_SELECT_LE_BE(AF_FORMAT_S32_LE, AF_FORMAT_S32_BE),
AF_FORMAT_FLOAT = AF_SELECT_LE_BE(AF_FORMAT_FLOAT_LE, AF_FORMAT_FLOAT_BE),
AF_FORMAT_DOUBLE = AF_SELECT_LE_BE(AF_FORMAT_DOUBLE_LE, AF_FORMAT_DOUBLE_BE),
AF_FORMAT_AC3 = AF_SELECT_LE_BE(AF_FORMAT_AC3_LE, AF_FORMAT_AC3_BE),
AF_FORMAT_IEC61937 = AF_SELECT_LE_BE(AF_FORMAT_IEC61937_LE, AF_FORMAT_IEC61937_BE),
// All of these use IEC61937 framing, and otherwise pretend to be like PCM.
AF_FORMAT_S_AAC = AF_FORMAT_S_(0),
AF_FORMAT_S_AC3 = AF_FORMAT_S_(1),
AF_FORMAT_S_DTS = AF_FORMAT_S_(2),
AF_FORMAT_S_DTSHD = AF_FORMAT_S_(3),
AF_FORMAT_S_EAC3 = AF_FORMAT_S_(4),
AF_FORMAT_S_MP3 = AF_FORMAT_S_(5),
AF_FORMAT_S_TRUEHD = AF_FORMAT_S_(6),
};
#define AF_FORMAT_IS_AC3(fmt) \
(((fmt) & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_S_AC3)
#define AF_FORMAT_IS_IEC61937(fmt) \
(AF_FORMAT_IS_AC3(fmt) || \
((fmt) & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_S_IEC61937)
#define AF_FORMAT_IS_SPECIAL(fmt) \
((fmt & AF_FORMAT_SPECIAL_MASK) != 0)
#define AF_FORMAT_IS_IEC61937(f) (((f) & AF_FORMAT_TYPE_MASK) == AF_FORMAT_S)
#define AF_FORMAT_IS_SPECIAL(f) AF_FORMAT_IS_IEC61937(f)
struct af_fmt_entry {
const char *name;
+10 -8
View File
@@ -36,7 +36,8 @@ struct mixer {
struct ao *ao;
struct af_stream *af;
// Static, dependent on ao/softvol settings
bool softvol; // use AO (true) or af_volume (false)
bool softvol; // use AO (false) or af_volume (true)
bool ao_softvol; // AO has private or per-app volume
bool emulate_mute; // if true, emulate mute with volume=0
// Last known values (possibly out of sync with reality)
float vol_l, vol_r;
@@ -71,7 +72,7 @@ bool mixer_audio_initialized(struct mixer *mixer)
float mixer_getneutralvolume(struct mixer *mixer)
{
// gain == 1
return 1.0 / mixer->opts->softvol_max * 100.0 * 100.0;
return mixer->softvol ? 1.0 / mixer->opts->softvol_max * 100.0 * 100.0 : 100;
}
static void checkvolume(struct mixer *mixer)
@@ -245,11 +246,13 @@ char *mixer_get_volume_restore_data(struct mixer *mixer)
static void probe_softvol(struct mixer *mixer)
{
mixer->ao_softvol =
ao_control(mixer->ao, AOCONTROL_HAS_SOFT_VOLUME, 0) == 1 ||
ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) == 1;
if (mixer->opts->softvol == SOFTVOL_AUTO) {
// No system-wide volume => fine with AO volume control.
mixer->softvol =
ao_control(mixer->ao, AOCONTROL_HAS_TEMP_VOLUME, 0) != 1 ||
ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) != 1;
mixer->softvol = !mixer->ao_softvol;
} else {
mixer->softvol = mixer->opts->softvol == SOFTVOL_YES;
}
@@ -282,8 +285,7 @@ static void restore_volume(struct mixer *mixer)
const char *prev_driver = mixer->driver;
mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao);
bool restore =
mixer->softvol || ao_control(ao, AOCONTROL_HAS_TEMP_VOLUME, 0) == 1;
bool restore = mixer->softvol || mixer->ao_softvol;
// Restore old parameters if volume won't survive reinitialization.
// But not if volume scale is possibly different.
@@ -361,7 +363,7 @@ void mixer_uninit_audio(struct mixer *mixer)
return;
checkvolume(mixer);
if (mixer->muted_by_us) {
if (mixer->muted_by_us && !mixer->softvol && !mixer->ao_softvol) {
/* Current audio output API combines playing the remaining buffered
* audio and uninitializing the AO into one operation, even though
* ideally unmute would happen between those two steps. We can't do
+183 -58
View File
@@ -29,15 +29,16 @@
#include "audio/format.h"
#include "audio/audio.h"
#include "input/input.h"
#include "options/options.h"
#include "options/m_config.h"
#include "osdep/timer.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_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;
@@ -60,18 +61,15 @@ static const struct ao_driver * const audio_out_drivers[] = {
#if HAVE_PULSE
&audio_out_pulse,
#endif
#if HAVE_SNDIO
&audio_out_sndio,
#endif
#if HAVE_ALSA
&audio_out_alsa,
#endif
#if HAVE_DSOUND
&audio_out_dsound,
#endif
#if HAVE_WASAPI
&audio_out_wasapi,
#endif
#if HAVE_DSOUND
&audio_out_dsound,
#endif
#if HAVE_OSS_AUDIO
&audio_out_oss,
#endif
@@ -87,6 +85,12 @@ static const struct ao_driver * const audio_out_drivers[] = {
#endif
#if HAVE_SDL1 || HAVE_SDL2
&audio_out_sdl,
#endif
#if HAVE_SNDIO
&audio_out_sndio,
#endif
#if HAVE_COREAUDIO
&audio_out_coreaudio_exclusive,
#endif
&audio_out_null,
// should not be auto-selected:
@@ -125,12 +129,34 @@ const struct m_obj_list ao_obj_list = {
.allow_trailer = true,
};
static struct ao *ao_create(bool probing, struct mpv_global *global,
struct input_ctx *input_ctx,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels,
char *name, char **args)
// Return true if the ao with the given name matches the opt (--audio-device
// contents). If opt is empty, matching always succeeds. If out_device is not
// NULL, it will be set to the implied audio device (or NULL).
static bool match_ao_driver(const char *ao_name, char *opt, char **out_device)
{
bstr ao_nameb = bstr0(ao_name);
bstr optb = bstr0(opt);
char *dummy;
if (!out_device)
out_device = &dummy;
*out_device = NULL;
if (!optb.len || bstr_equals0(optb, "auto"))
return true;
if (!bstr_startswith(optb, ao_nameb))
return false;
if (optb.len > ao_nameb.len && optb.start[ao_nameb.len] != '/')
return false;
char *split = strchr(opt, '/');
*out_device = split ? split + 1 : NULL;
return true;
}
static struct ao *ao_alloc(bool probing, struct mpv_global *global,
struct input_ctx *input_ctx, char *name, char **args)
{
struct MPOpts *opts = global->opts;
struct mp_log *log = mp_log_new(NULL, global->log, "ao");
struct m_obj_desc desc;
if (!m_obj_list_find(&desc, &ao_obj_list, bstr0(name))) {
@@ -143,33 +169,62 @@ static struct ao *ao_create(bool probing, struct mpv_global *global,
*ao = (struct ao) {
.driver = desc.p,
.probing = probing,
.encode_lavc_ctx = encode_lavc_ctx,
.input_ctx = input_ctx,
.samplerate = samplerate,
.channels = channels,
.format = format,
.log = mp_log_new(ao, log, name),
.def_buffer = opts->audio_buffer,
};
if (ao->driver->encode != !!ao->encode_lavc_ctx)
goto error;
struct m_config *config = m_config_from_obj_desc(ao, ao->log, &desc);
if (m_config_apply_defaults(config, name, global->opts->ao_defs) < 0)
if (m_config_apply_defaults(config, name, opts->ao_defs) < 0)
goto error;
if (m_config_set_obj_params(config, args) < 0)
goto error;
ao->priv = config->optstruct;
return ao;
error:
talloc_free(ao);
return NULL;
}
char *chmap = mp_chmap_to_str(&ao->channels);
static struct ao *ao_alloc_pb(bool probing, struct mpv_global *global,
struct input_ctx *input_ctx,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels,
char *name, char **args)
{
struct MPOpts *opts = global->opts;
struct ao *ao = ao_alloc(probing, global, input_ctx, name, args);
if (!ao)
return NULL;
ao->samplerate = samplerate;
ao->channels = channels;
ao->format = format;
ao->encode_lavc_ctx = encode_lavc_ctx;
if (ao->driver->encode != !!ao->encode_lavc_ctx) {
talloc_free(ao);
return NULL;
}
match_ao_driver(ao->driver->name, opts->audio_device, &ao->device);
ao->device = talloc_strdup(ao, ao->device);
ao->client_name = talloc_strdup(ao, opts->audio_client_name);
return ao;
}
static int ao_init(struct ao *ao)
{
MP_VERBOSE(ao, "requested format: %d Hz, %s channels, %s\n",
ao->samplerate, chmap, af_fmt_to_str(ao->format));
talloc_free(chmap);
ao->samplerate, mp_chmap_to_str(&ao->channels),
af_fmt_to_str(ao->format));
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);
if (ao->driver->init(ao) < 0)
goto error;
int r = ao->driver->init(ao);
if (r < 0)
return r;
ao->sstride = af_fmt2bps(ao->format);
ao->num_planes = 1;
@@ -180,18 +235,40 @@ static struct ao *ao_create(bool probing, struct mpv_global *global,
}
ao->bps = ao->samplerate * ao->sstride;
if (!ao->device_buffer && ao->driver->get_space) {
if (!ao->device_buffer && ao->driver->get_space)
ao->device_buffer = ao->driver->get_space(ao);
if (ao->device_buffer)
MP_VERBOSE(ao, "device buffer: %d samples.\n", ao->device_buffer);
}
ao->buffer = MPMAX(ao->device_buffer, MIN_BUFFER * ao->samplerate);
ao->buffer = MPMAX(ao->device_buffer, ao->def_buffer * ao->samplerate);
MP_VERBOSE(ao, "using soft-buffer of %d samples.\n", ao->buffer);
if (ao->api->init(ao) < 0)
goto error;
return ao->api->init(ao);
}
return ao;
error:
static struct ao *ao_create(bool probing, struct mpv_global *global,
struct input_ctx *input_ctx,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels,
char *name, char **args)
{
struct ao *ao = ao_alloc_pb(probing, global, input_ctx, encode_lavc_ctx,
samplerate, format, channels, name, args);
if (ao && ao_init(ao) >= 0)
return ao;
// Silly exception for coreaudio spdif redirection
if (ao && ao->redirect) {
char redirect[80], device[80];
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
snprintf(device, sizeof(device), "%s", ao->device ? ao->device : "");
talloc_free(ao);
ao = ao_alloc_pb(probing, global, input_ctx, encode_lavc_ctx,
samplerate, format, channels, redirect, args);
if (ao) {
ao->device = talloc_strdup(ao, device);
if (ao_init(ao) >= 0)
return ao;
}
}
talloc_free(ao);
return NULL;
}
@@ -201,9 +278,10 @@ struct ao *ao_init_best(struct mpv_global *global,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels)
{
struct MPOpts *opts = global->opts;
struct mp_log *log = mp_log_new(NULL, global->log, "ao");
struct ao *ao = NULL;
struct m_obj_settings *ao_list = global->opts->audio_driver_list;
struct m_obj_settings *ao_list = opts->audio_driver_list;
if (ao_list && ao_list[0].name) {
for (int n = 0; ao_list[n].name; n++) {
if (strlen(ao_list[n].name) == 0)
@@ -220,15 +298,21 @@ struct ao *ao_init_best(struct mpv_global *global,
}
goto done;
}
autoprobe:
autoprobe: ;
// now try the rest...
bool matched_dev = false;
for (int i = 0; audio_out_drivers[i]; i++) {
char *name = (char *)audio_out_drivers[i]->name;
if (!match_ao_driver(name, opts->audio_device, NULL))
continue;
matched_dev = true;
ao = ao_create(true, global, input_ctx, encode_lavc_ctx,
samplerate, format, channels,
(char *)audio_out_drivers[i]->name, NULL);
samplerate, format, channels, name, NULL);
if (ao)
goto done;
}
if (!matched_dev)
mp_err(log, "--audio-device option refers to missing output driver.\n");
done:
talloc_free(log);
return ao;
@@ -255,16 +339,7 @@ int ao_play(struct ao *ao, void **data, int samples, int flags)
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg)
{
switch (cmd) {
case AOCONTROL_HAS_TEMP_VOLUME:
return !ao->no_persistent_volume;
case AOCONTROL_HAS_PER_APP_VOLUME:
return !!ao->per_application_mixer;
default:
if (ao->api->control)
return ao->api->control(ao, cmd, arg);
}
return CONTROL_UNKNOWN;
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.
@@ -309,27 +384,32 @@ void ao_resume(struct ao *ao)
ao->api->resume(ao);
}
// Be careful with locking
void ao_wait_drain(struct ao *ao)
{
// This is probably not entirely accurate, but good enough.
mp_sleep_us(ao_get_delay(ao) * 1000000);
ao_reset(ao);
}
// Block until the current audio buffer has played completely.
void ao_drain(struct ao *ao)
{
if (ao->api->drain) {
if (ao->api->drain)
ao->api->drain(ao);
} else {
ao_wait_drain(ao);
}
}
bool ao_eof_reached(struct ao *ao)
{
return ao_get_delay(ao) < AO_EOF_DELAY;
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)
{
int actual_events = 0;
if (atomic_load(&ao->request_reload)) // don't need to reset it
actual_events |= AO_EVENT_RELOAD;
return actual_events & events;
}
// Request that the player core destroys and recreates the AO.
void ao_request_reload(struct ao *ao)
{
atomic_store(&ao->request_reload, true);
mp_input_wakeup(ao->input_ctx);
}
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
@@ -368,3 +448,48 @@ bool ao_untimed(struct ao *ao)
{
return ao->untimed;
}
struct ao_device_list *ao_get_device_list(struct mpv_global *global)
{
struct ao_device_list *list = talloc_zero(NULL, struct ao_device_list);
MP_TARRAY_APPEND(list, list->devices, list->num_devices,
(struct ao_device_desc){"auto", "Autoselect device"});
for (int n = 0; audio_out_drivers[n]; n++) {
const struct ao_driver *d = audio_out_drivers[n];
if (d == &audio_out_null)
break; // don't add unsafe/special entries
struct ao *ao = ao_alloc(true, global, NULL, (char *)d->name, NULL);
if (!ao)
continue;
int num = list->num_devices;
if (d->list_devs)
d->list_devs(ao, list);
// Add at least a default entry
if (list->num_devices == num)
ao_device_list_add(list, ao, &(struct ao_device_desc){"", "Default"});
talloc_free(ao);
}
return list;
}
void ao_device_list_add(struct ao_device_list *list, struct ao *ao,
struct ao_device_desc *e)
{
struct ao_device_desc c = *e;
const char *dname = ao->driver->name;
c.name = c.name[0] ? talloc_asprintf(list, "%s/%s", dname, c.name)
: talloc_strdup(list, dname);
c.desc = talloc_strdup(list, c.desc);
MP_TARRAY_APPEND(list, list->devices, list->num_devices, c);
}
void ao_print_devices(struct mpv_global *global, struct mp_log *log)
{
struct ao_device_list *list = ao_get_device_list(global);
mp_info(log, "List of detected audio devices:\n");
for (int n = 0; n < list->num_devices; n++) {
struct ao_device_desc *desc = &list->devices[n];
mp_info(log, " '%s' (%s)\n", desc->name, desc->desc);
}
talloc_free(list);
}
+23 -2
View File
@@ -21,7 +21,7 @@
#include <stdbool.h>
#include "bstr/bstr.h"
#include "misc/bstr.h"
#include "common/common.h"
#include "audio/chmap.h"
#include "audio/chmap_sel.h"
@@ -36,7 +36,9 @@ enum aocontrol {
AOCONTROL_SET_MUTE,
// Has char* as argument, which contains the desired stream title.
AOCONTROL_UPDATE_STREAM_TITLE,
AOCONTROL_HAS_TEMP_VOLUME,
// the AO does the equivalent of af_volume (return CONTROL_TRUE if yes)
AOCONTROL_HAS_SOFT_VOLUME,
// like above, but volume persists (per app), mpv won't restore volume
AOCONTROL_HAS_PER_APP_VOLUME,
};
@@ -44,11 +46,25 @@ enum aocontrol {
// data might be written again, instead of closing the AO.
#define AOPLAY_FINAL_CHUNK 1
enum {
AO_EVENT_RELOAD = 1,
};
typedef struct ao_control_vol {
float left;
float right;
} ao_control_vol_t;
struct ao_device_desc {
const char *name; // symbolic name; will be set on ao->device
const char *desc; // verbose human readable name
};
struct ao_device_list {
struct ao_device_desc *devices;
int num_devices;
};
struct ao;
struct mpv_global;
struct input_ctx;
@@ -73,5 +89,10 @@ void ao_pause(struct ao *ao);
void ao_resume(struct ao *ao);
void ao_drain(struct ao *ao);
bool ao_eof_reached(struct ao *ao);
int ao_query_and_reset_events(struct ao *ao, int events);
void ao_request_reload(struct ao *ao);
struct ao_device_list *ao_get_device_list(struct mpv_global *global);
void ao_print_devices(struct mpv_global *global, struct mp_log *log);
#endif /* MPLAYER_AUDIO_OUT_H */
+338 -166
View File
@@ -31,7 +31,6 @@
#include <sys/time.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
@@ -39,12 +38,13 @@
#include "options/options.h"
#include "options/m_option.h"
#include "common/msg.h"
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
#include "osdep/endian.h"
#include <alsa/asoundlib.h>
#define HAVE_CHMAP_API \
(defined(SND_CHMAP_API_VERSION) && SND_CHMAP_API_VERSION >= (1 << 16))
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
@@ -54,7 +54,7 @@ struct priv {
snd_pcm_format_t alsa_fmt;
int can_pause;
snd_pcm_sframes_t prepause_frames;
float delay_before_pause;
double delay_before_pause;
int buffersize; // in frames
int outburst; // in frames
@@ -64,6 +64,7 @@ struct priv {
char *cfg_mixer_name;
int cfg_mixer_index;
int cfg_resample;
int cfg_ni;
};
#define BUFFER_TIME 250000 // 250ms
@@ -77,10 +78,12 @@ struct priv {
} \
} while (0)
static float get_delay(struct ao *ao);
static void uninit(struct ao *ao);
#define CHECK_ALSA_WARN(message) \
do { \
if (err < 0) \
MP_WARN(ao, "%s: %s\n", (message), snd_strerror(err)); \
} while (0)
/* to set/get/query special features/parameters */
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
@@ -99,13 +102,11 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
long get_vol, set_vol;
float f_multi;
if (AF_FORMAT_IS_IEC61937(ao->format))
if (AF_FORMAT_IS_SPECIAL(ao->format))
return CONTROL_FALSE;
//allocate simple id
snd_mixer_selem_id_alloca(&sid);
//sets simple-mixer index and name
snd_mixer_selem_id_set_index(sid, p->cfg_mixer_index);
snd_mixer_selem_id_set_name(sid, p->cfg_mixer_name);
@@ -137,7 +138,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
ao_control_vol_t *vol = arg;
set_vol = vol->left / f_multi + pmin + 0.5;
//setting channels
err = snd_mixer_selem_set_playback_volume
(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol);
CHECK_ALSA_ERROR("Error setting left channel");
@@ -149,8 +149,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol);
CHECK_ALSA_ERROR("Error setting right channel");
MP_DBG(ao, "right=%li, pmin=%li, pmax=%li, mult=%f\n",
set_vol, pmin, pmax,
f_multi);
set_vol, pmin, pmax, f_multi);
break;
}
case AOCONTROL_GET_VOLUME: {
@@ -208,25 +207,15 @@ alsa_error:
static const int mp_to_alsa_format[][2] = {
{AF_FORMAT_S8, SND_PCM_FORMAT_S8},
{AF_FORMAT_U8, SND_PCM_FORMAT_U8},
{AF_FORMAT_U16_LE, SND_PCM_FORMAT_U16_LE},
{AF_FORMAT_U16_BE, SND_PCM_FORMAT_U16_BE},
{AF_FORMAT_S16_LE, SND_PCM_FORMAT_S16_LE},
{AF_FORMAT_S16_BE, SND_PCM_FORMAT_S16_BE},
{AF_FORMAT_U32_LE, SND_PCM_FORMAT_U32_LE},
{AF_FORMAT_U32_BE, SND_PCM_FORMAT_U32_BE},
{AF_FORMAT_S32_LE, SND_PCM_FORMAT_S32_LE},
{AF_FORMAT_S32_BE, SND_PCM_FORMAT_S32_BE},
{AF_FORMAT_U24_LE, SND_PCM_FORMAT_U24_3LE},
{AF_FORMAT_U24_BE, SND_PCM_FORMAT_U24_3BE},
{AF_FORMAT_S24_LE, SND_PCM_FORMAT_S24_3LE},
{AF_FORMAT_S24_BE, SND_PCM_FORMAT_S24_3BE},
{AF_FORMAT_FLOAT_LE, SND_PCM_FORMAT_FLOAT_LE},
{AF_FORMAT_FLOAT_BE, SND_PCM_FORMAT_FLOAT_BE},
{AF_FORMAT_AC3_LE, SND_PCM_FORMAT_S16_LE},
{AF_FORMAT_AC3_BE, SND_PCM_FORMAT_S16_BE},
{AF_FORMAT_IEC61937_LE, SND_PCM_FORMAT_S16_LE},
{AF_FORMAT_IEC61937_BE, SND_PCM_FORMAT_S16_BE},
{AF_FORMAT_MPEG2, SND_PCM_FORMAT_MPEG},
{AF_FORMAT_U16, SND_PCM_FORMAT_U16},
{AF_FORMAT_S16, SND_PCM_FORMAT_S16},
{AF_FORMAT_U32, SND_PCM_FORMAT_U32},
{AF_FORMAT_S32, SND_PCM_FORMAT_S32},
{AF_FORMAT_U24,
MP_SELECT_LE_BE(SND_PCM_FORMAT_U24_3LE, SND_PCM_FORMAT_U24_3BE)},
{AF_FORMAT_S24,
MP_SELECT_LE_BE(SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3BE)},
{AF_FORMAT_FLOAT, SND_PCM_FORMAT_FLOAT},
{AF_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN},
};
@@ -240,6 +229,98 @@ static int find_alsa_format(int af_format)
return SND_PCM_FORMAT_UNKNOWN;
}
#if HAVE_CHMAP_API
static const int alsa_to_mp_channels[][2] = {
{SND_CHMAP_FL, MP_SP(FL)},
{SND_CHMAP_FR, MP_SP(FR)},
{SND_CHMAP_RL, MP_SP(BL)},
{SND_CHMAP_RR, MP_SP(BR)},
{SND_CHMAP_FC, MP_SP(FC)},
{SND_CHMAP_LFE, MP_SP(LFE)},
{SND_CHMAP_SL, MP_SP(SL)},
{SND_CHMAP_SR, MP_SP(SR)},
{SND_CHMAP_RC, MP_SP(BC)},
{SND_CHMAP_FLC, MP_SP(FLC)},
{SND_CHMAP_FRC, MP_SP(FRC)},
{SND_CHMAP_FLW, MP_SP(WL)},
{SND_CHMAP_FRW, MP_SP(WR)},
{SND_CHMAP_TC, MP_SP(TC)},
{SND_CHMAP_TFL, MP_SP(TFL)},
{SND_CHMAP_TFR, MP_SP(TFR)},
{SND_CHMAP_TFC, MP_SP(TFC)},
{SND_CHMAP_TRL, MP_SP(TBL)},
{SND_CHMAP_TRR, MP_SP(TBR)},
{SND_CHMAP_TRC, MP_SP(TBC)},
{SND_CHMAP_MONO, MP_SP(FC)},
{SND_CHMAP_LAST, MP_SPEAKER_ID_COUNT}
};
static int find_mp_channel(int alsa_channel)
{
for (int i = 0; alsa_to_mp_channels[i][1] != MP_SPEAKER_ID_COUNT; i++) {
if (alsa_to_mp_channels[i][0] == alsa_channel)
return alsa_to_mp_channels[i][1];
}
return MP_SPEAKER_ID_COUNT;
}
static int find_alsa_channel(int mp_channel)
{
for (int i = 0; alsa_to_mp_channels[i][1] != MP_SPEAKER_ID_COUNT; i++) {
if (alsa_to_mp_channels[i][1] == mp_channel)
return alsa_to_mp_channels[i][0];
}
return SND_CHMAP_UNKNOWN;
}
static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
{
struct priv *p = ao->priv;
struct mp_chmap_sel chmap_sel = {.tmp = p};
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps(p->alsa);
if (!maps)
return false;
for (int i = 0; maps[i] != NULL; i++) {
if (maps[i]->map.channels > MP_NUM_CHANNELS) {
MP_VERBOSE(ao, "skipping ALSA channel map with too many channels.\n");
continue;
}
struct mp_chmap entry = {.num = maps[i]->map.channels};
for (int c = 0; c < entry.num; c++)
entry.speaker[c] = find_mp_channel(maps[i]->map.pos[c]);
if (mp_chmap_is_valid(&entry)) {
MP_VERBOSE(ao, "Got supported channel map: %s (type %s)\n",
mp_chmap_to_str(&entry),
snd_pcm_chmap_type_name(maps[i]->type));
mp_chmap_sel_add_map(&chmap_sel, &entry);
} else {
char tmp[128];
if (snd_pcm_chmap_print(&maps[i]->map, sizeof(tmp), tmp) > 0)
MP_VERBOSE(ao, "skipping unknown ALSA channel map: %s\n", tmp);
}
}
snd_pcm_free_chmaps(maps);
return ao_chmap_sel_adjust(ao, &chmap_sel, chmap);
}
#else /* HAVE_CHMAP_API */
static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
{
return false;
}
#endif /* else HAVE_CHMAP_API */
// Lists device names and their implied channel map.
// The second item must be resolvable with mp_chmap_from_str().
// Source: http://www.alsa-project.org/main/index.php/DeviceNames
@@ -257,11 +338,9 @@ static const char *const device_channel_layouts[][2] = {
{"surround71", "fl-fr-bl-br-fc-lfe-sl-sr"},
};
#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
#define NUM_ALSA_CHMAPS MP_ARRAY_SIZE(device_channel_layouts)
#define NUM_ALSA_CHMAPS ARRAY_LEN(device_channel_layouts)
static const char *select_chmap(struct ao *ao)
static const char *select_chmap(struct ao *ao, struct mp_chmap *chmap)
{
struct mp_chmap_sel sel = {0};
struct mp_chmap maps[NUM_ALSA_CHMAPS];
@@ -270,18 +349,16 @@ static const char *select_chmap(struct ao *ao)
mp_chmap_sel_add_map(&sel, &maps[n]);
};
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return NULL;
if (!ao_chmap_sel_adjust(ao, &sel, chmap))
return "default";
for (int n = 0; n < NUM_ALSA_CHMAPS; n++) {
if (mp_chmap_equals(&ao->channels, &maps[n]))
if (mp_chmap_equals(chmap, &maps[n]))
return device_channel_layouts[n][0];
}
char *name = mp_chmap_to_str(&ao->channels);
MP_ERR(ao, "channel layout %s (%d ch) not supported.\n",
name, ao->channels.num);
talloc_free(name);
mp_chmap_to_str(chmap), chmap->num);
return "default";
}
@@ -302,34 +379,44 @@ static int map_iec958_srate(int srate)
}
}
// ALSA device strings can have parameters. They are usually appended to the
// device name. Since there can be various forms, and we (sometimes) want to
// append them to unknown device strings, which possibly already include params.
static char *append_params(void *ta_parent, const char *device, const char *p)
{
if (!p || !p[0])
return talloc_strdup(ta_parent, device);
int len = strlen(device);
char *end = strchr(device, ':');
if (!end) {
/* no existing parameters: add it behind device name */
return talloc_asprintf(ta_parent, "%s:%s", device, p);
} else if (end[1] == '\0') {
/* ":" but no parameters */
return talloc_asprintf(ta_parent, "%s%s", device, p);
} else if (end[1] == '{' && device[len - 1] == '}') {
/* parameters in config syntax: add it inside the { } block */
return talloc_asprintf(ta_parent, "%.*s %s}", len - 1, device, p);
} else {
/* a simple list of parameters: add it at the end of the list */
return talloc_asprintf(ta_parent, "%s,%s", device, p);
}
abort();
}
static int try_open_device(struct ao *ao, const char *device, int open_mode)
{
struct priv *p = ao->priv;
if (AF_FORMAT_IS_IEC61937(ao->format)) {
void *tmp = talloc_new(NULL);
/* to set the non-audio bit, use AES0=6 */
char *params = talloc_asprintf(tmp,
"AES0=%d,AES1=%d,AES2=0,AES3=%d",
IEC958_AES0_NONAUDIO | IEC958_AES0_PRO_EMPHASIS_NONE,
IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
map_iec958_srate(ao->samplerate));
const char *ac3_device = device;
int len = strlen(device);
char *end = strchr(device, ':');
if (!end) {
/* no existing parameters: add it behind device name */
ac3_device = talloc_asprintf(tmp, "%s:%s", device, params);
} else if (end[1] == '\0') {
/* ":" but no parameters */
ac3_device = talloc_asprintf(tmp, "%s%s", device, params);
} else if (end[1] == '{' && device[len - 1] == '}') {
/* parameters in config syntax: add it inside the { } block */
ac3_device = talloc_asprintf(tmp, "%.*s %s}", len - 1, device, params);
} else {
/* a simple list of parameters: add it at the end of the list */
ac3_device = talloc_asprintf(tmp, "%s,%s", device, params);
}
const char *ac3_device = append_params(tmp, device, params);
int err = snd_pcm_open
(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, open_mode);
talloc_free(tmp);
@@ -340,48 +427,56 @@ static int try_open_device(struct ao *ao, const char *device, int open_mode)
return snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, open_mode);
}
/*
open & setup audio device
return: 0=success -1=fail
*/
static int init(struct ao *ao)
static void uninit(struct ao *ao)
{
int err;
snd_pcm_uframes_t chunk_size;
snd_pcm_uframes_t bufsize;
snd_pcm_uframes_t boundary;
struct priv *p = ao->priv;
/* switch for spdif
* sets opening sequence for SPDIF
* sets also the playback and other switches 'on the fly'
* while opening the abstract alias for the spdif subdevice
* 'iec958'
*/
if (p->alsa) {
int err;
err = snd_pcm_close(p->alsa);
CHECK_ALSA_ERROR("pcm close error");
}
alsa_error: ;
}
static int init(struct ao *ao)
{
struct priv *p = ao->priv;
int err;
if (!p->cfg_ni)
ao->format = af_fmt_from_planar(ao->format);
struct mp_chmap implied_chmap = ao->channels;
const char *device;
if (AF_FORMAT_IS_IEC61937(ao->format)) {
device = "iec958";
MP_VERBOSE(ao, "playing AC3/iec61937/iec958, %i channels\n",
ao->channels.num);
} else {
device = select_chmap(ao);
if (strcmp(device, "default") != 0 && (ao->format & AF_FORMAT_F)) {
// hack - use the converter plugin (why the heck?)
device = select_chmap(ao, &implied_chmap);
// Not-default likely means a hw device - enable software conversions.
if (strcmp(device, "default") != 0)
device = talloc_asprintf(ao, "plug:%s", device);
}
}
const char *old_dev = device;
if (ao->device)
device = ao->device;
if (p->cfg_device && p->cfg_device[0])
device = p->cfg_device;
bool user_set_device = device != old_dev; // not strcmp()
MP_VERBOSE(ao, "using device: %s\n", device);
MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version());
int open_mode = p->cfg_block ? 0 : SND_PCM_NONBLOCK;
//modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
err = try_open_device(ao, device, open_mode);
err = try_open_device(ao, device, p->cfg_block ? 0 : SND_PCM_NONBLOCK);
if (err < 0) {
if (err != -EBUSY && !p->cfg_block) {
if (err == -EBUSY && !user_set_device && strcmp(device, "default") != 0) {
MP_WARN(ao, "Device '%s' busy, retrying default.\n", device);
err = try_open_device(ao, "default", 0);
} else if (err != -EBUSY && !p->cfg_block) {
MP_WARN(ao, "Open in nonblock-mode "
"failed, trying to open in block-mode.\n");
err = try_open_device(ao, device, 0);
@@ -402,11 +497,18 @@ static int init(struct ao *ao)
snd_pcm_hw_params_alloca(&alsa_hwparams);
snd_pcm_sw_params_alloca(&alsa_swparams);
// setting hw-parameters
err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to get initial parameters");
p->alsa_fmt = find_alsa_format(ao->format);
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (ao->format == AF_FORMAT_S_MP3) {
p->alsa_fmt = SND_PCM_FORMAT_MPEG;
} else {
p->alsa_fmt = SND_PCM_FORMAT_S16;
}
} else {
p->alsa_fmt = find_alsa_format(ao->format);
}
if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) {
p->alsa_fmt = SND_PCM_FORMAT_S16;
ao->format = AF_FORMAT_S16;
@@ -414,15 +516,12 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt);
if (err < 0) {
if (AF_FORMAT_IS_IEC61937(ao->format))
CHECK_ALSA_ERROR("Unable to set IEC61937 format");
MP_INFO(ao, "Format %s is not supported by hardware, trying default.\n",
af_fmt_to_str(ao->format));
p->alsa_fmt = SND_PCM_FORMAT_S16_LE;
if (AF_FORMAT_IS_AC3(ao->format))
ao->format = AF_FORMAT_AC3_LE;
else if (AF_FORMAT_IS_IEC61937(ao->format))
ao->format = AF_FORMAT_IEC61937_LE;
else
ao->format = AF_FORMAT_S16_LE;
p->alsa_fmt = SND_PCM_FORMAT_S16;
ao->format = AF_FORMAT_S16;
}
err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt);
@@ -439,11 +538,24 @@ static int init(struct ao *ao)
}
CHECK_ALSA_ERROR("Unable to set access type");
struct mp_chmap dev_chmap = ao->channels;
if (query_chmaps(ao, &dev_chmap)) {
ao->channels = dev_chmap;
} else {
dev_chmap.num = 0;
ao->channels = implied_chmap;
}
int num_channels = ao->channels.num;
err = snd_pcm_hw_params_set_channels_near
(p->alsa, alsa_hwparams, &num_channels);
CHECK_ALSA_ERROR("Unable to set channels");
if (num_channels > MP_NUM_CHANNELS) {
MP_FATAL(ao, "Too many audio channels (%d).\n", num_channels);
goto alsa_error;
}
if (num_channels != ao->channels.num) {
MP_ERR(ao, "Couldn't get requested number of channels.\n");
mp_chmap_from_channels_alsa(&ao->channels, num_channels);
@@ -462,25 +574,82 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_set_buffer_time_near
(p->alsa, alsa_hwparams, &(unsigned int){BUFFER_TIME}, NULL);
CHECK_ALSA_ERROR("Unable to set buffer time near");
CHECK_ALSA_WARN("Unable to set buffer time near");
err = snd_pcm_hw_params_set_periods_near
(p->alsa, alsa_hwparams, &(unsigned int){FRAGCOUNT}, NULL);
CHECK_ALSA_ERROR("Unable to set periods");
CHECK_ALSA_WARN("Unable to set periods");
/* finally install hardware parameters */
err = snd_pcm_hw_params(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to set hw-parameters");
// end setting hw-params
/* end setting hw-params */
// gets buffersize for control
#if HAVE_CHMAP_API
if (mp_chmap_is_valid(&dev_chmap)) {
snd_pcm_chmap_t *alsa_chmap =
calloc(1, sizeof(*alsa_chmap) +
sizeof(alsa_chmap->pos[0]) * dev_chmap.num);
if (!alsa_chmap)
goto alsa_error;
alsa_chmap->channels = dev_chmap.num;
for (int c = 0; c < dev_chmap.num; c++)
alsa_chmap->pos[c] = find_alsa_channel(dev_chmap.speaker[c]);
char tmp[128];
if (snd_pcm_chmap_print(alsa_chmap, sizeof(tmp), tmp) > 0)
MP_VERBOSE(ao, "trying to set ALSA channel map: %s\n", tmp);
err = snd_pcm_set_chmap(p->alsa, alsa_chmap);
if (err == -ENXIO) {
MP_WARN(ao, "Device does not support requested channel map\n");
} else {
CHECK_ALSA_WARN("Channel map setup failed");
}
}
snd_pcm_chmap_t *alsa_chmap = snd_pcm_get_chmap(p->alsa);
if (alsa_chmap) {
char tmp[128];
if (snd_pcm_chmap_print(alsa_chmap, sizeof(tmp), tmp) > 0)
MP_VERBOSE(ao, "channel map reported by ALSA: %s\n", tmp);
struct mp_chmap chmap = {.num = alsa_chmap->channels};
for (int c = 0; c < chmap.num; c++)
chmap.speaker[c] = find_mp_channel(alsa_chmap->pos[c]);
MP_VERBOSE(ao, "which we understand as: %s\n", mp_chmap_to_str(&chmap));
if (mp_chmap_is_valid(&chmap)) {
if (mp_chmap_equals(&chmap, &ao->channels)) {
MP_VERBOSE(ao, "which is what we requested.\n");
} else if (chmap.num == ao->channels.num) {
MP_VERBOSE(ao, "using the ALSA channel map.\n");
ao->channels = chmap;
} else {
MP_WARN(ao, "ALSA channel map conflicts with channel count!\n");
}
} else {
MP_WARN(ao, "Got unknown channel map from ALSA.\n");
}
if (ao->channels.num == 1)
ao->channels.speaker[0] = MP_SP(FC);
free(alsa_chmap);
}
#endif
snd_pcm_uframes_t bufsize;
err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize);
CHECK_ALSA_ERROR("Unable to get buffersize");
p->buffersize = bufsize;
MP_VERBOSE(ao, "got buffersize=%i samples\n", p->buffersize);
snd_pcm_uframes_t chunk_size;
err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL);
CHECK_ALSA_ERROR("Unable to get period size");
@@ -491,6 +660,7 @@ static int init(struct ao *ao)
err = snd_pcm_sw_params_current(p->alsa, alsa_swparams);
CHECK_ALSA_ERROR("Unable to get sw-parameters");
snd_pcm_uframes_t boundary;
err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary);
CHECK_ALSA_ERROR("Unable to get boundary");
@@ -510,40 +680,17 @@ static int init(struct ao *ao)
CHECK_ALSA_ERROR("Unable to set silence size");
err = snd_pcm_sw_params(p->alsa, alsa_swparams);
CHECK_ALSA_ERROR("Unable to get sw-parameters");
CHECK_ALSA_ERROR("Unable to set sw-parameters");
/* end setting sw-params */
p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bps/%d samples buffer/%s\n",
ao->samplerate, ao->channels.num, af_fmt2bits(ao->format),
p->buffersize, snd_pcm_format_description(p->alsa_fmt));
return 0;
alsa_error:
uninit(ao);
return -1;
} // end init
/* close audio device */
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->alsa) {
int err;
err = snd_pcm_close(p->alsa);
CHECK_ALSA_ERROR("pcm close error");
MP_VERBOSE(ao, "uninit: pcm closed\n");
}
alsa_error:
p->alsa = NULL;
}
static void drain(struct ao *ao)
@@ -552,6 +699,46 @@ static void drain(struct ao *ao)
snd_pcm_drain(p->alsa);
}
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
snd_pcm_status_t *status;
int err;
snd_pcm_status_alloca(&status);
err = snd_pcm_status(p->alsa, status);
CHECK_ALSA_ERROR("cannot get pcm status");
unsigned space = snd_pcm_status_get_avail(status);
if (space > p->buffersize) // Buffer underrun?
space = p->buffersize;
return space / p->outburst * p->outburst;
alsa_error:
return 0;
}
/* delay in seconds between first and last sample in buffer */
static double get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
snd_pcm_sframes_t delay;
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_PAUSED)
return p->delay_before_pause;
if (snd_pcm_delay(p->alsa, &delay) < 0)
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;
}
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
@@ -568,7 +755,7 @@ static void audio_pause(struct ao *ao)
if (snd_pcm_delay(p->alsa, &p->prepause_frames) < 0
|| p->prepause_frames < 0)
p->prepause_frames = 0;
p->delay_before_pause = p->prepause_frames / (float)ao->samplerate;
p->delay_before_pause = p->prepause_frames / (double)ao->samplerate;
err = snd_pcm_drop(p->alsa);
CHECK_ALSA_ERROR("pcm drop error");
@@ -605,7 +792,6 @@ static void audio_resume(struct ao *ao)
alsa_error: ;
}
/* stop playing and empty buffers (for seeking/pause) */
static void reset(struct ao *ao)
{
struct priv *p = ao->priv;
@@ -638,8 +824,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
res = snd_pcm_writei(p->alsa, data[0], samples);
}
if (res == -EINTR) {
/* nothing to do */
if (res == -EINTR || res == -EAGAIN) { /* retry */
res = 0;
} else if (res == -ESTRPIPE) { /* suspend */
audio_resume(ao);
@@ -658,46 +843,6 @@ alsa_error:
return -1;
}
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
snd_pcm_status_t *status;
int err;
snd_pcm_status_alloca(&status);
err = snd_pcm_status(p->alsa, status);
CHECK_ALSA_ERROR("cannot get pcm status");
unsigned space = snd_pcm_status_get_avail(status);
if (space > p->buffersize) // Buffer underrun?
space = p->buffersize;
return space;
alsa_error:
return 0;
}
/* delay in seconds between first and last sample in buffer */
static float get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
snd_pcm_sframes_t delay;
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_PAUSED)
return p->delay_before_pause;
if (snd_pcm_delay(p->alsa, &delay) < 0)
return 0;
if (delay < 0) {
/* underrun - move the application pointer forward to catch up */
snd_pcm_forward(p->alsa, -delay);
delay = 0;
}
return (float)delay / (float)ao->samplerate;
}
#define MAX_POLL_FDS 20
static int audio_wait(struct ao *ao, pthread_mutex_t *lock)
{
@@ -732,10 +877,34 @@ alsa_error:
return -1;
}
static void list_devs(struct ao *ao, struct ao_device_list *list)
{
void **hints;
if (snd_device_name_hint(-1, "pcm", &hints) < 0)
return;
for (int n = 0; hints[n]; n++) {
char *name = snd_device_name_get_hint(hints[n], "NAME");
char *desc = snd_device_name_get_hint(hints[n], "DESC");
char *io = snd_device_name_get_hint(hints[n], "IOID");
if (io && strcmp(io, "Output") != 0)
continue;
char desc2[1024];
snprintf(desc2, sizeof(desc2), "%s", desc ? desc : "");
for (int i = 0; desc2[i]; i++) {
if (desc2[i] == '\n')
desc2[i] = '/';
}
ao_device_list_add(list, ao, &(struct ao_device_desc){name, desc2});
}
snd_device_name_free_hint(hints);
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_alsa = {
.description = "ALSA-0.9.x-1.x audio output",
.description = "ALSA audio output",
.name = "alsa",
.init = init,
.uninit = uninit,
@@ -749,12 +918,14 @@ const struct ao_driver audio_out_alsa = {
.drain = drain,
.wait = audio_wait,
.wakeup = ao_wakeup_poll,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.cfg_block = 1,
.cfg_mixer_device = "default",
.cfg_mixer_name = "Master",
.cfg_mixer_index = 0,
.cfg_ni = 0,
},
.options = (const struct m_option[]) {
OPT_STRING("device", cfg_device, 0),
@@ -763,6 +934,7 @@ const struct ao_driver audio_out_alsa = {
OPT_STRING("mixer-device", cfg_mixer_device, 0),
OPT_STRING("mixer-name", cfg_mixer_name, 0),
OPT_INTRANGE("mixer-index", cfg_mixer_index, 0, 0, 99),
OPT_FLAG("non-interleaved", cfg_ni, 0),
{0}
},
};
+274 -520
View File
@@ -1,39 +1,21 @@
/*
* CoreAudio audio output driver for Mac OS X
* This file is part of mpv.
*
* original copyright (C) Timothy J. Wood - Aug 2000
* ported to MPlayer libao2 by Dan Christiansen
*
* Chris Roccati
* Stefano Pigozzi
*
* The S/PDIF part of the code is based on the auhal audio output
* module from VideoLAN:
* Copyright (c) 2006 Derk-Jan Hartman <hartman at videolan dot org>
*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* 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.
*
* MPlayer is distributed in the hope that it will be useful,
* 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
* along with MPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* The MacOS X CoreAudio framework doesn't mesh as simply as some
* simpler frameworks do. This is due to the fact that CoreAudio pulls
* audio samples rather than having them pushed at it (which is nice
* when you are wanting to do good buffering of audio).
*/
#include <CoreAudio/HostTime.h>
#include "config.h"
#include "ao.h"
@@ -46,61 +28,60 @@
#include "audio/out/ao_coreaudio_properties.h"
#include "audio/out/ao_coreaudio_utils.h"
static void audio_pause(struct ao *ao);
static void audio_resume(struct ao *ao);
static void reset(struct ao *ao);
struct priv {
AudioDeviceID device;
AudioUnit audio_unit;
static void print_buffer(struct ao *ao, struct mp_ring *buffer)
uint64_t hw_latency_us;
};
bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
struct mp_chmap *chmap);
static int64_t ca_frames_to_us(struct ao *ao, uint32_t frames)
{
void *tctx = talloc_new(NULL);
MP_VERBOSE(ao, "%s\n", mp_ring_repr(buffer, tctx));
talloc_free(tctx);
return frames / (float) ao->samplerate * 1e6;
}
struct priv_d {
// digital render callback
AudioDeviceIOProcID render_cb;
static int64_t ca_get_hardware_latency(struct ao *ao) {
struct priv *p = ao->priv;
// pid set for hog mode, (-1) means that hog mode on the device was
// released. hog mode is exclusive access to a device
pid_t hog_pid;
double audiounit_latency_sec = 0.0;
uint32_t size = sizeof(audiounit_latency_sec);
OSStatus err = AudioUnitGetProperty(
p->audio_unit,
kAudioUnitProperty_Latency,
kAudioUnitScope_Global,
0,
&audiounit_latency_sec,
&size);
CHECK_CA_ERROR("cannot get audio unit latency");
// stream selected for digital playback by the detection in init
AudioStreamID stream;
uint32_t frames = 0;
err = CA_GET_O(p->device, kAudioDevicePropertyLatency, &frames);
CHECK_CA_ERROR("cannot get device latency");
// stream index in an AudioBufferList
int stream_idx;
uint64_t audiounit_latency_us = audiounit_latency_sec * 1e6;
uint64_t device_latency_us = ca_frames_to_us(ao, frames);
// format we changed the stream to: for the digital case each application
// sets the stream format for a device to what it needs
AudioStreamBasicDescription stream_asbd;
AudioStreamBasicDescription original_asbd;
MP_VERBOSE(ao, "audiounit latency [us]: %lld\n", audiounit_latency_us);
MP_VERBOSE(ao, "device latency [us]: %lld\n", device_latency_us);
bool changed_mixing;
int stream_asbd_changed;
bool muted;
};
return audiounit_latency_us + device_latency_us;
struct priv {
AudioDeviceID device; // selected device
bool is_digital; // running in digital mode?
coreaudio_error:
return 0;
}
AudioUnit audio_unit; // AudioUnit for lpcm output
bool paused;
struct mp_ring *buffer;
struct priv_d *digital;
// options
int opt_device_id;
int opt_list;
};
static int get_ring_size(struct ao *ao)
static int64_t ca_get_latency(const AudioTimeStamp *ts)
{
return af_fmt_seconds_to_bytes(
ao->format, 0.5, ao->channels.num, ao->samplerate);
uint64_t out = AudioConvertHostTimeToNanos(ts->mHostTime);
uint64_t now = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
if (now > out)
return 0;
return (out - now) * 1e-3;
}
static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags,
@@ -109,259 +90,130 @@ static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags,
{
struct ao *ao = ctx;
struct priv *p = ao->priv;
AudioBuffer buf = buffer_list->mBuffers[0];
int requested = buf.mDataByteSize;
if (mp_ring_buffered(p->buffer) < requested) {
MP_VERBOSE(ao, "buffer underrun\n");
audio_pause(ao);
memset(buf.mData, 0, requested);
} else {
mp_ring_read(p->buffer, buf.mData, requested);
}
int64_t end = mp_time_us();
end += p->hw_latency_us + ca_get_latency(ts) + ca_frames_to_us(ao, frames);
ao_read_data(ao, &buf.mData, frames, end);
return noErr;
}
static OSStatus render_cb_digital(
AudioDeviceID device, const AudioTimeStamp *ts,
const void *in_data, const AudioTimeStamp *in_ts,
AudioBufferList *out_data, const AudioTimeStamp *out_ts, void *ctx)
{
struct ao *ao = ctx;
struct priv *p = ao->priv;
struct priv_d *d = p->digital;
AudioBuffer buf = out_data->mBuffers[d->stream_idx];
int requested = buf.mDataByteSize;
static int get_volume(struct ao *ao, struct ao_control_vol *vol) {
struct priv *p = ao->priv;
float auvol;
OSStatus err =
AudioUnitGetParameter(p->audio_unit, kHALOutputParam_Volume,
kAudioUnitScope_Global, 0, &auvol);
if (d->muted)
mp_ring_drain(p->buffer, requested);
else
mp_ring_read(p->buffer, buf.mData, requested);
CHECK_CA_ERROR("could not get HAL output volume");
vol->left = vol->right = auvol * 100.0;
return CONTROL_TRUE;
coreaudio_error:
return CONTROL_ERROR;
}
return noErr;
static int set_volume(struct ao *ao, struct ao_control_vol *vol) {
struct priv *p = ao->priv;
float auvol = (vol->left + vol->right) / 200.0;
OSStatus err =
AudioUnitSetParameter(p->audio_unit, kHALOutputParam_Volume,
kAudioUnitScope_Global, 0, auvol, 0);
CHECK_CA_ERROR("could not set HAL output volume");
return CONTROL_TRUE;
coreaudio_error:
return CONTROL_ERROR;
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
ao_control_vol_t *control_vol;
OSStatus err;
Float32 vol;
switch (cmd) {
case AOCONTROL_GET_VOLUME:
control_vol = (ao_control_vol_t *)arg;
if (p->is_digital) {
struct priv_d *d = p->digital;
// Digital output has no volume adjust.
int digitalvol = d->muted ? 0 : 100;
*control_vol = (ao_control_vol_t) {
.left = digitalvol, .right = digitalvol,
};
return CONTROL_TRUE;
}
err = AudioUnitGetParameter(p->audio_unit, kHALOutputParam_Volume,
kAudioUnitScope_Global, 0, &vol);
CHECK_CA_ERROR("could not get HAL output volume");
control_vol->left = control_vol->right = vol * 100.0;
return CONTROL_TRUE;
return get_volume(ao, arg);
case AOCONTROL_SET_VOLUME:
control_vol = (ao_control_vol_t *)arg;
if (p->is_digital) {
struct priv_d *d = p->digital;
// Digital output can not set volume. Here we have to return true
// to make mixer forget it. Else mixer will add a soft filter,
// that's not we expected and the filter not support ac3 stream
// will cause mplayer die.
// Although not support set volume, but at least we support mute.
// MPlayer set mute by set volume to zero, we handle it.
if (control_vol->left == 0 && control_vol->right == 0)
d->muted = true;
else
d->muted = false;
return CONTROL_TRUE;
}
vol = (control_vol->left + control_vol->right) / 200.0;
err = AudioUnitSetParameter(p->audio_unit, kHALOutputParam_Volume,
kAudioUnitScope_Global, 0, vol, 0);
CHECK_CA_ERROR("could not set HAL output volume");
return set_volume(ao, arg);
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
case AOCONTROL_HAS_PER_APP_VOLUME:
return CONTROL_TRUE;
} // end switch
return CONTROL_UNKNOWN;
coreaudio_error:
return CONTROL_ERROR;
}
static void print_list(struct ao *ao)
{
char *help = talloc_strdup(NULL, "Available output devices:\n");
AudioDeviceID *devs;
size_t n_devs;
OSStatus err =
CA_GET_ARY(kAudioObjectSystemObject, kAudioHardwarePropertyDevices,
&devs, &n_devs);
CHECK_CA_ERROR("Failed to get list of output devices.");
for (int i = 0; i < n_devs; i++) {
char *name;
err = CA_GET_STR(devs[i], kAudioObjectPropertyName, &name);
if (err == noErr)
talloc_steal(devs, name);
else
name = "Unknown";
help = talloc_asprintf_append(
help, " * %s (id: %" PRIu32 ")\n", name, devs[i]);
}
talloc_free(devs);
coreaudio_error:
MP_INFO(ao, "%s", help);
talloc_free(help);
return CONTROL_UNKNOWN;
}
static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd);
static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd);
static bool init_chmap(struct ao *ao);
static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd);
static int init(struct ao *ao)
{
OSStatus err;
struct priv *p = ao->priv;
if (p->opt_list) print_list(ao);
struct priv_d *d = talloc_zero(p, struct priv_d);
*d = (struct priv_d) {
.muted = false,
.stream_asbd_changed = 0,
.hog_pid = -1,
.stream = 0,
.stream_idx = -1,
.changed_mixing = false,
};
p->digital = d;
ao->per_application_mixer = true;
ao->no_persistent_volume = true;
AudioDeviceID selected_device = 0;
if (p->opt_device_id < 0) {
// device not set by user, get the default one
err = CA_GET(kAudioObjectSystemObject,
kAudioHardwarePropertyDefaultOutputDevice,
&selected_device);
CHECK_CA_ERROR("could not get default audio device");
} else {
selected_device = p->opt_device_id;
if (AF_FORMAT_IS_IEC61937(ao->format)) {
MP_WARN(ao, "detected IEC61937, redirecting to coreaudio_exclusive\n");
ao->redirect = "coreaudio_exclusive";
return CONTROL_ERROR;
}
if (mp_msg_test(ao->log, MSGL_V)) {
char *name;
err = CA_GET_STR(selected_device, kAudioObjectPropertyName, &name);
CHECK_CA_ERROR("could not get selected audio device name");
struct priv *p = ao->priv;
MP_VERBOSE(ao, "selected audio output device: %s (%" PRIu32 ")\n",
name, selected_device);
OSStatus err = ca_select_device(ao, ao->device, &p->device);
CHECK_CA_ERROR("failed to select device");
talloc_free(name);
}
// Save selected device id
p->device = selected_device;
if (!init_chmap(ao))
goto coreaudio_error;
ao->format = af_fmt_from_planar(ao->format);
bool supports_digital = false;
/* Probe whether device support S/PDIF stream output if input is AC3 stream. */
if (AF_FORMAT_IS_AC3(ao->format)) {
if (ca_device_supports_digital(ao, selected_device))
supports_digital = true;
}
if (!supports_digital) {
AudioChannelLayout *layouts;
size_t n_layouts;
err = CA_GET_ARY_O(selected_device,
kAudioDevicePropertyPreferredChannelLayout,
&layouts, &n_layouts);
CHECK_CA_ERROR("could not get audio device prefered layouts");
struct mp_chmap_sel chmap_sel = {0};
for (int i = 0; i < n_layouts; i++) {
struct mp_chmap chmap = {0};
if (ca_layout_to_mp_chmap(ao, &layouts[i], &chmap))
mp_chmap_sel_add_map(&chmap_sel, &chmap);
}
talloc_free(layouts);
if (ao->channels.num < 3) {
struct mp_chmap chmap;
mp_chmap_from_channels(&chmap, ao->channels.num);
mp_chmap_sel_add_map(&chmap_sel, &chmap);
}
if (!ao_chmap_sel_adjust(ao, &chmap_sel, &ao->channels)) {
MP_ERR(ao, "could not select a suitable channel map among the "
"hardware supported ones. Make sure to configure your "
"output device correctly in 'Audio MIDI Setup.app'\n");
goto coreaudio_error;
}
} // closes if (!supports_digital)
// Build ASBD for the input format
AudioStreamBasicDescription asbd;
asbd.mSampleRate = ao->samplerate;
asbd.mFormatID = supports_digital ?
kAudioFormat60958AC3 : kAudioFormatLinearPCM;
asbd.mChannelsPerFrame = ao->channels.num;
asbd.mBitsPerChannel = af_fmt2bits(ao->format);
asbd.mFormatFlags = kAudioFormatFlagIsPacked;
ca_fill_asbd(ao, &asbd);
if ((ao->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F)
asbd.mFormatFlags |= kAudioFormatFlagIsFloat;
if (!init_audiounit(ao, asbd))
goto coreaudio_error;
if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI)
asbd.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
if ((ao->format & AF_FORMAT_END_MASK) == AF_FORMAT_BE)
asbd.mFormatFlags |= kAudioFormatFlagIsBigEndian;
asbd.mFramesPerPacket = 1;
asbd.mBytesPerPacket = asbd.mBytesPerFrame =
asbd.mFramesPerPacket * asbd.mChannelsPerFrame *
(asbd.mBitsPerChannel / 8);
ca_print_asbd(ao, "source format:", &asbd);
if (supports_digital)
return init_digital(ao, asbd);
else
return init_lpcm(ao, asbd);
return CONTROL_OK;
coreaudio_error:
return CONTROL_ERROR;
}
static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
static bool init_chmap(struct ao *ao)
{
struct priv *p = ao->priv;
OSStatus err;
AudioChannelLayout *layouts;
size_t n_layouts;
err = CA_GET_ARY_O(p->device,
kAudioDevicePropertyPreferredChannelLayout,
&layouts, &n_layouts);
CHECK_CA_ERROR("could not get audio device prefered layouts");
struct mp_chmap_sel chmap_sel = {.tmp = p};
for (int i = 0; i < n_layouts; i++) {
struct mp_chmap chmap = {0};
if (ca_layout_to_mp_chmap(ao, &layouts[i], &chmap))
mp_chmap_sel_add_map(&chmap_sel, &chmap);
}
talloc_free(layouts);
if (ao->channels.num < 3) {
struct mp_chmap chmap;
mp_chmap_from_channels(&chmap, ao->channels.num);
mp_chmap_sel_add_map(&chmap_sel, &chmap);
}
if (!ao_chmap_sel_adjust(ao, &chmap_sel, &ao->channels)) {
MP_ERR(ao, "could not select a suitable channel map among the "
"hardware supported ones. Make sure to configure your "
"output device correctly in 'Audio MIDI Setup.app'\n");
goto coreaudio_error;
}
return true;
coreaudio_error:
return false;
}
static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd)
{
OSStatus err;
uint32_t size;
@@ -369,9 +221,9 @@ static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
AudioComponentDescription desc = (AudioComponentDescription) {
.componentType = kAudioUnitType_Output,
.componentSubType = (p->opt_device_id < 0) ?
kAudioUnitSubType_DefaultOutput :
kAudioUnitSubType_HALOutput,
.componentSubType = (ao->device) ?
kAudioUnitSubType_HALOutput :
kAudioUnitSubType_DefaultOutput,
.componentManufacturer = kAudioUnitManufacturer_Apple,
.componentFlags = 0,
.componentFlagsMask = 0,
@@ -386,7 +238,6 @@ static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
err = AudioComponentInstanceNew(comp, &(p->audio_unit));
CHECK_CA_ERROR("unable to open audio component");
// Initialize AudioUnit
err = AudioUnitInitialize(p->audio_unit);
CHECK_CA_ERROR_L(coreaudio_error_component,
"unable to initialize audio unit");
@@ -399,7 +250,6 @@ static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
CHECK_CA_ERROR_L(coreaudio_error_audiounit,
"unable to set the input format on the audio unit");
//Set the Current Device to the Default Output Unit.
err = AudioUnitSetProperty(p->audio_unit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global, 0, &p->device,
@@ -407,8 +257,7 @@ static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
CHECK_CA_ERROR_L(coreaudio_error_audiounit,
"can't link audio unit to selected device");
p->buffer = mp_ring_new(p, get_ring_size(ao));
print_buffer(ao, p->buffer);
p->hw_latency_us = ca_get_hardware_latency(ao);
AURenderCallbackStruct render_cb = (AURenderCallbackStruct) {
.inputProc = render_cb_lpcm,
@@ -423,283 +272,188 @@ static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
CHECK_CA_ERROR_L(coreaudio_error_audiounit,
"unable to set render callback on audio unit");
reset(ao);
return CONTROL_OK;
return true;
coreaudio_error_audiounit:
AudioUnitUninitialize(p->audio_unit);
coreaudio_error_component:
AudioComponentInstanceDispose(p->audio_unit);
coreaudio_error:
return CONTROL_ERROR;
return false;
}
static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
static void stop(struct ao *ao)
{
struct priv *p = ao->priv;
struct priv_d *d = p->digital;
OSStatus err = noErr;
uint32_t is_alive = 1;
err = CA_GET(p->device, kAudioDevicePropertyDeviceIsAlive, &is_alive);
CHECK_CA_WARN("could not check whether device is alive");
if (!is_alive)
MP_WARN(ao , "device is not alive\n");
p->is_digital = 1;
err = ca_lock_device(p->device, &d->hog_pid);
CHECK_CA_WARN("failed to set hogmode");
err = ca_disable_mixing(ao, p->device, &d->changed_mixing);
CHECK_CA_WARN("failed to disable mixing");
AudioStreamID *streams;
size_t n_streams;
/* Get a list of all the streams on this device. */
err = CA_GET_ARY_O(p->device, kAudioDevicePropertyStreams,
&streams, &n_streams);
CHECK_CA_ERROR("could not get number of streams");
for (int i = 0; i < n_streams && d->stream_idx < 0; i++) {
bool digital = ca_stream_supports_digital(ao, streams[i]);
if (digital) {
err = CA_GET(streams[i], kAudioStreamPropertyPhysicalFormat,
&d->original_asbd);
if (!CHECK_CA_WARN("could not get stream's physical format to "
"revert to, getting the next one"))
continue;
AudioStreamRangedDescription *formats;
size_t n_formats;
err = CA_GET_ARY(streams[i],
kAudioStreamPropertyAvailablePhysicalFormats,
&formats, &n_formats);
if (!CHECK_CA_WARN("could not get number of stream formats"))
continue; // try next one
int req_rate_format = -1;
int max_rate_format = -1;
d->stream = streams[i];
d->stream_idx = i;
for (int j = 0; j < n_formats; j++)
if (ca_format_is_digital(formats[j].mFormat)) {
// select the digital format that has exactly the same
// samplerate. If an exact match cannot be found, select
// the format with highest samplerate as backup.
if (formats[j].mFormat.mSampleRate == asbd.mSampleRate) {
req_rate_format = j;
break;
} else if (max_rate_format < 0 ||
formats[j].mFormat.mSampleRate >
formats[max_rate_format].mFormat.mSampleRate)
max_rate_format = j;
}
if (req_rate_format >= 0)
d->stream_asbd = formats[req_rate_format].mFormat;
else
d->stream_asbd = formats[max_rate_format].mFormat;
talloc_free(formats);
}
}
talloc_free(streams);
if (d->stream_idx < 0) {
MP_WARN(ao , "can't find any digital output stream format\n");
goto coreaudio_error;
}
if (!ca_change_format(ao, d->stream, d->stream_asbd))
goto coreaudio_error;
void *changed = (void *) &(d->stream_asbd_changed);
err = ca_enable_device_listener(p->device, changed);
CHECK_CA_ERROR("cannot install format change listener during init");
#if BYTE_ORDER == BIG_ENDIAN
if (!(p->stream_asdb.mFormatFlags & kAudioFormatFlagIsBigEndian))
#else
/* tell mplayer that we need a byteswap on AC3 streams, */
if (d->stream_asbd.mFormatID & kAudioFormat60958AC3)
ao->format = AF_FORMAT_AC3_LE;
else if (d->stream_asbd.mFormatFlags & kAudioFormatFlagIsBigEndian)
#endif
MP_WARN(ao, "stream has non-native byte order, output may fail\n");
ao->samplerate = d->stream_asbd.mSampleRate;
ao->bps = ao->samplerate *
(d->stream_asbd.mBytesPerPacket /
d->stream_asbd.mFramesPerPacket);
p->buffer = mp_ring_new(p, get_ring_size(ao));
print_buffer(ao, p->buffer);
err = AudioDeviceCreateIOProcID(p->device,
(AudioDeviceIOProc)render_cb_digital,
(void *)ao,
&d->render_cb);
CHECK_CA_ERROR("failed to register digital render callback");
reset(ao);
return CONTROL_TRUE;
coreaudio_error:
err = ca_unlock_device(p->device, &d->hog_pid);
CHECK_CA_WARN("can't release hog mode");
return CONTROL_ERROR;
OSStatus err = AudioOutputUnitStop(p->audio_unit);
CHECK_CA_WARN("can't stop audio unit");
}
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
struct priv_d *d = p->digital;
void *output_samples = data[0];
int num_bytes = samples * ao->sstride;
// Check whether we need to reset the digital output stream.
if (p->is_digital && d->stream_asbd_changed) {
d->stream_asbd_changed = 0;
if (ca_stream_supports_digital(ao, d->stream)) {
if (!ca_change_format(ao, d->stream, d->stream_asbd)) {
MP_WARN(ao , "can't restore digital output\n");
} else {
MP_WARN(ao, "restoring digital output succeeded.\n");
reset(ao);
}
}
}
int wrote = mp_ring_write(p->buffer, output_samples, num_bytes);
audio_resume(ao);
return wrote / ao->sstride;
}
static void reset(struct ao *ao)
static void start(struct ao *ao)
{
struct priv *p = ao->priv;
audio_pause(ao);
mp_ring_reset(p->buffer);
OSStatus err = AudioOutputUnitStart(p->audio_unit);
CHECK_CA_WARN("can't start audio unit");
}
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
return mp_ring_available(p->buffer) / ao->sstride;
}
static float get_delay(struct ao *ao)
{
// FIXME: should also report the delay of coreaudio itself (hardware +
// internal buffers)
struct priv *p = ao->priv;
return mp_ring_buffered(p->buffer) / (float)ao->bps;
}
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
OSStatus err = noErr;
AudioOutputUnitStop(p->audio_unit);
AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit);
}
if (!p->is_digital) {
AudioOutputUnitStop(p->audio_unit);
AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit);
} else {
struct priv_d *d = p->digital;
// Channel Mapping functions
static const int speaker_map[][2] = {
{ kAudioChannelLabel_Left, MP_SPEAKER_ID_FL },
{ kAudioChannelLabel_Right, MP_SPEAKER_ID_FR },
{ kAudioChannelLabel_Center, MP_SPEAKER_ID_FC },
{ kAudioChannelLabel_LFEScreen, MP_SPEAKER_ID_LFE },
{ kAudioChannelLabel_LeftSurround, MP_SPEAKER_ID_BL },
{ kAudioChannelLabel_RightSurround, MP_SPEAKER_ID_BR },
{ kAudioChannelLabel_LeftCenter, MP_SPEAKER_ID_FLC },
{ kAudioChannelLabel_RightCenter, MP_SPEAKER_ID_FRC },
{ kAudioChannelLabel_CenterSurround, MP_SPEAKER_ID_BC },
{ kAudioChannelLabel_LeftSurroundDirect, MP_SPEAKER_ID_SL },
{ kAudioChannelLabel_RightSurroundDirect, MP_SPEAKER_ID_SR },
{ kAudioChannelLabel_TopCenterSurround, MP_SPEAKER_ID_TC },
{ kAudioChannelLabel_VerticalHeightLeft, MP_SPEAKER_ID_TFL },
{ kAudioChannelLabel_VerticalHeightCenter, MP_SPEAKER_ID_TFC },
{ kAudioChannelLabel_VerticalHeightRight, MP_SPEAKER_ID_TFR },
{ kAudioChannelLabel_TopBackLeft, MP_SPEAKER_ID_TBL },
{ kAudioChannelLabel_TopBackCenter, MP_SPEAKER_ID_TBC },
{ kAudioChannelLabel_TopBackRight, MP_SPEAKER_ID_TBR },
void *changed = (void *) &(d->stream_asbd_changed);
err = ca_disable_device_listener(p->device, changed);
CHECK_CA_WARN("can't remove device listener, this may cause a crash");
// unofficial extensions
{ kAudioChannelLabel_RearSurroundLeft, MP_SPEAKER_ID_SDL },
{ kAudioChannelLabel_RearSurroundRight, MP_SPEAKER_ID_SDR },
{ kAudioChannelLabel_LeftWide, MP_SPEAKER_ID_WL },
{ kAudioChannelLabel_RightWide, MP_SPEAKER_ID_WR },
{ kAudioChannelLabel_LFE2, MP_SPEAKER_ID_LFE2 },
err = AudioDeviceStop(p->device, d->render_cb);
CHECK_CA_WARN("failed to stop audio device");
{ kAudioChannelLabel_HeadphonesLeft, MP_SPEAKER_ID_DL },
{ kAudioChannelLabel_HeadphonesRight, MP_SPEAKER_ID_DR },
err = AudioDeviceDestroyIOProcID(p->device, d->render_cb);
CHECK_CA_WARN("failed to remove device render callback");
{ kAudioChannelLabel_Unknown, -1 },
};
if (!ca_change_format(ao, d->stream, d->original_asbd))
MP_WARN(ao, "can't revert to original device format");
static int ca_label_to_mp_speaker_id(AudioChannelLabel label)
{
for (int i = 0; speaker_map[i][1] >= 0; i++)
if (speaker_map[i][0] == label)
return speaker_map[i][1];
return -1;
}
err = ca_enable_mixing(ao, p->device, d->changed_mixing);
CHECK_CA_WARN("can't re-enable mixing");
static void ca_log_layout(struct ao *ao, AudioChannelLayout *layout)
{
if (!mp_msg_test(ao->log, MSGL_V))
return;
err = ca_unlock_device(p->device, &d->hog_pid);
CHECK_CA_WARN("can't release hog mode");
AudioChannelDescription *descs = layout->mChannelDescriptions;
MP_VERBOSE(ao, "layout: tag: <%u>, bitmap: <%u>, "
"descriptions <%u>\n",
(unsigned) layout->mChannelLayoutTag,
(unsigned) layout->mChannelBitmap,
(unsigned) layout->mNumberChannelDescriptions);
for (int i = 0; i < layout->mNumberChannelDescriptions; i++) {
AudioChannelDescription d = descs[i];
MP_VERBOSE(ao, " - description %d: label <%u, %u>, "
" flags: <%u>, coords: <%f, %f, %f>\n", i,
(unsigned) d.mChannelLabel,
(unsigned) ca_label_to_mp_speaker_id(d.mChannelLabel),
(unsigned) d.mChannelFlags,
d.mCoordinates[0],
d.mCoordinates[1],
d.mCoordinates[2]);
if (i >= 32) {
MP_VERBOSE(ao, " detected more than 32 channel descriptions, "
"skipping output");
break;
}
}
}
static void audio_pause(struct ao *ao)
bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
struct mp_chmap *chmap)
{
struct priv *p = ao->priv;
OSErr err = noErr;
AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
uint32_t layout_size = sizeof(layout);
OSStatus err;
if (p->paused)
return;
if (!p->is_digital) {
err = AudioOutputUnitStop(p->audio_unit);
CHECK_CA_WARN("can't stop audio unit");
} else {
struct priv_d *d = p->digital;
err = AudioDeviceStop(p->device, d->render_cb);
CHECK_CA_WARN("can't stop digital device");
if (tag == kAudioChannelLayoutTag_UseChannelBitmap) {
err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
sizeof(uint32_t),
&layout->mChannelBitmap,
&layout_size,
layout);
CHECK_CA_ERROR("failed to convert channel bitmap to descriptions");
} else if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) {
err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
sizeof(AudioChannelLayoutTag),
&layout->mChannelLayoutTag,
&layout_size,
layout);
CHECK_CA_ERROR("failed to convert channel tag to descriptions");
}
p->paused = true;
}
ca_log_layout(ao, layout);
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
OSErr err = noErr;
// If the channel layout uses channel descriptions, from my
// experiments there are there three possibile cases:
// * The description has a label kAudioChannelLabel_Unknown:
// Can't do anything about this (looks like non surround
// layouts are like this).
// * The description uses positional information: this in
// theory could be used but one would have to map spatial
// positions to labels which is not really feasible.
// * The description has a well known label which can be mapped
// to the waveextensible definition: this is the kind of
// descriptions we process here.
if (!p->paused)
return;
if (!p->is_digital) {
err = AudioOutputUnitStart(p->audio_unit);
CHECK_CA_WARN("can't start audio unit");
} else {
struct priv_d *d = p->digital;
err = AudioDeviceStart(p->device, d->render_cb);
CHECK_CA_WARN("can't start digital device");
if (layout->mNumberChannelDescriptions > MP_NUM_CHANNELS) {
MP_VERBOSE(ao, "layout has too many descriptions (%u, max: %d)\n",
(unsigned) layout->mNumberChannelDescriptions,
MP_NUM_CHANNELS);
return false;
}
p->paused = false;
for (int n = 0; n < layout->mNumberChannelDescriptions; n++) {
AudioChannelLabel label = layout->mChannelDescriptions[n].mChannelLabel;
uint8_t speaker = ca_label_to_mp_speaker_id(label);
if (label == kAudioChannelLabel_Unknown)
continue;
if (speaker < 0) {
MP_VERBOSE(ao, "channel label=%u unusable to build channel "
"bitmap, skipping layout\n", (unsigned) label);
goto coreaudio_error;
} else {
chmap->speaker[n] = speaker;
chmap->num = n + 1;
}
}
return chmap->num > 0;
coreaudio_error:
ca_log_layout(ao, layout);
return false;
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_coreaudio = {
.description = "CoreAudio (OS X Audio Output)",
.description = "CoreAudio AudioUnit",
.name = "coreaudio",
.uninit = uninit,
.init = init,
.play = play,
.control = control,
.get_space = get_space,
.get_delay = get_delay,
.reset = reset,
.pause = audio_pause,
.resume = audio_resume,
.pause = stop,
.resume = start,
.list_devs = ca_get_device_list,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_INT("device_id", opt_device_id, 0, OPTDEF_INT(-1)),
OPT_FLAG("list", opt_list, 0),
{0}
},
};
+667
View File
@@ -0,0 +1,667 @@
/*
* CoreAudio audio output driver for Mac OS X
*
* original copyright (C) Timothy J. Wood - Aug 2000
* ported to MPlayer libao2 by Dan Christiansen
*
* Chris Roccati
* Stefano Pigozzi
*
* The S/PDIF part of the code is based on the auhal audio output
* module from VideoLAN:
* Copyright (c) 2006 Derk-Jan Hartman <hartman at videolan dot org>
*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* along with MPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* The MacOS X CoreAudio framework doesn't mesh as simply as some
* simpler frameworks do. This is due to the fact that CoreAudio pulls
* audio samples rather than having them pushed at it (which is nice
* when you are wanting to do good buffering of audio).
*/
#include "config.h"
#include "ao.h"
#include "internal.h"
#include "audio/format.h"
#include "osdep/timer.h"
#include "options/m_option.h"
#include "misc/ring.h"
#include "common/msg.h"
#include "audio/out/ao_coreaudio_properties.h"
#include "audio/out/ao_coreaudio_utils.h"
static void audio_pause(struct ao *ao);
static void audio_resume(struct ao *ao);
static void reset(struct ao *ao);
static bool ca_format_is_digital(AudioStreamBasicDescription asbd)
{
switch (asbd.mFormatID)
case 'IAC3':
case 'iac3':
case kAudioFormat60958AC3:
case kAudioFormatAC3:
return true;
return false;
}
static bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream)
{
AudioStreamRangedDescription *formats = NULL;
size_t n_formats;
OSStatus err =
CA_GET_ARY(stream, kAudioStreamPropertyAvailablePhysicalFormats,
&formats, &n_formats);
CHECK_CA_ERROR("Could not get number of stream formats.");
for (int i = 0; i < n_formats; i++) {
AudioStreamBasicDescription asbd = formats[i].mFormat;
ca_print_asbd(ao, "supported format:", &(asbd));
if (ca_format_is_digital(asbd)) {
talloc_free(formats);
return true;
}
}
talloc_free(formats);
coreaudio_error:
return false;
}
static bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device)
{
AudioStreamID *streams = NULL;
size_t n_streams;
/* Retrieve all the output streams. */
OSStatus err =
CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams);
CHECK_CA_ERROR("could not get number of streams.");
for (int i = 0; i < n_streams; i++) {
if (ca_stream_supports_digital(ao, streams[i])) {
talloc_free(streams);
return true;
}
}
talloc_free(streams);
coreaudio_error:
return false;
}
static OSStatus ca_property_listener(
AudioObjectPropertySelector selector,
AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data)
{
void *talloc_ctx = talloc_new(NULL);
for (int i = 0; i < n_addresses; i++) {
if (addresses[i].mSelector == selector) {
if (data) *(volatile int *)data = 1;
break;
}
}
talloc_free(talloc_ctx);
return noErr;
}
static OSStatus ca_stream_listener(
AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data)
{
return ca_property_listener(kAudioStreamPropertyPhysicalFormat,
object, n_addresses, addresses, data);
}
static OSStatus ca_device_listener(
AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data)
{
return ca_property_listener(kAudioDevicePropertyDeviceHasChanged,
object, n_addresses, addresses, data);
}
static OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) {
*pid = getpid();
OSStatus err = CA_SET(device, kAudioDevicePropertyHogMode, pid);
if (err != noErr)
*pid = -1;
return err;
}
static OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid) {
if (*pid == getpid()) {
*pid = -1;
return CA_SET(device, kAudioDevicePropertyHogMode, &pid);
}
return noErr;
}
static OSStatus ca_change_mixing(struct ao *ao, AudioDeviceID device,
uint32_t val, bool *changed) {
*changed = false;
AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) {
.mSelector = kAudioDevicePropertySupportsMixing,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster,
};
if (AudioObjectHasProperty(device, &p_addr)) {
OSStatus err;
Boolean writeable = 0;
err = CA_SETTABLE(device, kAudioDevicePropertySupportsMixing,
&writeable);
if (!CHECK_CA_WARN("can't tell if mixing property is settable")) {
return err;
}
if (!writeable)
return noErr;
err = CA_SET(device, kAudioDevicePropertySupportsMixing, &val);
if (err != noErr)
return err;
if (!CHECK_CA_WARN("can't set mix mode")) {
return err;
}
*changed = true;
}
return noErr;
}
static OSStatus ca_disable_mixing(struct ao *ao,
AudioDeviceID device, bool *changed) {
return ca_change_mixing(ao, device, 0, changed);
}
static OSStatus ca_enable_mixing(struct ao *ao,
AudioDeviceID device, bool changed) {
if (changed) {
bool dont_care = false;
return ca_change_mixing(ao, device, 1, &dont_care);
}
return noErr;
}
static OSStatus ca_change_device_listening(AudioDeviceID device,
void *flag, bool enabled)
{
AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) {
.mSelector = kAudioDevicePropertyDeviceHasChanged,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster,
};
if (enabled) {
return AudioObjectAddPropertyListener(
device, &p_addr, ca_device_listener, flag);
} else {
return AudioObjectRemovePropertyListener(
device, &p_addr, ca_device_listener, flag);
}
}
static OSStatus ca_enable_device_listener(AudioDeviceID device, void *flag) {
return ca_change_device_listening(device, flag, true);
}
static OSStatus ca_disable_device_listener(AudioDeviceID device, void *flag) {
return ca_change_device_listening(device, flag, false);
}
static bool ca_change_format(struct ao *ao, AudioStreamID stream,
AudioStreamBasicDescription change_format)
{
OSStatus err = noErr;
AudioObjectPropertyAddress p_addr;
volatile int stream_format_changed = 0;
ca_print_asbd(ao, "setting stream format:", &change_format);
/* Install the callback. */
p_addr = (AudioObjectPropertyAddress) {
.mSelector = kAudioStreamPropertyPhysicalFormat,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster,
};
err = AudioObjectAddPropertyListener(stream, &p_addr, ca_stream_listener,
(void *)&stream_format_changed);
if (!CHECK_CA_WARN("can't add property listener during format change")) {
return false;
}
/* Change the format. */
err = CA_SET(stream, kAudioStreamPropertyPhysicalFormat, &change_format);
if (!CHECK_CA_WARN("error changing physical format")) {
return false;
}
/* The AudioStreamSetProperty is not only asynchronious,
* it is also not Atomic, in its behaviour.
* Therefore we check 5 times before we really give up. */
bool format_set = false;
for (int i = 0; !format_set && i < 5; i++) {
for (int j = 0; !stream_format_changed && j < 50; j++)
mp_sleep_us(10000);
if (stream_format_changed) {
stream_format_changed = 0;
} else {
MP_VERBOSE(ao, "reached timeout\n");
}
AudioStreamBasicDescription actual_format;
err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &actual_format);
ca_print_asbd(ao, "actual format in use:", &actual_format);
if (actual_format.mSampleRate == change_format.mSampleRate &&
actual_format.mFormatID == change_format.mFormatID &&
actual_format.mFramesPerPacket == change_format.mFramesPerPacket) {
format_set = true;
}
}
err = AudioObjectRemovePropertyListener(stream, &p_addr, ca_stream_listener,
(void *)&stream_format_changed);
if (!CHECK_CA_WARN("can't remove property listener")) {
return false;
}
return format_set;
}
struct priv {
AudioDeviceID device; // selected device
bool paused;
struct mp_ring *buffer;
// digital render callback
AudioDeviceIOProcID render_cb;
// pid set for hog mode, (-1) means that hog mode on the device was
// released. hog mode is exclusive access to a device
pid_t hog_pid;
// stream selected for digital playback by the detection in init
AudioStreamID stream;
// stream index in an AudioBufferList
int stream_idx;
// format we changed the stream to: for the digital case each application
// sets the stream format for a device to what it needs
AudioStreamBasicDescription stream_asbd;
AudioStreamBasicDescription original_asbd;
bool changed_mixing;
int stream_asbd_changed;
bool muted;
};
static int get_ring_size(struct ao *ao)
{
return af_fmt_seconds_to_bytes(
ao->format, 0.5, ao->channels.num, ao->samplerate);
}
static OSStatus render_cb_digital(
AudioDeviceID device, const AudioTimeStamp *ts,
const void *in_data, const AudioTimeStamp *in_ts,
AudioBufferList *out_data, const AudioTimeStamp *out_ts, void *ctx)
{
struct ao *ao = ctx;
struct priv *p = ao->priv;
AudioBuffer buf = out_data->mBuffers[p->stream_idx];
int requested = buf.mDataByteSize;
if (p->muted)
mp_ring_drain(p->buffer, requested);
else
mp_ring_read(p->buffer, buf.mData, requested);
return noErr;
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
ao_control_vol_t *control_vol;
switch (cmd) {
case AOCONTROL_GET_VOLUME:
control_vol = (ao_control_vol_t *)arg;
// Digital output has no volume adjust.
int digitalvol = p->muted ? 0 : 100;
*control_vol = (ao_control_vol_t) {
.left = digitalvol, .right = digitalvol,
};
return CONTROL_TRUE;
case AOCONTROL_SET_VOLUME:
control_vol = (ao_control_vol_t *)arg;
// Digital output can not set volume. Here we have to return true
// to make mixer forget it. Else mixer will add a soft filter,
// that's not we expected and the filter not support ac3 stream
// will cause mplayer die.
// Although not support set volume, but at least we support mute.
// MPlayer set mute by set volume to zero, we handle it.
if (control_vol->left == 0 && control_vol->right == 0)
p->muted = true;
else
p->muted = false;
return CONTROL_TRUE;
} // end switch
return CONTROL_UNKNOWN;
}
static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd);
static int init(struct ao *ao)
{
struct priv *p = ao->priv;
OSStatus err = ca_select_device(ao, ao->device, &p->device);
CHECK_CA_ERROR("failed to select device");
ao->format = af_fmt_from_planar(ao->format);
bool supports_digital = false;
/* Probe whether device support S/PDIF stream output if input is AC3 stream,
* or anything else IEC61937-framed. */
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (ca_device_supports_digital(ao, p->device))
supports_digital = true;
}
if (!supports_digital) {
MP_ERR(ao, "selected device doesn't support digital formats\n");
goto coreaudio_error;
} // closes if (!supports_digital)
// Build ASBD for the input format
AudioStreamBasicDescription asbd;
ca_fill_asbd(ao, &asbd);
return init_digital(ao, asbd);
coreaudio_error:
return CONTROL_ERROR;
}
static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
{
struct priv *p = ao->priv;
OSStatus err = noErr;
uint32_t is_alive = 1;
err = CA_GET(p->device, kAudioDevicePropertyDeviceIsAlive, &is_alive);
CHECK_CA_WARN("could not check whether device is alive");
if (!is_alive)
MP_WARN(ao , "device is not alive\n");
err = ca_lock_device(p->device, &p->hog_pid);
CHECK_CA_WARN("failed to set hogmode");
err = ca_disable_mixing(ao, p->device, &p->changed_mixing);
CHECK_CA_WARN("failed to disable mixing");
AudioStreamID *streams;
size_t n_streams;
/* Get a list of all the streams on this device. */
err = CA_GET_ARY_O(p->device, kAudioDevicePropertyStreams,
&streams, &n_streams);
CHECK_CA_ERROR("could not get number of streams");
for (int i = 0; i < n_streams && p->stream_idx < 0; i++) {
bool digital = ca_stream_supports_digital(ao, streams[i]);
if (digital) {
err = CA_GET(streams[i], kAudioStreamPropertyPhysicalFormat,
&p->original_asbd);
if (!CHECK_CA_WARN("could not get stream's physical format to "
"revert to, getting the next one"))
continue;
AudioStreamRangedDescription *formats;
size_t n_formats;
err = CA_GET_ARY(streams[i],
kAudioStreamPropertyAvailablePhysicalFormats,
&formats, &n_formats);
if (!CHECK_CA_WARN("could not get number of stream formats"))
continue; // try next one
int req_rate_format = -1;
int max_rate_format = -1;
p->stream = streams[i];
p->stream_idx = i;
for (int j = 0; j < n_formats; j++)
if (ca_format_is_digital(formats[j].mFormat)) {
// select the digital format that has exactly the same
// samplerate. If an exact match cannot be found, select
// the format with highest samplerate as backup.
if (formats[j].mFormat.mSampleRate == asbd.mSampleRate) {
req_rate_format = j;
break;
} else if (max_rate_format < 0 ||
formats[j].mFormat.mSampleRate >
formats[max_rate_format].mFormat.mSampleRate)
max_rate_format = j;
}
if (req_rate_format >= 0)
p->stream_asbd = formats[req_rate_format].mFormat;
else
p->stream_asbd = formats[max_rate_format].mFormat;
talloc_free(formats);
}
}
talloc_free(streams);
if (p->stream_idx < 0) {
MP_WARN(ao , "can't find any digital output stream format\n");
goto coreaudio_error;
}
if (!ca_change_format(ao, p->stream, p->stream_asbd))
goto coreaudio_error;
void *changed = (void *) &(p->stream_asbd_changed);
err = ca_enable_device_listener(p->device, changed);
CHECK_CA_ERROR("cannot install format change listener during init");
if (p->stream_asbd.mFormatFlags & kAudioFormatFlagIsBigEndian)
MP_WARN(ao, "stream has non-native byte order, output may fail\n");
ao->samplerate = p->stream_asbd.mSampleRate;
ao->bps = ao->samplerate *
(p->stream_asbd.mBytesPerPacket /
p->stream_asbd.mFramesPerPacket);
p->buffer = mp_ring_new(p, get_ring_size(ao));
err = AudioDeviceCreateIOProcID(p->device,
(AudioDeviceIOProc)render_cb_digital,
(void *)ao,
&p->render_cb);
CHECK_CA_ERROR("failed to register digital render callback");
reset(ao);
return CONTROL_TRUE;
coreaudio_error:
err = ca_unlock_device(p->device, &p->hog_pid);
CHECK_CA_WARN("can't release hog mode");
return CONTROL_ERROR;
}
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
void *output_samples = data[0];
int num_bytes = samples * ao->sstride;
// Check whether we need to reset the digital output stream.
if (p->stream_asbd_changed) {
p->stream_asbd_changed = 0;
if (ca_stream_supports_digital(ao, p->stream)) {
if (!ca_change_format(ao, p->stream, p->stream_asbd)) {
MP_WARN(ao , "can't restore digital output\n");
} else {
MP_WARN(ao, "restoring digital output succeeded.\n");
reset(ao);
}
}
}
int wrote = mp_ring_write(p->buffer, output_samples, num_bytes);
audio_resume(ao);
return wrote / ao->sstride;
}
static void reset(struct ao *ao)
{
struct priv *p = ao->priv;
audio_pause(ao);
mp_ring_reset(p->buffer);
}
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
return mp_ring_available(p->buffer) / ao->sstride;
}
static double get_delay(struct ao *ao)
{
// FIXME: should also report the delay of coreaudio itself (hardware +
// internal buffers)
struct priv *p = ao->priv;
return mp_ring_buffered(p->buffer) / (double)ao->bps;
}
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
OSStatus err = noErr;
void *changed = (void *) &(p->stream_asbd_changed);
err = ca_disable_device_listener(p->device, changed);
CHECK_CA_WARN("can't remove device listener, this may cause a crash");
err = AudioDeviceStop(p->device, p->render_cb);
CHECK_CA_WARN("failed to stop audio device");
err = AudioDeviceDestroyIOProcID(p->device, p->render_cb);
CHECK_CA_WARN("failed to remove device render callback");
if (!ca_change_format(ao, p->stream, p->original_asbd))
MP_WARN(ao, "can't revert to original device format");
err = ca_enable_mixing(ao, p->device, p->changed_mixing);
CHECK_CA_WARN("can't re-enable mixing");
err = ca_unlock_device(p->device, &p->hog_pid);
CHECK_CA_WARN("can't release hog mode");
}
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->paused)
return;
OSStatus err = AudioDeviceStop(p->device, p->render_cb);
CHECK_CA_WARN("can't stop digital device");
p->paused = true;
}
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
if (!p->paused)
return;
OSStatus err = AudioDeviceStart(p->device, p->render_cb);
CHECK_CA_WARN("can't start digital device");
p->paused = false;
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_coreaudio_exclusive = {
.description = "CoreAudio Exclusive Mode",
.name = "coreaudio_exclusive",
.uninit = uninit,
.init = init,
.play = play,
.control = control,
.get_space = get_space,
.get_delay = get_delay,
.reset = reset,
.pause = audio_pause,
.resume = audio_resume,
.list_devs = ca_get_device_list,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv){
.muted = false,
.stream_asbd_changed = 0,
.hog_pid = -1,
.stream = 0,
.stream_idx = -1,
.changed_mixing = false,
},
};
+2 -2
View File
@@ -62,7 +62,7 @@ OSStatus ca_get_ary(AudioObjectID id, ca_scope scope, ca_sel selector,
err = AudioObjectGetPropertyDataSize(id, &p_addr, 0, NULL, &p_size);
CHECK_CA_ERROR_SILENT_L(coreaudio_error);
*data = talloc_size(NULL, p_size);
*data = talloc_zero_size(NULL, p_size);
*elements = p_size / element_size;
err = ca_get(id, scope, selector, p_size, *data);
@@ -87,7 +87,7 @@ OSStatus ca_get_str(AudioObjectID id, ca_scope scope, ca_sel selector,
CFStringGetMaximumSizeForEncoding(
CFStringGetLength(string), CA_CFSTR_ENCODING) + 1;
*data = talloc_size(NULL, size);
*data = talloc_zero_size(NULL, size);
CFStringGetCString(string, *data, size, CA_CFSTR_ENCODING);
CFRelease(string);
coreaudio_error:
+1
View File
@@ -37,6 +37,7 @@ OSStatus ca_set(AudioObjectID id, ca_scope scope, ca_sel selector,
#define CA_GET(id, sel, data) ca_get(id, CA_GLOBAL, sel, sizeof(*(data)), data)
#define CA_SET(id, sel, data) ca_set(id, CA_GLOBAL, sel, sizeof(*(data)), data)
#define CA_GET_O(id, sel, data) ca_get(id, CA_OUTPUT, sel, sizeof(*(data)), data)
OSStatus ca_get_ary(AudioObjectID id, ca_scope scope, ca_sel selector,
uint32_t element_size, void **data, size_t *elements);
+98 -374
View File
@@ -25,12 +25,82 @@
#include "audio/out/ao_coreaudio_utils.h"
#include "audio/out/ao_coreaudio_properties.h"
#include "osdep/timer.h"
#include "osdep/endian.h"
#include "audio/format.h"
static bool ca_is_output_device(struct ao *ao, AudioDeviceID dev)
{
size_t n_buffers;
AudioBufferList *buffers;
const ca_scope scope = kAudioDevicePropertyStreamConfiguration;
CA_GET_ARY_O(dev, scope, &buffers, &n_buffers);
talloc_free(buffers);
return n_buffers > 0;
}
void ca_get_device_list(struct ao *ao, struct ao_device_list *list)
{
AudioDeviceID *devs;
size_t n_devs;
OSStatus err =
CA_GET_ARY(kAudioObjectSystemObject, kAudioHardwarePropertyDevices,
&devs, &n_devs);
CHECK_CA_ERROR("Failed to get list of output devices.");
for (int i = 0; i < n_devs; i++) {
if (!ca_is_output_device(ao, devs[i]))
continue;
char name[32];
char *desc;
sprintf(name, "%d", devs[i]);
err = CA_GET_STR(devs[i], kAudioObjectPropertyName, &desc);
if (err != noErr)
desc = "Unknown";
ao_device_list_add(list, ao, &(struct ao_device_desc){name, desc});
}
talloc_free(devs);
coreaudio_error:
return;
}
OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
{
OSStatus err = noErr;
int selection = name ? strtol(name, (char **)NULL, 10) : -1;
if (errno == EINVAL || errno == ERANGE) {
selection = -1;
MP_WARN(ao, "device identifier '%s' is invalid\n", name);
}
*device = 0;
if (selection < 0) {
// device not set by user, get the default one
err = CA_GET(kAudioObjectSystemObject,
kAudioHardwarePropertyDefaultOutputDevice,
device);
CHECK_CA_ERROR("could not get default audio device");
} else {
*device = selection;
}
if (mp_msg_test(ao->log, MSGL_V)) {
char *desc;
err = CA_GET_STR(*device, kAudioObjectPropertyName, &desc);
CHECK_CA_ERROR("could not get selected audio device name");
MP_VERBOSE(ao, "selected audio output device: %s (%" PRIu32 ")\n",
desc, *device);
talloc_free(desc);
}
coreaudio_error:
return err;
}
char *fourcc_repr(void *talloc_ctx, uint32_t code)
{
// Extract FourCC letters from the uint32_t and finde out if it's a valid
// code that is made of letters.
char fcc[4] = {
unsigned char fcc[4] = {
(code >> 24) & 0xFF,
(code >> 16) & 0xFF,
(code >> 8) & 0xFF,
@@ -39,7 +109,7 @@ char *fourcc_repr(void *talloc_ctx, uint32_t code)
bool valid_fourcc = true;
for (int i = 0; i < 4; i++)
if (!isprint(fcc[i]))
if (fcc[i] >= 32 && fcc[i] < 128)
valid_fourcc = false;
char *repr;
@@ -63,6 +133,32 @@ bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message)
return false;
}
void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd)
{
asbd->mSampleRate = ao->samplerate;
// Set "AC3" for other spdif formats too - unknown if that works.
asbd->mFormatID = AF_FORMAT_IS_IEC61937(ao->format) ?
kAudioFormat60958AC3 :
kAudioFormatLinearPCM;
asbd->mChannelsPerFrame = ao->channels.num;
asbd->mBitsPerChannel = af_fmt2bits(ao->format);
asbd->mFormatFlags = kAudioFormatFlagIsPacked;
if ((ao->format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F)
asbd->mFormatFlags |= kAudioFormatFlagIsFloat;
if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI)
asbd->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
if (BYTE_ORDER == BIG_ENDIAN)
asbd->mFormatFlags |= kAudioFormatFlagIsBigEndian;
asbd->mFramesPerPacket = 1;
asbd->mBytesPerPacket = asbd->mBytesPerFrame =
asbd->mFramesPerPacket * asbd->mChannelsPerFrame *
(asbd->mBitsPerChannel / 8);
}
void ca_print_asbd(struct ao *ao, const char *description,
const AudioStreamBasicDescription *asbd)
{
@@ -87,375 +183,3 @@ void ca_print_asbd(struct ao *ao, const char *description,
talloc_free(format);
}
bool ca_format_is_digital(AudioStreamBasicDescription asbd)
{
switch (asbd.mFormatID)
case 'IAC3':
case 'iac3':
case kAudioFormat60958AC3:
case kAudioFormatAC3:
return true;
return false;
}
bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream)
{
AudioStreamRangedDescription *formats = NULL;
size_t n_formats;
OSStatus err =
CA_GET_ARY(stream, kAudioStreamPropertyAvailablePhysicalFormats,
&formats, &n_formats);
CHECK_CA_ERROR("Could not get number of stream formats.");
for (int i = 0; i < n_formats; i++) {
AudioStreamBasicDescription asbd = formats[i].mFormat;
ca_print_asbd(ao, "supported format:", &(asbd));
if (ca_format_is_digital(asbd)) {
talloc_free(formats);
return true;
}
}
talloc_free(formats);
coreaudio_error:
return false;
}
bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device)
{
AudioStreamID *streams = NULL;
size_t n_streams;
/* Retrieve all the output streams. */
OSStatus err =
CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams);
CHECK_CA_ERROR("could not get number of streams.");
for (int i = 0; i < n_streams; i++) {
if (ca_stream_supports_digital(ao, streams[i])) {
talloc_free(streams);
return true;
}
}
talloc_free(streams);
coreaudio_error:
return false;
}
OSStatus ca_property_listener(AudioObjectPropertySelector selector,
AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data)
{
void *talloc_ctx = talloc_new(NULL);
for (int i = 0; i < n_addresses; i++) {
if (addresses[i].mSelector == selector) {
if (data) *(volatile int *)data = 1;
break;
}
}
talloc_free(talloc_ctx);
return noErr;
}
OSStatus ca_stream_listener(AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data)
{
return ca_property_listener(kAudioStreamPropertyPhysicalFormat,
object, n_addresses, addresses, data);
}
OSStatus ca_device_listener(AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data)
{
return ca_property_listener(kAudioDevicePropertyDeviceHasChanged,
object, n_addresses, addresses, data);
}
OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) {
*pid = getpid();
OSStatus err = CA_SET(device, kAudioDevicePropertyHogMode, pid);
if (err != noErr)
*pid = -1;
return err;
}
OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid) {
if (*pid == getpid()) {
*pid = -1;
return CA_SET(device, kAudioDevicePropertyHogMode, &pid);
}
return noErr;
}
static OSStatus ca_change_mixing(struct ao *ao, AudioDeviceID device,
uint32_t val, bool *changed) {
*changed = false;
AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) {
.mSelector = kAudioDevicePropertySupportsMixing,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster,
};
if (AudioObjectHasProperty(device, &p_addr)) {
OSStatus err;
Boolean writeable = 0;
err = CA_SETTABLE(device, kAudioDevicePropertySupportsMixing,
&writeable);
if (!CHECK_CA_WARN("can't tell if mixing property is settable")) {
return err;
}
if (!writeable)
return noErr;
err = CA_SET(device, kAudioDevicePropertySupportsMixing, &val);
if (err != noErr)
return err;
if (!CHECK_CA_WARN("can't set mix mode")) {
return err;
}
*changed = true;
}
return noErr;
}
OSStatus ca_disable_mixing(struct ao *ao, AudioDeviceID device, bool *changed) {
return ca_change_mixing(ao, device, 0, changed);
}
OSStatus ca_enable_mixing(struct ao *ao, AudioDeviceID device, bool changed) {
if (changed) {
bool dont_care = false;
return ca_change_mixing(ao, device, 1, &dont_care);
}
return noErr;
}
static OSStatus ca_change_device_listening(AudioDeviceID device,
void *flag, bool enabled)
{
AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) {
.mSelector = kAudioDevicePropertyDeviceHasChanged,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster,
};
if (enabled) {
return AudioObjectAddPropertyListener(
device, &p_addr, ca_device_listener, flag);
} else {
return AudioObjectRemovePropertyListener(
device, &p_addr, ca_device_listener, flag);
}
}
OSStatus ca_enable_device_listener(AudioDeviceID device, void *flag) {
return ca_change_device_listening(device, flag, true);
}
OSStatus ca_disable_device_listener(AudioDeviceID device, void *flag) {
return ca_change_device_listening(device, flag, false);
}
bool ca_change_format(struct ao *ao, AudioStreamID stream,
AudioStreamBasicDescription change_format)
{
OSStatus err = noErr;
AudioObjectPropertyAddress p_addr;
volatile int stream_format_changed = 0;
ca_print_asbd(ao, "setting stream format:", &change_format);
/* Install the callback. */
p_addr = (AudioObjectPropertyAddress) {
.mSelector = kAudioStreamPropertyPhysicalFormat,
.mScope = kAudioObjectPropertyScopeGlobal,
.mElement = kAudioObjectPropertyElementMaster,
};
err = AudioObjectAddPropertyListener(stream, &p_addr, ca_stream_listener,
(void *)&stream_format_changed);
if (!CHECK_CA_WARN("can't add property listener during format change")) {
return false;
}
/* Change the format. */
err = CA_SET(stream, kAudioStreamPropertyPhysicalFormat, &change_format);
if (!CHECK_CA_WARN("error changing physical format")) {
return false;
}
/* The AudioStreamSetProperty is not only asynchronious,
* it is also not Atomic, in its behaviour.
* Therefore we check 5 times before we really give up. */
bool format_set = false;
for (int i = 0; !format_set && i < 5; i++) {
for (int j = 0; !stream_format_changed && j < 50; j++)
mp_sleep_us(10000);
if (stream_format_changed) {
stream_format_changed = 0;
} else {
MP_VERBOSE(ao, "reached timeout\n");
}
AudioStreamBasicDescription actual_format;
err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &actual_format);
ca_print_asbd(ao, "actual format in use:", &actual_format);
if (actual_format.mSampleRate == change_format.mSampleRate &&
actual_format.mFormatID == change_format.mFormatID &&
actual_format.mFramesPerPacket == change_format.mFramesPerPacket) {
format_set = true;
}
}
err = AudioObjectRemovePropertyListener(stream, &p_addr, ca_stream_listener,
(void *)&stream_format_changed);
if (!CHECK_CA_WARN("can't remove property listener")) {
return false;
}
return format_set;
}
static const int speaker_map[][2] = {
{ kAudioChannelLabel_Left, MP_SPEAKER_ID_FL },
{ kAudioChannelLabel_Right, MP_SPEAKER_ID_FR },
{ kAudioChannelLabel_Center, MP_SPEAKER_ID_FC },
{ kAudioChannelLabel_LFEScreen, MP_SPEAKER_ID_LFE },
{ kAudioChannelLabel_LeftSurround, MP_SPEAKER_ID_BL },
{ kAudioChannelLabel_RightSurround, MP_SPEAKER_ID_BR },
{ kAudioChannelLabel_LeftCenter, MP_SPEAKER_ID_FLC },
{ kAudioChannelLabel_RightCenter, MP_SPEAKER_ID_FRC },
{ kAudioChannelLabel_CenterSurround, MP_SPEAKER_ID_BC },
{ kAudioChannelLabel_LeftSurroundDirect, MP_SPEAKER_ID_SL },
{ kAudioChannelLabel_RightSurroundDirect, MP_SPEAKER_ID_SR },
{ kAudioChannelLabel_TopCenterSurround, MP_SPEAKER_ID_TC },
{ kAudioChannelLabel_VerticalHeightLeft, MP_SPEAKER_ID_TFL },
{ kAudioChannelLabel_VerticalHeightCenter, MP_SPEAKER_ID_TFC },
{ kAudioChannelLabel_VerticalHeightRight, MP_SPEAKER_ID_TFR },
{ kAudioChannelLabel_TopBackLeft, MP_SPEAKER_ID_TBL },
{ kAudioChannelLabel_TopBackCenter, MP_SPEAKER_ID_TBC },
{ kAudioChannelLabel_TopBackRight, MP_SPEAKER_ID_TBR },
// unofficial extensions
{ kAudioChannelLabel_RearSurroundLeft, MP_SPEAKER_ID_SDL },
{ kAudioChannelLabel_RearSurroundRight, MP_SPEAKER_ID_SDR },
{ kAudioChannelLabel_LeftWide, MP_SPEAKER_ID_WL },
{ kAudioChannelLabel_RightWide, MP_SPEAKER_ID_WR },
{ kAudioChannelLabel_LFE2, MP_SPEAKER_ID_LFE2 },
{ kAudioChannelLabel_HeadphonesLeft, MP_SPEAKER_ID_DL },
{ kAudioChannelLabel_HeadphonesRight, MP_SPEAKER_ID_DR },
{ kAudioChannelLabel_Unknown, -1 },
};
static int ca_label_to_mp_speaker_id(AudioChannelLabel label)
{
for (int i = 0; speaker_map[i][1] >= 0; i++)
if (speaker_map[i][0] == label)
return speaker_map[i][1];
return -1;
}
static void ca_log_layout(struct ao *ao, AudioChannelLayout *layout)
{
if (!mp_msg_test(ao->log, MSGL_V))
return;
AudioChannelDescription *descs = layout->mChannelDescriptions;
MP_VERBOSE(ao, "layout: tag: <%d>, bitmap: <%d>, "
"descriptions <%d>\n",
layout->mChannelLayoutTag,
layout->mChannelBitmap,
layout->mNumberChannelDescriptions);
for (int i = 0; i < layout->mNumberChannelDescriptions; i++) {
AudioChannelDescription d = descs[i];
MP_VERBOSE(ao, " - description %d: label <%d, %d>, flags: <%u>, "
"coords: <%f, %f, %f>\n", i,
d.mChannelLabel,
ca_label_to_mp_speaker_id(d.mChannelLabel),
d.mChannelFlags,
d.mCoordinates[0],
d.mCoordinates[1],
d.mCoordinates[2]);
}
}
bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
struct mp_chmap *chmap)
{
AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
uint32_t layout_size = sizeof(layout);
OSStatus err;
if (tag == kAudioChannelLayoutTag_UseChannelBitmap) {
err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
sizeof(uint32_t),
&layout->mChannelBitmap,
&layout_size,
layout);
CHECK_CA_ERROR("failed to convert channel bitmap to descriptions");
} else if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) {
err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
sizeof(AudioChannelLayoutTag),
&layout->mChannelLayoutTag,
&layout_size,
layout);
CHECK_CA_ERROR("failed to convert channel tag to descriptions");
}
ca_log_layout(ao, layout);
// If the channel layout uses channel descriptions, from my
// experiments there are there three possibile cases:
// * The description has a label kAudioChannelLabel_Unknown:
// Can't do anything about this (looks like non surround
// layouts are like this).
// * The description uses positional information: this in
// theory could be used but one would have to map spatial
// positions to labels which is not really feasible.
// * The description has a well known label which can be mapped
// to the waveextensible definition: this is the kind of
// descriptions we process here.
for (int n = 0; n < layout->mNumberChannelDescriptions; n++) {
AudioChannelLabel label = layout->mChannelDescriptions[n].mChannelLabel;
uint8_t speaker = ca_label_to_mp_speaker_id(label);
if (label == kAudioChannelLabel_Unknown)
continue;
if (speaker < 0) {
MP_VERBOSE(ao, "channel label=%d unusable to build channel "
"bitmap, skipping layout\n", label);
} else {
chmap->speaker[n] = speaker;
chmap->num = n + 1;
}
}
return chmap->num > 0;
coreaudio_error:
ca_log_layout(ao, layout);
return false;
}
+4 -31
View File
@@ -46,38 +46,11 @@ bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message);
if (err != noErr) goto label; \
} while (0)
void ca_get_device_list(struct ao *ao, struct ao_device_list *list);
OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device);
void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd);
void ca_print_asbd(struct ao *ao, const char *description,
const AudioStreamBasicDescription *asbd);
bool ca_format_is_digital(AudioStreamBasicDescription asbd);
bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream);
bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device);
OSStatus ca_property_listener(AudioObjectPropertySelector selector,
AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data);
OSStatus ca_stream_listener(AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data);
OSStatus ca_device_listener(AudioObjectID object, uint32_t n_addresses,
const AudioObjectPropertyAddress addresses[],
void *data);
OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid);
OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid);
OSStatus ca_disable_mixing(struct ao *ao, AudioDeviceID device, bool *changed);
OSStatus ca_enable_mixing(struct ao *ao, AudioDeviceID device, bool changed);
OSStatus ca_enable_device_listener(AudioDeviceID device, void *flag);
OSStatus ca_disable_device_listener(AudioDeviceID device, void *flag);
bool ca_change_format(struct ao *ao, AudioStreamID stream,
AudioStreamBasicDescription change_format);
bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
struct mp_chmap *chmap);
#endif /* MPV_COREAUDIO_UTILS_H */
+104 -37
View File
@@ -41,6 +41,7 @@
#include "internal.h"
#include "common/msg.h"
#include "osdep/timer.h"
#include "osdep/io.h"
#include "options/m_option.h"
/**
@@ -98,9 +99,10 @@ struct priv {
int outburst; ///play in multiple of chunks of this size
int cfg_device;
};
int cfg_buffersize;
static float get_delay(struct ao *ao);
struct ao_device_list *listing; ///temporary during list_devs()
};
/***************************************************************************************/
@@ -171,11 +173,84 @@ static BOOL CALLBACK DirectSoundEnum(LPGUID guid, LPCSTR desc, LPCSTR module,
if (guid)
memcpy(&p->device, guid, sizeof(GUID));
}
char *guidstr = talloc_strdup(NULL, "");
if (guid) {
wchar_t guidwstr[80] = {0};
StringFromGUID2(guid, guidwstr, MP_ARRAY_SIZE(guidwstr));
char *nstr = mp_to_utf8(NULL, guidwstr);
if (nstr) {
talloc_free(guidstr);
guidstr = nstr;
}
}
if (p->device_num < 0 && ao->device) {
if (strcmp(ao->device, guidstr) == 0) {
MP_VERBOSE(ao, "<--");
p->device_num = p->device_index;
if (guid)
memcpy(&p->device, guid, sizeof(GUID));
}
}
if (p->listing) {
struct ao_device_desc e = {guidstr, desc};
ao_device_list_add(p->listing, ao, &e);
}
talloc_free(guidstr);
MP_VERBOSE(ao, "\n");
p->device_index++;
return TRUE;
}
static void EnumDevs(struct ao *ao)
{
struct priv *p = ao->priv;
p->device_index = 0;
p->device_num = p->cfg_device;
HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID);
OurDirectSoundEnumerate = (void *)GetProcAddress(p->hdsound_dll,
"DirectSoundEnumerateA");
if (OurDirectSoundEnumerate == NULL) {
MP_ERR(ao, "GetProcAddress FAILED\n");
return;
}
// Enumerate all directsound p->devices
MP_VERBOSE(ao, "Output Devices:\n");
OurDirectSoundEnumerate(DirectSoundEnum, ao);
}
static int LoadDirectSound(struct ao *ao)
{
struct priv *p = ao->priv;
// initialize directsound
p->hdsound_dll = LoadLibrary("DSOUND.DLL");
if (p->hdsound_dll == NULL) {
MP_ERR(ao, "cannot load DSOUND.DLL\n");
return 0;
}
return 1;
}
static void list_devs(struct ao *ao, struct ao_device_list *list)
{
struct priv *p = ao->priv;
bool need_init = !p->hdsound_dll;
if (need_init && !LoadDirectSound(ao))
return;
p->listing = list;
EnumDevs(ao);
p->listing = NULL;
if (need_init)
UninitDirectSound(ao);
}
/**
\brief initilize direct sound
@@ -187,34 +262,23 @@ static int InitDirectSound(struct ao *ao)
DSCAPS dscaps;
// initialize directsound
HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID);
p->device_index = 0;
p->device_num = p->cfg_device;
p->hdsound_dll = LoadLibrary("DSOUND.DLL");
if (p->hdsound_dll == NULL) {
MP_ERR(ao, "cannot load DSOUND.DLL\n");
if (!LoadDirectSound(ao))
return 0;
}
OurDirectSoundCreate = (void *)GetProcAddress(p->hdsound_dll,
"DirectSoundCreate");
OurDirectSoundEnumerate = (void *)GetProcAddress(p->hdsound_dll,
"DirectSoundEnumerateA");
if (OurDirectSoundCreate == NULL || OurDirectSoundEnumerate == NULL) {
HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
OurDirectSoundCreate =
(void *)GetProcAddress(p->hdsound_dll, "DirectSoundCreate");
if (OurDirectSoundCreate == NULL) {
MP_ERR(ao, "GetProcAddress FAILED\n");
FreeLibrary(p->hdsound_dll);
return 0;
}
// Enumerate all directsound p->devices
MP_VERBOSE(ao, "Output Devices:\n");
OurDirectSoundEnumerate(DirectSoundEnum, ao);
EnumDevs(ao);
// Create the direct sound object
if (FAILED(OurDirectSoundCreate((p->device_num) ? &p->device : NULL,
if (FAILED(OurDirectSoundCreate((p->device_num > 0) ? &p->device : NULL,
&p->hds, NULL)))
{
MP_ERR(ao, "cannot create a DirectSound device\n");
@@ -350,6 +414,8 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
IDirectSoundBuffer_SetVolume(p->hdsbuf, volume);
return CONTROL_OK;
}
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
@@ -370,7 +436,6 @@ static int init(struct ao *ao)
if (!InitDirectSound(ao))
return -1;
ao->no_persistent_volume = true;
p->audio_volume = 100;
// ok, now create the buffers
@@ -380,34 +445,33 @@ static int init(struct ao *ao)
int format = af_fmt_from_planar(ao->format);
int rate = ao->samplerate;
if (AF_FORMAT_IS_AC3(format))
format = AF_FORMAT_AC3;
else {
if (!AF_FORMAT_IS_IEC61937(format)) {
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
}
switch (format) {
case AF_FORMAT_AC3:
case AF_FORMAT_S24_LE:
case AF_FORMAT_S16_LE:
case AF_FORMAT_S24:
case AF_FORMAT_S16:
case AF_FORMAT_U8:
break;
default:
if (AF_FORMAT_IS_IEC61937(format))
break;
MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n",
af_fmt_to_str(format));
format = AF_FORMAT_S16_LE;
format = AF_FORMAT_S16;
}
//set our audio parameters
ao->samplerate = rate;
ao->format = format;
ao->bps = ao->channels.num * rate * af_fmt2bps(format);
int buffersize = ao->bps; // space for 1 sec
int buffersize = ao->bps * p->cfg_buffersize / 1000;
MP_VERBOSE(ao, "Samplerate:%iHz Channels:%i Format:%s\n", rate,
ao->channels.num, af_fmt_to_str(format));
MP_VERBOSE(ao, "Buffersize:%d bytes (%d msec)\n",
buffersize, buffersize / ao->bps * 1000);
MP_VERBOSE(ao, "Buffersize:%d bytes (%f msec)\n",
buffersize, buffersize * 1000.0 / ao->bps);
//fill waveformatex
ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
@@ -415,7 +479,8 @@ static int init(struct ao *ao)
? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = ao->channels.num;
wformat.Format.nSamplesPerSec = rate;
if (AF_FORMAT_IS_AC3(format)) {
if (AF_FORMAT_IS_IEC61937(format)) {
// Whether it also works with e.g. DTS is unknown, but probably does.
wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
wformat.Format.wBitsPerSample = 16;
wformat.Format.nBlockAlign = 4;
@@ -583,7 +648,7 @@ static int get_space(struct ao *ao)
int space = check_free_buffer_size(ao);
if (space < p->min_free_space)
return 0;
return (space - p->min_free_space) / ao->sstride;
return (space - p->min_free_space) / p->outburst * p->outburst / ao->sstride;
}
/**
@@ -611,12 +676,12 @@ static int play(struct ao *ao, void **data, int samples, int flags)
\brief get the delay between the first and last sample in the buffer
\return delay in seconds
*/
static float get_delay(struct ao *ao)
static double get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
int space = check_free_buffer_size(ao);
return (float)(p->buffer_size - space) / (float)ao->bps;
return (p->buffer_size - space) / (double)ao->bps;
}
#define OPT_BASE_STRUCT struct priv
@@ -633,9 +698,11 @@ const struct ao_driver audio_out_dsound = {
.pause = audio_pause,
.resume = audio_resume,
.reset = reset,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_INT("device", cfg_device, 0),
OPT_INT("device", cfg_device, 0, OPTDEF_INT(-1)),
OPT_INTRANGE("buffersize", cfg_buffersize, 0, 1, 10000, OPTDEF_INT(200)),
{0}
},
};
+25 -15
View File
@@ -28,7 +28,6 @@
#include <libavutil/common.h>
#include <libavutil/audioconvert.h>
#include "compat/libav.h"
#include "config.h"
#include "options/options.h"
#include "common/common.h"
@@ -57,6 +56,8 @@ struct priv {
AVRational worst_time_base;
int worst_time_base_is_stream;
bool shutdown;
};
static void select_format(struct ao *ao, AVCodec *codec)
@@ -71,7 +72,7 @@ static void select_format(struct ao *ao, AVCodec *codec)
{
int fmt = af_from_avformat(*sampleformat);
if (!fmt) {
MP_WARN(ao, "unsupported lavc format %s",
MP_WARN(ao, "unsupported lavc format %s\n",
av_get_sample_fmt_name(*sampleformat));
continue;
}
@@ -114,12 +115,11 @@ static int init(struct ao *ao)
codec = encode_lavc_get_codec(ao->encode_lavc_ctx, ac->stream);
// ac->stream->time_base.num = 1;
// ac->stream->time_base.den = ao->samplerate;
// doing this breaks mpeg2ts in ffmpeg
// which doesn't properly force the time base to be 90000
// furthermore, ffmpeg.c doesn't do this either and works
// TODO: Remove this redundancy with encode_lavc_alloc_stream also
// setting the time base.
// Using codec->time_bvase is deprecated, but needed for older lavf.
ac->stream->time_base.num = 1;
ac->stream->time_base.den = ao->samplerate;
ac->stream->codec->time_base.num = 1;
ac->stream->codec->time_base.den = ao->samplerate;
@@ -176,6 +176,7 @@ static int init(struct ao *ao)
fail:
pthread_mutex_unlock(&ao->encode_lavc_ctx->lock);
ac->shutdown = true;
return -1;
}
@@ -186,6 +187,9 @@ static void uninit(struct ao *ao)
struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
if (!ac || ac->shutdown)
return;
pthread_mutex_lock(&ectx->lock);
if (!encode_lavc_start(ectx)) {
@@ -203,6 +207,8 @@ static void uninit(struct ao *ao)
}
pthread_mutex_unlock(&ectx->lock);
ac->shutdown = true;
}
// return: how many bytes can be played without blocking
@@ -236,8 +242,9 @@ static int encode(struct ao *ao, double apts, void **data)
frame->format = af_to_avformat(ao->format);
frame->nb_samples = ac->aframesize;
assert(ao->channels.num <= AV_NUM_DATA_POINTERS);
for (int n = 0; n < ao->channels.num; n++)
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;
@@ -342,18 +349,17 @@ static int play(struct ao *ao, void **data, int samples, int flags)
}
double pts = ectx->last_audio_in_pts;
pts += ectx->samples_since_last_pts / ao->samplerate;
ectx->samples_since_last_pts += samples;
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;
void *padded[MP_NUM_CHANNELS];
for (int n = 0; n < num_planes; n++) {
padded[n] = talloc_size(tempdata, bytelen + extralen);
memcpy(padded[n], data[n], bytelen);
@@ -433,7 +439,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
outpts += encode_lavc_getoffset(ectx, ac->stream);
while (samples - bufpos >= ac->aframesize) {
void *start[MP_NUM_CHANNELS];
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);
@@ -451,6 +457,10 @@ static int play(struct ao *ao, void **data, int samples, int flags)
}
talloc_free(tempdata);
int taken = FFMIN(bufpos, orig_samples);
ectx->samples_since_last_pts += taken;
pthread_mutex_unlock(&ectx->lock);
if (flags & AOPLAY_FINAL_CHUNK) {
@@ -463,7 +473,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
}
}
return FFMIN(bufpos, orig_samples);
return taken;
}
static void drain(struct ao *ao)
+4 -4
View File
@@ -90,7 +90,7 @@ static int init(struct ao *ao)
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_any(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
mp_chmap_from_channels(&ao->channels, 2);
priv->latency = priv->latency_sec * ao->samplerate;
@@ -148,7 +148,8 @@ static int get_space(struct ao *ao)
struct priv *priv = ao->priv;
drain(ao);
return priv->buffersize - priv->latency - priv->buffered;
int samples = priv->buffersize - priv->latency - priv->buffered;
return samples / priv->outburst * priv->outburst;
}
static int play(struct ao *ao, void **data, int samples, int flags)
@@ -175,7 +176,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return accepted;
}
static float get_delay(struct ao *ao)
static double get_delay(struct ao *ao)
{
struct priv *priv = ao->priv;
@@ -210,7 +211,6 @@ const struct ao_driver audio_out_null = {
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.bufferlen = 0.2,
.latency_sec = 0.5,
.outburst = 256,
.speed = 1,
},
+20 -4
View File
@@ -76,6 +76,8 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
vol->left = vol->right = volume * 100;
return CONTROL_TRUE;
}
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
@@ -99,6 +101,17 @@ static int validate_device_opt(struct mp_log *log, const m_option_t *opt,
return 0;
}
static void list_devs(struct ao *ao, struct ao_device_list *list)
{
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_TRUE)
return;
const char *devs = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
while (devs && *devs) {
ao_device_list_add(list, ao, &(struct ao_device_desc){devs, devs});
devs = devs + strlen(devs) + 1;
}
}
struct speaker {
int id;
float pos[3];
@@ -132,7 +145,6 @@ static int init(struct ao *ao)
return -1;
}
ao_data = ao;
ao->no_persistent_volume = true;
struct mp_chmap_sel sel = {0};
for (i = 0; speaker_pos[i].id != -1; i++)
mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id);
@@ -150,7 +162,10 @@ static int init(struct ao *ao)
goto err_out;
}
}
dev = alcOpenDevice(p->cfg_device && p->cfg_device[0] ? p->cfg_device : NULL);
char *dev_name = p->cfg_device;
if (!dev_name || !dev_name[0])
dev_name = ao->device;
dev = alcOpenDevice(dev_name && dev_name[0] ? dev_name : NULL);
if (!dev) {
MP_FATAL(ao, "could not open device\n");
goto err_out;
@@ -278,12 +293,12 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return num * CHUNK_SAMPLES;
}
static float get_delay(struct ao *ao)
static double get_delay(struct ao *ao)
{
ALint queued;
unqueue_buffers();
alGetSourcei(sources[0], AL_BUFFERS_QUEUED, &queued);
return queued * CHUNK_SAMPLES / (float)ao->samplerate;
return queued * CHUNK_SAMPLES / (double)ao->samplerate;
}
#define OPT_BASE_STRUCT struct priv
@@ -301,6 +316,7 @@ const struct ao_driver audio_out_openal = {
.resume = audio_resume,
.reset = reset,
.drain = drain,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt),
+339 -299
View File
@@ -31,12 +31,16 @@
#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/msg.h"
#include "osdep/timer.h"
#include "osdep/endian.h"
#if HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
@@ -51,14 +55,20 @@
#include "ao.h"
#include "internal.h"
// 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.
#define KEEP_DEVICE (defined(SNDCTL_DSP_RESET) && !defined(__NetBSD__))
struct priv {
int audio_fd;
int prepause_space;
int prepause_samples;
int oss_mixer_channel;
audio_buf_info zz;
int audio_delay_method;
int buffersize;
int outburst;
bool device_failed;
double audio_end;
char *dsp;
char *oss_mixer_device;
@@ -80,53 +90,60 @@ static const struct mp_chmap oss_layouts[MP_NUM_CHANNELS + 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_U16_NE) && defined(AFMT_U16_LE) && defined(AFMT_U16_BE)
#define AFMT_U16_NE MP_SELECT_LE_BE(AFMT_U16_LE, AFMT_U16_BE)
#endif
#if !defined(AFMT_U24_NE) && defined(AFMT_U24_LE) && defined(AFMT_U24_BE)
#define AFMT_U24_NE MP_SELECT_LE_BE(AFMT_U24_LE, AFMT_U24_BE)
#endif
#if !defined(AFMT_S24_NE) && defined(AFMT_S24_LE) && defined(AFMT_S24_BE)
#define AFMT_S24_NE MP_SELECT_LE_BE(AFMT_S24_LE, AFMT_S24_BE)
#endif
#if !defined(AFMT_U32_NE) && defined(AFMT_U32_LE) && defined(AFMT_U32_BE)
#define AFMT_U32MP_SELECT_LE_BE(AFMT_U32_LE, AFMT_U32_BE)
#endif
#if !defined(AFMT_S32_NE) && defined(AFMT_S32_LE) && defined(AFMT_S32_BE)
#define AFMT_S32MP_SELECT_LE_BE(AFMT_S32_LE, AFMT_S32_BE)
#endif
static const int format_table[][2] = {
{AFMT_U8, AF_FORMAT_U8},
{AFMT_S8, AF_FORMAT_S8},
{AFMT_U16_LE, AF_FORMAT_U16_LE},
{AFMT_U16_BE, AF_FORMAT_U16_BE},
{AFMT_S16_LE, AF_FORMAT_S16_LE},
{AFMT_S16_BE, AF_FORMAT_S16_BE},
#ifdef AFMT_S24_PACKED
{AFMT_S24_PACKED, AF_FORMAT_S24_LE},
{AFMT_U16_NE, AF_FORMAT_U16},
{AFMT_S16_NE, AF_FORMAT_S16},
#ifdef AFMT_U24_NE
{AFMT_U24_NE, AF_FORMAT_U24},
#endif
#ifdef AFMT_U24_LE
{AFMT_U24_LE, AF_FORMAT_U24_LE},
#ifdef AFMT_S24_NE
{AFMT_S24_NE, AF_FORMAT_S24},
#endif
#ifdef AFMT_U24_BE
{AFMT_U24_BE, AF_FORMAT_U24_BE},
#ifdef AFMT_U32_NE
{AFMT_U32_NE, AF_FORMAT_U32},
#endif
#ifdef AFMT_S24_LE
{AFMT_S24_LE, AF_FORMAT_S24_LE},
#endif
#ifdef AFMT_S24_BE
{AFMT_S24_BE, AF_FORMAT_S24_BE},
#endif
#ifdef AFMT_U32_LE
{AFMT_U32_LE, AF_FORMAT_U32_LE},
#endif
#ifdef AFMT_U32_BE
{AFMT_U32_BE, AF_FORMAT_U32_BE},
#endif
#ifdef AFMT_S32_LE
{AFMT_S32_LE, AF_FORMAT_S32_LE},
#endif
#ifdef AFMT_S32_BE
{AFMT_S32_BE, AF_FORMAT_S32_BE},
#ifdef AFMT_S32_NE
{AFMT_S32_NE, AF_FORMAT_S32},
#endif
#ifdef AFMT_FLOAT
{AFMT_FLOAT, AF_FORMAT_FLOAT},
#endif
// SPECIALS
#ifdef AFMT_MPEG
{AFMT_MPEG, AF_FORMAT_MPEG2},
#endif
#ifdef AFMT_AC3
{AFMT_AC3, AF_FORMAT_AC3},
{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++) {
@@ -142,7 +159,7 @@ static int oss2format(int format)
if (format_table[n][0] == format)
return format_table[n][1];
}
return -1;
return 0;
}
@@ -177,8 +194,7 @@ 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:
{
case AOCONTROL_SET_VOLUME: {
ao_control_vol_t *vol = (ao_control_vol_t *)arg;
int fd, v, devs;
@@ -188,7 +204,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return CONTROL_OK;
#endif
if (AF_FORMAT_IS_AC3(ao->format))
if (AF_FORMAT_IS_SPECIAL(ao->format))
return CONTROL_TRUE;
if ((fd = open(p->oss_mixer_device, O_RDONLY)) != -1) {
@@ -209,22 +225,205 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
close(fd);
return CONTROL_OK;
}
}
return CONTROL_ERROR;
}
#ifdef SNDCTL_DSP_GETPLAYVOL
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
#endif
}
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_FORMAT_IS_IEC61937(*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;
#ifdef __linux__
p->audio_fd = open(p->dsp, O_WRONLY | O_NONBLOCK);
#else
p->audio_fd = open(p->dsp, O_WRONLY);
#endif
if (p->audio_fd < 0) {
MP_ERR(ao, "Can't open audio device %s: %s\n", p->dsp, 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", strerror(errno));
goto fail;
}
#endif
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
if (AF_FORMAT_IS_IEC61937(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[] = {format, AF_FORMAT_S32, AF_FORMAT_S24, AF_FORMAT_S16, 0};
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_FORMAT_IS_IEC61937(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 reqchannels = channels.num;
// We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
if (reqchannels > 2) {
int nchannels = reqchannels;
if (ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1 ||
nchannels != reqchannels)
{
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
goto fail;
}
} else {
int c = reqchannels - 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;
}
}
p->outburst -= p->outburst % (channels.num * af_fmt2bps(format)); // round down
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;
int oss_format;
#ifdef SNDCTL_DSP_GETPLAYVOL
ao->no_persistent_volume = true;
#endif
const char *mchan = NULL;
if (p->cfg_oss_mixer_channel && p->cfg_oss_mixer_channel[0])
@@ -265,178 +464,36 @@ static int init(struct ao *ao)
MP_VERBOSE(ao, "using '%s' mixer device\n", p->oss_mixer_device);
MP_VERBOSE(ao, "using '%s' mixer device\n", mixer_channels[p->oss_mixer_channel]);
#ifdef __linux__
p->audio_fd = open(p->dsp, O_WRONLY | O_NONBLOCK);
#else
p->audio_fd = open(p->dsp, O_WRONLY);
#endif
if (p->audio_fd < 0) {
MP_ERR(ao, "Can't open audio device %s: %s\n", p->dsp, strerror(errno));
return -1;
}
#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", strerror(errno));
return -1;
}
#endif
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
ao->format = af_fmt_from_planar(ao->format);
if (AF_FORMAT_IS_AC3(ao->format)) {
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
}
ac3_retry:
if (AF_FORMAT_IS_AC3(ao->format))
ao->format = AF_FORMAT_AC3;
oss_format = format2oss(ao->format);
if (oss_format == -1) {
MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n",
af_fmt_to_str(ao->format));
#if defined(AFMT_S32_LE) && defined(AFMT_S32_BE)
#if BYTE_ORDER == BIG_ENDIAN
oss_format = AFMT_S32_BE;
#else
oss_format = AFMT_S32_LE;
#endif
ao->format = AF_FORMAT_S32;
#elif defined(AFMT_S24_LE) && defined(AFMT_S24_BE)
#if BYTE_ORDER == BIG_ENDIAN
oss_format = AFMT_S24_BE;
#else
oss_format = AFMT_S24_LE;
#endif
ao->format = AF_FORMAT_S24;
#else
#if BYTE_ORDER == BIG_ENDIAN
oss_format = AFMT_S16_BE;
#else
oss_format = AFMT_S16_LE;
#endif
ao->format = AF_FORMAT_S16;
#endif
}
if (ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &oss_format) < 0 ||
oss_format != format2oss(ao->format))
{
MP_WARN(ao, "Can't set audio device %s to %s output, trying %s...\n",
p->dsp, af_fmt_to_str(ao->format),
af_fmt_to_str(AF_FORMAT_S16));
ao->format = AF_FORMAT_S16;
goto ac3_retry;
}
ao->format = oss2format(oss_format);
if (ao->format == -1) {
MP_ERR(ao, "Unknown/Unsupported OSS format: %x.\n", oss_format);
return -1;
}
MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(ao->format));
if (!AF_FORMAT_IS_AC3(ao->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, &ao->channels))
return -1;
int reqchannels = ao->channels.num;
// We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
if (reqchannels > 2) {
int nchannels = reqchannels;
if (ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1 ||
nchannels != reqchannels)
{
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
return -1;
}
} else {
int c = reqchannels - 1;
if (ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
return -1;
}
if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, c + 1))
return -1;
}
MP_VERBOSE(ao, "using %d channels (requested: %d)\n",
ao->channels.num, reqchannels);
// set rate
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
MP_VERBOSE(ao, "using %d Hz samplerate\n", ao->samplerate);
}
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->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",
p->zz.fragments, p->zz.fragstotal, p->zz.fragsize, p->zz.bytes);
p->buffersize = p->zz.bytes;
p->outburst = p->zz.fragsize;
}
if (reopen_device(ao, true) < 0)
goto fail;
if (p->buffersize == -1) {
// Measuring buffer size:
void *data;
void *data = malloc(p->outburst);
if (!data) {
MP_ERR(ao, "Out of memory, or broken outburst size.\n");
goto fail;
}
p->buffersize = 0;
#if HAVE_AUDIO_SELECT
data = malloc(p->outburst);
memset(data, 0, p->outburst);
while (p->buffersize < 0x40000) {
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(p->audio_fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
if (!select(p->audio_fd + 1, NULL, &rfds, NULL, &tv))
break;
while (p->buffersize < 0x40000 && device_writable(ao) > 0) {
write(p->audio_fd, data, p->outburst);
p->buffersize += p->outburst;
}
free(data);
if (p->buffersize == 0) {
MP_ERR(ao, "*** Your audio driver DOES NOT support select() ***\n");
MP_ERR(ao, "Recompile mpv with #define HAVE_AUDIO_SELECT 0 in config.h!\n");
return -1;
MP_ERR(ao, "Your OSS audio driver DOES NOT support poll().\n");
goto fail;
}
#endif
}
ao->bps = ao->channels.num * af_fmt2bps(ao->format);
p->outburst -= p->outburst % ao->bps; // round down
ao->bps *= ao->samplerate;
return 0;
}
// close audio device
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->audio_fd == -1)
return;
#ifdef SNDCTL_DSP_RESET
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#endif
close(p->audio_fd);
p->audio_fd = -1;
fail:
uninit(ao);
return -1;
}
static void drain(struct ao *ao)
@@ -449,104 +506,39 @@ static void drain(struct ao *ao)
#endif
}
#ifndef SNDCTL_DSP_RESET
static void close_device(struct ao *ao)
{
struct priv *p = ao->priv;
close(p->audio_fd);
p->audio_fd = -1;
}
#endif
// stop playing and empty buffers (for seeking/pause)
static void reset(struct ao *ao)
{
#if KEEP_DEVICE
struct priv *p = ao->priv;
int oss_format;
#ifdef SNDCTL_DSP_RESET
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
p->audio_fd = open(p->dsp, O_WRONLY);
if (p->audio_fd < 0) {
MP_ERR(ao, "Fatal error: *** CANNOT "
"RE-OPEN / RESET AUDIO DEVICE *** %s\n", strerror(errno));
return;
}
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
#endif
oss_format = format2oss(ao->format);
if (AF_FORMAT_IS_AC3(ao->format))
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &oss_format);
if (!AF_FORMAT_IS_AC3(ao->format)) {
int c = ao->channels.num;
if (ao->channels.num > 2)
ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &c);
else {
c--;
ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c);
}
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
}
}
// return: how many bytes can be played without blocking
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
int playsize = p->outburst;
#ifdef SNDCTL_DSP_GETOSPACE
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) != -1) {
// calculate exact buffer space:
playsize = p->zz.fragments * p->zz.fragsize;
return playsize / ao->sstride;
}
#endif
// check buffer
#if HAVE_AUDIO_SELECT
{
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(p->audio_fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
if (!select(p->audio_fd + 1, NULL, &rfds, NULL, &tv))
return 0; // not block!
}
#endif
return p->outburst / ao->sstride;
}
// stop playing, keep buffers (for pause)
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
p->prepause_space = get_space(ao) * ao->sstride;
#ifdef SNDCTL_DSP_RESET
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
#endif
}
// plays 'len' bytes of 'data'
// plays 'len' samples of 'data'
// it should round it down to outburst*n
// return: number of bytes played
// 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;
@@ -555,40 +547,86 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return len / ao->sstride;
}
// resume playing, after audio_pause()
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
#ifndef SNDCTL_DSP_RESET
reset(ao);
#endif
int fillframes = get_space(ao) - p->prepause_space / ao->sstride;
if (fillframes > 0)
ao_play_silence(ao, fillframes);
}
// return: delay in seconds between first and last sample in buffer
static float get_delay(struct ao *ao)
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 ((float)r) / (float)ao->bps;
return r / (double)ao->bps;
#endif
p->audio_delay_method = 1; // fallback if not supported
}
if (p->audio_delay_method == 1) {
// SNDCTL_DSP_GETOSPACE
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) != -1) {
return ((float)(p->buffersize -
p->zz.bytes)) / (float)ao->bps;
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 ((float)p->buffersize) / (float)ao->bps;
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;
}
#define OPT_BASE_STRUCT struct priv
@@ -606,6 +644,8 @@ const struct ao_driver audio_out_oss = {
.resume = audio_resume,
.reset = reset,
.drain = drain,
.wait = audio_wait,
.wakeup = ao_wakeup_poll,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.audio_fd = -1,
+29 -26
View File
@@ -35,6 +35,7 @@
#include "ao.h"
#include "internal.h"
#include "common/msg.h"
#include "osdep/endian.h"
#ifdef __MINGW32__
// for GetFileType to detect pipes
@@ -71,40 +72,35 @@ static void fput32le(uint32_t val, FILE *fp)
static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length)
{
bool use_waveex = true;
uint16_t fmt = ao->format == AF_FORMAT_FLOAT_LE ?
WAV_ID_FLOAT_PCM : WAV_ID_PCM;
uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
uint16_t fmt = ao->format == AF_FORMAT_FLOAT ? WAV_ID_FLOAT_PCM : WAV_ID_PCM;
int bits = af_fmt2bits(ao->format);
// Master RIFF chunk
fput32le(WAV_ID_RIFF, fp);
// RIFF chunk size: 'WAVE' + 'fmt ' + 4 + fmt_chunk_size +
// RIFF chunk size: 'WAVE' + 'fmt ' + 4 + 40 +
// data chunk hdr (8) + data length
fput32le(12 + fmt_chunk_size + 8 + data_length, fp);
fput32le(12 + 40 + 8 + data_length, fp);
fput32le(WAV_ID_WAVE, fp);
// Format chunk
fput32le(WAV_ID_FMT, fp);
fput32le(fmt_chunk_size, fp);
fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp);
fput32le(40, fp);
fput16le(WAV_ID_FORMAT_EXTENSIBLE, fp);
fput16le(ao->channels.num, fp);
fput32le(ao->samplerate, fp);
fput32le(ao->bps, fp);
fput16le(ao->channels.num * (bits / 8), fp);
fput16le(bits, fp);
if (use_waveex) {
// Extension chunk
fput16le(22, fp);
fput16le(bits, fp);
fput32le(mp_chmap_to_waveext(&ao->channels), fp);
// 2 bytes format + 14 bytes guid
fput32le(fmt, fp);
fput32le(0x00100000, fp);
fput32le(0xAA000080, fp);
fput32le(0x719B3800, fp);
}
// Extension chunk
fput16le(22, fp);
fput16le(bits, fp);
fput32le(mp_chmap_to_waveext(&ao->channels), fp);
// 2 bytes format + 14 bytes guid
fput32le(fmt, fp);
fput32le(0x00100000, fp);
fput32le(0xAA000080, fp);
fput32le(0x719B3800, fp);
// Data chunk
fput32le(WAV_ID_DATA, fp);
@@ -124,16 +120,23 @@ static int init(struct ao *ao)
if (priv->waveheader) {
// WAV files must have one of the following formats
// And they don't work in big endian; fixing it would be simple, but
// nobody cares.
if (BYTE_ORDER == BIG_ENDIAN) {
MP_FATAL(ao, "Not supported on big endian.\n");
return -1;
}
switch (ao->format) {
case AF_FORMAT_U8:
case AF_FORMAT_S16_LE:
case AF_FORMAT_S24_LE:
case AF_FORMAT_S32_LE:
case AF_FORMAT_FLOAT_LE:
case AF_FORMAT_AC3_LE:
case AF_FORMAT_S16:
case AF_FORMAT_S24:
case AF_FORMAT_S32:
case AF_FORMAT_FLOAT:
break;
default:
ao->format = AF_FORMAT_S16_LE;
if (!AF_FORMAT_IS_IEC61937(ao->format))
ao->format = AF_FORMAT_S16;
break;
}
}
@@ -203,7 +206,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
fwrite(data[0], len, 1, priv->fp);
priv->data_length += len;
return len / ao->sstride;
return samples;
}
#define OPT_BASE_STRUCT struct priv
+24 -2
View File
@@ -125,6 +125,24 @@ static int validate_device_opt(struct mp_log *log, const m_option_t *opt,
return 0;
}
static void list_devs(struct ao *ao, struct ao_device_list *list)
{
if (Pa_Initialize() < 0)
return;
int count = Pa_GetDeviceCount(); // negative on error
for (int n = 0; n < count; n++) {
const PaDeviceInfo* info = Pa_GetDeviceInfo(n);
char desc[1024];
snprintf(desc, sizeof(desc), "%s, %d channels, latency: %.2f "
"ms, sample rate: %.0f", info->name,
info->maxOutputChannels,
info->defaultHighOutputLatency * 1000,
info->defaultSampleRate);
ao_device_list_add(list, ao, &(struct ao_device_desc){info->name, desc});
}
Pa_Terminate();
}
static int stream_callback(const void *input,
void *output_v,
unsigned long frameCount,
@@ -167,8 +185,11 @@ static int init(struct ao *ao)
return -1;
int pa_device = Pa_GetDefaultOutputDevice();
if (priv->cfg_device && priv->cfg_device[0])
pa_device = find_device(ao->log, priv->cfg_device);
char *dev_name = priv->cfg_device;
if (!dev_name || !dev_name[0])
dev_name = ao->device;
if (dev_name && dev_name[0])
pa_device = find_device(ao->log, dev_name);
if (pa_device == paNoDevice)
goto error_exit;
@@ -246,6 +267,7 @@ const struct ao_driver audio_out_portaudio = {
.uninit = uninit,
.reset = reset,
.resume = resume,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt),
+202 -85
View File
@@ -35,8 +35,6 @@
#include "ao.h"
#include "internal.h"
#define PULSE_CLIENT_NAME "mpv"
#define VOL_PA2MP(v) ((v) * 100 / PA_VOLUME_NORM)
#define VOL_MP2PA(v) ((v) * PA_VOLUME_NORM / 100)
@@ -53,7 +51,6 @@ struct priv {
// temporary during control()
struct pa_sink_input_info pi;
bool broken_pause;
int retval;
// for wakeup handling
@@ -64,6 +61,7 @@ struct priv {
char *cfg_host;
char *cfg_sink;
int cfg_buffer;
int cfg_latency_hacks;
};
#define GENERIC_ERR_MSG(str) \
@@ -113,7 +111,7 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata)
pa_threaded_mainloop_signal(priv->mainloop, 0);
}
static int wait(struct ao *ao, pthread_mutex_t *lock)
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
@@ -169,16 +167,31 @@ static const struct format_map {
int mp_format;
pa_sample_format_t pa_format;
} format_maps[] = {
{AF_FORMAT_S16_LE, PA_SAMPLE_S16LE},
{AF_FORMAT_S16_BE, PA_SAMPLE_S16BE},
{AF_FORMAT_S32_LE, PA_SAMPLE_S32LE},
{AF_FORMAT_S32_BE, PA_SAMPLE_S32BE},
{AF_FORMAT_FLOAT_LE, PA_SAMPLE_FLOAT32LE},
{AF_FORMAT_FLOAT_BE, PA_SAMPLE_FLOAT32BE},
{AF_FORMAT_S16, PA_SAMPLE_S16NE},
{AF_FORMAT_S32, PA_SAMPLE_S32NE},
{AF_FORMAT_FLOAT, PA_SAMPLE_FLOAT32NE},
{AF_FORMAT_U8, PA_SAMPLE_U8},
{AF_FORMAT_UNKNOWN, 0}
};
static pa_encoding_t map_digital_format(int format)
{
switch (format) {
case AF_FORMAT_S_AC3: return PA_ENCODING_AC3_IEC61937;
case AF_FORMAT_S_EAC3: return PA_ENCODING_EAC3_IEC61937;
case AF_FORMAT_S_MP3: return PA_ENCODING_MPEG_IEC61937;
case AF_FORMAT_S_DTS:
case AF_FORMAT_S_DTSHD: return PA_ENCODING_DTS_IEC61937;
#ifdef PA_ENCODING_MPEG2_AAC_IEC61937
case AF_FORMAT_S_AAC: return PA_ENCODING_MPEG2_AAC_IEC61937;
#endif
default:
if (AF_FORMAT_IS_IEC61937(format))
return PA_ENCODING_ANY;
return PA_ENCODING_PCM;
}
}
static const int speaker_map[][2] = {
{PA_CHANNEL_POSITION_FRONT_LEFT, MP_SPEAKER_ID_FL},
{PA_CHANNEL_POSITION_FRONT_RIGHT, MP_SPEAKER_ID_FR},
@@ -272,81 +285,105 @@ static void uninit(struct ao *ao)
pthread_mutex_destroy(&priv->wakeup_lock);
}
static int init(struct ao *ao)
static int pa_init_boilerplate(struct ao *ao)
{
struct pa_sample_spec ss;
struct pa_channel_map map;
pa_proplist *proplist = NULL;
struct priv *priv = ao->priv;
char *host = priv->cfg_host && priv->cfg_host[0] ? priv->cfg_host : NULL;
char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : NULL;
const char *version = pa_get_library_version();
bool locked = false;
pthread_mutex_init(&priv->wakeup_lock, NULL);
pthread_cond_init(&priv->wakeup, NULL);
ao->per_application_mixer = true;
priv->broken_pause = false;
/* not sure which versions are affected, assume 0.9.11* to 0.9.14*
* known bad: 0.9.14, 0.9.13
* known good: 0.9.9, 0.9.10, 0.9.15
* To test: pause, wait ca. 5 seconds, framestep and see if MPlayer
* hangs somewhen. */
if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1'
&& version[5] <= '4') {
MP_WARN(ao, "working around probably broken pause functionality,\n"
" see http://www.pulseaudio.org/ticket/440\n");
priv->broken_pause = true;
}
if (!(priv->mainloop = pa_threaded_mainloop_new())) {
MP_ERR(ao, "Failed to allocate main loop\n");
goto fail;
}
if (pa_threaded_mainloop_start(priv->mainloop) < 0)
goto fail;
pa_threaded_mainloop_lock(priv->mainloop);
locked = true;
if (!(priv->context = pa_context_new(pa_threaded_mainloop_get_api(
priv->mainloop), PULSE_CLIENT_NAME))) {
priv->mainloop), ao->client_name)))
{
MP_ERR(ao, "Failed to allocate context\n");
goto fail;
}
MP_VERBOSE(ao, "Library version: %s\n", pa_get_library_version());
MP_VERBOSE(ao, "Proto: %lu\n",
(long)pa_context_get_protocol_version(priv->context));
MP_VERBOSE(ao, "Server proto: %lu\n",
(long)pa_context_get_server_protocol_version(priv->context));
pa_context_set_state_callback(priv->context, context_state_cb, ao);
if (pa_context_connect(priv->context, host, 0, NULL) < 0)
goto fail;
/* Wait until the context is ready */
while (1) {
int state = pa_context_get_state(priv->context);
if (state == PA_CONTEXT_READY)
break;
if (!PA_CONTEXT_IS_GOOD(state))
goto fail;
pa_threaded_mainloop_wait(priv->mainloop);
}
pa_threaded_mainloop_unlock(priv->mainloop);
return 0;
fail:
if (locked)
pa_threaded_mainloop_unlock(priv->mainloop);
if (priv->context) {
pa_threaded_mainloop_lock(priv->mainloop);
if (!(pa_context_errno(priv->context) == PA_ERR_CONNECTIONREFUSED
&& ao->probing))
GENERIC_ERR_MSG("Init failed");
pa_threaded_mainloop_unlock(priv->mainloop);
}
uninit(ao);
return -1;
}
static int init(struct ao *ao)
{
struct pa_channel_map map;
pa_proplist *proplist = NULL;
pa_format_info *format = NULL;
struct priv *priv = ao->priv;
char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : ao->device;
if (pa_init_boilerplate(ao) < 0)
return -1;
pa_threaded_mainloop_lock(priv->mainloop);
if (pa_threaded_mainloop_start(priv->mainloop) < 0)
if (!(format = pa_format_info_new()))
goto unlock_and_fail;
/* Wait until the context is ready */
pa_threaded_mainloop_wait(priv->mainloop);
if (pa_context_get_state(priv->context) != PA_CONTEXT_READY)
goto unlock_and_fail;
ss.channels = ao->channels.num;
ss.rate = ao->samplerate;
ao->format = af_fmt_from_planar(ao->format);
const struct format_map *fmt_map = format_maps;
while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
MP_VERBOSE(ao, "Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
fmt_map++;
}
ao->format = fmt_map->mp_format;
ss.format = fmt_map->pa_format;
format->encoding = map_digital_format(ao->format);
if (format->encoding == PA_ENCODING_PCM) {
const struct format_map *fmt_map = format_maps;
if (!pa_sample_spec_valid(&ss)) {
MP_ERR(ao, "Invalid sample spec\n");
goto unlock_and_fail;
while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
MP_VERBOSE(ao, "Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
fmt_map++;
}
ao->format = fmt_map->mp_format;
pa_format_info_set_sample_format(format, fmt_map->pa_format);
}
if (!select_chmap(ao, &map))
@@ -357,10 +394,19 @@ static int init(struct ao *ao)
goto unlock_and_fail;
}
(void)pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "video");
(void)pa_proplist_sets(proplist, PA_PROP_MEDIA_ICON_NAME, ao->client_name);
if (!(priv->stream = pa_stream_new_with_proplist(priv->context,
"audio stream", &ss,
&map, proplist)))
pa_format_info_set_rate(format, ao->samplerate);
pa_format_info_set_channels(format, ao->channels.num);
pa_format_info_set_channel_map(format, &map);
if (!pa_format_info_valid(format)) {
MP_ERR(ao, "Invalid audio format\n");
goto unlock_and_fail;
}
if (!(priv->stream = pa_stream_new_extended(priv->context, "audio stream",
&format, 1, proplist)))
goto unlock_and_fail;
pa_proplist_free(proplist);
@@ -370,39 +416,47 @@ 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);
int buf_size = af_fmt_seconds_to_bytes(ao->format, priv->cfg_buffer / 1000.0,
ao->channels.num, ao->samplerate);
pa_buffer_attr bufattr = {
.maxlength = -1,
.tlength = priv->cfg_buffer > 0 ?
pa_usec_to_bytes(priv->cfg_buffer * 1000, &ss) : (uint32_t)-1,
.tlength = buf_size > 0 ? buf_size : (uint32_t)-1,
.prebuf = -1,
.minreq = -1,
.fragsize = -1,
};
int flags = PA_STREAM_NOT_MONOTONIC;
if (!priv->cfg_latency_hacks)
flags |= PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE;
if (pa_stream_connect_playback(priv->stream, sink, &bufattr,
PA_STREAM_NOT_MONOTONIC, NULL, NULL) < 0)
flags, NULL, NULL) < 0)
goto unlock_and_fail;
/* Wait until the stream is ready */
pa_threaded_mainloop_wait(priv->mainloop);
while (1) {
int state = pa_stream_get_state(priv->stream);
if (state == PA_STREAM_READY)
break;
if (!PA_STREAM_IS_GOOD(state))
goto unlock_and_fail;
pa_threaded_mainloop_wait(priv->mainloop);
}
if (pa_stream_get_state(priv->stream) != PA_STREAM_READY)
if (pa_stream_is_suspended(priv->stream)) {
MP_ERR(ao, "The stream is suspended. Bailing out.\n");
goto unlock_and_fail;
}
pa_threaded_mainloop_unlock(priv->mainloop);
return 0;
unlock_and_fail:
pa_threaded_mainloop_unlock(priv->mainloop);
if (priv->mainloop)
pa_threaded_mainloop_unlock(priv->mainloop);
fail:
if (priv->context) {
if (!(pa_context_errno(priv->context) == PA_ERR_CONNECTIONREFUSED
&& ao->probing))
GENERIC_ERR_MSG("Init failed");
}
if (format)
pa_format_info_free(format);
if (proplist)
pa_proplist_free(proplist);
@@ -463,12 +517,6 @@ static void pause(struct ao *ao)
// Resume the audio stream by uncorking it on the server
static void resume(struct ao *ao)
{
struct priv *priv = ao->priv;
/* Without this, certain versions will cause an infinite hang because
* pa_stream_writable_size returns 0 always.
* Note that this workaround causes A-V desync after pause. */
if (priv->broken_pause)
reset(ao);
cork(ao, false);
}
@@ -482,8 +530,7 @@ static int get_space(struct ao *ao)
return space / ao->sstride;
}
// Return the current latency in seconds
static float get_delay(struct ao *ao)
static double get_delay_hackfixed(struct ao *ao)
{
/* This code basically does what pa_stream_get_latency() _should_
* do, but doesn't due to multiple known bugs in PulseAudio (at
@@ -538,6 +585,34 @@ static float get_delay(struct ao *ao)
return latency / 1e6;
}
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");
break;
}
/* 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)
{
struct priv *priv = ao->priv;
if (priv->cfg_latency_hacks) {
return get_delay_hackfixed(ao);
} else {
return get_delay_pulse(ao);
}
}
/* A callback function that is called when the
* pa_context_get_sink_input_info() operation completes. Saves the
* volume field of the specified structure to the global variable volume.
@@ -567,7 +642,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
pa_threaded_mainloop_lock(priv->mainloop);
if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx,
info_func, ao))) {
GENERIC_ERR_MSG("pa_stream_get_sink_input_info() failed");
GENERIC_ERR_MSG("pa_context_get_sink_input_info() failed");
return CONTROL_ERROR;
}
// Warning: some information in pi might be unaccessible, because
@@ -630,6 +705,9 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return CONTROL_OK;
}
case AOCONTROL_HAS_PER_APP_VOLUME:
return CONTROL_TRUE;
case AOCONTROL_UPDATE_STREAM_TITLE: {
char *title = (char *)arg;
pa_threaded_mainloop_lock(priv->mainloop);
@@ -647,6 +725,42 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
}
}
struct sink_cb_ctx {
struct ao *ao;
struct ao_device_list *list;
};
static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol, void *ud)
{
struct sink_cb_ctx *ctx = ud;
struct priv *priv = ctx->ao->priv;
if (eol) {
pa_threaded_mainloop_signal(priv->mainloop, 0); // wakeup waitop()
return;
}
struct ao_device_desc entry = {.name = i->name, .desc = i->description};
ao_device_list_add(ctx->list, ctx->ao, &entry);
}
static void list_devs(struct ao *ao, struct ao_device_list *list)
{
struct priv *priv = ao->priv;
bool need_uninit = !priv->mainloop;
struct sink_cb_ctx ctx = {ao, list};
if (need_uninit && pa_init_boilerplate(ao) < 0)
return;
pa_threaded_mainloop_lock(priv->mainloop);
waitop(priv, pa_context_get_sink_info_list(priv->context, sink_info_cb, &ctx));
if (need_uninit)
uninit(ao);
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_pulse = {
@@ -662,16 +776,19 @@ const struct ao_driver audio_out_pulse = {
.pause = pause,
.resume = resume,
.drain = drain,
.wait = wait,
.wait = wait_audio,
.wakeup = wakeup,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.cfg_buffer = 250,
.cfg_latency_hacks = 1,
},
.options = (const struct m_option[]) {
OPT_STRING("host", cfg_host, 0),
OPT_STRING("sink", cfg_sink, 0),
OPT_CHOICE_OR_INT("buffer", cfg_buffer, 0, 1, 2000, ({"native", -1})),
OPT_CHOICE_OR_INT("buffer", cfg_buffer, 0, 1, 2000, ({"native", 0})),
OPT_FLAG("latency-hacks", cfg_latency_hacks, 0),
{0}
},
};
+15 -29
View File
@@ -52,40 +52,26 @@ static int set_format(struct ao *ao)
case AF_FORMAT_S8:
rsd_format = RSD_S8;
break;
case AF_FORMAT_S16_LE:
rsd_format = RSD_S16_LE;
case AF_FORMAT_S16:
rsd_format = RSD_S16_NE;
break;
case AF_FORMAT_S16_BE:
rsd_format = RSD_S16_BE;
case AF_FORMAT_U16:
rsd_format = RSD_U16_NE;
break;
case AF_FORMAT_U16_LE:
rsd_format = RSD_U16_LE;
case AF_FORMAT_S24:
case AF_FORMAT_U24:
rsd_format = RSD_S32_NE;
ao->format = AF_FORMAT_S32;
break;
case AF_FORMAT_U16_BE:
rsd_format = RSD_U16_BE;
case AF_FORMAT_S32:
rsd_format = RSD_S32_NE;
break;
case AF_FORMAT_S24_LE:
case AF_FORMAT_S24_BE:
case AF_FORMAT_U24_LE:
case AF_FORMAT_U24_BE:
rsd_format = RSD_S32_LE;
ao->format = AF_FORMAT_S32_LE;
break;
case AF_FORMAT_S32_LE:
rsd_format = RSD_S32_LE;
break;
case AF_FORMAT_S32_BE:
rsd_format = RSD_S32_BE;
break;
case AF_FORMAT_U32_LE:
rsd_format = RSD_U32_LE;
break;
case AF_FORMAT_U32_BE:
rsd_format = RSD_U32_BE;
case AF_FORMAT_U32:
rsd_format = RSD_U32_NE;
break;
default:
rsd_format = RSD_S16_LE;
ao->format = AF_FORMAT_S16_LE;
rsd_format = RSD_S16_NE;
ao->format = AF_FORMAT_S16;
}
return rsd_format;
@@ -167,7 +153,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return rsd_write(priv->rd, data[0], samples * ao->sstride) / ao->sstride;
}
static float get_delay(struct ao *ao)
static double get_delay(struct ao *ao)
{
struct priv *priv = ao->priv;
return rsd_delay_ms(priv->rd) / 1000.0;
Loaded 100 of 401 files, more files were not shown because too many files have changed in this diff. Show more