Compare commits

...
133 Commits
Author SHA1 Message Date
Diogo Franco (Kovensky) 6beed16016 Release 0.9.2 2015-05-19 11:19:25 +09:00
Diogo Franco (Kovensky) abfa51e890 Update RELEASE_NOTES 2015-05-19 11:19:09 +09:00
wm4 a7794d6fc1 x11: never forcefully terminate xdg-screensaver process
It sometimes happens on exit, and it's probably a bad idea. If the
process hangs on exit (possibly due to stupid hardcoded timeouts it's
doing), mpv will also hang now, unfortunately.

(cherry picked from commit be9bf4cc7c)
2015-05-19 11:12:47 +09:00
wm4 4d6470fde0 sub: add .sup file extension for subtitle autoloading
(cherry picked from commit 21cb1f7075)
2015-05-19 11:12:13 +09:00
Avi Halachmi (:avih) b9f073d5cb manpage: improve osc help
Signed-off-by: wm4 <wm4@nowhere>
(cherry picked from commit bc503a0e88)
2015-05-19 11:12:01 +09:00
torque d5b6419eec DOCS/client_api_examples: Qt: force qmake to use pkg-config.
(cherry picked from commit 5d2a2c7fc2)
2015-05-19 11:11:54 +09:00
wm4 679de2b295 manpage: lua: clarify OSD differences between mp.command/mp.commandv
Conflicts:
	player/audio.c
	player/video.c

(cherry picked from commit f9ff4b59a2)
2015-05-19 11:11:46 +09:00
wm4 8f9cb82f4f x11: attempt to make initial fullscreening more reliable
It appears some WMs have a problem with out method of setting initial
fullscreen mode. We assume that if the window's _NET_WM_STATE includes
_NET_WM_STATE_FULLSCREEN before mapping the window, the WM will show it
as fullscreen at mapped. EWMH doesn't say anything that this should
work, although one could argue that it's implied.

In any case, since it's not standard behavior without at least some
doubt, it's probably a good idea to try the "old" method as well.
Fortunately, it should be idempotent.

See #1937, #1920.

(cherry picked from commit a4f3df5970)
2015-05-19 11:11:38 +09:00
wm4 b4fdb25611 vf_vapoursynth: reject unaligned video sizes
Leads to some nice memory corruption otherwise.

(cherry picked from commit 06bfa9309d)
2015-05-19 11:11:24 +09:00
wm4 a9cac8ade0 vo: remove suspicious line
pts can never be 0 or negative. If there is no frame, some code below
catches this case by checking hasframe.

(cherry picked from commit 372b85b9d2)
2015-05-19 11:11:19 +09:00
Diogo Franco (Kovensky) 4422c1698f Update RELEASE_NOTES 2015-05-15 19:29:14 +09:00
Michael Vetter 6eab622e7b Remove trailing whitespaces
(cherry picked from commit 9251fa125f)
2015-05-15 19:16:47 +09:00
wm4 6a5f3c3928 manpage: explain some property expansion restrictions
(cherry picked from commit 0468a4ea47)
2015-05-15 19:15:43 +09:00
wm4 721ec88068 manpage: remove stray newline
(cherry picked from commit a23a46c6ed)
2015-05-15 19:15:31 +09:00
Christian Hesse f3c699a904 build: check for lua52
Arch linux is about to update to lua 5.3.x, but lua 5.2.x will be
provided by package lua52, which contains pkg-config file lua52.pc.

Signed-off-by: wm4 <wm4@nowhere>
(cherry picked from commit 5b085fd8b1)
2015-05-15 19:15:14 +09:00
wm4 42fc0d96fc vo: avoid burning CPU when paused
Some code always calls vo_event(), even with event==0, which leads to
immediate wakeup, which in turn causes the function to be called again.
This would burn CPU, which was especially noticeable when paused.

(cherry picked from commit 0bdef9979f)
2015-05-15 19:15:05 +09:00
wm4 bbbedddddc vo_opengl_cb: actually set requested options
Quite an oversight.

(cherry picked from commit 4d9255a5e1)
2015-05-15 10:30:49 +09:00
wm4 e34c02981f vo: always call draw_image_timed() if available
Gives the VOs more flexibility.

gl_video.c already ignores the timing info if no interpolation is
active, so this requires no further changes.

(cherry picked from commit af157db7e5)
2015-05-15 10:30:32 +09:00
wm4 37ad3e79dd threads: use utility+POSIX functions instead of weird wrappers
There is not much of a reason to have these wrappers around. Use POSIX
standard functions directly, and use a separate utility function to take
care of the timespec calculations. (Course POSIX for using this weird
format for time values.)

(cherry picked from commit 92b9d75d72)
2015-05-15 10:30:15 +09:00
wm4 328d0c7fc3 ao: make better use of atomics
The main reason for this was compatibility; but some associated problems
have been solved in the previous commit.

(cherry picked from commit ca9964a4fb)
2015-05-15 10:30:03 +09:00
wm4 26409165ed atomics: add atomic_fetch_and/atomic_fetch_or
As usual, we prefer plain C11 names and semantics, and have to emulate
them if C11 atomics are not available.

For the non-atomic fallback (which is just there to make code compile in
situations the atomic property is not overly important), we require a
gross hack to make the generic macros work without using compiler-
specific extensions.

(cherry picked from commit cc24ec5b3c)
2015-05-15 10:29:53 +09:00
wm4 a7e35fadb1 cocoa: add missing break statements in switch
The first one (for VOCTRL_GET_DISPLAY_FPS) could have led to undefined
behavior if the FPS was unknown. The second is for general symmetry.

(cherry picked from commit 10149f68a5)
2015-05-15 10:29:40 +09:00
rrooij b9a6e18720 DOCS/man/options.rst: Remove trailing whitespaces
(cherry picked from commit 47ee67b8a2)
2015-05-15 10:28:58 +09:00
rrooij 33689ba945 DOCS/man/opions.rst: Elaborate on --no-video
When --no-video is set, the ytdl-format is set to "bestaudio/best". This
wasn't documented in the man page yet.

(cherry picked from commit 5d7468a06e)
2015-05-15 10:28:52 +09:00
wm4 a96dceaae2 ytdl_hook: remove tabs
We don't allow tabs in normal source code.

(cherry picked from commit 9438f811ae)
2015-05-15 10:28:34 +09:00
wm4 002c387781 old-configure: bump libbluray version
Fixes #1927.

(cherry picked from commit 1f389b05fc)
2015-05-15 10:28:09 +09:00
wm4 9ed399f27c player: avoid undefined behavior when resumign DVD/BD playback
These device options can be NULL, and NULL can't be passed for %s.

(cherry picked from commit 34ee78f2cb)
2015-05-15 10:27:30 +09:00
wm4 0d9275b931 vo_drm: allow changing video rectangle settings
Now among other things panscan can be changed during playback.

Unfortunately, it flickers. The issue is that reconfig() clears the
framebuffer. Removing the clearing shows that the "unused" parts of
the picture are not cleared - even though OSD could render there. As
such, this is a separate issue.

(cherry picked from commit 5631060569)
2015-05-09 21:15:26 +09:00
wm4 b2f44f131f vo_drm: don't mutate the current frame when clamping for panscan
When running with --panscan=1, this could crash - because the current
frame was reduced in size each time the image was redrawn, which would
result in a failed assertion the second time it's drawn.

(cherry picked from commit 859ddc9906)
2015-05-09 21:15:15 +09:00
wm4 5f81da0b88 input: filter out redundant mp_input_set_mouse_pos() calls
Prevents the OSC from showing up on start on Cocoa.

(cherry picked from commit 51120c9c7f)
2015-05-09 21:15:04 +09:00
wm4 01c452cfba audio: simplify further
Drop mp_chmap_diff() (which is unused too now), and implement
mp_chmap_diffn() in a slightly simpler way. (Too bad there is no
standard function for counting set bits.)

(cherry picked from commit 00130651da)
2015-05-09 21:14:51 +09:00
wm4 ba799895e1 audio: remove mp_chmap_contains()
It's unsued now.

(cherry picked from commit 8d5924f2c9)
2015-05-09 21:14:35 +09:00
wm4 438ae9f742 ao: log reordered versions of channel maps
Useful for debugging cases when no standard orders are used.

(cherry picked from commit 8b7035c8ff)
2015-05-09 21:14:25 +09:00
wm4 015a7638fb audio: redo channel map fallback selection
Instead of somehow having 4 different cases with each their own weight,
do it with a single function that decides which channel layout is the
better fallback.

This is simpler, and also introduces new (fixed) semantics. The new test
added to test/chmap_sel.c actually works now. This is a mixed case with
no perfect upmix or downmix, but the better choice is the one which
loses the least channels from the original layout.

One test also changes. If the input is 7.1(wide-side), and the available
layouts are 7.1 and 5.1(side), the latter is now chosen instead of the
former. This makes sense: both layouts contain 6 out of 8 channels from
the original layout, but the 5.1(side) one is smaller. This follows the
general logic. The 7.1 layout has FLC/RLC speakers instead of BL/BR,
and judging by the names, "front left center" is completely different
from "back left". If these should be exchangeable, a separate exception
would have to be added.

(cherry picked from commit 3560a50029)
2015-05-09 21:14:15 +09:00
wm4 1f4e087e6f test: simplify chmap_sel tests
(cherry picked from commit 5142b0e3f3)
2015-05-09 21:14:00 +09:00
wm4 0ed627d5ab audio: remove UNKNOWN pseudo speakers
Reuse MP_SPEAKER_ID_NA for this. If all mp_chmap entries are set to NA,
the channel layout has special "unknown channel layout" semantics, which
are used to deal with some corner cases.

(cherry picked from commit 55e777f10b)
2015-05-09 21:13:52 +09:00
wm4 1127bb41c2 audio: define only a single NA speaker ID
Remove the requirement from mp_chmap that speaker entries must be
unique. Use this to get rid of all the redundant NA speaker IDs.

(cherry picked from commit b91b4944bd)
2015-05-09 21:13:21 +09:00
wm4 f58646c85c audio: add chmap utility function
(cherry picked from commit d32b71d52e)
2015-05-09 20:18:54 +09:00
wm4 d224c89034 ao_alsa: log requested numbers of channels if ALSA rejects them
(cherry picked from commit ad9bce2a5c)
2015-05-09 20:18:35 +09:00
Diogo Franco (Kovensky) 63b92944d0 Revert "csputils: apply contrast equalizer in RGB"
This reverts commit af930e2a2e.

Better avoid big behavior changes within a release series.
2015-05-08 16:40:01 +09:00
Diogo Franco (Kovensky) d939de5a71 Update RELEASE_NOTES 2015-05-08 16:38:46 +09:00
wm4 0f834d0d5a audio: fix messed up assert()
This made no sense and always evaluated to true.

(cherry picked from commit 7b09654c33)
2015-05-08 16:38:46 +09:00
wm4 375437f204 m_config: make m_config_set_profile() use a name
Is simpler and avoids exposing profile structs to a degree.

(cherry picked from commit 036a49478f)
2015-05-08 16:38:46 +09:00
wm4 ceea08d7fe DOCS: add a link to LIRC wiki entry
(cherry picked from commit b12ca2b980)
2015-05-08 16:38:46 +09:00
wm4 b76df84687 ao_coreaudio_utils: don't list some formats as "unusable"
While mpv has no internal equivalent representation, they can still be
used as physical CoreAudio formats. Thus this label is confusing.

(cherry picked from commit 1bcb82ec93)
2015-05-08 16:38:46 +09:00
ChrisK2 8db3a5b3e4 ytdl_hook: Escape EDL URLs
Should prevent the EDL parser from tripping over = and , in the
URL.

(cherry picked from commit 6a0a67034d)
2015-05-08 16:38:45 +09:00
wm4 eccea21361 ao_sndio: add notice about padding channels
(I won't do this, but someone else seeing this might.)

(cherry picked from commit cd5ab98ff9)
2015-05-07 10:55:34 +09:00
wm4 52ed30e9b8 ao_alsa: use new padding channels support
Sometimes, ALSA will return channel layouts with padded channels (NA
speakers). Use them instead of failing.

This still includes the old "braindeath" code to retry with a layout
without NA channels. This might be helpful for performance, and also the
padded channel layout string looks confusing.

To be fair, I have not encountered a case yet which would really need
this, and for which the old "braindeath" code did not fix it.

(cherry picked from commit 85fc6b2a05)
2015-05-07 10:54:49 +09:00
wm4 76d2ba6283 ao_alsa: move ALSA -> mp channel map to a function
One side effect is that the warning about too many channels goes away,
and is replaced with printing the ALSA channel map as "unknown".

(cherry picked from commit d577872a28)
2015-05-07 10:54:32 +09:00
wm4 048cd1e73d manpage: do not use deprecated syntax in example
(cherry picked from commit 9434aa75b2)
2015-05-07 10:54:10 +09:00
wm4 d7cfe38f06 cocoa: remove an unused parameter
(cherry picked from commit f58d3591d9)
2015-05-07 10:53:55 +09:00
wm4 283a300aa9 ao_coreaudio_exclusive: check new format before waiting for change
It seems if the format was already set, setting the same format will
not cause a property change.

(cherry picked from commit 0ae0e90eb5)
2015-05-07 10:53:47 +09:00
wm4 099f2138bb ao_coreaudio_exclusive: use atomics instead of volatile
volatile barely means anything.

The polling is kind of bad too, but relatively harmless as device
opening/closing is a rare event, and the format change is not expected
to take long.

Remove the pointless talloc call too (must have been a leftover
from previous refactoring).

(cherry picked from commit 4444ff48fa)
2015-05-07 10:53:37 +09:00
wm4 b7ef055917 ao_coreaudio_exclusive: rename "digital" -> "compressed"
PCM is digital too.

(cherry picked from commit 028739932b)
2015-05-07 10:53:25 +09:00
wm4 4002258b3f ao_coreaudio_exclusive: explicitly check for spdif formats
(cherry picked from commit 1e1045b13e)
2015-05-07 10:53:18 +09:00
wm4 3b471462eb ao_coreaudio_exclusive: merge init_digital() function
No reason to keep them separate. It's an artifact from the old
ao_coreaudio.c, which kept usage of two different APIs in the same file.
Removes a forward reference too.

(cherry picked from commit 32bc61ae07)
2015-05-07 10:52:50 +09:00
wm4 9b41d17dc0 cocoa: lock cocoa main thread on uninit
This should fix some crashes due to dangling pointers.

The problem was that with_cocoa_lock_on_main_thread() is asynchronous.
It will not wait until it is finished. In the uninit case, this means
the VO could be deallocated and destroyed while cocoa was still running
uninit code.

So simply wait until it is done by using dispatch_sync(). There were
concerns that this could introduce a deadlock by the main thread trying
to wait for something on the VO thread. But from what I can see, this
never happens, and even if it does, it would crash anyway since the VO
is already gone.

One remaining worry is the video_resize_redraw_callback. From what I can
see, it still can mess things up, and will need a more elaborate fix.

(cherry picked from commit e777756301)
2015-05-07 10:52:39 +09:00
wm4 5523c04af5 ao_coreaudio_utils: decide formats by comparing raw bits
Instead of trying to use af_format_conversion_score() (which tries to be
all kinds of clever), just compare the raw bits as a quality measure. Do
this because otherwise, weird formats like padded 24 bit formats will be
excluded, even though they might be the highest precision formats for
some hardware.

This means that for now, the user would have to check whether the format
is usable at all before calling ca_asbd_is_better(). But since this is
currently only used for ao_coreaudio.c and for the physical format, it
doesn't matter.

If coreaudio-exclusive should get PCM support, the best would be to
revert this change, and to add support for 24 bit formats directly.

(cherry picked from commit 4ffcf2531b)
2015-05-07 10:52:02 +09:00
wm4 625fb59d08 af: don't attempt to remove last filter for spdif filter removal
Some time ago, a mechanism was added for automatically removing PCM-only
filters if the input format is spdif.

This could cause an infinite loop if the AO did not support spdif, but
was falling back to some PCM format. Then this code tried to remove the
last filter, which is a dummy filter for receiving and queuing filter
output. af_remove() simply fails gracefully in this case, so this
happens over and over again.

Fix by explicitly checking whether the filter to remove is a dummy
filter. (af_remove() also fails only if the dummy filters are attempted
to be removed - checking this directly is simpler.)

(cherry picked from commit 0025030cef)
2015-05-07 10:51:30 +09:00
wm4 71a88d75ff audio: minor cosmetics
These ( ) were probably not removed when the format constants were
changed from defines to an enum.

(cherry picked from commit d76f9a484e)
2015-05-07 10:50:59 +09:00
wm4 938008fff1 ao_coreaudio_utils: don't require talloc for fourcc_repr()
Instead, apply a trick to make the caller allocate enough space on the
stack.

(cherry picked from commit 399267393b)
2015-05-07 10:50:32 +09:00
wm4 d723970279 ao_coreaudio_utils: unbreak default device selection
It appears this is the reason coreaudio-exclusive does not work without
explicitly specifying a device, even if the default device maps to
something passthrough-capable.

(cherry picked from commit 7a5f5a8adf)
2015-05-07 10:49:20 +09:00
wm4 0e37672270 ao_coreaudio_exclusive: fix latency calculation non-sense
Didn't use the properties it was supposed to use.

(cherry picked from commit bbedceb467)
2015-05-07 10:48:44 +09:00
wm4 2d35c84ebf ao_coreaudio_utils: refine format selection
Instead of always picking a somehow better format over the previous one,
select a format that is equal to or better the requested format, but is
also reasonably close.

Drop the mFormatID comparison - checking the sample format handles this
already.

Make sure to exclude channel counts that can't be used.

(cherry picked from commit fd6809f98a)
2015-05-07 10:48:34 +09:00
wm4 bdbbf4ae48 vo_opengl: change default FBO format
Reduces (but likely does not remove) the danger of rounding intermediate
values down to 8 bit. This is important for cscale, or any other
processing that might store raw YUV values in framebuffers.

Fixes #1918.

(cherry picked from commit cf210c4ffc)
2015-05-07 10:47:51 +09:00
wm4 774e9ef261 ao_coreaudio_utils: add a format negotiation helper function
(cherry picked from commit 305a85cc9a)
2015-05-07 10:47:21 +09:00
wm4 b38766133b ao_coreaudio: support padded channel layouts
If for example the audio settings are set to 5.1 output, but the
hardware does 8 channels natively (HDMI), the reported channel
layout will have 2 dummy channels. To avoid falling back to stereo,
we have to write audio in this format to the device.

(cherry picked from commit 4d8a7e0394)
2015-05-07 10:47:07 +09:00
wm4 604daa861f audio: introduce support for padding channels
Some audio APIs explicitly require you to add dummy channels. These are
not rendered, and only exist for the sake of the audio API or hardware
strangeness. At least ALSA, Sndio, and CoreAudio seem to have them.

This commit is preparation for using them with ao_coreaudio.

The result is a bit messy. libavresample/libswresample don't have good
API for this; avresample_set_channel_mapping() is pretty useless.
Although in theory you can use it to add and remove channels, you
can't set the channel counts. So we do the ordering ourselves by making
sure the audio data is planar, and by swapping the plane pointers. This
requires lots of messiness to get the conversions in place. Also, the
input reordering is still done with the "old" method, and doesn't
support padded channels - hopefully this will never be needed. (I tried
to come up with cleaner solutions, but compared to my other attempts,
the final commit is not that bad.)

(cherry picked from commit 06050aed99)
2015-05-07 10:47:00 +09:00
wm4 322c79a6e1 audio: introduce mp_audio readonly bit
Convenience for the following commit.

(cherry picked from commit 1b0b094ca2)
2015-05-07 10:46:53 +09:00
wm4 6bcb8d200f audio: chmap: explicitly drop channels not supported by lavc
Basically as before, but avoid undefined behavior.

(cherry picked from commit 937c8e513f)
2015-05-07 10:46:48 +09:00
wm4 d9c42ff9ff audio: drop unused function
(cherry picked from commit 548cd826c2)
2015-05-07 10:46:41 +09:00
wm4 e0ad4ec8aa ao_coreaudio: fix out of bounds access
ca_label_to_mp_speaker_id() checked whether the last entry was >= 0, but
actually this condition was never true, and MP_SPEAKER_ID_UNKNOWN0 is
not negative.

(cherry picked from commit eead97f103)
2015-05-07 10:46:36 +09:00
James Ross-Gowan 8a46b5b711 subprocess-win: use the correct pipe namespace
This was a mistake, it should definitely be using the device namespace
rather than the file namespace. As it says in the docs, all pipe names
must start with \\.\pipe\

(cherry picked from commit b6381a0ee3)
2015-05-07 10:46:29 +09:00
Niklas Haas 052b6d406d sws_utils: re-use avcolorspace for sws colorspaces
This lets us avoid having to maintain two separate copies of the
colorspace mapping functions.

(cherry picked from commit 08d3ef3d9e)
2015-05-07 10:46:23 +09:00
wm4 f56a7af9f6 win32: fix desktop directory
The folder argument wasn't used, so it always returned the APPDATA dir.

(cherry picked from commit a2da53027b)
2015-05-07 10:46:15 +09:00
wm4 90ba8040d9 win32: move platform specifics to osdep
This will probably disable this code for Cygwin. I don't know if this
matters, since Cygwin should strictly behave like a Unix anyway.

(cherry picked from commit 3508a3fbd1)
2015-05-07 10:45:39 +09:00
wm4 26e779c9aa build: move main-fn files to osdep
And split the Cocoa and Unix cases. Simplify the Cocoa case slightly by
calling mpv_main directly, instead of passing a function pointer. Also
add a comment explaining why Cocoa needs a special case at all.

(cherry picked from commit 1e7831070f)
2015-05-07 10:45:33 +09:00
wm4 fe19db9cc0 cocoa: always compile OSX application code with cocoa
This unbreaks compiling command line player and libmpv at the same
time. The problem was that doing so silently disabled the OSX
application thing - but the command line player can not use the
vo_opengl Cocoa backend without it.

The OSX application code is basically dead in libmpv, but it's not
that much code anyway.

If you want a mpv binary that does not create an OSX application
singleton (and creates a menu etc.), you must disable cocoa
completely, as cocoa can't be used anyway in this case.

(cherry picked from commit 19a5b20752)
2015-05-07 10:45:20 +09:00
wm4 196e2d426c player: handle hotplug events in idle mode too
(cherry picked from commit d8e92322fa)
2015-05-07 10:45:14 +09:00
wm4 99e9294fc9 vo_opengl: gl_lcms: make sure win32 unicode fopen() wrapper is enabled
(cherry picked from commit dce941b99c)
2015-05-07 10:45:05 +09:00
wm4 2ca19ba1b5 timer: add "static" to a variable
(cherry picked from commit 6814830b9a)
2015-05-07 10:43:12 +09:00
wm4 d0216842d3 path: refactor
Somewhat less ifdeffery, higher flexibility. Now there are 3 separate
config file resolvers for 3 platforms (unix, win, osx), and they can
still interact with each other somewhat. For example, OSX for now uses
most of Unix, but adds the OSX bundle path.

This can be extended to resolve very specific platform paths, such as
location of the desktop.

Most of the Unix specific code moves to path-unix.c.

The behavior should be the same - if not, it is likely a bug.

(cherry picked from commit d3a3cfe54c)
2015-05-07 10:43:05 +09:00
wm4 527550dfe6 vo_rpi: update renderer size on display size changes too
(Not sure why it worked without this when I tested the previous
changes.)

Untested, but should be fine. This is equivalent what is done on e.g.
panscan changes.

(cherry picked from commit 94a3a76ee3)
2015-05-07 10:42:30 +09:00
wm4 275694a002 video/out: remove VOFLAG_FLIPPING
I think this used to be quite important, because the ancient VfW support
in MPlayer used to output flipped frames. This code has been dead in mpv
for quite some time (because VfW decoders were removed, and the --flip
option was dropped too), so get rid of it.

(cherry picked from commit e185887ba0)
2015-05-07 10:42:16 +09:00
wm4 8c3a92d6cb vo_opengl: refactor wayland frame skipping
Currently, the wayland backend needs extra work to avoid drawing more
often than the wayland frame callback allows. (This is not ideal, but
will be fixed at a later time.)

Unify this with the start_frame callback added for cocoa. Some details
change for the better. For example, if a frame is dropped, and a redraw
is done afterwards, the actually correct frame is redrawn, instead
whatever was in the textures from before the dropped frame.

(cherry picked from commit 0a7abbda6b)
2015-05-07 10:42:10 +09:00
wm4 488b5e3ac3 cocoa: don't accidentally drop initial screen drawing
With --idle --force-window, or when started from the bundle, the cocoa
code dropped the first frame. This resulted in a black frame on start
sometimes.

The reason was that the live resizing/redrawing code was invoked, which
simply set skip_swap_buffer to false, blocking redrawing whatever was
going to be rendered next. Normally this is done so that the following
works:

1. vo_opengl draw a frame, releases GL lock
2. live resizing kicks in, redraw the frame
3. vo_opengl wants to call SwapBuffers, drawing a stale buffer
   overwritten by the live resizing code

This is solved by setting skip_swap_buffer in 2., and querying it in 3.

Fix this by resetting the skip_swap_buffer at a known good point: when
vo_opengl starts drawing a new frame.

The start_frame function returns bool, so that it can be merged with
is_active in a following commit.

(cherry picked from commit e23e4c7c60)
2015-05-07 10:41:57 +09:00
Avi Halachmi (:avih) afb97c517d vo: improve frame drop logic on high playback rate
Commit f1746741de changed the drop
logic to have more slack (drop more frames but less frequent) to prevent
drops due to timing jitter when the clip and screen have similar rates.

However, if the clip has higher rate than the screen (or just higher
playback rate), then that policy hurts smoothness since these "chunked
drops" look worse than one frame drop at a time.

This patch restores the old drop logic when the playback frame rate is
higher than ~5% above the screen refresh rate, and solves this issue.

Fixes #1897

(cherry picked from commit ffcad1a72b)
2015-05-07 10:41:50 +09:00
wm4 b99f78412b player: properly destroy client context if thread can't be created
Minor leak in an obscure out of memory case.

(cherry picked from commit d01228058b)
2015-05-07 10:41:43 +09:00
wm4 a4ba496539 vo_rpi: update display size on display mode switches
(cherry picked from commit 8c7f3adb41)
2015-05-07 10:41:38 +09:00
wm4 73fc12c4e2 vo_rpi: actually draw a black background
Also factor the display size initialization into a separate function.

For some reason this seems to work, although setting the background
color using this 1x1 pixel bitmap does not work. I blame the RPI
beign a terrible piece of hardware with even worse drivers.

(cherry picked from commit 6ae66e717f)
2015-05-07 10:41:33 +09:00
wm4 63402eb1dd ao_coreaudio_exclusive: check format explicitly on change notifcation
This should for now be equivalent; it's merely more explicit and will
be required if we add PCM support.

Note that the property listeners actually tell you what property
exactly changed, but resolving the current listener mess would be too
hard. So check for changes manually.

(cherry picked from commit 382434d45a)
2015-05-07 10:41:26 +09:00
wm4 8bcd9ea671 ao_coreaudio_utils: log mp format with CoreAudio format description
As a consequence, it also logs whether mpv can a this format at all.

(cherry picked from commit 34a5229b23)
2015-05-07 10:41:15 +09:00
wm4 e37fae4f9e ao_coreaudio_utils: add function for ASBD -> mp format lookup
Useful with some of the following commits.

ca_fill_asbd() should behave exactly as before.

Instead of actually implementing the inverse function of ca_fill_asbd(),
just loop over the (small) list of mpv functions and check if any mpv
equivalent to a given ASBD exists.

(cherry picked from commit 32b835c03b)
2015-05-07 10:41:00 +09:00
wm4 047c761f90 ao_coreaudio_utils: float is not a signed integer format
kAudioFormatFlagIsSignedInteger implicates that it's only used with
integer formats. The mpv internal flag on the other hand signals the
presence of a sign, and this is set on float formats.

Until now, this probably worked fine, because at least AudioUnit is
ignoring the uncorrect flag.

(cherry picked from commit 3295ce48ab)
2015-05-07 10:40:53 +09:00
Niklas Haas 99389eb174 csputils: improve contrast semantics for limited range output
The previous version of this logic resulted in black crush and incorrect
brightness scaling when combined with limited range (TV) output.

(cherry picked from commit 99439f11ea)
2015-05-07 10:40:44 +09:00
wm4 af930e2a2e csputils: apply contrast equalizer in RGB
It's weird that this basically adjusts the contrast between luma and
chroma, and not blackness.

This is more in line with the behavior of libswscale, the vdpau
"procamp" (which mpv doesn't use), and Xv.

(cherry picked from commit 0600d378f9)
2015-05-07 10:40:35 +09:00
wm4 5f4e4ede89 stream: don't print reconnection message if no stream support
This code does not know whether the stream supports reconnecting until
STREAM_CTRL_RECONNECT is called. So the message should be printed after
it. To avoid that reconnects that succeed on the first try go unnoticed,
print a warning on success.

(cherry picked from commit 38114b6a36)
2015-05-07 10:39:47 +09:00
Niklas Haas 4a6fdb7361 x11: query ICC profile based on center of window
Right now, the default behavior is to pick the numerically lowest screen
ID that overlaps the window in any way - but this means that mpv will
decide to pick an ICC profile in a pretty arbitrary way even if the
window only overlaps another screen by a single pixel.

The new behavior is to query it based on the center of the window
instead.

(cherry picked from commit daf4334697)
2015-05-07 10:39:40 +09:00
Diogo Franco (Kovensky) f6158c324e Release 0.9.1 2015-04-29 19:03:56 +09:00
Diogo Franco (Kovensky) f534c83da6 Update RELEASE_NOTES 2015-04-29 18:47:11 +09:00
wm4 39f6824b30 manpage: put explicit links to config file path details
It seems users still have trouble finding the exact paths, especially on
Windows. Maybe this helps.

(cherry picked from commit 0b72f5e5ad)
2015-04-29 18:40:42 +09:00
wm4 477eefa63f ao_coreaudio_exclusive: move code for getting original format
Should be almost equivalent, unless there are streams on which this call
does not work for unknown reasons.

(cherry picked from commit 8b4ca58062)
2015-04-29 18:40:37 +09:00
wm4 87713640ae ao_coreaudio_utils: change audio format logging
Make it easier to distinguish the fields.

(cherry picked from commit d5e9bf66a1)
2015-04-29 18:40:30 +09:00
wm4 63bd171c0d ao_coreaudio_exclusive: account for additional latency
Whether this is correct is unknown. This change tripples the latency
from ~15ms to ~45ms.

XBMC does this, VLC does not from what I could see.

(cherry picked from commit 5f86fad2f0)
2015-04-29 18:40:20 +09:00
wm4 73086a6ba3 player: log track list when adding or removing external files
Should help with debugging, and might be slightly more userfriendly.

Note that this is called manually in multiple entry-points, instead of
the functions doing the actual work (like mp_remove_track()). This is
done so that exiting the player or calling the sub_reload command won't
print redundant in-between states.

(cherry picked from commit 0c0c8cd44e)
2015-04-29 18:39:49 +09:00
wm4 0126999cde player: clamp display time to known time range on seeking
During seeking, and there is momemtarily no new data available yet, the
player will display the seek target as current time. Clamp this time to
the known time range as implied by the start time and the duration of
the file.

This improves behavior especially when seeking in audio files, for which
this for some reason triggers rather often. There were some users
complaining about this.

This makes behavior worse for files with timestamp resets, or
incorrectly reported duration. (The latter is relatively common,
e.g. libavformat shortcomings, or incomplete files.)

(cherry picked from commit 0ff93a8357)
2015-04-29 18:39:33 +09:00
wm4 2a6b10c9ca audio: separate fallbacks for upmix and downmix cases
We always want to prefer upmix to downmix, as long as it makes sense.
Even if the upmix is not "perfect" (not just adding channels), we want
to prefer the upmix.

Cleanup for commit d3c7fd9d.

(cherry picked from commit c4aa136155)
2015-04-29 18:38:57 +09:00
ChrisK2 3fa249b4e1 osc: redo slider position translation
Now done in one place instead of mulitple times all over the code.

Fixes #1876

(cherry picked from commit 2fcf0e6183)
2015-04-29 18:38:44 +09:00
wm4 0a55f43181 json: fix UTF-8 handling
We escape only characters below 32, plus " and \. UTF-8 should be apssed
through verbatim. Since char can be signed (and usually is), the check
broke and happened to escape UTF-8 encoded bytes too. This broke UTF-8
completely.

Note that we don't check for broken or invalid UTF-8, such as described
both in the client API and IPC docs.

Fixes #1874.

(cherry picked from commit f77e3cbf0c)
2015-04-29 18:38:34 +09:00
Diogo Franco (Kovensky) 5aa2d496e6 Update RELEASE_NOTES 2015-04-28 09:05:00 +09:00
Diogo Franco (Kovensky) 76ba91415b Add github links to compare pages for the commit logs
Unfortunately, the commit logs are truncated at 250 commits :(
2015-04-28 08:57:10 +09:00
Diogo Franco (Kovensky) 20a1418af6 Update RELEASE_NOTES 2015-04-28 08:49:50 +09:00
robin 277dc33268 ytdl_hook.lua: Change format options when vid is "off"
This will change the format option to "bestaudio/best" instead of
passing the "-x" argument to yt-dl.

Prevents the video still being downloaded in the new mpv versions where
the yt-dl format is set to "best" by default.

(cherry picked from commit 5555f6fc2c)
2015-04-28 08:34:50 +09:00
wm4 cb2461044b audio: avoid downmixing in a certain special-case
As indicated by the added test. In this case, fallback and downmix have
the same score, but fallback happens to give better results. So prefer
fallback over downmix.

(This is probably not a correct solution.)

(cherry picked from commit d3c7fd9d7c)
2015-04-28 08:34:36 +09:00
Niklas Haas 1eb7db70d5 manpage: update mpv IRC channels
Moved to #mpv and #mpv-devel, respectively. Travis details were also
updated.

(cherry picked from commit d2292c179c)
2015-04-28 08:34:05 +09:00
wm4 a8c764acb4 player: fix removing external tracks at runtime
This could make the player crash on exit if the "sub_reload" command was
used successfully. the reason was that the mpctx->sources array could
have dangling pointers to the unloaded demuxers.

Also fix a memory leak by actually always freeing the per-stream
subtitle decoders (which are a hack to make ordered chapters behave
better).

(cherry picked from commit 4d2ed847ce)
2015-04-28 08:33:57 +09:00
wm4 62a66e2ff8 manpage: update colormatrix property description
(cherry picked from commit 0c70f94c53)
2015-04-28 08:33:44 +09:00
akemi-san e8f8d3462e vo_drm: zero screen buffers in reconfig function.
(cherry picked from commit 1e2e504349)
2015-04-28 08:33:36 +09:00
Marcin Kurczewski 7669fe39f6 vo_drm: add window screenshots support
(cherry picked from commit 5f21a68ce9)
2015-04-28 08:33:28 +09:00
wm4 6a1902a2bf ytdl: force "best" format by default
If the --ytdl-format option is not used, force the "best" format. Do
this because youtube-dl is going to change its default format to one
that will trigger the (partially broken) DASH support in our own code.

Fixes #1867.

(cherry picked from commit 95a0488ac2)
2015-04-28 08:33:17 +09:00
wm4 192af725e6 vdpau: always render to cropped size at most
vo_opengl (or gl_hwdec_vdpau.c to be specific) calls
mp_vdpau_mixer_render() with video_rect=NULL, which means to use the
full surface. This is incorrect if the surface is actually cropped, as
it can happen with h264. In this case, it was rendering the parts
outside of the image.

Fix it by making this case use the cropped size instead.

Alternative fix for PR #1863.

(cherry picked from commit a5ed6e49bf)
2015-04-28 08:32:45 +09:00
wm4 d27bb1ce80 DOCS/client-api-changes: fix release marker
The release was pushed back and now actually happened; the marker became
incorrect.

(cherry picked from commit 4df8c21f81)
2015-04-28 08:32:28 +09:00
Diogo Franco (Kovensky) e795a1781f Bump version to v0.9.0, remove Draft status from RELEASE_NOTES 2015-04-25 21:54:38 +09:00
Diogo Franco (Kovensky) 6e4abfb017 Fix typo in RELEASE_NOTES 2015-04-25 18:31:59 +09:00
Diogo Franco (Kovensky) 62195c174a Add v0.7.x RELEASE_NOTES to RELEASE_NOTES 2015-04-25 18:30:06 +09:00
Diogo Franco (Kovensky) 79efe85cf5 Update RELEASE_NOTES 2015-04-25 18:28:25 +09:00
Diogo Franco (Kovensky) 5f1d6b6e5a Merge branch 'master' into release/0.9
* master: (87 commits)
  manpage: move --autosync description
  player: add --window-scale option
  player: flush decoder even if cover art is decoded
  player: don't show A/V desync message in non-sense situations
  w32_common: add more rounded-down frame rates
  w32_common: use the current monitor's refresh rate
  dxva2: fix broken build with gcc 5.1
  terminal: printf() is not signal-safe
  man: fix PDF build
  DOCS/mplayer-changes: Eleborate on joystick input
  osc: add nil check for element.eventresponder
  mp_image: remove some unused interlacing flags
  vf_vapoursynth: update _FieldBased semantics
  options: remove unneeded hack from command line parser
  manpage: document ff-index sub-property
  demux_mkv: limit timestamp fixing to 1ms max
  demux_mkv: attempt to fix rounded timestamps
  demux_mkv: move global options to the demuxer
  demux_mkv: better seeking after video end
  lua: add utils.format_json() function
  ...
2015-04-25 18:28:17 +09:00
Diogo Franco (Kovensky) d64ff3aa51 Update RELEASE_NOTES 2015-04-13 20:05:18 +09:00
Diogo Franco (Kovensky) 3287825bd2 Merge branch 'master' into release/0.9
* master: (39 commits)
  Update license headers
  af_lavrresample: minor simplification
  af_lavrresample: allow resetting output sample format
  audio/filter: fully renegotiate audio formats on every reconfig
  DOCS/waf: Edit --enable-feature sentences
  vo_opengl: slightly simplify check_gl_features()
  vo_opengl: unify blend-subtitles-res and blend-subtitles
  vo_opengl: fix blend-subtitles-res=video & anamorphic video
  manpage: mention how pseudo-gui mode is enabled on win32
  main-fn-win: fix handle validity check for XP
  win32: use pseudo-gui profile when started without stdio
  win32: only attach to the console from mpv.com
  win32: use a platform-specific unicode entry-point
  vo_opengl: add blend-subtitles-res
  manpage: document pseudo-gui stuff
  mp_image: remove redundant flags field
  mp_image: remove redundant chroma_x/y_shift fields
  mp_image: remove redundant plane_w/h fields
  player: use config parser for setting up pseudo-gui profile
  player: change pseudo-gui settings
  ...
2015-04-13 19:55:48 +09:00
Diogo Franco (Kovensky) 9e65b5db0b Update RELEASE_NOTES 2015-04-13 19:51:35 +09:00
Diogo Franco (Kovensky) d9d8c9ce13 Update RELEASE_NOTES 2015-04-09 20:45:44 +09:00
Diogo Franco (Kovensky) 35e9d75083 Merge branch 'master' into release/0.9
All commits are bugfixes anyway, so just taking everything.

* master:
  sub: don't truncate timestamps to int
  sub: unprefer libavcodec's MicroDVD converter
  manpage: lua: clarify timer usage
  audio: automatically deatch filters if spdif prevents their use
  audio: change a detail about filter insertion
  ao_alsa: change log output
  audio: avoid one more redundant audio filter reinit
  ao_coreaudio: do not error if retrieving info for verbose mode fails
  travis: re-enable OSX
  video/out: fix screenshot image formats
  vdpau: don't use a transparent image format for screenshots
  screenshot: use GPU readback only for hardware decoded images
  manpage: remove confusing statement
  screenshots: select best image format the encoder supports
2015-04-09 20:42:14 +09:00
Diogo Franco (Kovensky) 4a84cd37f3 Add RELEASE_NOTES 2015-04-06 21:20:45 +09:00
109 changed files with 2150 additions and 1093 deletions

No files matched your search

+1 -1
View File
@@ -47,7 +47,7 @@ notifications:
email: false
irc:
channels:
- "irc.freenode.org#mpv-player-dev"
- "irc.freenode.org#mpv-devel"
on_success: change
on_failure: always
+1 -1
View File
@@ -25,8 +25,8 @@ API changes
::
--- mpv 0.9.0 is released ---
1.17 - add MPV_FORMAT_BYTE_ARRAY
--- mpv 0.9.0 will be released ---
1.16 - add mpv_opengl_cb_report_flip()
- introduce mpv_opengl_cb_draw() and deprecate mpv_opengl_cb_render()
1.15 - mpv_initialize() will now load config files. This requires setting
+1
View File
@@ -3,6 +3,7 @@ QT += qml quick
HEADERS += main.h
SOURCES += main.cpp
QT_CONFIG -= no-pkg-config
CONFIG += link_pkgconfig debug
PKGCONFIG += mpv
@@ -3,6 +3,7 @@ QT += qml quick
HEADERS += main.h
SOURCES += main.cpp
QT_CONFIG -= no-pkg-config
CONFIG += link_pkgconfig debug
PKGCONFIG += mpv
@@ -5,6 +5,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qtexample
TEMPLATE = app
QT_CONFIG -= no-pkg-config
CONFIG += link_pkgconfig debug
PKGCONFIG += mpv
+2 -2
View File
@@ -4,8 +4,8 @@ How to contribute
General
-------
The main contact for mpv development is IRC, specifically #mpv-player
and #mpv-player-dev on Freenode.
The main contact for mpv development is IRC, specifically #mpv
and #mpv-devel on Freenode.
Sending patches
---------------
+13 -10
View File
@@ -1167,17 +1167,18 @@ Property list
``field-dominance`` (RW)
See ``--field-dominance``
``colormatrix`` (RW)
See ``--colormatrix``.
``colormatrix`` (R)
Redirects to ``video-params/colormatrix``. This parameter (as well as
similar ones) can be overridden with the ``format`` video filter.
``colormatrix-input-range`` (RW)
See ``--colormatrix-input-range``.
``colormatrix-input-range`` (R)
See ``colormatrix``.
``colormatrix-output-range`` (RW)
See ``--colormatrix-output-range``.
``colormatrix-output-range`` (R)
See ``colormatrix``.
``colormatrix-primaries`` (RW)
See ``--colormatrix-primaries``.
``colormatrix-primaries`` (R)
See ``colormatrix``.
``ontop`` (RW)
See ``--ontop``.
@@ -1778,7 +1779,6 @@ Property list
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).
@@ -1805,7 +1805,10 @@ Property Expansion
------------------
All string arguments to input commands as well as certain options (like
``--term-playing-msg``) are subject to property expansion.
``--term-playing-msg``) are subject to property expansion. Note that property
expansion does not work in places where e.g. numeric parameters are expected.
(For example, the ``add`` command does not do property expansion. The ``set``
command is an exception and not a general rule.)
.. admonition:: Example for input.conf
+7
View File
@@ -73,6 +73,10 @@ The ``mp`` module is preloaded, although it can be loaded manually with
Run the given command. This is similar to the commands used in input.conf.
See `List of Input Commands`_.
By default, this will show something on the OSD (depending on the command),
as if it was used in ``input.conf``. See `Input Command Prefixes`_ how
to influence OSD usage per command.
Returns ``true`` on success, or ``nil, error`` on error.
``mp.commandv(arg1, arg2, ...)``
@@ -94,6 +98,9 @@ The ``mp`` module is preloaded, although it can be loaded manually with
the ``expand-properties`` prefix, or the ``mp.get_property`` family of
functions.
Unlike ``mp.command``, this will not use OSD by default either (except
for some OSd-specific commands).
``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
+4 -1
View File
@@ -378,7 +378,8 @@ 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 ``~/.config/mpv/mpv.conf``.
user-specific one is ``~/.config/mpv/mpv.conf``. For details and platform
specifics see the `FILES`_ section.
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
@@ -796,6 +797,8 @@ input command can take an exit code: in this case, that exit code is returned.
FILES
=====
For Windows-specifics, see `FILES ON WINDOWS`_ section.
``/usr/local/etc/mpv/mpv.conf``
mpv system-wide settings (depends on ``--prefix`` passed to configure - mpv
in default configuration will use ``/usr/local/etc/mpv/`` as config
+7 -3
View File
@@ -459,12 +459,12 @@ Program Behavior
``--ytdl-raw-options=<key>=<value>[,<key>=<value>[,...]]``
Pass arbitraty options to youtube-dl. Parameter and argument should be
passed as a key-value pair. Options without argument must include ``=``.
There is no sanity checking so it's possible to break things (i.e.
passing invalid parameters to youtube-dl).
.. admonition:: Example
``--ytdl-raw-options=username=user,password=pass``
``--ytdl-raw-options=force-ipv6=``
@@ -498,6 +498,10 @@ Video
Do not play video. With some demuxers this may not work. In those cases
you can try ``--vo=null`` instead.
mpv will try to download the audio only if media is streamed with
youtube-dl, because it saves bandwidth. This is done by setting the ytdl_format
to "bestaudio/best" in the ytdl_hook.lua script.
``--untimed``
Do not sleep when outputting video frames. Useful for benchmarks when used
with ``--no-audio.``
@@ -2140,7 +2144,7 @@ Demuxer
Play a raw YUV sample::
mpv sample-720x576.yuv --demuxer=rawvideo \
--demuxer-rawvideo=w=720:h=576
--demuxer-rawvideo-w=720 --demuxer-rawvideo-h=576
``--demuxer-rawvideo-format=<value>``
Color space (fourcc) in hex or string for ``--demuxer=rawvideo``
+11 -10
View File
@@ -169,34 +169,35 @@ Configurable Options
``showwindowed``
| Default: yes
| Show OSC when windowed?
| Enable the OSC when windowed
``showfullscreen``
| Default: yes
| Show OSC when fullscreen?
| Enable the OSC when fullscreen
``scalewindowed``
| Default: 1
| Scaling of the controller when windowed
| Default: 1.0
| Scale factor of the OSC when windowed
``scalefullscreen``
| Default: 1
| Scaling of the controller when fullscreen
| Default: 1.0
| Scale factor of the OSC when fullscreen
``scaleforcedwindow``
| Default: 2
| Scaling of the controller when rendered on a forced (dummy) window
| Default: 2.0
| Scale factor of the OSC when rendered on a forced (dummy) window
``vidscale``
| Default: yes
| Scale the controller with the video?
| Scale the OSC with the video
| ``no`` tries to keep the OSC size constant as much as the window size allows
``valign``
| Default: 0.8
| Vertical alignment, -1 (top) to 1 (bottom)
``halign``
| Default: 0
| Default: 0.0
| Horizontal alignment, -1 (left) to 1 (right)
``boxalpha``
+1 -1
View File
@@ -198,7 +198,7 @@ Available filters are:
``<aspect>``
Force an aspect ratio.
``format[=fmt[:outfmt]]``
``format=fmt=<value>:colormatrix=<value>:...``
Restricts the color space for the next filter without doing any conversion.
Use together with the scale filter for a real conversion.
+2 -2
View File
@@ -586,7 +586,7 @@ Available video output drivers are:
always used, and typically only when using extended scalers.)
``fmt`` can be one of: rgb, rgba, rgb8, rgb10, rgb10_a2, rgb16, rgb16f,
rgb32f, rgba12, rgba16, rgba16f, rgba32f.
Default: rgba.
Default: rgba16.
``gamma=<0.1..2.0>``
Set a gamma value (default: 1.0). If gamma is adjusted in other ways
@@ -744,7 +744,7 @@ Available video output drivers are:
This is equivalent to::
--vo=opengl:scale=spline36:cscale=spline36:dscale=mitchell:dither-depth=auto:fbo-format=rgba16:fancy-downscaling:sigmoid-upscaling
--vo=opengl:scale=spline36:cscale=spline36:dscale=mitchell:dither-depth=auto:fancy-downscaling:sigmoid-upscaling
Note that some cheaper LCDs do dithering that gravely interferes with
``opengl``'s dithering. Disabling dithering with ``dither-depth=no`` helps.
+1
View File
@@ -49,6 +49,7 @@ Input
* Classic LIRC support was removed. Install remotes as input devices instead.
This way they will send X11 key events to the mpv window, which can be bound
using the normal ``input.conf``.
Also see: http://github.com/mpv-player/mpv/wiki/IR-remotes
* Joystick support was removed. It was considered useless and was the cause
of some problems (e.g. a laptop's accelerator being recognized as joystick).
+2 -2
View File
@@ -175,8 +175,8 @@ Most activity happens on the IRC channel and the github issue tracker. The
mailing lists are mostly unused.
- **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`
- **User IRC Channel**: `#mpv` on `irc.freenode.net`
- **Developer IRC Channel**: `#mpv-devel` 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])
+694
View File
@@ -0,0 +1,694 @@
Release 0.9.2
=============
Changes
-------
- The Lua check now also checks for `lua52.pc`, as used by Arch Linux testing.
- (X11) `vo_opengl`'s `icc-profile-auto` now queries the current ICC profile
relative to the center of the window.
- `ao_coreaudio`, `ao_alsa` now support adding dummy padding channels for
better compatibility with hardware decoders that only support specific
channel counts (e.g. 5.1 now should work on a decoder that only accepts 7.1).
- Channel fallback (in case the audio device doesn't natively support a given
channel layout) has been improved.
- `vf_vapoursynth` now rejects unaligned video instead of outputting corrupted
video.
- mpv now tries to autoload `.sup` subtitles as well.
Bug fixes
---------
- `vo_opengl`'s default for `fbo-format` is now `rgba16`, to avoid rounding
errors when using non-default `cscale` (issue #1918).
- Improved framedrop behavior when playing video that has higher framerate
than the display (issue #1897).
- Trying to play a directory will no longer spam `Connection lost!` to the
console log.
- (Linux) Several `vo_rpi` bugfixes.
- (Linux) Several `vo_drm` bugfixes. Pan&Scan is now supported.
- (X11) Fix fullscreen behavior on certain window managers (issues #1937,
#1920).
- (OSX) The OSD no longer always shows up on startup.
- (OSX) Several `ao_coreaudio` and `ao_coreaudio_exclusive` bugfixes.
- (OSX) Fixed potential crash on exit when using Cocoa.
- (ClientAPI) `vo_opengl_cb` now actually applies options changed at runtime.
- (OSX, ClientAPI) Cocoa now works when both the `cplayer` (`mpv`) and `libmpv`
are built at the same time; however, `libmpv` now always creates an
application singleton. Cocoa has to be disabled completely to prevent
`libmpv` from creating the singleton.
This listing is not complete. A complete changelog can be seen by running
`git log v0.9.1..` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.9.1...release/0.9.
Release 0.9.1
=============
Changes
-------
- mpv's IRC channel moved from #mpv-player to #mpv on chat.freenode.net.
- Documentation updates.
- The default value for the `--ytdl-format` option is now `best`, in order to
work around `youtube-dl`'s 2015.04.26 release enabling DASH by default, as
FFmpeg / Libav do not yet properly support DASH.
- When seeking, the current timestamp will show the predicted seek timestamp
instead, until the final timestamp is resolved. Improves UI responsiveness
on slow streams and/or large seeks.
Bug fixes
---------
- Corrected the release marker on DOCS/client-api-changes. The release manager
forgot to fix it before release...
- Fix `vo_vdpau` rendering garbage lines on H.264 video with non-mod16 size
(issue #1863).
- Fix a crash on exit if the "sub_reload" command had run successfully.
- Fixed seeking with the mouse when `osc-seekbarstyle=bar` is set (issue
#1876).
- (IPC) Fixed encoding of UTF-8 data in JSON (issue #1874).
New features
------------
This listing is not complete. A complete changelog can be seen by running
`git log v0.9.0..v0.9.1` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.9.0...v0.9.1.
Release 0.9.0
=============
Changes
-------
Changes that may break users' config files have been annotated with a `(!)`.
- Note: mpv is not compatible with Lua 5.3. Lua 5.1 or 5.2 is required.
- The minimum required libass version is now 0.12.1 or newer.
- The minimum required FFmpeg version is now 2.4.0 (equiv. Libav 11) or newer.
- The internal libmpg123 support was removed. This was already not used by
default in the previous release.
- `(!)` The LIRC support was removed. Configure LIRC remotes as input devices
instead.
- `(!)` The Linux Joystick support was removed.
- `(!)` `vf_screenshot` was removed, as they are now handled at a VO level and
is compatible with all VOs.
- `(!)` `--ass-use-margins` has been renamed to `--sub-use-margins` and applies
only to plain-text (non-ASS) subtitles (enabled by default). The new
`--ass-force-margins` option applies only to ASS subtitles (disabled by
default). To get the old behaviour back, enable both at the same time.
- `(!)` The `--sub-scale-with-window` option now only applies to plain text
(non-ASS) subtitles (enabled by default). The new `--ass-scale-with-window`
option does the same but only with ASS subtitles (disabled by default).
- `(!)` The range for the `param1` for the `gaussian` `vo_opengl` scaler has
been redefined. Instead of being an arbitrary 1-100 range, have a default
value of 1.0, and anything higher is blurrier.
- `(!)` The `seek`, `playlist_next, `playlist_prev`, `loadfile` and `loadlist`
parameters no longer accept numerical parameters where symbolic parameter
names exist.
- `(!)` `vo_opengl` changes:
- `(!)` The `smoothmotion` suboption has been renamed to `interpolation`.
The old name is still supported for now.
- `(!)` The `bilinear_slow` scaler has been renamed to `triangle`.
- `(!)` `scale-down` has been renamed to `dscale` and now has its own set of
config options (e.g. `dscale-radius`).
- `(!)` Scaler radius no longer defaults to `3` but to a preferred value
that may be different for each filter.
- The `scale-radius` option may now go down as low as `0.5`, which is the
value used by the `nearest` filter.
- `spline36` is the new `cscale` default for `opengl-hq`. This might break
setups that use `fbo-format=rgb8`. To work around it, leave `fbo-format`
as its default, or set to something higher than 8, or set `cscale=bilinear`,
the previous default.
- `(!)` `vf_format` no longer converts video to YUYV if there is no parameter.
Video is now passed unchanged unless a format is specifically requested.
- `(!)` The `--colormatrix`, `--colormatrix-input-range`,
`--colormatrix-output-range` and `--colormatrix-primaries` options have been
converted into `vf_format` suboptions. See commit 27715b7 and the manual for
details.
- `vf_mirror`'s implementation was replaced with calling into `libavfilter`'s
`vf_hflip` filter, thus depending on `libavfilter` to function.
- The `device` subption to `ao_wasapi` has been deprecated in favor of
`--audio-device`.
- `--video-rotate` now allows 360 as an argument instead of stopping at 359.
- Several improvements to `af_scaletempo`.
- Options that have multiple options and also include a "yes" option now
default to that if specified with no arguments.
- The default value of `--cache-default` is now 150000 (153.6 MB, ~146 MiB).
- JPEG screenshots now use the same subsampling as the source video. The images
are still RGB regardless of source format though.
Bug fixes
---------
- mpv no longer saves position on files that can't be resumed (issue #1701).
- (X11) Fix the player thinking the mouse has left the window in some WMs /
embeddings (issue #1672).
- mpv no longer freezes on wayland when the compositor stops asking it to draw
itself (e.g. when minimized) (issue #249).
- `.ac3` files are no longer rejected by `--audio-file-auto` (issue #1759).
- `ao_wasapi` now automatically enables `exclusive` when passthrough is
attempted (issue #1742).
- Attempt to fix flickering on Intel VAAPI drivers with `--hwdec=vaapi` and
`--vo=opengl` (issue #1765).
- `youtube-dl` will no longer download video streams when video playback
is disabled with `--no-video`.
- (Windows) mpv now prevents system sleep when playing a video-only file.
Previously, only files with an opened audio track would prevent sleep.
New features
------------
- `vo_opengl` features:
- Added `ewa_ginseng`, `ewa_hanning`, `robidoux`, `robidouxsharp`,
`oversample` and `haasnsoft` scalers.
- There are now `ewa_lanczossoft` and `ewa_lanczossharp` aliases to
`ewa_lanczos` that are tuned to be blurrier and sharper, respectively.
- Added `gamma-auto` option that uses ambient light sensors to automatically
adjust the video gamma. See commit c028d78 for details.
- Added `blend-subtitles` option to draw subtitles directly into the video
instead of rendered afterwards. Potentially necessary for correct rendering
with files that use ASS subtitles for typesetting in combination with an
`icc-profile`. There is a default option for drawing after upscaling,
and a `video` option for drawing before upscaling. See details and warning
on the manual.
- There is now a `tscale` option, used to choose the temporal scaler used
in the `interpolation` mode (previously `smoothmotion`).
- There is a new `scale-blur` parameter to adjust the amount of blur that
most of the filters produce. Deviating from the default may introduce
artifacts in EWA filters.
- (Windows) There is now a `dwmflush` option that might help improve
rendering of high-fps video. Disabled by default. See manual for options.
- New Linux-only `vo_drm` video output driver. Uses the direct rendering /
kernel modesetting drivers to draw directly to the framebuffer, but with
no hardware acceleration. See manual for details.
- New `pseudo-gui` builtin profile, automatically used when launched from
`mpv.desktop` by opening `mpv.exe` on windows (`mpv.com` still works as
usual), or by opening the `mpv.app` bundle. The `pseudo-gui` tries to make
the player window behave closer to what a desktop player would do, by not
immediately closing and allowing the user to drag&drop files for playback.
See manual for details.
- mpv can now play directories by automatically playing their contents instead.
Works everywhere but on Windows, due to issues with Windows' C runtime.
- Add support to pitch correct stretched audio with librubberband.
- Add support for the Raspberry Pi 2's hardware decoder when FFmpeg (or Libav)
is built with `--enable-mmal`. See commit 8fff125 for details.
- The `--cache` option now accepts a "yes" option, that always enables a
`--cache-default`-sized cache on all cases a cache can be used, unless
`--cache-default` disables caching.
- `ao_pulse`, `ao_coreaudio` and `ao_wasapi` now support device hotplugging.
- New `--osd-align-x` and `--osd-align-y` options can be used to align the OSD
independently from subtitles.
- New `--osd-bold` and `--sub-text-bold` options can be enabled to bold all
OSD or plain-text subtitle text, respectively.
- Added a default keybind to the `u` key that enables/disables ASS style
overriding. When enabled, is equivalent to `--ass-style-override=force`.
- There is now a `MOUSE_ENTER` keybind, that is called when the mouse cursor
enters the VO from outside.
- The new `--ytdl-params` option can be set to arguments that are always given
to `youtube-dl` invocations. There is no sanity checking, so invalid options
can prevent `mpv` from working with http URLs.
- There's a new `--demuxer-mkv-fix-timestamps` option, enabled by default, that
tries to guess more accurate video timestamps by using FPS information, if
available. See manual for details.
- The new `--window-scale` option can be used to scale the video window by the
specified multiplier, before other options such as `--autofit` are applied.
- `vo_direct3d_shaders` now supports NV12 colorspace without using stretchrect,
but it seems no drivers actually support that.
- (Client API) Added a `rescan_external_files` command, as requested on issue
#1586.
- (Client API) If enabled, initializing the Client API will now also load the
user's `mpv.conf`.
- (Client API) There's a new `mpv_opengl_cb_report_flip()` call for API users
to call to inform mpv of when exactly a frame was displayed.
- (Client API) The `mpv_opengl_cb_render()` function was deprecated in favor
of the new, simpler `mpv_opengl_cb_draw()` function.
- (Client API) There is a new `screenshot_raw` command. See `input.rst` for
details.
- The `--input-file` argument may now also be a file descriptor in the form
"fd://N", where N is the FD number.
This listing is not complete. A complete changelog can be seen by running
`git log v0.8.0..v0.9.0` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.8.0...v0.9.0 (only 250 commits).
Release 0.8.3
=============
Changes
-------
- Documentation fixes and updates.
- (Client API) Clarify `mpv_opengl_cb_render`'s viewport parameter behavior.
Bug fixes
---------
- (X11) Fix crash on `vo_xv:no-colorkey` with the Overlay adapter. (bug #1629)
- (X11) `--stop-screensaver` is now implemented by calling into
`xdg-screensaver`, fixing some compatibility issues that prevented it from
actually stopping screensavers.
- Make the video equalizer work correctly on some VAAPI drivers. (bug #1647)
- Prevent OSD from disappearing when clicking on mozplugger. (bug #1672)
- The new DVB-S2 support code, using S2API, now builds on FreeBSD.
- Fix decoding of seekable matroska from unseekable network stream. (bug #1656)
- (OSX) Fix crashing when closing a VO's window (usually at exit). (bug #1657)
- (OSX) Unhide the mouse cursor when over the Dock or Launchpad. (bug #513)
- (OSX) Fix mouse cursor autohiding when the player is fullscreen.
- `vf_vavpp` (VAAPI postprocessing) now deinterlaces video correctly.
- `smb://` streams now use the stream cache (used to be inefficient).
- (Windows) Do not hide the mouse cursor when it is hovering the window menu.
- Fix 8-channel output on `ao_jack`. (bug #1688)
- Fix `--mf-fps` parameter on JPEG files. (bug #1689)
- Fix anamorphic scaling being ignored if it was very minor.
This listing is not complete. A complete changelog can be seen by running
`git log v0.8.2..v0.8.3` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.8.2...v0.8.3.
Release 0.8.2
=============
Bug fixes
---------
- Fix OSD placement accidentally messed up in 0.8.1 (commit 22863d6).
Release 0.8.1
=============
Changes
-------
- DOCS/client-api-changes has been correctly updated for the v0.8.0 release
series.
- Quality and major perfomance improvements to smoothmotion.
- Silence the "[ytdl_hook] WARNING: video doesn't have subtitles" warning.
- Other documentation updates.
Bug fixes
---------
- Attempt to fix OpenGL shader compilation on Intel windows drivers. (bug
#1536)
- Attempt to improve the OpenGL shader's compatibility with GLES2.
- (Windows) Fix noise when seeking while using wasapi:exclusive. (bug #1529)
- Fix the waf-based build system when used with newer versions of waf with
python3.
- Documentation fixes. (includes bug #1608)
New features
------------
- mpv now tries to load '.vtt' subtitles.
This listing is not complete. A complete changelog can be seen by running
`git log v0.8.0..v0.8.1` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.8.0...v0.8.1.
Release 0.8.0
=============
Changes
-------
Changes that may break users' config files have been annotated with a `(!)`.
- `(!)` vo_opengl_old has been removed. OpenGL rendering now requires hardware
that can do at least OpenGL 2.1, the oldest version supported by vo_opengl.
- `(!)` vf_pp has been removed. A version of it can still be accessed through
lavfilter (e.g. --vf=lavfi=[pp...]), but it receives no QP information.
Also, vf_dlopen no longer passes QP information to its loaded plugin either
(it's always 0).
- `(!)` vf_softpulldown, vf_swapuv, vf_phase, vf_divtc and vf_ilpack have all
been removed. Ports or alternative versions of these filters are available
through libavfilter (vf_lavfi).
- vf_pullup and vf_noise now are simply wrappers to their libavfilter
equivalents. Both are only currently available on FFmpeg (not Libav).
- `(!)` ao_portaudio has been removed. There is good support for the native
audio drivers of all major desktop platforms, as well as ao_sdl and
ao_openal as fallbacks.
- `(!)` vo_opengl's `lscale` suboption has been renamed to `scale`; `lradius`
is now `scale-radius`, `lparam1` and `lparam2` are now respectively
`scale-param1` and `scale-param2`; `lscale-down` is now `scale-down`.
The `cscale` suboption remains as is.
- `(!)` Several of the `vo_opengl` radius-preset aliases supported by `scale`
have been removed; use `scale-radius` to set if needed. For example, use
`--vo=opengl:scale=lanczos:scale-radius=2` instead of `scale=lanczos2`.
The default radius is recommended for most filters.
- `(!)` vo_opengl no longer supports the `stereo` suboption. The anaglyph
effect can be reproduced with the stereo3d filter. The quadbuffer support,
which requires expensive specialized hardware to begin with, is removed.
- `(!)` The `approx-gamma` suboption to vo_opengl has been removed. The
BT.1886 specification says that it's actually how it's supposed to be done
so it is now the default when `srgb` or `icc-profile` are enabled. This does
not include BT.1886's gamma drop.
- `(!)` The `no-scale-sep` and `indirect` suboptions to vo_opengl have been
removed. These are now autodetected and enabled whenever they would have
benefit.
- `(!)` The `--lua` and `--lua-opts` parameters / options are now called
`--script` and `--script-opts`, respectively. The `lua` subdir of the mpv
config dir is also now expected to be called `scripts` instead.
- `(!)` The `--fixed-vo` option has been removed. It has been the default for
a long time anyway, and disabling fixed-vo is not useful.
- vo_opengl_hq has been updated to take into account new features.
`fancy-downscaling` and `sigmoid-upscaling` are enabled,
"mitchell" is now the default for `scale-down`.
- The `sub-visibility` OSD message is now clearer about whether subtitles
are hidden or just not available / selected.
- The device IDs given to `--audio-device` for use with ao_coreaudio now use
UIDs, so they don't change when devices are added/removed or after reboots.
- `--msg-level` now also accepts ',' as separator.
- (Client API) The client API now refuses to initialize if the LC_NUMERIC
locale is not "C".
- (Client API) The native type of the `msg-level` parameter is now a key-value
list. Setting or reading it as a string still works.
- (Slave API) The `get_property` command is now deprecated.
- Documentation updates.
- PDF documentation is now disabled by default due to rst2pdf being fickle,
causing weird build errors.
- Print desync messages with negative A/V sync as well. While rare, it could
happen with some uses of `--autosync`.
Bug fixes
---------
- (Windows) Avoid resizing the video window when player is minimized, might
address bug #1547.
- (NetBSD) Fix build with v4l2.
- (Linux) Attempt to address conflicts with the pulseaudio mixer. (bug #1578)
- Multiple cdda:// fixes. (bugs #1555, #1560)
- VP9 timestamps no longer cause "missing PTS" warnings with new enough FFmpeg
builds.
- Fix a crash when using H.264 hardware decoding on new enough libavcodecs.
(bug #1587)
New features
------------
- vo_opengl now supports frame blending to eliminate stuttering when the video
framerate does not nicely match the display framerate through the
`smoothmotion` suboption. This is not meant to artificially increase the
video's FPS, so there is no "soap opera effect" or difficulties with some
video types (e.g. anime).
- vo_opengl now supports sigmoidal upscaling (e.g. for fullscreen), which
reduces ringing induced by upscaling, enabled through the
`sigmoid-upscaling` suboption.
- vo_opengl now supports ewa_lanczos (Jinc) scaling, which provides higher
quality with less aliasing. It supports an experimental `scale-antiringing`
parameter, which tries to further reduce video ringing.
- vo_opengl now has a `linear-scaling` suboption, that makes the scalers work
in linear light. Implied by the `srgb`, `icc-profile` or the new
`sigmoid-upscaling` suboption.
- vo_opengl has improved downscaling for higher downscale ratios when
`fancy-downscaling` is enabled.
- Add `--keep-open=always` to make `--keep-open` apply to all files instead of
only the last.
- mpv now filters the tags that are printed on the console to try to hide
useless metadata. The filter works as a whitelist, and can be configured
with the `--display-tags` option.
- Add a `--sub-scale-by-window` option that, when set to 'no', prevents
subtitles from changing their pixel size when the window changes sizes.
- vo_opengl now technically has GLES 2 and 3 support (but not GLES 1). GLES 3
support is only tested on Mesa's software emulation. GLES 2 has been tested
on nvidia drivers. Both GLES modes are feature deficient and inefficient due
to GLES limitations, so they should not be preferred over the standard
OpenGL mode.
- (X11) vo_opengl now supports the `icc-profile-auto` option on X11 hosts.
- The 'A' key now by default cycles through a list of preset aspect ratios.
Meant to be used to work around broken files.
- There is now a "force" mode for `--loop`. Works like "inf", but tries to
open files/streams even if there was an error on the previous attempt.
- There is now a `--log-file` option to write mpv's log messages to a specifed
file.
- There is now a `--audio-file-auto` option to automatically load an external
audio file with certain constraints. Will only load external audio if the
playing file has a video stream. Set to "exact" by default. (bug #967)
- There is now a `--network-timeout` option to specify a timeout in seconds
for network access. If 0 (default), uses the libavformat default. If a
protocol that doesn't support timeouts is used, this option is ignored.
- (X11) The XF86 special keys are now all mappable in `input.conf`. All keys
documented in `XF86keysym.h` are available, but only as their numeric codes.
- (Linux) The DVB implementation now supports DVB-S2 through S2API.
- (Linux) The VDR format for `channels.conf` is now supported and preferred.
See http://linuxtv.org/vdrwiki/index.php/Syntax_of_channels.conf for the
syntax. Tuning to DVB-S2 channels requires the VDR-format `channels.conf`.
- (Linux) There is now a `--dvbin-full-transponder` option for handling
special broadcast cases where PIDs switch, or just to work around incomplete
PID data.
- (Client API) There is now an opengl_cb VO, which receives the OpenGL context
from the libmpv client. This allows a client to render libmpv video directly
to a provided OpenGL context without having to use --wid embedding.
- (Client API) The aforementioned --wid parameter can now be set at any time,
but has no effect if a file is already loaded.
- (Client API) The list of DVD titles can now be queried.
- (Client API) There is now a `filtered-metadata` property, containing only
the tags allowed by `--display-tags`.
- (Client API) There is now support for XEmbed `--wid` targets, such as a
`GtkSocket`'s `gtk_socket_get_id()`.
- (Client API) There is now a `file-format` property with a symbolic name
for the file format. In some cases this might be a comma separated list
of various different extensions due to libavformat idiosyncrasies.
- (Client API) There is now a `mouse` command for generating mouse events
over the video window.
- (Client API) There is now a `partially-seekable` property that indicates
whether a file is only considered `seekable` because of the stream cache,
but would not be seekable otherwise (e.g. realtime stream, or HTTP with
no resume support). Small relative seeks may be fine, but larger seeks
will likely fail.
- (Client API) There is now an MPV_EVENT_QUEUE_OVERFLOW event that is posted
whenever events have to be dropped because the queue is full. No further
events are posted until the MPV_EVENT_QUEUE_OVERFLOW is consumed to avoid
duplicated posting.
- (Client API) There is now a helper `mpv_wait_async_requests()` function
that blocks until all known async requests have completed. (bug #1542)
- (Client API) There is now a `detected-hwdec` property that returns the
detected hardware decoder when one is successfully opened. This probably
only returns a valid value after playback has started.
- (Client API) There are now `audio_add`, `audio_remove` and `audio_reload`
counterparts to the equivalent `sub_` commands for handling external audio
files.
This listing is not complete. A complete changelog can be seen by running
`git log v0.7.0..v0.8.0` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.7.0...v0.8.0 (only 250 commits).
Release 0.7.3
=============
Changes
-------
- Several documentation updates and typo fixes.
- Don't show "0%" position when the stream is infinite / has unknown length.
- Fixes the config file loading order so that lower priority `mpv.conf` files
don't override higher priority `config` files.
- (OSX) Remove coreaudio_exclusive from the "auto" codec list.
- Failing to create a GL3 context is now a warning instead of error, to reduce
user confusion.
- The subtitle decoder now gets reset when cycling subtitles. This makes the
currently shown subtitle event disappear even if cycling back to the current
subtitle track.
- `--shuffle` and `--merge-files` now affects the contents of playlist files,
instead of just the list of files given as arguments to mpv.
- `./waf install` avoids installing a few additional data/config files if only
libmpv was built.
- Improved channel mapping when the file's channel map doesn't match the AO's
available channel maps.
- (OSX) VDA now gracefully refuses to run on non-OpenGL3-capable systems instead
of trying and failing to build its shaders.
- Add workaround for vf_vapoursynth filters that expect an FPS.
- The default value for `--screenshot-template` now shows up in
`--list-options`.
- `ao_pulse`'s `latency-hacks` suboption is now off by default, as it causes
issues with newer pulseaudio releases. If A/V Sync issues happen, either
add the `latency-hacks=on` pulse suboption in mpv.conf, or update the
pulseaudio daemon (bug #1430).
- (Linux) `ao_alsa` now deals better with audio device disconnection.
- Client API: timestamp properties that have no value return "no" instead of
magic number.
Bug fixes
---------
- (Windows, OSX) Many `ao_wasapi` and `ao_coreaudio` fixes.
- (OSX) Make the window title update correctly on OS X Yosemite.
- Fixes for handling mono audio on various AOs.
- (Linux) Fixes resuming from suspend on ao_alsa.
- Fixes for playlist file parsing.
- Overly long options in the --list-options output now break the column layout
instead of getting truncated; fixes shell completion scripts.
- Fix rendering resolution of certain DVB subtitles (bug #1425).
- Fix EDL or --merge-files breaking timestamps with .avi files.
- Workaround for libavcodec bug with the VP9 codec parser (bug #1448),
fixes possible crash.
- Improve robustness of the matroska parser with broken files (bugs #1457,
#1461).
- Improve 10bit video compatibility with older GPUs (specially Intel) (bug
#1383).
- Fixes flashing the VO window when playing a list of files that includes
non-media files (bug #1459).
- Workaround for window embedding in OpenBox (bug #1235)
- Fixes for several crashes and lockups (bugs #838, #1389, #1408, #1463, #1473,
#1474).
- Fixes for the zsh completion script (bugs #997)
New features
------------
- mpv now prints the contents of its config.h when running in verbose mode, to
aid with debugging.
- The `include=` option now accepts `~` to refer to the HOME dir (bug #1406).
- `af_volume` now prints ReplayGain values in verbose mode.
- m3u playlists that don't have the `#EXTM3U` header are now accepted if they
"look like" ASCII or UTF-8 text and have the .m3u extension.
- Chapter marks in the seek bar now update when switching files.
- Supports embedded cover art in MKV files (bug #1374).
- (Windows) Video window can now be resized even with --no-border.
- (Windows) Client API: the "run" command now works on Windows too.
- (Linux) vo_wayland now supports key modifiers (Meta, Alt, Control, Shift)
- Client API: "display-names" property is now observable.
This listing is not complete. A complete changelog can be seen by running
`git log v0.7.2..v0.7.3` in the git repository or by visiting
https://github.com/mpv-player/mpv/compare/v0.7.2...v0.7.3.
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 or by visiting
https://github.com/mpv-player/mpv/compare/47ec404...c7d6b21.
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 or by visiting
https://github.com/mpv-player/mpv/compare/8d8b36d...6583ad6.
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 or by visiting
https://github.com/mpv-player/mpv/compare/7759c18...9479daa (only 250 commits).
+1 -1
View File
@@ -102,7 +102,7 @@ function judge()
mp.msg.verbose("progressive = "..num_progressive)
mp.msg.verbose("interlaced-tff = "..num_tff)
mp.msg.verbose("interlaced-bff = "..num_bff)
mp.msg.verbose("interlaced-bff = "..num_bff)
mp.msg.verbose("undetermined = "..num_undetermined)
if num_determined < num_undetermined then
+2 -2
View File
@@ -4,7 +4,7 @@
-- parameters. See the entry for "drc" under the "AUDIO FILTERS"
-- section of the man page for a complete description of the filter.
--
-- This script registers the key-binding "\" to toggle the filter between
-- This script registers the key-binding "\" to toggle the filter between
--
-- * off
-- * method=1 (single-sample smoothing)
@@ -92,7 +92,7 @@ function drc_quieter_handler()
drc_scale_target(0.5)
end
-- toggle between off, method 1 and method 2
-- toggle between off, method 1 and method 2
mp.add_key_binding("\\", "drc_toggle_method", drc_toggle_method_handler)
-- increase or decrease target volume
mp.add_key_binding("ctrl+9", "drc_quieter", drc_quieter_handler)
+1
View File
@@ -0,0 +1 @@
0.9.2
+2 -1
View File
@@ -118,6 +118,7 @@ void mp_audio_set_null_data(struct mp_audio *mpa)
mpa->allocated[n] = NULL;
}
mpa->samples = 0;
mpa->readonly = false;
}
static int get_plane_size(const struct mp_audio *mpa, int samples)
@@ -250,7 +251,7 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
// Will return true for non-refcounted frames.
bool mp_audio_is_writeable(struct mp_audio *data)
{
bool ok = true;
bool ok = !data->readonly;
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
if (data->allocated[n])
ok &= av_buffer_is_writable(data->allocated[n]);
+1
View File
@@ -38,6 +38,7 @@ struct mp_audio {
int bps; // size of sub-samples (af_fmt2bps(format))
// private
bool readonly;
struct AVBufferRef *allocated[MP_NUM_CHANNELS];
};
+63 -52
View File
@@ -50,6 +50,7 @@ static const char *const speaker_names[MP_SPEAKER_ID_COUNT][2] = {
[MP_SPEAKER_ID_SDL] = {"sdl", "surround direct left"},
[MP_SPEAKER_ID_SDR] = {"sdr", "surround direct right"},
[MP_SPEAKER_ID_LFE2] = {"lfe2", "low frequency 2"},
[MP_SPEAKER_ID_NA] = {"na", "not available"},
};
// Names taken from libavutil/channel_layout.c (Not accessible by API.)
@@ -127,7 +128,8 @@ bool mp_chmap_is_valid(const struct mp_chmap *src)
int sp = src->speaker[n];
if (sp >= MP_SPEAKER_ID_COUNT || mapped[sp])
return false;
mapped[sp] = true;
if (sp != MP_SPEAKER_ID_NA)
mapped[sp] = true;
}
return src->num > 0;
}
@@ -142,12 +144,10 @@ bool mp_chmap_is_empty(const struct mp_chmap *src)
bool mp_chmap_is_unknown(const struct mp_chmap *src)
{
for (int n = 0; n < src->num; n++) {
int speaker = src->speaker[n];
if (speaker >= MP_SPEAKER_ID_UNKNOWN0 &&
speaker <= MP_SPEAKER_ID_UNKNOWN_LAST)
return true;
if (src->speaker[n] != MP_SPEAKER_ID_NA)
return false;
}
return false;
return mp_chmap_is_valid(src);
}
// Note: empty channel maps compare as equal. Invalid ones can equal too.
@@ -171,15 +171,6 @@ bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *
return mp_chmap_equals(&t1, &t2);
}
bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b)
{
if (mp_chmap_equals(a, b))
return true;
if (a->num == b->num && (mp_chmap_is_unknown(a) || mp_chmap_is_unknown(b)))
return true;
return false;
}
bool mp_chmap_is_stereo(const struct mp_chmap *src)
{
static const struct mp_chmap stereo = MP_CHMAP_INIT_STEREO;
@@ -199,6 +190,26 @@ void mp_chmap_reorder_norm(struct mp_chmap *map)
qsort(arr, map->num, 1, comp_uint8);
}
// Remove silent (NA) channels, if any.
void mp_chmap_remove_na(struct mp_chmap *map)
{
struct mp_chmap new = {0};
for (int n = 0; n < map->num; n++) {
int sp = map->speaker[n];
if (sp != MP_SPEAKER_ID_NA)
new.speaker[new.num++] = map->speaker[n];
}
*map = new;
}
// Add silent (NA) channels to map until map->num >= num.
void mp_chmap_fill_na(struct mp_chmap *map, int num)
{
assert(num <= MP_NUM_CHANNELS);
while (map->num < num)
map->speaker[map->num++] = MP_SPEAKER_ID_NA;
}
// Set *dst to a standard layout with the given number of channels.
// If the number of channels is invalid, an invalid map is set, and
// mp_chmap_is_valid(dst) will return false.
@@ -227,6 +238,8 @@ void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels)
// Set *dst to an unknown layout for the given numbers of channels.
// If the number of channels is invalid, an invalid map is set, and
// mp_chmap_is_valid(dst) will return false.
// A mp_chmap with all entries set to NA is treated specially in some
// contexts (watch out for mp_chmap_is_unknown()).
void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels)
{
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
@@ -234,7 +247,7 @@ void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels)
} else {
dst->num = num_channels;
for (int n = 0; n < dst->num; n++)
dst->speaker[n] = MP_SPEAKER_ID_UNKNOWN0 + n;
dst->speaker[n] = MP_SPEAKER_ID_NA;
}
}
@@ -277,6 +290,7 @@ void mp_chmap_remove_useless_channels(struct mp_chmap *map,
}
// Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>.
// Speakers not representable by ffmpeg/libav are dropped.
// Warning: this ignores the order of the channels, and will return a channel
// mask even if the order is different from libavcodec's.
uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src)
@@ -286,8 +300,10 @@ uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src)
if (mp_chmap_is_unknown(&t))
mp_chmap_from_channels(&t, t.num);
uint64_t mask = 0;
for (int n = 0; n < t.num; n++)
mask |= 1ULL << t.speaker[n];
for (int n = 0; n < t.num; n++) {
if (t.speaker[n] < 64) // ignore MP_SPEAKER_ID_NA etc.
mask |= 1ULL << t.speaker[n];
}
return mask;
}
@@ -348,56 +364,51 @@ void mp_chmap_reorder_to_lavc(struct mp_chmap *map)
// Get reordering array for from->to reordering. from->to must have the same set
// of speakers (i.e. same number and speaker IDs, just different order). Then,
// for each speaker n, dst[n] will be set such that:
// to->speaker[dst[n]] = from->speaker[n]
// (dst[n] gives the source channel for destination channel n)
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
// for each speaker n, src[n] will be set such that:
// to->speaker[n] = from->speaker[src[n]]
// (src[n] gives the source channel for destination channel n)
// If *from and *to don't contain the same set of speakers, then the above
// invariant is not guaranteed. Instead, src[n] can be set to -1 if the channel
// at to->speaker[n] is unmapped.
void mp_chmap_get_reorder(int src[MP_NUM_CHANNELS], const struct mp_chmap *from,
const struct mp_chmap *to)
{
assert(from->num == to->num);
for (int n = 0; n < MP_NUM_CHANNELS; n++)
src[n] = -1;
if (mp_chmap_is_unknown(from) || mp_chmap_is_unknown(to)) {
for (int n = 0; n < from->num; n++)
dst[n] = n;
for (int n = 0; n < to->num; n++)
src[n] = n < from->num ? n : -1;
return;
}
// Same set of speakers required
assert(mp_chmap_equals_reordered(from, to));
for (int n = 0; n < from->num; n++) {
int src = from->speaker[n];
dst[n] = -1;
for (int i = 0; i < to->num; i++) {
if (src == to->speaker[i]) {
dst[n] = i;
if (to->speaker[n] == from->speaker[i]) {
src[n] = i;
break;
}
}
assert(dst[n] != -1);
}
for (int n = 0; n < from->num; n++)
assert(to->speaker[dst[n]] == from->speaker[n]);
for (int n = 0; n < to->num; n++)
assert(src[n] < 0 || (to->speaker[n] == from->speaker[src[n]]));
}
// Performs the difference between a and b, and store it in diff. If b has
// channels that do not appear in a, those will not appear in the difference.
// To get to those the argument ordering in the function call has to be
// inverted. For the same reason, the diff with a superset will return no
// speakers.
void mp_chmap_diff(const struct mp_chmap *a, const struct mp_chmap *b,
struct mp_chmap *diff)
static int popcount64(uint64_t bits)
{
int r = 0;
for (int n = 0; n < 64; n++)
r += !!(bits & (1ULL << n));
return r;
}
// Return the number of channels only in a.
int mp_chmap_diffn(const struct mp_chmap *a, const struct mp_chmap *b)
{
uint64_t a_mask = mp_chmap_to_lavc_unchecked(a);
uint64_t b_mask = mp_chmap_to_lavc_unchecked(b);
mp_chmap_from_lavc(diff, (a_mask ^ b_mask) & a_mask);
}
// Checks whether a contains all the speakers in b
bool mp_chmap_contains(const struct mp_chmap *a, const struct mp_chmap *b)
{
struct mp_chmap d1;
struct mp_chmap d2;
mp_chmap_diff(a, b, &d1);
mp_chmap_diff(b, a, &d2);
return a->num >= b->num && d1.num >= 0 && d2.num == 0;
return popcount64((a_mask ^ b_mask) & a_mask);
}
// Returns something like "fl-fr-fc". If there's a standard layout in lavc
+10 -10
View File
@@ -56,10 +56,12 @@ enum mp_speaker_id {
MP_SPEAKER_ID_SDR, // SURROUND_DIRECT_RIGHT
MP_SPEAKER_ID_LFE2, // LOW_FREQUENCY_2
// Special mpv-specific speaker entries reserved for channels which have no
// known meaning.
MP_SPEAKER_ID_UNKNOWN0 = 64,
MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1,
// Speaker IDs >= 64 are not representable in WAVEFORMATEXTENSIBLE or libav*.
// "Silent" channels. These are sometimes used to insert padding for
// unused channels. Unlike other speaker types, multiple of these can
// occur in a single mp_chmap.
MP_SPEAKER_ID_NA = 64,
// Including the unassigned IDs in between. This is not a valid ID anymore,
// but is still within uint8_t.
@@ -98,10 +100,11 @@ bool mp_chmap_is_empty(const struct mp_chmap *src);
bool mp_chmap_is_unknown(const struct mp_chmap *src);
bool mp_chmap_equals(const struct mp_chmap *a, const struct mp_chmap *b);
bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *b);
bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b);
bool mp_chmap_is_stereo(const struct mp_chmap *src);
void mp_chmap_reorder_norm(struct mp_chmap *map);
void mp_chmap_remove_na(struct mp_chmap *map);
void mp_chmap_fill_na(struct mp_chmap *map, int num);
void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels);
void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels);
@@ -117,13 +120,10 @@ void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src);
bool mp_chmap_is_lavc(const struct mp_chmap *src);
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,
void mp_chmap_get_reorder(int src[MP_NUM_CHANNELS], const struct mp_chmap *from,
const struct mp_chmap *to);
void mp_chmap_diff(const struct mp_chmap *a, const struct mp_chmap *b,
struct mp_chmap *diff);
bool mp_chmap_contains(const struct mp_chmap *a, const struct mp_chmap *b);
int mp_chmap_diffn(const struct mp_chmap *a, const struct mp_chmap *b);
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))
+27 -53
View File
@@ -199,51 +199,29 @@ bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map)
return false;
}
#define UPMIX_IDX 0
#define DOWNMIX_IDX 1
#define FALLBACK_IDX 2
static bool test_fallbacks(struct mp_chmap *a, struct mp_chmap *b,
int best_diffs[2], struct mp_chmap best[2])
// Decide whether we should prefer old or new for the requested layout.
// Return true if new should be used, false if old should be used.
// If old is empty, always return new (initial case).
static bool mp_chmap_is_better(struct mp_chmap *req, struct mp_chmap *old,
struct mp_chmap *new)
{
struct mp_chmap diff1, diff2;
int old_lost = mp_chmap_diffn(req, old); // num. channels only in req
int new_lost = mp_chmap_diffn(req, new);
mp_chmap_diff(a, b, &diff1);
if (mp_chmap_contains(a, b) && best_diffs[UPMIX_IDX] > diff1.num) {
best[UPMIX_IDX] = *a;
best_diffs[UPMIX_IDX] = diff1.num;
// Initial case
if (!old->num)
return true;
}
mp_chmap_diff(b, a, &diff2);
if (mp_chmap_contains(b, a) && best_diffs[DOWNMIX_IDX] > diff2.num) {
best[DOWNMIX_IDX] = *a;
best_diffs[DOWNMIX_IDX] = diff2.num;
return true;
}
// Imperfect upmix (no real superset) - minimize lost channels
if (new_lost != old_lost)
return new_lost < old_lost;
if (diff1.num > 0 && best_diffs[FALLBACK_IDX] > diff1.num) {
best[FALLBACK_IDX] = *a;
best_diffs[FALLBACK_IDX] = diff1.num;
return true;
}
if (diff2.num > 0 && best_diffs[FALLBACK_IDX] > diff2.num) {
best[FALLBACK_IDX] = *a;
best_diffs[FALLBACK_IDX] = diff2.num;
return true;
}
return false;
// Some kind of upmix. If it's perfect, prefer the smaller one. Even if not,
// both have equal loss, so also prefer the smaller one.
return new->num < old->num;
}
// Determine which channel map to fallback to given a source channel map. It
// uses the following heuristic:
// 1) If mono is required always prefer stereo to a multichannel upmix.
// 2) Search for an upmix that is an exact superset of the required chmap.
// 3) Search for a downmix that is the exact subset of the required chmap.
// 4) Search for either an upmix or downmix that is the closest (minimum
// difference of speakers) to the required chmap.
// Determine which channel map to fallback to given a source channel map.
bool mp_chmap_sel_fallback(const struct mp_chmap_sel *s, struct mp_chmap *map)
{
// special case: if possible always fallback mono to stereo (instead of
@@ -255,8 +233,7 @@ bool mp_chmap_sel_fallback(const struct mp_chmap_sel *s, struct mp_chmap *map)
return true;
}
int best_diffs[] = { INT_MAX, INT_MAX, INT_MAX };
struct mp_chmap best[] = { {0}, {0}, {0} };
struct mp_chmap best = {0};
for (int n = 0; n < s->num_chmaps; n++) {
struct mp_chmap e = s->chmaps[n];
@@ -264,25 +241,22 @@ bool mp_chmap_sel_fallback(const struct mp_chmap_sel *s, struct mp_chmap *map)
if (mp_chmap_is_unknown(&e))
continue;
if (test_fallbacks(&e, map, best_diffs, best))
continue;
// in case we didn't match any fallback retry after replacing speakers
for (int i = 0; i < MP_ARRAY_SIZE(speaker_replacements); i++) {
struct mp_chmap t = e;
struct mp_chmap *r = (struct mp_chmap *)speaker_replacements[i];
if (replace_speakers(&t, r)) {
if (test_fallbacks(&t, map, best_diffs, best))
for (int i = -1; i < (int)MP_ARRAY_SIZE(speaker_replacements); i++) {
struct mp_chmap t = *map;
if (i >= 0) {
struct mp_chmap *r = (struct mp_chmap *)speaker_replacements[i];
if (!replace_speakers(&t, r))
continue;
}
if (mp_chmap_is_better(&t, &best, &e))
best = e;
}
}
for (int i = UPMIX_IDX; i < MP_ARRAY_SIZE(best); i++) {
if (best_diffs[i] < INT_MAX) {
*map = best[i];
return true;
}
if (best.num) {
*map = best;
return true;
}
return false;
+1 -1
View File
@@ -577,7 +577,7 @@ static int af_reinit(struct af_stream *s)
if (af_fmt_is_valid(fmt_in1) && af_fmt_is_valid(fmt_in2)) {
bool spd1 = AF_FORMAT_IS_IEC61937(fmt_in1);
bool spd2 = AF_FORMAT_IS_IEC61937(fmt_in2);
if (spd1 != spd2) {
if (spd1 != spd2 && af->next) {
MP_WARN(af, "Filter %s apparently cannot be used due to "
"spdif passthrough - removing it.\n",
af->info->name);
+82 -37
View File
@@ -81,6 +81,7 @@ struct af_resample {
struct mp_audio *pending;
bool avrctx_ok;
struct AVAudioResampleContext *avrctx;
struct mp_audio avrctx_fmt; // output format of avrctx
struct AVAudioResampleContext *avrctx_out; // for output channel reordering
struct af_resample_opts ctx; // opts in the context
struct af_resample_opts opts; // opts requested by the user
@@ -163,6 +164,22 @@ static bool test_conversion(int src_format, int dst_format)
af_to_avformat(dst_format) != AV_SAMPLE_FMT_NONE;
}
// mp_chmap_get_reorder() performs:
// to->speaker[n] = from->speaker[src[n]]
// but libavresample does:
// to->speaker[dst[n]] = from->speaker[n]
static void transpose_order(int *map, int num)
{
int nmap[MP_NUM_CHANNELS] = {0};
for (int n = 0; n < num; n++) {
for (int i = 0; i < num; i++) {
if (map[n] == i)
nmap[i] = n;
}
}
memcpy(map, nmap, sizeof(nmap));
}
static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
struct mp_audio *out)
{
@@ -172,8 +189,12 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
enum AVSampleFormat out_samplefmt = af_to_avformat(out->format);
enum AVSampleFormat out_samplefmtp =
af_to_avformat(af_fmt_to_planar(out->format));
if (in_samplefmt == AV_SAMPLE_FMT_NONE || out_samplefmt == AV_SAMPLE_FMT_NONE)
if (in_samplefmt == AV_SAMPLE_FMT_NONE ||
out_samplefmt == AV_SAMPLE_FMT_NONE ||
out_samplefmtp == AV_SAMPLE_FMT_NONE)
return AF_ERROR;
avresample_close(s->avrctx);
@@ -220,27 +241,52 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
uint64_t in_ch_layout = mp_chmap_to_lavc_unchecked(&map_in);
uint64_t out_ch_layout = mp_chmap_to_lavc_unchecked(&map_out);
av_opt_set_int(s->avrctx, "in_channel_layout", in_ch_layout, 0);
av_opt_set_int(s->avrctx, "out_channel_layout", out_ch_layout, 0);
av_opt_set_int(s->avrctx, "in_sample_rate", s->ctx.in_rate, 0);
av_opt_set_int(s->avrctx, "out_sample_rate", s->ctx.out_rate, 0);
av_opt_set_int(s->avrctx, "in_sample_fmt", in_samplefmt, 0);
av_opt_set_int(s->avrctx, "out_sample_fmt", out_samplefmt, 0);
struct mp_chmap in_lavc;
mp_chmap_from_lavc(&in_lavc, in_ch_layout);
if (in_lavc.num != map_in.num) {
// For handling NA channels, we would have to add a planarization step.
MP_FATAL(af, "Unsupported channel remapping.\n");
return AF_ERROR;
}
mp_chmap_get_reorder(s->reorder_in, &map_in, &in_lavc);
transpose_order(s->reorder_in, map_in.num);
struct mp_chmap out_lavc;
mp_chmap_from_lavc(&out_lavc, out_ch_layout);
mp_chmap_get_reorder(s->reorder_out, &out_lavc, &map_out);
if (mp_chmap_equals(&out_lavc, &map_out)) {
// No intermediate step required - output new format directly.
out_samplefmtp = out_samplefmt;
} else {
// Verify that we really just reorder and/or insert NA channels.
struct mp_chmap withna = out_lavc;
mp_chmap_fill_na(&withna, map_out.num);
if (withna.num != map_out.num)
return AF_ERROR;
mp_chmap_get_reorder(s->reorder_out, &out_lavc, &map_out);
}
// Same configuration; we just reorder.
av_opt_set_int(s->avrctx_out, "in_channel_layout", out_ch_layout, 0);
av_opt_set_int(s->avrctx_out, "out_channel_layout", out_ch_layout, 0);
av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmt, 0);
s->avrctx_fmt = *out;
mp_audio_set_channels(&s->avrctx_fmt, &out_lavc);
mp_audio_set_format(&s->avrctx_fmt, af_from_avformat(out_samplefmtp));
// Real conversion; output is input to avrctx_out.
av_opt_set_int(s->avrctx, "in_channel_layout", in_ch_layout, 0);
av_opt_set_int(s->avrctx, "out_channel_layout", out_ch_layout, 0);
av_opt_set_int(s->avrctx, "in_sample_rate", s->ctx.in_rate, 0);
av_opt_set_int(s->avrctx, "out_sample_rate", s->ctx.out_rate, 0);
av_opt_set_int(s->avrctx, "in_sample_fmt", in_samplefmt, 0);
av_opt_set_int(s->avrctx, "out_sample_fmt", out_samplefmtp, 0);
// Just needs the correct number of channels.
int fake_out_ch_layout = av_get_default_channel_layout(map_out.num);
if (!fake_out_ch_layout)
return AF_ERROR;
// Deplanarize if needed.
av_opt_set_int(s->avrctx_out, "in_channel_layout", fake_out_ch_layout, 0);
av_opt_set_int(s->avrctx_out, "out_channel_layout", fake_out_ch_layout, 0);
av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmtp, 0);
av_opt_set_int(s->avrctx_out, "out_sample_fmt", out_samplefmt, 0);
av_opt_set_int(s->avrctx_out, "in_sample_rate", s->ctx.out_rate, 0);
av_opt_set_int(s->avrctx_out, "out_sample_rate", s->ctx.out_rate, 0);
@@ -249,7 +295,6 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
// * This function can only be called when the allocated context is not open.
// * Also, the input channel layout must have already been set.
avresample_set_channel_mapping(s->avrctx, s->reorder_in);
avresample_set_channel_mapping(s->avrctx_out, s->reorder_out);
if (avresample_open(s->avrctx) < 0 ||
avresample_open(s->avrctx_out) < 0)
@@ -354,22 +399,22 @@ static void uninit(struct af_instance *af)
talloc_free(s->pending);
}
static bool needs_reorder(int *reorder, int num_ch)
{
for (int n = 0; n < num_ch; n++) {
if (reorder[n] != n)
return true;
}
return false;
}
static void reorder_planes(struct mp_audio *mpa, int *reorder)
static void reorder_planes(struct mp_audio *mpa, int *reorder,
struct mp_chmap *newmap)
{
struct mp_audio prev = *mpa;
for (int n = 0; n < mpa->num_planes; n++) {
assert(reorder[n] >= 0 && reorder[n] < mpa->num_planes);
mpa->planes[n] = prev.planes[reorder[n]];
for (int n = 0; n < newmap->num; n++) {
int src = reorder[n];
if (src < 0) {
src = 0; // Use the first plane for padding channels.
mpa->readonly = true;
}
assert(src < mpa->num_planes);
mpa->planes[n] = prev.planes[src];
}
mp_audio_set_channels(mpa, newmap);
}
static int filter(struct af_instance *af, struct mp_audio *in)
@@ -388,14 +433,14 @@ static int filter(struct af_instance *af, struct mp_audio *in)
int samples = avresample_available(s->avrctx) +
av_rescale_rnd(get_delay(s) + (in ? in->samples : 0),
s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP);
struct mp_audio *out = mp_audio_pool_get(af->out_pool, af->data, samples);
struct mp_audio out_format = s->avrctx_fmt;
struct mp_audio *out = mp_audio_pool_get(af->out_pool, &out_format, samples);
if (!out)
goto error;
if (in)
mp_audio_copy_attributes(out, in);
mp_audio_realloc_min(out, out->samples);
af->delay = get_delay(s) / (double)s->ctx.in_rate;
if (out->samples) {
@@ -404,11 +449,11 @@ static int filter(struct af_instance *af, struct mp_audio *in)
goto error;
}
if (needs_reorder(s->reorder_out, out->nch)) {
if (AF_FORMAT_IS_PLANAR(out->format)) {
reorder_planes(out, s->reorder_out);
} else if (out->samples) {
struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer, out,
if (out->samples && !mp_audio_config_equals(out, af->data)) {
assert(AF_FORMAT_IS_PLANAR(out->format));
reorder_planes(out, s->reorder_out, &af->data->channels);
if (!mp_audio_config_equals(out, af->data)) {
struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer, af->data,
out->samples);
if (!new)
goto error;
+15 -15
View File
@@ -64,24 +64,24 @@
enum af_format {
AF_FORMAT_UNKNOWN = 0,
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_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 = (AF_FORMAT_F|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLE = (AF_FORMAT_F|AF_FORMAT_64BIT),
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_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),
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,
// All of these use IEC61937 framing, and otherwise pretend to be like PCM.
AF_FORMAT_S_AAC = AF_FORMAT_S_(0),
+20 -16
View File
@@ -385,28 +385,26 @@ bool ao_eof_reached(struct ao *ao)
// 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;
if (atomic_load(&ao->request_hotplug))
actual_events |= AO_EVENT_HOTPLUG;
return actual_events & events;
return atomic_fetch_and(&ao->events_, ~(unsigned)events) & events;
}
static void ao_add_events(struct ao *ao, int events)
{
atomic_fetch_or(&ao->events_, events);
if (ao->input_ctx)
mp_input_wakeup(ao->input_ctx);
}
// Request that the player core destroys and recreates the AO. Fully thread-safe.
void ao_request_reload(struct ao *ao)
{
atomic_store(&ao->request_reload, true);
if (ao->input_ctx)
mp_input_wakeup(ao->input_ctx);
ao_add_events(ao, AO_EVENT_RELOAD);
}
// Notify the player that the device list changed. Fully thread-safe.
void ao_hotplug_event(struct ao *ao)
{
atomic_store(&ao->request_hotplug, true);
if (ao->input_ctx)
mp_input_wakeup(ao->input_ctx);
ao_add_events(ao, AO_EVENT_HOTPLUG);
}
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
@@ -415,12 +413,19 @@ bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
if (mp_msg_test(ao->log, MSGL_DEBUG)) {
for (int i = 0; i < s->num_chmaps; i++) {
struct mp_chmap c = s->chmaps[i];
MP_DBG(ao, "chmap_sel #%d: %s\n", i, mp_chmap_to_str(&c));
struct mp_chmap cr = c;
mp_chmap_reorder_norm(&cr);
MP_DBG(ao, "chmap_sel #%d: %s (%s)\n", i, mp_chmap_to_str(&c),
mp_chmap_to_str(&cr));
}
}
bool r = mp_chmap_sel_adjust(s, map);
if (r)
MP_DBG(ao, "result: %s\n", mp_chmap_to_str(map));
if (r) {
struct mp_chmap mapr = *map;
mp_chmap_reorder_norm(&mapr);
MP_DBG(ao, "result: %s (%s)\n", mp_chmap_to_str(map),
mp_chmap_to_str(&mapr));
}
return r;
}
@@ -496,7 +501,6 @@ bool ao_hotplug_check_update(struct ao_hotplug *hp)
{
if (hp->ao && ao_query_and_reset_events(hp->ao, AO_EVENT_HOTPLUG)) {
hp->needs_update = true;
atomic_store(&hp->ao->request_hotplug, false);
return true;
}
return false;
+41 -33
View File
@@ -252,6 +252,7 @@ static const int alsa_to_mp_channels[][2] = {
{SND_CHMAP_TRR, MP_SP(TBR)},
{SND_CHMAP_TRC, MP_SP(TBC)},
{SND_CHMAP_MONO, MP_SP(FC)},
{SND_CHMAP_NA, MP_SPEAKER_ID_NA},
{SND_CHMAP_LAST, MP_SPEAKER_ID_COUNT}
};
@@ -275,6 +276,20 @@ static int find_alsa_channel(int mp_channel)
return SND_CHMAP_UNKNOWN;
}
static int mp_chmap_from_alsa(struct mp_chmap *dst, snd_pcm_chmap_t *src)
{
*dst = (struct mp_chmap) {0};
if (src->channels > MP_NUM_CHANNELS)
return -1;
dst->num = src->channels;
for (int c = 0; c < dst->num; c++)
dst->speaker[c] = find_mp_channel(src->pos[c]);
return 0;
}
static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
{
struct priv *p = ao->priv;
@@ -285,14 +300,8 @@ static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
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]);
struct mp_chmap entry;
mp_chmap_from_alsa(&entry, &maps[i]->map);
if (mp_chmap_is_valid(&entry)) {
MP_VERBOSE(ao, "Got supported channel map: %s (type %s)\n",
@@ -404,7 +413,7 @@ alsa_error: ;
#define INIT_OK 0
#define INIT_ERROR -1
#define INIT_BRAINDEATH -2
static int init_device(struct ao *ao)
static int init_device(struct ao *ao, bool second_try)
{
struct priv *p = ao->priv;
int err;
@@ -492,11 +501,12 @@ static int init_device(struct ao *ao)
}
if (num_channels != ao->channels.num) {
int req = ao->channels.num;
mp_chmap_from_channels_alsa(&ao->channels, num_channels);
if (!mp_chmap_is_valid(&ao->channels))
mp_chmap_from_channels(&ao->channels, 2);
MP_ERR(ao, "Couldn't get requested number of channels, fallback to %s.\n",
mp_chmap_to_str(&ao->channels));
MP_ERR(ao, "Couldn't get requested number of channels (%d), fallback "
"to %s.\n", req, mp_chmap_to_str(&ao->channels));
}
// Some ALSA drivers have broken delay reporting, so disable the ALSA
@@ -564,9 +574,8 @@ static int init_device(struct ao *ao)
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]);
struct mp_chmap chmap;
mp_chmap_from_alsa(&chmap, alsa_chmap);
MP_VERBOSE(ao, "which we understand as: %s\n", mp_chmap_to_str(&chmap));
@@ -575,24 +584,14 @@ static int init_device(struct ao *ao)
} else if (AF_FORMAT_IS_IEC61937(ao->format)) {
MP_VERBOSE(ao, "using spdif passthrough; ignoring the channel map.\n");
} else 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 {
// Is it one that contains NA channels?
struct mp_chmap chmap2 = {0};
for (int c = 0; c < alsa_chmap->channels; c++) {
int alsa_ch = alsa_chmap->pos[c];
if (alsa_ch != SND_CHMAP_NA)
chmap2.speaker[chmap2.num++] = find_mp_channel(alsa_ch);
}
struct mp_chmap without_na = chmap;
mp_chmap_remove_na(&without_na);
if (mp_chmap_is_valid(&chmap2)) {
if (mp_chmap_is_valid(&without_na) &&
!mp_chmap_equals(&without_na, &chmap) &&
!second_try)
{
// Sometimes, ALSA will advertise certain chmaps, but it's not
// possible to set them. This can happen with dmix: as of
// alsa 1.0.28, dmix can do stereo only, but advertises the
@@ -609,10 +608,19 @@ static int init_device(struct ao *ao)
err = snd_pcm_close(p->alsa);
p->alsa = NULL;
CHECK_ALSA_ERROR("pcm close error");
ao->channels = chmap2;
ao->channels = without_na;
return INIT_BRAINDEATH;
}
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");
}
@@ -683,9 +691,9 @@ static int init(struct ao *ao)
MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version());
int r = init_device(ao);
int r = init_device(ao, false);
if (r == INIT_BRAINDEATH)
r = init_device(ao); // retry with normalized channel layout
r = init_device(ao, true); // retry with normalized channel layout
return r == INIT_OK ? 0 : -1;
}
+9 -7
View File
@@ -78,7 +78,6 @@ static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags,
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;
}
@@ -381,8 +380,8 @@ static int hotplug_init(struct ao *ao)
err = AudioObjectAddPropertyListener(
kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
if (err != noErr) {
char *c1 = fourcc_repr(ao, hotplug_properties[i]);
char *c2 = fourcc_repr(ao, err);
char *c1 = fourcc_repr(hotplug_properties[i]);
char *c2 = fourcc_repr(err);
MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
goto coreaudio_error;
}
@@ -406,8 +405,8 @@ static void hotplug_uninit(struct ao *ao)
err = AudioObjectRemovePropertyListener(
kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
if (err != noErr) {
char *c1 = fourcc_repr(ao, hotplug_properties[i]);
char *c2 = fourcc_repr(ao, err);
char *c1 = fourcc_repr(hotplug_properties[i]);
char *c2 = fourcc_repr(err);
MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
}
}
@@ -445,7 +444,9 @@ static const int speaker_map[][2] = {
{ kAudioChannelLabel_HeadphonesLeft, MP_SPEAKER_ID_DL },
{ kAudioChannelLabel_HeadphonesRight, MP_SPEAKER_ID_DR },
{ kAudioChannelLabel_Unknown, MP_SPEAKER_ID_UNKNOWN0 },
{ kAudioChannelLabel_Unknown, MP_SPEAKER_ID_NA },
{ 0, -1 },
};
static int ca_label_to_mp_speaker_id(AudioChannelLabel label)
@@ -541,9 +542,10 @@ bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
return false;
}
int next_na = MP_SPEAKER_ID_NA;
for (int n = 0; n < l->mNumberChannelDescriptions; n++) {
AudioChannelLabel label = l->mChannelDescriptions[n].mChannelLabel;
uint8_t speaker = ca_label_to_mp_speaker_id(label);
int speaker = ca_label_to_mp_speaker_id(label);
if (speaker < 0) {
MP_VERBOSE(ao, "channel label=%u unusable to build channel "
"bitmap, skipping layout\n", (unsigned) label);
+79 -88
View File
@@ -41,12 +41,13 @@
#include "internal.h"
#include "audio/format.h"
#include "osdep/timer.h"
#include "osdep/atomics.h"
#include "options/m_option.h"
#include "common/msg.h"
#include "audio/out/ao_coreaudio_properties.h"
#include "audio/out/ao_coreaudio_utils.h"
static bool ca_format_is_digital(AudioStreamBasicDescription asbd)
static bool ca_format_is_compressed(AudioStreamBasicDescription asbd)
{
switch (asbd.mFormatID)
case 'IAC3':
@@ -57,7 +58,7 @@ static bool ca_format_is_digital(AudioStreamBasicDescription asbd)
return false;
}
static bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream)
static bool ca_stream_supports_compressed(struct ao *ao, AudioStreamID stream)
{
AudioStreamRangedDescription *formats = NULL;
size_t n_formats;
@@ -71,7 +72,7 @@ static bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream)
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)) {
if (ca_format_is_compressed(asbd)) {
talloc_free(formats);
return true;
}
@@ -82,7 +83,7 @@ coreaudio_error:
return false;
}
static bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device)
static bool ca_device_supports_compressed(struct ao *ao, AudioDeviceID device)
{
AudioStreamID *streams = NULL;
size_t n_streams;
@@ -94,7 +95,7 @@ static bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device)
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])) {
if (ca_stream_supports_compressed(ao, streams[i])) {
talloc_free(streams);
return true;
}
@@ -112,15 +113,13 @@ static OSStatus ca_property_listener(
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;
if (data)
atomic_store((atomic_bool *)data, true);
break;
}
}
talloc_free(talloc_ctx);
return noErr;
}
@@ -242,7 +241,7 @@ static bool ca_change_format(struct ao *ao, AudioStreamID stream,
{
OSStatus err = noErr;
AudioObjectPropertyAddress p_addr;
volatile int stream_format_changed = 0;
atomic_bool stream_format_changed = ATOMIC_VAR_INIT(false);
ca_print_asbd(ao, "setting stream format:", &change_format);
@@ -254,7 +253,7 @@ static bool ca_change_format(struct ao *ao, AudioStreamID stream,
};
err = AudioObjectAddPropertyListener(stream, &p_addr, ca_stream_listener,
(void *)&stream_format_changed);
&stream_format_changed);
if (!CHECK_CA_WARN("can't add property listener during format change")) {
return false;
}
@@ -265,33 +264,32 @@ static bool ca_change_format(struct ao *ao, AudioStreamID stream,
return false;
}
/* The AudioStreamSetProperty is not only asynchronious,
/* The AudioStreamSetProperty is not only asynchronous,
* 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++)
AudioStreamBasicDescription actual_format = {0};
for (int i = 0; i < 5; i++) {
err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &actual_format);
if (!CHECK_CA_WARN("could not retrieve physical format"))
break;
format_set = ca_asbd_equals(&change_format, &actual_format);
if (format_set)
break;
for (int j = 0; !atomic_load(&stream_format_changed) && j < 50; j++)
mp_sleep_us(10000);
if (stream_format_changed) {
stream_format_changed = 0;
} else {
bool old = true;
if (!atomic_compare_exchange_strong(&stream_format_changed, &old, false))
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;
}
}
ca_print_asbd(ao, "actual format in use:", &actual_format);
err = AudioObjectRemovePropertyListener(stream, &p_addr, ca_stream_listener,
(void *)&stream_format_changed);
&stream_format_changed);
if (!CHECK_CA_WARN("can't remove property listener")) {
return false;
@@ -306,32 +304,30 @@ struct priv {
bool paused;
// digital render callback
// audio 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
// format we changed the stream to, and the original format to restore
AudioStreamBasicDescription stream_asbd;
AudioStreamBasicDescription original_asbd;
bool changed_mixing;
int stream_asbd_changed;
atomic_bool stream_asbd_changed;
bool reload_requested;
uint32_t hw_latency_us;
};
static OSStatus render_cb_digital(
static OSStatus render_cb_compressed(
AudioDeviceID device, const AudioTimeStamp *ts,
const void *in_data, const AudioTimeStamp *in_ts,
AudioBufferList *out_data, const AudioTimeStamp *out_ts, void *ctx)
@@ -355,58 +351,47 @@ static OSStatus render_cb_digital(
ao_read_data(ao, &buf.mData, pseudo_frames, end);
// Check whether we need to reset the digital output stream.
if (p->stream_asbd_changed) {
p->stream_asbd_changed = 0;
if (!p->reload_requested && ca_stream_supports_digital(ao, p->stream)) {
p->reload_requested = true;
ao_request_reload(ao);
MP_INFO(ao, "Stream format changed! Reloading.\n");
}
// Check whether we need to reset the compressed output stream.
if (atomic_load(&p->stream_asbd_changed)) {
AudioStreamBasicDescription f;
OSErr err = CA_GET(p->stream, kAudioStreamPropertyPhysicalFormat, &f);
CHECK_CA_WARN("could not get stream format");
if (err == noErr && ca_asbd_equals(&p->stream_asbd, &f))
atomic_store(&p->stream_asbd_changed, false);
}
if (atomic_load(&p->stream_asbd_changed) && !p->reload_requested) {
p->reload_requested = true;
ao_request_reload(ao);
MP_INFO(ao, "Stream format changed! Reloading.\n");
}
return noErr;
}
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");
CHECK_CA_ERROR_L(coreaudio_error_nounlock, "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 (!AF_FORMAT_IS_IEC61937(ao->format)) {
MP_ERR(ao, "Only compressed formats are supported.\n");
goto coreaudio_error_nounlock;
}
if (!supports_digital) {
MP_ERR(ao, "selected device doesn't support digital formats\n");
goto coreaudio_error;
} // closes if (!supports_digital)
if (!ca_device_supports_compressed(ao, p->device)) {
MP_ERR(ao, "selected device doesn't support compressed formats\n");
goto coreaudio_error_nounlock;
}
// 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");
@@ -430,15 +415,9 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
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;
bool compressed = ca_stream_supports_compressed(ao, streams[i]);
if (compressed) {
AudioStreamRangedDescription *formats;
size_t n_formats;
@@ -456,8 +435,8 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
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
if (ca_format_is_compressed(formats[j].mFormat)) {
// select the compressed 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) {
@@ -481,14 +460,18 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
talloc_free(streams);
if (p->stream_idx < 0) {
MP_WARN(ao , "can't find any digital output stream format\n");
MP_WARN(ao , "can't find any compressed output stream format\n");
goto coreaudio_error;
}
err = CA_GET(p->stream, kAudioStreamPropertyPhysicalFormat,
&p->original_asbd);
CHECK_CA_ERROR("could not get stream's original physical format");
if (!ca_change_format(ao, p->stream, p->stream_asbd))
goto coreaudio_error;
void *changed = (void *) &(p->stream_asbd_changed);
void *changed = &p->stream_asbd_changed;
err = ca_enable_device_listener(p->device, changed);
CHECK_CA_ERROR("cannot install format change listener during init");
@@ -501,26 +484,34 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
p->stream_asbd.mFramesPerPacket);
uint32_t latency_frames = 0;
err = CA_GET_O(p->device, kAudioDevicePropertyLatency, &latency_frames);
if (err != noErr) {
uint32_t latency_properties[] = {
kAudioDevicePropertyLatency,
kAudioDevicePropertyBufferFrameSize,
kAudioDevicePropertySafetyOffset,
};
for (int n = 0; n < MP_ARRAY_SIZE(latency_properties); n++) {
uint32_t temp;
err = CA_GET_O(p->device, latency_properties[n], &temp);
CHECK_CA_WARN("cannot get device latency");
latency_frames = 0;
if (err == noErr)
latency_frames += temp;
}
p->hw_latency_us = ca_frames_to_us(ao, latency_frames);
MP_VERBOSE(ao, "base latency: %d microseconds\n", (int)p->hw_latency_us);
err = AudioDeviceCreateIOProcID(p->device,
(AudioDeviceIOProc)render_cb_digital,
(AudioDeviceIOProc)render_cb_compressed,
(void *)ao,
&p->render_cb);
CHECK_CA_ERROR("failed to register digital render callback");
CHECK_CA_ERROR("failed to register audio render callback");
return CONTROL_TRUE;
coreaudio_error:
err = ca_unlock_device(p->device, &p->hog_pid);
CHECK_CA_WARN("can't release hog mode");
coreaudio_error_nounlock:
return CONTROL_ERROR;
}
@@ -529,7 +520,7 @@ static void uninit(struct ao *ao)
struct priv *p = ao->priv;
OSStatus err = noErr;
void *changed = (void *) &(p->stream_asbd_changed);
void *changed = &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");
@@ -554,7 +545,7 @@ static void audio_pause(struct ao *ao)
struct priv *p = ao->priv;
OSStatus err = AudioDeviceStop(p->device, p->render_cb);
CHECK_CA_WARN("can't stop digital device");
CHECK_CA_WARN("can't stop audio device");
}
static void audio_resume(struct ao *ao)
@@ -562,7 +553,7 @@ static void audio_resume(struct ao *ao)
struct priv *p = ao->priv;
OSStatus err = AudioDeviceStart(p->device, p->render_cb);
CHECK_CA_WARN("can't start digital device");
CHECK_CA_WARN("can't start audio device");
}
#define OPT_BASE_STRUCT struct priv
@@ -577,7 +568,7 @@ const struct ao_driver audio_out_coreaudio_exclusive = {
.list_devs = ca_get_device_list,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv){
.stream_asbd_changed = 0,
.stream_asbd_changed = ATOMIC_VAR_INIT(false),
.hog_pid = -1,
.stream = 0,
.stream_idx = -1,
+113 -28
View File
@@ -88,7 +88,7 @@ OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
OSStatus err = noErr;
*device = kAudioObjectUnknown;
if (name) {
if (name && name[0]) {
CFStringRef uid = cfstr_from_cstr(name);
AudioValueTranslation v = (AudioValueTranslation) {
.mInputData = &uid,
@@ -116,9 +116,8 @@ OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
if (mp_msg_test(ao->log, MSGL_V)) {
char *desc;
err = CA_GET_STR(*device, kAudioObjectPropertyName, &desc);
CHECK_CA_WARN("could not get selected audio device name");
if (err == noErr) {
OSStatus err2 = CA_GET_STR(*device, kAudioObjectPropertyName, &desc);
if (err2 == noErr) {
MP_VERBOSE(ao, "selected audio output device: %s (%" PRIu32 ")\n",
desc, *device);
talloc_free(desc);
@@ -129,7 +128,7 @@ coreaudio_error:
return err;
}
char *fourcc_repr(void *talloc_ctx, uint32_t code)
char *fourcc_repr_buf(char *buf, size_t buf_size, uint32_t code)
{
// Extract FourCC letters from the uint32_t and finde out if it's a valid
// code that is made of letters.
@@ -146,43 +145,40 @@ char *fourcc_repr(void *talloc_ctx, uint32_t code)
valid_fourcc = false;
}
char *repr;
if (valid_fourcc)
repr = talloc_asprintf(talloc_ctx, "'%c%c%c%c'",
fcc[0], fcc[1], fcc[2], fcc[3]);
snprintf(buf, buf_size, "'%c%c%c%c'", fcc[0], fcc[1], fcc[2], fcc[3]);
else
repr = talloc_asprintf(NULL, "%u", (unsigned int)code);
snprintf(buf, buf_size, "%u", (unsigned int)code);
return repr;
return buf;
}
bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message)
{
if (code == noErr) return true;
char *error_string = fourcc_repr(NULL, code);
mp_msg(ao->log, level, "%s (%s)\n", message, error_string);
talloc_free(error_string);
mp_msg(ao->log, level, "%s (%s)\n", message, fourcc_repr(code));
return false;
}
void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd)
static void ca_fill_asbd_raw(AudioStreamBasicDescription *asbd, int mp_format,
int samplerate, int num_channels)
{
asbd->mSampleRate = ao->samplerate;
asbd->mSampleRate = samplerate;
// Set "AC3" for other spdif formats too - unknown if that works.
asbd->mFormatID = AF_FORMAT_IS_IEC61937(ao->format) ?
asbd->mFormatID = AF_FORMAT_IS_IEC61937(mp_format) ?
kAudioFormat60958AC3 :
kAudioFormatLinearPCM;
asbd->mChannelsPerFrame = ao->channels.num;
asbd->mBitsPerChannel = af_fmt2bits(ao->format);
asbd->mChannelsPerFrame = num_channels;
asbd->mBitsPerChannel = af_fmt2bits(mp_format);
asbd->mFormatFlags = kAudioFormatFlagIsPacked;
if ((ao->format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F)
if ((mp_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F) {
asbd->mFormatFlags |= kAudioFormatFlagIsFloat;
if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI)
} else if ((mp_format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI) {
asbd->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
}
if (BYTE_ORDER == BIG_ENDIAN)
asbd->mFormatFlags |= kAudioFormatFlagIsBigEndian;
@@ -193,17 +189,66 @@ void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd)
(asbd->mBitsPerChannel / 8);
}
void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd)
{
ca_fill_asbd_raw(asbd, ao->format, ao->samplerate, ao->channels.num);
}
static bool ca_formatid_is_digital(uint32_t formatid)
{
switch (formatid)
case 'IAC3':
case 'iac3':
case kAudioFormat60958AC3:
case kAudioFormatAC3:
return true;
return false;
}
// This might be wrong, but for now it's sufficient for us.
static uint32_t ca_normalize_formatid(uint32_t formatID)
{
return ca_formatid_is_digital(formatID) ? kAudioFormat60958AC3 : formatID;
}
bool ca_asbd_equals(const AudioStreamBasicDescription *a,
const AudioStreamBasicDescription *b)
{
int flags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsFloat |
kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsBigEndian;
return (a->mFormatFlags & flags) == (b->mFormatFlags & flags) &&
a->mBitsPerChannel == b->mBitsPerChannel &&
ca_normalize_formatid(a->mFormatID) ==
ca_normalize_formatid(b->mFormatID) &&
a->mBytesPerPacket == b->mBytesPerPacket;
}
// Return the AF_FORMAT_* (AF_FORMAT_S16 etc.) corresponding to the asbd.
int ca_asbd_to_mp_format(const AudioStreamBasicDescription *asbd)
{
for (int n = 0; af_fmtstr_table[n].format; n++) {
int mp_format = af_fmtstr_table[n].format;
AudioStreamBasicDescription mp_asbd = {0};
ca_fill_asbd_raw(&mp_asbd, mp_format, 0, asbd->mChannelsPerFrame);
if (ca_asbd_equals(&mp_asbd, asbd))
return mp_format;
}
return 0;
}
void ca_print_asbd(struct ao *ao, const char *description,
const AudioStreamBasicDescription *asbd)
{
uint32_t flags = asbd->mFormatFlags;
char *format = fourcc_repr(NULL, asbd->mFormatID);
char *format = fourcc_repr(asbd->mFormatID);
int mpfmt = ca_asbd_to_mp_format(asbd);
MP_VERBOSE(ao,
"%s %7.1fHz %" PRIu32 "bit [%s]"
"[%" PRIu32 "][%" PRIu32 "][%" PRIu32 "]"
"[%" PRIu32 "][%" PRIu32 "] "
"%s %s %s%s%s%s\n",
"%s %7.1fHz %" PRIu32 "bit %s "
"[%" PRIu32 "][%" PRIu32 "bpp][%" PRIu32 "fbp]"
"[%" PRIu32 "bpf][%" PRIu32 "ch] "
"%s %s %s%s%s%s (%s)\n",
description, asbd->mSampleRate, asbd->mBitsPerChannel, format,
asbd->mFormatFlags, asbd->mBytesPerPacket, asbd->mFramesPerPacket,
asbd->mBytesPerFrame, asbd->mChannelsPerFrame,
@@ -212,9 +257,49 @@ void ca_print_asbd(struct ao *ao, const char *description,
(flags & kAudioFormatFlagIsSignedInteger) ? "S" : "U",
(flags & kAudioFormatFlagIsPacked) ? " packed" : "",
(flags & kAudioFormatFlagIsAlignedHigh) ? " aligned" : "",
(flags & kAudioFormatFlagIsNonInterleaved) ? " P" : "");
(flags & kAudioFormatFlagIsNonInterleaved) ? " P" : "",
mpfmt ? af_fmt_to_str(mpfmt) : "-");
}
talloc_free(format);
// Return whether new is an improvement over old. Assume a higher value means
// better quality, and we always prefer the value closest to the requested one,
// which is still larger than the requested one.
// Equal values prefer the new one (so ca_asbd_is_better() checks other params).
static bool value_is_better(double req, double old, double new)
{
if (new >= req) {
return old < req || new <= old;
} else {
return old < req && new >= old;
}
}
// Return whether new is an improvement over old (req is the requested format).
bool ca_asbd_is_better(AudioStreamBasicDescription *req,
AudioStreamBasicDescription *old,
AudioStreamBasicDescription *new)
{
if (new->mChannelsPerFrame > MP_NUM_CHANNELS)
return false;
if (old->mChannelsPerFrame > MP_NUM_CHANNELS)
return true;
if (req->mFormatID != new->mFormatID)
return false;
if (req->mFormatID != old->mFormatID)
return true;
if (!value_is_better(req->mBitsPerChannel, old->mBitsPerChannel,
new->mBitsPerChannel))
return false;
if (!value_is_better(req->mSampleRate, old->mSampleRate, new->mSampleRate))
return false;
if (!value_is_better(req->mChannelsPerFrame, old->mChannelsPerFrame,
new->mChannelsPerFrame))
return false;
return true;
}
int64_t ca_frames_to_us(struct ao *ao, uint32_t frames)
+9 -1
View File
@@ -31,7 +31,9 @@
CFStringRef cfstr_from_cstr(char *str);
char *cfstr_get_cstr(CFStringRef cfstr);
char *fourcc_repr(void *talloc_ctx, uint32_t code);
char *fourcc_repr_buf(char *buf, size_t buf_size, uint32_t code);
#define fourcc_repr(code) fourcc_repr_buf((char[40]){0}, 40, code)
bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message);
#define CHECK_CA_ERROR_L(label, message) \
@@ -55,6 +57,12 @@ 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_asbd_equals(const AudioStreamBasicDescription *a,
const AudioStreamBasicDescription *b);
int ca_asbd_to_mp_format(const AudioStreamBasicDescription *asbd);
bool ca_asbd_is_better(AudioStreamBasicDescription *req,
AudioStreamBasicDescription *old,
AudioStreamBasicDescription *new);
int64_t ca_frames_to_us(struct ao *ao, uint32_t frames);
int64_t ca_get_latency(const AudioTimeStamp *ts);
+3 -1
View File
@@ -98,7 +98,9 @@ static const struct mp_chmap sndio_layouts[MP_NUM_CHANNELS + 1] = {
{0}, // 6.1
MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), // 7.1
/* above is the fixed channel assignment for sndio, since we need to fill
all channels and cannot insert silence, not all layouts are supported. */
all channels and cannot insert silence, not all layouts are supported.
NOTE: MP_SPEAKER_ID_NA could be used to add padding channels. Keep
in mind that they don't actually contain silence. */
};
/*
+1 -1
View File
@@ -59,7 +59,7 @@ struct ao {
char *redirect;
// Internal events (use ao_request_reload(), ao_hotplug_event())
atomic_bool request_reload, request_hotplug;
atomic_int events_;
int buffer;
double def_buffer;
+6 -3
View File
@@ -340,7 +340,8 @@ static void *playthread(void *arg)
pthread_cond_signal(&p->wakeup); // for draining
if (p->still_playing && timeout > 0) {
mpthread_cond_timedwait_rel(&p->wakeup, &p->lock, timeout);
struct timespec ts = mp_rel_time_to_timespec(timeout);
pthread_cond_timedwait(&p->wakeup, &p->lock, &ts);
} else {
pthread_cond_wait(&p->wakeup, &p->lock);
}
@@ -352,8 +353,10 @@ static void *playthread(void *arg)
if (ao->driver->get_delay)
timeout = ao->driver->get_delay(ao);
timeout *= 0.25; // wake up if 25% played
if (!p->need_wakeup)
mpthread_cond_timedwait_rel(&p->wakeup, &p->lock, timeout);
if (!p->need_wakeup) {
struct timespec ts = mp_rel_time_to_timespec(timeout);
pthread_cond_timedwait(&p->wakeup, &p->lock, &ts);
}
}
}
MP_STATS(ao, "end audio wait");
+6
View File
@@ -95,6 +95,12 @@ void mp_rect_union(struct mp_rect *rc, const struct mp_rect *rc2)
rc->y1 = FFMAX(rc->y1, rc2->y1);
}
// Returns whether or not a point is contained by rc
bool mp_rect_contains(struct mp_rect *rc, int x, int y)
{
return rc->x0 <= x && x < rc->x1 && rc->y0 <= y && y < rc->y1;
}
// Set rc to the intersection of rc and src.
// Return false if the result is empty.
bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2)
+1
View File
@@ -75,6 +75,7 @@ struct mp_rect {
void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src);
bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2);
bool mp_rect_contains(struct mp_rect *rc, int x, int y);
int mp_snprintf_cat(char *str, size_t size, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
+3 -1
View File
@@ -702,7 +702,9 @@ void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y)
input_lock(ictx);
MP_DBG(ictx, "mouse move %d/%d\n", x, y);
if (!ictx->opts->enable_mouse_movements) {
if ((ictx->mouse_vo_x == x && ictx->mouse_vo_y == y) ||
!ictx->opts->enable_mouse_movements)
{
input_unlock(ictx);
return;
}
+2 -1
View File
@@ -206,7 +206,8 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout)
}
} else {
if (wait > 0) {
mpthread_cond_timedwait(&queue->cond, &queue->lock, wait);
struct timespec ts = mp_time_us_to_timespec(wait);
pthread_cond_timedwait(&queue->cond, &queue->lock, &ts);
} else {
pthread_cond_wait(&queue->cond, &queue->lock);
}
+2 -2
View File
@@ -218,11 +218,11 @@ int json_parse(void *ta_parent, struct mpv_node *dst, char **src, int max_depth)
#define APPEND(b, s) bstr_xappend(NULL, (b), bstr0(s))
static void write_json_str(bstr *b, char *str)
static void write_json_str(bstr *b, unsigned char *str)
{
APPEND(b, "\"");
while (1) {
char *cur = str;
unsigned char *cur = str;
while (cur[0] && cur[0] >= 32 && cur[0] != '"' && cur[0] != '\\')
cur++;
if (!cur[0])
+1 -1
View File
@@ -709,7 +709,7 @@ check_pkg_config "OpenAL" $_openal OPENAL 'openal >= 1.13'
check_pkg_config "ALSA audio" $_alsa ALSA 'alsa >= 1.0.9'
check_pkg_config "Blu-ray support" $_bluray LIBBLURAY 'libbluray >= 0.2.1'
check_pkg_config "Blu-ray support" $_bluray LIBBLURAY 'libbluray >= 0.3.0'
check_pkg_config "dvdread" $_dvdread DVDREAD 'dvdread >= 4.1.0'
+2 -1
View File
@@ -195,6 +195,7 @@ SOURCES = audio/audio.c \
options/parse_configfile.c \
options/path.c \
osdep/io.c \
osdep/path-unix.c \
osdep/semaphore_osx.c \
osdep/subprocess.c \
osdep/subprocess-posix.c \
@@ -334,7 +335,7 @@ all: $(ALL_TARGETS)
%.o: %.c
$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
mpv: $(OBJECTS) player/main-fn-unix.o
mpv: $(OBJECTS) osdep/main-fn-unix.o
$(CC) -o $@ $^ $(EXTRALIBS)
input/input.c: input/input_conf.h
+14 -9
View File
@@ -102,12 +102,10 @@ static int parse_profile(struct m_config *config, const struct m_option *opt,
if (!list || !list[0])
return M_OPT_INVALID;
for (int i = 0; list[i]; i++) {
struct m_profile *p = m_config_get_profile0(config, list[i]);
if (!p) {
MP_WARN(config, "Unknown profile '%s'.\n", list[i]);
r = M_OPT_INVALID;
} else if (set)
m_config_set_profile(config, p, flags);
if (set)
r = m_config_set_profile(config, list[i], flags);
if (r < 0)
break;
}
m_option_free(opt, &list);
return r;
@@ -897,12 +895,17 @@ int m_config_set_profile_option(struct m_config *config, struct m_profile *p,
return 1;
}
void m_config_set_profile(struct m_config *config, struct m_profile *p,
int flags)
int m_config_set_profile(struct m_config *config, char *name, int flags)
{
struct m_profile *p = m_config_get_profile0(config, name);
if (!p) {
MP_WARN(config, "Unknown profile '%s'.\n", name);
return M_OPT_INVALID;
}
if (config->profile_depth > MAX_PROFILE_DEPTH) {
MP_WARN(config, "WARNING: Profile inclusion too deep.\n");
return;
return M_OPT_UNKNOWN;
}
config->profile_depth++;
for (int i = 0; i < p->num_opts; i++) {
@@ -912,6 +915,8 @@ void m_config_set_profile(struct m_config *config, struct m_profile *p,
flags | M_SETOPT_FROM_CONFIG_FILE);
}
config->profile_depth--;
return 0;
}
void *m_config_alloc_struct(void *talloc_ctx,
+2 -2
View File
@@ -241,9 +241,9 @@ int m_config_set_profile_option(struct m_config *config, struct m_profile *p,
* \param config The config object.
* \param p The profile object.
* \param flags M_SETOPT_* bits
* Returns error code (<0) or 0 on success
*/
void m_config_set_profile(struct m_config *config, struct m_profile *p,
int flags);
int m_config_set_profile(struct m_config *config, char *name, int flags);
void *m_config_alloc_struct(void *talloc_ctx,
const struct m_sub_options *subopts);
+1 -1
View File
@@ -691,7 +691,7 @@ const struct MPOpts mp_default_opts = {
#if HAVE_LUA
.lua_load_osc = 1,
.lua_load_ytdl = 1,
.lua_ytdl_format = NULL,
.lua_ytdl_format = "best",
.lua_ytdl_raw_options = NULL,
#endif
.auto_load_scripts = 1,
+43 -46
View File
@@ -43,41 +43,36 @@
#include "osdep/io.h"
#include "osdep/path.h"
#if !defined(_WIN32) || defined(__CYGWIN__)
static int mp_add_xdg_config_dirs(struct mpv_global *global, char **dirs, int i)
#define MAX_CONFIG_PATHS 32
static const char *mp_get_forced_home(void *talloc_ctx, const char *type)
{
void *talloc_ctx = dirs;
char *home = getenv("HOME");
char *tmp = NULL;
char *xdg_home = NULL;
tmp = getenv("XDG_CONFIG_HOME");
if (tmp && *tmp)
xdg_home = talloc_asprintf(talloc_ctx, "%s/mpv", tmp);
else if (home && *home)
xdg_home = talloc_asprintf(talloc_ctx, "%s/.config/mpv", home);
// Maintain compatibility with old ~/.mpv
char *old_home = NULL;
if (home && *home)
old_home = talloc_asprintf(talloc_ctx, "%s/.mpv", home);
// If the old ~/.mpv exists, and the XDG config dir doesn't, use the old
// config dir only.
if (mp_path_exists(xdg_home) || !mp_path_exists(old_home))
dirs[i++] = xdg_home;
dirs[i++] = old_home;
#if HAVE_COCOA
i = mp_add_macosx_bundle_dir(global, dirs, i);
#endif
dirs[i++] = MPV_CONFDIR;
return i;
return strcmp(type, "home") == 0 ? getenv("MPV_HOME") : NULL;
}
// In order of increasing priority: the first hiz has highest priority.
static const mp_get_platform_path_cb path_resolvers[] = {
mp_get_forced_home,
#if HAVE_COCOA
mp_get_platform_path_osx,
#endif
#if !defined(_WIN32) || defined(__CYGWIN__)
mp_get_platform_path_unix,
#endif
#if defined(_WIN32)
mp_get_platform_path_win,
#endif
};
static const char *mp_get_platform_path(void *talloc_ctx, const char *type)
{
for (int n = 0; n < MP_ARRAY_SIZE(path_resolvers); n++) {
const char *path = path_resolvers[n](talloc_ctx, type);
if (path && path[0])
return path;
}
return NULL;
}
// Return NULL-terminated array of config directories, from highest to lowest
// priority
@@ -85,7 +80,8 @@ static char **mp_config_dirs(void *talloc_ctx, struct mpv_global *global)
{
struct MPOpts *opts = global->opts;
char **ret = talloc_zero_array(talloc_ctx, char*, MAX_CONFIG_PATHS);
char **ret = talloc_zero_array(talloc_ctx, char*, MAX_CONFIG_PATHS + 1);
int num_ret = 0;
if (!opts->load_config)
return ret;
@@ -95,22 +91,23 @@ static char **mp_config_dirs(void *talloc_ctx, struct mpv_global *global)
return ret;
}
const char *tmp = NULL;
int i = 0;
// from highest (most preferred) to lowest priority
static const char *const configdirs[] = {
"home",
"old_home",
"osxbundle",
"global",
};
tmp = getenv("MPV_HOME");
if (tmp && *tmp)
ret[i++] = talloc_strdup(ret, tmp);
#if defined(_WIN32) && !defined(__CYGWIN__)
i = mp_add_win_config_dirs(global, ret, i);
#else
i = mp_add_xdg_config_dirs(global, ret, i);
#endif
for (int n = 0; n < MP_ARRAY_SIZE(configdirs); n++) {
const char *path = mp_get_platform_path(ret, configdirs[n]);
if (path && path[0] && num_ret < MAX_CONFIG_PATHS)
ret[num_ret++] = (char *)path;
}
MP_VERBOSE(global, "search dirs:");
for (char **c = ret; *c; c++)
MP_VERBOSE(global, " %s", *c);
for (int n = 0; n < num_ret; n++)
MP_VERBOSE(global, " %s", ret[n]);
MP_VERBOSE(global, "\n");
return ret;
+22 -22
View File
@@ -12,21 +12,21 @@
//
// Copyright (c) 2007-2011 IOSPIRIT GmbH (http://www.iospirit.com/)
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//
// * Redistributions of source code must retain the above copyright notice, this list
// of conditions and the following disclaimer.
//
//
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// * Neither the name of IOSPIRIT GmbH nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior
// written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
@@ -166,7 +166,7 @@ typedef enum
newID:(SInt32)newID
forHardwareWithAttributes:(NSMutableDictionary *)attributes;
// Notification about hardware additions/removals
// Notification about hardware additions/removals
- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware was found / added to HIDRemote's pool
foundNewHardwareWithAttributes:(NSMutableDictionary *)attributes;
@@ -180,7 +180,7 @@ typedef enum
// Matching of newly found receiver hardware
- (BOOL)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware is inspected
inspectNewHardwareWithService:(io_service_t)service //
inspectNewHardwareWithService:(io_service_t)service //
prematchResult:(BOOL)prematchResult; // Return YES if HIDRemote should go on with this hardware and try
// to use it, or NO if it should not be persued further.
@@ -194,7 +194,7 @@ typedef enum
- (BOOL)hidRemote:(HIDRemote *)hidRemote
shouldRetryExclusiveLockWithInfo:(NSDictionary *)applicationInfo;
@end
@end
#pragma mark -- Actual header file for class --
@@ -207,55 +207,55 @@ typedef enum
// Notification ports
IONotificationPortRef _notifyPort;
CFRunLoopSourceRef _notifyRLSource;
// Matching iterator
io_iterator_t _matchingServicesIterator;
// SecureInput notification
io_object_t _secureInputNotification;
// Service attributes
NSMutableDictionary *_serviceAttribMap;
// Mode
HIDRemoteMode _mode;
BOOL _autoRecover;
NSTimer *_autoRecoveryTimer;
// Delegate
NSObject <HIDRemoteDelegate> *_delegate;
// Last seen ID and remote model
SInt32 _lastSeenRemoteID;
HIDRemoteModel _lastSeenModel;
SInt32 _lastSeenModelRemoteID;
// Unused button codes
NSArray *_unusedButtonCodes;
// Simulate Plus/Minus Hold
BOOL _simulateHoldEvents;
// SecureEventInput workaround
BOOL _secureEventInputWorkAround;
UInt64 _lastSecureEventInputPIDSum;
uid_t _lastFrontUserSession;
// Exclusive lock lending
BOOL _exclusiveLockLending;
BOOL _sendExclusiveResourceReuseNotification;
NSNumber *_waitForReturnByPID;
NSNumber *_returnToPID;
BOOL _isRestarting;
// Status notifications
BOOL _sendStatusNotifications;
NSString *_pidString;
// Status
BOOL _applicationIsTerminating;
BOOL _isStopping;
// Thread safety
#ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING /* #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if you're running your HIDRemote instance on a background thread (requires OS X 10.5 or later) */
NSThread *_runOnThread;
@@ -271,7 +271,7 @@ typedef enum
- (HIDRemoteAluminumRemoteSupportLevel)aluminiumRemoteSystemSupportLevel;
#pragma mark -- PUBLIC: Interface / API --
- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode;
- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode;
- (void)stopRemoteControl;
- (BOOL)isStarted;
+178 -178
View File
File diff suppressed because it is too large. Load diff
+21 -7
View File
@@ -30,13 +30,15 @@
// Emulate the parts of C11 stdatomic.h needed by mpv.
// Still relies on gcc/clang atomic builtins.
// The t field is a hack to make the non-atomic fallback macro mess work.
typedef struct { volatile unsigned long v; } atomic_ulong;
typedef struct { volatile int v; } atomic_int;
typedef struct { volatile _Bool v; } atomic_bool;
typedef struct { volatile long long v; } atomic_llong;
typedef struct { volatile uint_least32_t v; } atomic_uint_least32_t;
typedef struct { volatile unsigned long long v; } atomic_ullong;
typedef struct { volatile unsigned long v, t; } atomic_ulong;
typedef struct { volatile int v, t; } atomic_int;
typedef struct { volatile unsigned int v, t; } atomic_uint;
typedef struct { volatile _Bool v, t; } atomic_bool;
typedef struct { volatile long long v, t; } atomic_llong;
typedef struct { volatile uint_least32_t v, t; } atomic_uint_least32_t;
typedef struct { volatile unsigned long long v, t; } atomic_ullong;
#define ATOMIC_VAR_INIT(x) \
{.v = (x)}
@@ -54,6 +56,10 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
__atomic_store_n(&(p)->v, val, __ATOMIC_SEQ_CST)
#define atomic_fetch_add(a, b) \
__atomic_fetch_add(&(a)->v, b, __ATOMIC_SEQ_CST)
#define atomic_fetch_and(a, b) \
__atomic_fetch_and(&(a)->v, b, __ATOMIC_SEQ_CST)
#define atomic_fetch_or(a, b) \
__atomic_fetch_or(&(a)->v, b, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong(a, b, c) \
__atomic_compare_exchange_n(&(a)->v, b, c, 0, __ATOMIC_SEQ_CST, \
__ATOMIC_SEQ_CST)
@@ -66,6 +72,10 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
(__sync_synchronize(), (p)->v = (val), __sync_synchronize())
#define atomic_fetch_add(a, b) \
__sync_fetch_and_add(&(a)->v, b)
#define atomic_fetch_and(a, b) \
__sync_fetch_and_and(&(a)->v, b)
#define atomic_fetch_or(a, b) \
__sync_fetch_and_or(&(a)->v, b)
// Assumes __sync_val_compare_and_swap is "strong" (using the C11 meaning).
#define atomic_compare_exchange_strong(p, old, new) \
({ __typeof__((p)->v) val_ = __sync_val_compare_and_swap(&(p)->v, *(old), new); \
@@ -79,7 +89,11 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
// a serious dependency on working atomics, so this is barely ok.
#define atomic_load(p) ((p)->v)
#define atomic_store(p, val) ((p)->v = (val))
#define atomic_fetch_add(a, b) (((a)->v += (b)) - (b))
#define atomic_fetch_op_(a, b, op) \
((a)->t = (a)->v, (a)->v = (a)->v op (b), (a)->t)
#define atomic_fetch_add(a, b) atomic_fetch_op_(a, b, +)
#define atomic_fetch_and(a, b) atomic_fetch_op_(a, b, &)
#define atomic_fetch_or(a, b) atomic_fetch_op_(a, b, |)
#define atomic_compare_exchange_strong(p, old, new) \
((p)->v == *(old) ? ((p)->v = (new), 1) : (*(old) = (p)->v, 0))
+1 -4
View File
@@ -18,8 +18,6 @@
#ifndef MPV_MACOSX_APPLICATION
#define MPV_MACOSX_APPLICATION
typedef int (*mpv_main_fn)(int, char**);
// Menu Keys identifing menu items
typedef enum {
MPM_H_SIZE,
@@ -30,8 +28,7 @@ typedef enum {
} MPMenuKey;
// multithreaded wrapper for mpv_main
int cocoa_main(mpv_main_fn mpv_main, int argc, char *argv[]);
int cocoa_main(int argc, char *argv[]);
void cocoa_register_menu_item_action(MPMenuKey key, void* action);
void terminate_cocoa_application(void);
#endif /* MPV_MACOSX_APPLICATION */
+18 -12
View File
@@ -26,9 +26,14 @@
#include "osdep/macosx_compat.h"
#import "osdep/macosx_events_objc.h"
#include "osdep/threads.h"
#include "osdep/main-fn.h"
#define MPV_PROTOCOL @"mpv://"
// Whether the NSApplication singleton was created. If this is false, we are
// running in libmpv mode, and cocoa_main() was never called.
static bool application_instantiated;
static pthread_t playback_thread_id;
@interface Application ()
@@ -53,11 +58,17 @@ static pthread_t playback_thread_id;
- (void)setAppleMenu:(NSMenu *)aMenu;
@end
Application *mpv_shared_app(void)
static Application *mpv_shared_app(void)
{
return (Application *)[Application sharedApplication];
}
static void terminate_cocoa_application(void)
{
[NSApp hide:NSApp];
[NSApp terminate:NSApp];
}
@implementation Application
@synthesize menuItems = _menu_items;
@synthesize openCount = _open_count;
@@ -242,17 +253,10 @@ Application *mpv_shared_app(void)
@end
struct playback_thread_ctx {
mpv_main_fn mpv_main;
int *argc;
char ***argv;
};
void terminate_cocoa_application(void)
{
[NSApp hide:NSApp];
[NSApp terminate:NSApp];
}
static void cocoa_run_runloop(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -265,7 +269,7 @@ static void *playback_thread(void *ctx_obj)
mpthread_set_name("playback core (OSX)");
@autoreleasepool {
struct playback_thread_ctx *ctx = (struct playback_thread_ctx*) ctx_obj;
int r = ctx->mpv_main(*ctx->argc, *ctx->argv);
int r = mpv_main(*ctx->argc, *ctx->argv);
terminate_cocoa_application();
// normally never reached - unless the cocoa mainloop hasn't started yet
exit(r);
@@ -274,7 +278,8 @@ static void *playback_thread(void *ctx_obj)
void cocoa_register_menu_item_action(MPMenuKey key, void* action)
{
[NSApp registerSelector:(SEL)action forKey:key];
if (application_instantiated)
[NSApp registerSelector:(SEL)action forKey:key];
}
static void init_cocoa_application(bool regular)
@@ -356,11 +361,12 @@ static bool bundle_started_from_finder(int argc, char **argv)
}
}
int cocoa_main(mpv_main_fn mpv_main, int argc, char *argv[])
int cocoa_main(int argc, char *argv[])
{
@autoreleasepool {
application_instantiated = true;
struct playback_thread_ctx ctx = {0};
ctx.mpv_main = mpv_main;
ctx.argc = &argc;
ctx.argv = &argv;
-2
View File
@@ -27,5 +27,3 @@
@property(nonatomic, retain) NSArray *files;
@property(nonatomic, assign) size_t openCount;
@end
Application *mpv_shared_app(void);
+10
View File
@@ -0,0 +1,10 @@
#include "osdep/macosx_application.h"
// This is needed because Cocoa absolutely requires creating the NSApplication
// singleton and running it in the "main" thread. It is apparently not
// possible to do this on a separate thread at all. It is not known how
// Apple managed this colossal fuckup.
int main(int argc, char *argv[])
{
return cocoa_main(argc, argv);
}
+6
View File
@@ -0,0 +1,6 @@
#include "main-fn.h"
int main(int argc, char *argv[])
{
return mpv_main(argc, argv);
}
+30 -2
View File
@@ -1,11 +1,15 @@
#include <windows.h>
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE (0x0001)
#endif
#include "config.h"
#include "common/common.h"
#include "osdep/io.h"
#include "osdep/terminal.h"
#include "core.h"
#include "osdep/main-fn.h"
int wmain(int argc, wchar_t *argv[]);
@@ -25,8 +29,32 @@ static bool has_redirected_stdio(void)
is_valid_handle(GetStdHandle(STD_ERROR_HANDLE));
}
static void microsoft_nonsense(void)
{
// stop Windows from showing all kinds of annoying error dialogs
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
// Enable heap corruption detection
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
WINBOOL (WINAPI *pSetDllDirectory)(LPCWSTR lpPathName) =
(WINBOOL (WINAPI *)(LPCWSTR))GetProcAddress(kernel32, "SetDllDirectoryW");
WINBOOL (WINAPI *pSetSearchPathMode)(DWORD Flags) =
(WINBOOL (WINAPI *)(DWORD))GetProcAddress(kernel32, "SetSearchPathMode");
// Always use safe search paths for DLLs and other files, ie. never use the
// current directory
if (pSetSearchPathMode)
pSetDllDirectory(L"");
if (pSetSearchPathMode)
pSetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
}
int wmain(int argc, wchar_t *argv[])
{
microsoft_nonsense();
// If started from the console wrapper (see osdep/win32-console-wrapper.c),
// attach to the console and set up the standard IO handles
bool has_console = terminal_try_attach();
+1
View File
@@ -0,0 +1 @@
int mpv_main(int argc, char *argv[]);
+9 -7
View File
@@ -19,12 +19,14 @@
#include "options/path.h"
#include "osdep/path.h"
int mp_add_macosx_bundle_dir(struct mpv_global *global, char **dirs, int i)
const char *mp_get_platform_path_osx(void *talloc_ctx, const char *type)
{
void *talloc_ctx = dirs;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *path = [[NSBundle mainBundle] resourcePath];
dirs[i++] = talloc_strdup(talloc_ctx, [path UTF8String]);
[pool release];
return i;
if (strcmp(type, "osxbundle") == 0) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *path = [[NSBundle mainBundle] resourcePath];
char *res = talloc_strdup(talloc_ctx, [path UTF8String]);
[pool release];
return res;
}
return NULL;
}
+64
View File
@@ -0,0 +1,64 @@
/*
* 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 <string.h>
#include <pthread.h>
#include "options/path.h"
#include "path.h"
#include "config.h"
static pthread_once_t path_init_once = PTHREAD_ONCE_INIT;
static char mpv_home[512];
static char old_home[512];
static void path_init(void)
{
char *home = getenv("HOME");
char *xdg_dir = getenv("XDG_CONFIG_HOME");
if (xdg_dir && xdg_dir[0]) {
snprintf(mpv_home, sizeof(mpv_home), "%s/mpv", xdg_dir);
} else if (home && home[0]) {
snprintf(mpv_home, sizeof(mpv_home), "%s/.config/mpv", home);
}
// Maintain compatibility with old ~/.mpv
if (home && home[0])
snprintf(old_home, sizeof(old_home), "%s/.mpv", home);
// If the old ~/.mpv exists, and the XDG config dir doesn't, use the old
// config dir only.
if (mp_path_exists(old_home) && !mp_path_exists(mpv_home)) {
snprintf(mpv_home, sizeof(mpv_home), "%s", old_home);
old_home[0] = '\0';
}
}
const char *mp_get_platform_path_unix(void *talloc_ctx, const char *type)
{
pthread_once(&path_init_once, path_init);
if (strcmp(type, "home") == 0)
return mpv_home;
if (strcmp(type, "old_home") == 0)
return old_home;
if (strcmp(type, "global") == 0)
return MPV_CONFDIR;
return NULL;
}
+10 -10
View File
@@ -51,21 +51,21 @@ static char *mp_get_win_app_dir(void *talloc_ctx)
{
wchar_t w_appdir[MAX_PATH + 1] = {0};
if (SHGetFolderPathW(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL,
if (SHGetFolderPathW(NULL, folder|CSIDL_FLAG_CREATE, NULL,
SHGFP_TYPE_CURRENT, w_appdir) != S_OK)
return NULL;
return talloc_asprintf(talloc_ctx, "%s/mpv", mp_to_utf8(talloc_ctx, w_appdir));
}
int mp_add_win_config_dirs(struct mpv_global *global, char **dirs, int i)
const char *mp_get_platform_path_win(void *talloc_ctx, const char *type)
{
void *talloc_ctx = dirs;
if ((dirs[i] = mp_get_win_app_dir(talloc_ctx)))
i++;
if ((dirs[i] = mp_get_win_exe_dir(talloc_ctx)))
i++;
if ((dirs[i] = mp_get_win_exe_subdir(talloc_ctx)))
i++;
return i;
if (strcmp(type, "home") == 0)
return mp_get_win_app_dir(talloc_ctx);
if (strcmp(type, "old_home") == 0)
return mp_get_win_exe_dir(talloc_ctx);
// Not really true, but serves as a way to return a lowest-priority dir.
if (strcmp(type, "global") == 0)
return mp_get_win_exe_subdir(talloc_ctx);
return NULL;
}
+16 -9
View File
@@ -1,15 +1,22 @@
#ifndef OSDEP_PATH_H
#define OSDEP_PATH_H
#define MAX_CONFIG_PATHS 32
// Return a platform-specific path, identified by the type parameter. If the
// return value is allocated, talloc_ctx is used as talloc parent context.
//
// The following type values are defined:
// "home" the native mpv-specific user config dir
// "old_home" same as "home", but lesser priority (compatibility)
// "osxbundle" OSX bundle path
// "global" the least priority, global config file location
//
// It is allowed to return a static string, so the caller must set talloc_ctx
// to something other than NULL to avoid memory leaks.
typedef const char *(*mp_get_platform_path_cb)(void *talloc_ctx, const char *type);
struct mpv_global;
// Append paths starting at dirs[i]. The dirs array has place only for at most
// MAX_CONFIG_PATHS paths, but it's guaranteed that at least 4 paths can be
// added without checking for i>=MAX_CONFIG_PATHS.
// Return the new value of i.
int mp_add_win_config_dirs(struct mpv_global *global, char **dirs, int i);
int mp_add_macosx_bundle_dir(struct mpv_global *global, char **dirs, int i);
// Conforming to mp_get_platform_path_cb.
const char *mp_get_platform_path_win(void *talloc_ctx, const char *type);
const char *mp_get_platform_path_osx(void *talloc_ctx, const char *type);
const char *mp_get_platform_path_unix(void *talloc_ctx, const char *type);
#endif
+1 -1
View File
@@ -112,7 +112,7 @@ static int create_overlapped_pipe(HANDLE *read, HANDLE *write)
unsigned long id = atomic_fetch_add(&counter, 1);
unsigned pid = GetCurrentProcessId();
wchar_t buf[36];
swprintf(buf, sizeof(buf), L"\\\\?\\pipe\\mpv-anon-%08x-%08lx", pid, id);
swprintf(buf, sizeof(buf), L"\\\\.\\pipe\\mpv-anon-%08x-%08lx", pid, id);
// The function for creating anonymous pipes (CreatePipe) can't create
// overlapped pipes, so instead, use a named pipe with a unique name
-13
View File
@@ -27,19 +27,6 @@
#include "threads.h"
#include "timer.h"
int mpthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
int64_t abstime)
{
struct timespec ts = mp_time_us_to_timespec(abstime);
return pthread_cond_timedwait(cond, mutex, &ts);
}
int mpthread_cond_timedwait_rel(pthread_cond_t *cond, pthread_mutex_t *mutex,
double s)
{
return mpthread_cond_timedwait(cond, mutex, mp_add_timeout(mp_time_us(), s));
}
int mpthread_mutex_init_recursive(pthread_mutex_t *mutex)
{
pthread_mutexattr_t attr;
-9
View File
@@ -4,15 +4,6 @@
#include <pthread.h>
#include <inttypes.h>
// Call pthread_cond_timedwait() with an absolute timeout using the same
// time source/unit as mp_time_us() (microseconds).
int mpthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
int64_t abstime);
// Wait by a relative amount of time in seconds.
int mpthread_cond_timedwait_rel(pthread_cond_t *cond, pthread_mutex_t *mutex,
double seconds);
// Helper to reduce boiler plate.
int mpthread_mutex_init_recursive(pthread_mutex_t *mutex);
+8 -2
View File
@@ -28,7 +28,7 @@
#include "timer.h"
static uint64_t raw_time_offset;
pthread_once_t timer_init_once = PTHREAD_ONCE_INIT;
static pthread_once_t timer_init_once = PTHREAD_ONCE_INIT;
static void do_timer_init(void)
{
@@ -116,6 +116,11 @@ struct timespec mp_time_us_to_timespec(int64_t time_us)
return ts;
}
struct timespec mp_rel_time_to_timespec(double timeout_sec)
{
return mp_time_us_to_timespec(mp_add_timeout(mp_time_us(), timeout_sec));
}
#if 0
#include <stdio.h>
#include "threads.h"
@@ -138,7 +143,8 @@ int main(void) {
#if TEST_SLEEP
mp_sleep_us(delay);
#else
mpthread_cond_timedwait(&cnd, &mtx, r + delay);
struct timespec ts = mp_time_us_to_timespec(r + delay);
pthread_cond_timedwait(&cnd, &mtx, &ts);
#endif
j = (mp_time_us() - r) - delay;
printf("sleep time: t=%"PRId64" sleep=%8i err=%5i\n", r, delay, (int)j);
+4
View File
@@ -52,4 +52,8 @@ int64_t mp_add_timeout(int64_t time_us, double timeout_sec);
// Convert the mp time in microseconds to a timespec using CLOCK_REALTIME.
struct timespec mp_time_us_to_timespec(int64_t time_us);
// Convert the relative timeout in seconds to a timespec.
// The timespec is absolute, using CLOCK_REALTIME.
struct timespec mp_rel_time_to_timespec(double timeout_sec);
#endif /* MPLAYER_TIMER_H */
+4 -2
View File
@@ -284,8 +284,10 @@ static int wait_wakeup(struct mpv_handle *ctx, int64_t end)
int r = 0;
pthread_mutex_unlock(&ctx->lock);
pthread_mutex_lock(&ctx->wakeup_lock);
if (!ctx->need_wakeup)
r = mpthread_cond_timedwait(&ctx->wakeup, &ctx->wakeup_lock, end);
if (!ctx->need_wakeup) {
struct timespec ts = mp_time_us_to_timespec(end);
r = pthread_cond_timedwait(&ctx->wakeup, &ctx->wakeup_lock, &ts);
}
if (r == 0)
ctx->need_wakeup = false;
pthread_mutex_unlock(&ctx->wakeup_lock);
+5
View File
@@ -4530,6 +4530,7 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
char *lang = cmd->args[3].v.s;
if (lang && lang[0])
t->lang = talloc_strdup(t, lang);
print_track_list(mpctx);
break;
}
@@ -4540,6 +4541,7 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
if (!t)
return -1;
mp_remove_track(mpctx, t);
print_track_list(mpctx);
break;
}
@@ -4553,6 +4555,7 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
if (nt) {
mp_remove_track(mpctx, t);
mp_switch_track(mpctx, nt->type, nt);
print_track_list(mpctx);
return 0;
}
}
@@ -4573,6 +4576,8 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
opts->sub_id_ff, opts->sub_lang);
if (s && s->is_external)
mp_switch_track(mpctx, STREAM_SUB, s);
print_track_list(mpctx);
}
break;
}
+5 -5
View File
@@ -84,7 +84,7 @@ void mp_parse_cfgfiles(struct MPContext *mpctx)
load_all_cfgfiles(mpctx, section, "mpv.conf|config");
if (encoding)
m_config_set_profile(conf, m_config_add_profile(conf, SECT_ENCODE), 0);
m_config_set_profile(conf, SECT_ENCODE, 0);
}
static int try_load_config(struct MPContext *mpctx, const char *file, int flags)
@@ -143,7 +143,7 @@ static void mp_auto_load_profile(struct MPContext *mpctx, char *category,
m_profile_t *p = m_config_get_profile0(mpctx->mconfig, t);
if (p) {
MP_INFO(mpctx, "Auto-loading profile '%s'\n", t);
m_config_set_profile(mpctx->mconfig, p, FILE_LOCAL_FLAGS);
m_config_set_profile(mpctx->mconfig, t, FILE_LOCAL_FLAGS);
}
}
@@ -184,10 +184,10 @@ static char *mp_get_playback_resume_config_filename(struct mpv_global *global,
realpath = mp_path_join(tmp, bstr0(cwd), bstr0(fname));
}
}
if (bstr_startswith0(bfname, "dvd://"))
if (bstr_startswith0(bfname, "dvd://") && opts->dvd_device)
realpath = talloc_asprintf(tmp, "%s - %s", realpath, opts->dvd_device);
if (bstr_startswith0(bfname, "br://") || bstr_startswith0(bfname, "bd://") ||
bstr_startswith0(bfname, "bluray://"))
if ((bstr_startswith0(bfname, "br://") || bstr_startswith0(bfname, "bd://") ||
bstr_startswith0(bfname, "bluray://")) && opts->bluray_device)
realpath = talloc_asprintf(tmp, "%s - %s", realpath, opts->bluray_device);
uint8_t md5[16];
av_md5_sum(md5, realpath, strlen(realpath));
+1 -1
View File
@@ -396,6 +396,7 @@ struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction,
void mp_set_playlist_entry(struct MPContext *mpctx, struct playlist_entry *e);
void mp_play_files(struct MPContext *mpctx);
void update_demuxer_properties(struct MPContext *mpctx);
void print_track_list(struct MPContext *mpctx);
void reselect_demux_streams(struct MPContext *mpctx);
void prepare_playlist(struct MPContext *mpctx, struct playlist *pl);
void autoload_external_files(struct MPContext *mpctx);
@@ -403,7 +404,6 @@ struct track *select_track(struct MPContext *mpctx, enum stream_type type,
int tid, int ffid, char **langs);
// main.c
int mpv_main(int argc, char *argv[]);
int mp_initialize(struct MPContext *mpctx, char **argv);
struct MPContext *mp_create(void);
void mp_destroy(struct MPContext *mpctx);
+19 -6
View File
@@ -143,6 +143,15 @@ static void print_stream(struct MPContext *mpctx, struct track *t)
MP_INFO(mpctx, "%s\n", b);
}
void print_track_list(struct MPContext *mpctx)
{
for (int t = 0; t < STREAM_TYPE_COUNT; t++) {
for (int n = 0; n < mpctx->num_tracks; n++)
if (mpctx->tracks[n]->type == t)
print_stream(mpctx, mpctx->tracks[n]);
}
}
void update_demuxer_properties(struct MPContext *mpctx)
{
struct demuxer *demuxer = mpctx->master_demuxer;
@@ -167,11 +176,7 @@ void update_demuxer_properties(struct MPContext *mpctx)
struct demuxer *tracks = mpctx->track_layout;
if (tracks->events & DEMUX_EVENT_STREAMS) {
add_demuxer_tracks(mpctx, tracks);
for (int t = 0; t < STREAM_TYPE_COUNT; t++) {
for (int n = 0; n < mpctx->num_tracks; n++)
if (mpctx->tracks[n]->type == t)
print_stream(mpctx, mpctx->tracks[n]);
}
print_track_list(mpctx);
tracks->events &= ~DEMUX_EVENT_STREAMS;
}
if (events & DEMUX_EVENT_METADATA) {
@@ -653,8 +658,16 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track)
for (int n = mpctx->num_tracks - 1; n >= 0 && !in_use; n--)
in_use |= mpctx->tracks[n]->demuxer == d;
if (!in_use)
if (!in_use) {
for (int n = 0; n < mpctx->num_sources; n++) {
if (mpctx->sources[n] == d) {
MP_TARRAY_REMOVE_AT(mpctx->sources, mpctx->num_sources, n);
break;
}
}
uninit_stream_sub_decoders(d);
free_demuxer_and_stream(d);
}
mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL);
+57 -35
View File
@@ -141,16 +141,35 @@ function limit_range(min, max, val)
return val
end
-- translate value into element coordinates
function get_slider_ele_pos_for(element, val)
local ele_pos = scale_value(
element.slider.min.value, element.slider.max.value,
element.slider.min.ele_pos, element.slider.max.ele_pos,
val)
return limit_range(
element.slider.min.ele_pos, element.slider.max.ele_pos,
ele_pos)
end
-- translates global (mouse) coordinates to value
function get_slider_value_at(element, glob_pos)
local val = scale_value(
element.slider.min.glob_pos, element.slider.max.glob_pos,
element.slider.min.value, element.slider.max.value,
glob_pos)
return limit_range(
element.slider.min.value, element.slider.max.value,
val)
end
-- get value at current mouse position
function get_slider_value(element)
local foV = element.layout.slider.border
local pH = (element.layout.geometry.h - (2*foV)) / 2
local b_x1, b_x2 = element.hitbox.x1 + pH, element.hitbox.x2 - pH
local s_min, s_max = element.slider.min, element.slider.max
local pos = scale_value(b_x1, b_x2, s_min, s_max, mp.get_mouse_pos())
return limit_range(s_min, s_max, pos)
return get_slider_value_at(element, mp.get_mouse_pos())
end
function countone(val)
@@ -303,6 +322,11 @@ function prepare_elements()
for _,element in pairs(elements) do
local elem_geo = element.layout.geometry
-- Calculate the hitbox
local bX1, bY1, bX2, bY2 = get_hitbox_coords_geo(elem_geo)
element.hitbox = {x1 = bX1, y1 = bY1, x2 = bX2, y2 = bY2}
local style_ass = assdraw.ass_new()
-- prepare static elements
@@ -331,13 +355,26 @@ function prepare_elements()
local slider_lo = element.layout.slider
-- offset between element outline and drag-area
local foV = slider_lo.border + slider_lo.gap
local foH = 0
-- calculate positions of min and max points
if (slider_lo.stype == "slider") then
foH = elem_geo.h / 2
element.slider.min.ele_pos = elem_geo.h / 2
element.slider.max.ele_pos = elem_geo.w - (elem_geo.h / 2)
elseif (slider_lo.stype == "bar") then
foH = slider_lo.border + slider_lo.gap
element.slider.min.ele_pos =
slider_lo.border + slider_lo.gap
element.slider.max.ele_pos =
elem_geo.w - (slider_lo.border + slider_lo.gap)
end
element.slider.min.glob_pos =
element.hitbox.x1 + element.slider.min.ele_pos
element.slider.max.glob_pos =
element.hitbox.x1 + element.slider.max.ele_pos
-- -- --
static_ass:draw_start()
-- the box
@@ -351,11 +388,10 @@ function prepare_elements()
if not (element.slider.markerF == nil) and (slider_lo.gap > 0) then
local markers = element.slider.markerF()
for _,marker in pairs(markers) do
if (marker > element.slider.min) and
(marker < element.slider.max) then
if (marker > element.slider.min.value) and
(marker < element.slider.max.value) then
local s = scale_value(element.slider.min,
element.slider.max, foH, (elem_geo.w - foH), marker)
local s = get_slider_ele_pos_for(element, marker)
if (slider_lo.gap > 1) then -- draw triangles
@@ -408,18 +444,6 @@ function prepare_elements()
element.layout.alpha[1] = 136
element.eventresponder = nil
end
-- Calculate the hitbox
local bX1, bY1, bX2, bY2 = get_hitbox_coords_geo(elem_geo)
if type == "slider" then
-- if it's a slider, cut the border off,
-- as it is not of interest for eventhandling
element.hitbox = {
x1 = bX1 + slider.border, y1 = bY1 + slider.border,
x2 = bX2 - slider.border, y2 = bY2 - slider.border}
else
element.hitbox = {x1 = bX1, y1 = bY1, x2 = bX2, y2 = bY2}
end
end
end
@@ -485,7 +509,8 @@ function render_elements(master_ass)
local slider_lo = element.layout.slider
local elem_geo = element.layout.geometry
local s_min, s_max = element.slider.min, element.slider.max
local s_min, s_max = element.slider.min.value, element.slider.max.value
-- draw pos marker
local pos = element.slider.posF()
@@ -500,12 +525,9 @@ function render_elements(master_ass)
foH = slider_lo.border + slider_lo.gap
end
pos = limit_range(s_min, s_max, pos)
local xp = get_slider_ele_pos_for(element, pos)
local xp = scale_value(s_min, s_max,
foH, (elem_geo.w - foH), pos)
-- the filling, draw it only if positive
-- the filling
local innerH = elem_geo.h - (2*foV)
if (slider_lo.stype == "bar") then
@@ -657,7 +679,7 @@ function new_element(name, type)
elements[name].state = {}
if (type == "slider") then
elements[name].slider = {min = 0, max = 100}
elements[name].slider = {min = {value = 0}, max = {value = 100}}
end
+10 -7
View File
@@ -103,16 +103,17 @@ mp.add_hook("on_load", 10, function ()
ytdl.path, "--no-warnings", "-J", "--flat-playlist", "--all-subs",
"--sub-format", subformat, "--no-playlist"
}
-- Checks if video option is "no", change options accordingly
if (mp.get_property("options/vid") == "no") then
format = "bestaudio/best"
msg.verbose("Video disabled. Only using audio")
end
if (format ~= "") then
table.insert(command, "--format")
table.insert(command, format)
end
-- Checks if no-video option is set and disables video in ytdl if set
if (mp.get_property("options/vid") == "no") then
table.insert(command, "-x")
msg.verbose("Video disabled. Only using audio")
end
for param, arg in pairs(raw_options) do
table.insert(command, "--" .. param)
@@ -161,7 +162,9 @@ mp.add_hook("on_load", 10, function ()
local playlist = "edl://"
for i, entry in pairs(json.entries) do
playlist = playlist .. entry.url .. ";"
local urllength = string.len(entry.url)
playlist = playlist .. "%" .. urllength .. "%" .. entry.url .. ";"
end
msg.debug("EDL: " .. playlist)
-15
View File
@@ -1,15 +0,0 @@
#include "config.h"
#include "core.h"
#if HAVE_COCOA_APPLICATION
#include "osdep/macosx_application.h"
#endif
int main(int argc, char *argv[])
{
#if HAVE_COCOA_APPLICATION
return cocoa_main(mpv_main, argc, argv);
#else
return mpv_main(argc, argv);
#endif
}
+1 -25
View File
@@ -30,6 +30,7 @@
#include "osdep/io.h"
#include "osdep/terminal.h"
#include "osdep/timer.h"
#include "osdep/main-fn.h"
#include "common/av_log.h"
#include "common/codecs.h"
@@ -64,10 +65,6 @@
#ifdef _WIN32
#include <windows.h>
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE (0x0001)
#endif
#endif
#if HAVE_COCOA
@@ -282,27 +279,6 @@ static void osdep_preinit(int argc, char **argv)
enable_talloc = "1";
if (enable_talloc && strcmp(enable_talloc, "1") == 0)
talloc_enable_leak_report();
#ifdef _WIN32
// stop Windows from showing all kinds of annoying error dialogs
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
// Enable heap corruption detection
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
WINBOOL (WINAPI *pSetDllDirectory)(LPCWSTR lpPathName) =
(WINBOOL (WINAPI *)(LPCWSTR))GetProcAddress(kernel32, "SetDllDirectoryW");
WINBOOL (WINAPI *pSetSearchPathMode)(DWORD Flags) =
(WINBOOL (WINAPI *)(DWORD))GetProcAddress(kernel32, "SetSearchPathMode");
// Always use safe search paths for DLLs and other files, ie. never use the
// current directory
if (pSetSearchPathMode)
pSetDllDirectory(L"");
if (pSetSearchPathMode)
pSetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
#endif
}
static int cfg_include(void *ctx, char *filename, int flags)
+8
View File
@@ -382,6 +382,13 @@ double get_playback_time(struct MPContext *mpctx)
{
double cur = get_current_time(mpctx);
double start = get_start_time(mpctx);
// During seeking, the time corresponds to the last seek time - apply some
// cosmetics to it.
if (mpctx->playback_pts == MP_NOPTS_VALUE) {
double length = get_time_length(mpctx);
if (length >= 0)
cur = MPCLAMP(cur, start, start + length);
}
return cur >= start ? cur - start : cur;
}
@@ -1042,6 +1049,7 @@ void mp_idle(struct MPContext *mpctx)
mp_wait_events(mpctx, mpctx->sleeptime);
mpctx->sleeptime = 100.0;
mp_process_input(mpctx);
handle_command_updates(mpctx);
handle_cursor_autohide(mpctx);
handle_vo_events(mpctx);
update_osd_msg(mpctx);
+4 -1
View File
@@ -135,8 +135,11 @@ static void mp_load_script(struct MPContext *mpctx, const char *fname)
MP_VERBOSE(arg, "Loading script %s...\n", fname);
pthread_t thread;
if (pthread_create(&thread, NULL, script_thread, arg))
if (pthread_create(&thread, NULL, script_thread, arg)) {
mpv_detach_destroy(arg->client);
talloc_free(arg);
return;
}
wait_loaded(mpctx);
MP_VERBOSE(mpctx, "Done loading %s.\n", fname);
+6 -3
View File
@@ -134,7 +134,8 @@ static void cache_wakeup_and_wait(struct priv *s, double *retry_time)
}
pthread_cond_signal(&s->wakeup);
mpthread_cond_timedwait_rel(&s->wakeup, &s->mutex, CACHE_WAIT_TIME);
struct timespec ts = mp_rel_time_to_timespec(CACHE_WAIT_TIME);
pthread_cond_timedwait(&s->wakeup, &s->mutex, &ts);
if (*retry_time >= 0)
*retry_time += mp_time_sec() - start;
@@ -465,8 +466,10 @@ static void *cache_thread(void *arg)
pthread_cond_signal(&s->wakeup);
s->control = CACHE_CTRL_NONE;
}
if (s->idle && s->control == CACHE_CTRL_NONE)
mpthread_cond_timedwait_rel(&s->wakeup, &s->mutex, CACHE_IDLE_SLEEP_TIME);
if (s->idle && s->control == CACHE_CTRL_NONE) {
struct timespec ts = mp_rel_time_to_timespec(CACHE_IDLE_SLEEP_TIME);
pthread_cond_timedwait(&s->wakeup, &s->mutex, &ts);
}
}
pthread_cond_signal(&s->wakeup);
pthread_mutex_unlock(&s->mutex);
+5 -3
View File
@@ -401,13 +401,15 @@ static bool stream_reconnect(stream_t *s)
if (mp_cancel_wait(s->cancel, sleep_secs))
break;
MP_WARN(s, "Connection lost! Attempting to reconnect (%d)...\n", retry + 1);
int r = stream_control(s, STREAM_CTRL_RECONNECT, NULL);
if (r == STREAM_UNSUPPORTED)
break;
if (r == STREAM_OK && stream_seek_unbuffered(s, pos) && s->pos == pos)
if (r == STREAM_OK && stream_seek_unbuffered(s, pos) && s->pos == pos) {
MP_WARN(s, "Reconnected successfully.\n");
return true;
}
MP_WARN(s, "Connection lost! Attempting to reconnect (%d)...\n", retry + 1);
sleep_secs = MPMAX(sleep_secs, 0.1);
sleep_secs = MPMIN(sleep_secs * 4, 10.0);
+4 -4
View File
@@ -455,8 +455,8 @@ static void handle_nav_command(stream_t *s, struct mp_nav_cmd *ev)
bd_vk_key_e key = translate_nav_menu_action(action);
if (key != BD_VK_NONE) {
if (key == BD_VK_MOUSE_ACTIVATE)
ev->mouse_on_button = bd_mouse_select(priv->bd, pts,
priv->mousex,
ev->mouse_on_button = bd_mouse_select(priv->bd, pts,
priv->mousex,
priv->mousey);
bd_user_input(priv->bd, pts, key);
} else if (strcmp(action, "menu") == 0) {
@@ -469,8 +469,8 @@ static void handle_nav_command(stream_t *s, struct mp_nav_cmd *ev)
} case MP_NAV_CMD_MOUSE_POS:
priv->mousex = ev->u.mouse_pos.x;
priv->mousey = ev->u.mouse_pos.y;
ev->mouse_on_button = bd_mouse_select(priv->bd, mp_time_us(),
priv->mousex,
ev->mouse_on_button = bd_mouse_select(priv->bd, mp_time_us(),
priv->mousex,
priv->mousey);
break;
case MP_NAV_CMD_SKIP_STILL:
+1 -1
View File
@@ -16,7 +16,7 @@
static const char *const sub_exts[] = {"utf", "utf8", "utf-8", "idx", "sub", "srt",
"smi", "rt", "txt", "ssa", "aqt", "jss",
"js", "ass", "mks", "vtt", NULL};
"js", "ass", "mks", "vtt", "sup", NULL};
static const char *const audio_exts[] = {"mp3", "aac", "mka", "dts", "flac",
"ogg", "m4a", "ac3", NULL};
+3 -36
View File
@@ -4,53 +4,20 @@
static void test_mp_chmap_diff(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap diff;
mp_chmap_from_str(&a, bstr0("3.1"));
mp_chmap_from_str(&b, bstr0("2.1"));
mp_chmap_diff(&a, &b, &diff);
assert_int_equal(diff.num, 1);
assert_int_equal(diff.speaker[0], MP_SPEAKER_ID_FC);
assert_int_equal(mp_chmap_diffn(&a, &b), 1);
mp_chmap_from_str(&b, bstr0("6.1(back)"));
mp_chmap_diff(&a, &b, &diff);
assert_int_equal(diff.num, 0);
mp_chmap_diff(&b, &a, &diff);
assert_int_equal(diff.num, 3);
assert_int_equal(diff.speaker[0], MP_SPEAKER_ID_BL);
assert_int_equal(diff.speaker[1], MP_SPEAKER_ID_BR);
assert_int_equal(diff.speaker[2], MP_SPEAKER_ID_BC);
}
static void test_mp_chmap_contains_with_related_chmaps(void **state) {
struct mp_chmap a;
struct mp_chmap b;
mp_chmap_from_str(&a, bstr0("3.1"));
mp_chmap_from_str(&b, bstr0("2.1"));
assert_true(mp_chmap_contains(&a, &b));
assert_false(mp_chmap_contains(&b, &a));
}
static void test_mp_chmap_contains_with_unrelated_chmaps(void **state) {
struct mp_chmap a;
struct mp_chmap b;
mp_chmap_from_str(&a, bstr0("mono"));
mp_chmap_from_str(&b, bstr0("stereo"));
assert_false(mp_chmap_contains(&a, &b));
assert_false(mp_chmap_contains(&b, &a));
assert_int_equal(mp_chmap_diffn(&a, &b), 0);
assert_int_equal(mp_chmap_diffn(&b, &a), 3);
}
int main(void) {
const UnitTest tests[] = {
unit_test(test_mp_chmap_diff),
unit_test(test_mp_chmap_contains_with_related_chmaps),
unit_test(test_mp_chmap_contains_with_unrelated_chmaps),
};
return run_tests(tests);
}
+54 -110
View File
@@ -1,87 +1,76 @@
#include "test_helpers.h"
#include "audio/chmap_sel.h"
static void test_mp_chmap_sel_fallback_upmix(void **state) {
struct mp_chmap a;
struct mp_chmap b;
#define LAYOUTS(...) (char*[]){__VA_ARGS__, NULL}
static void test_sel(const char *input, const char *expected_selection,
char **layouts)
{
struct mp_chmap_sel s = {0};
struct mp_chmap input_map;
struct mp_chmap expected_map;
mp_chmap_from_str(&a, bstr0("7.1"));
mp_chmap_from_str(&b, bstr0("5.1"));
assert_true(mp_chmap_from_str(&input_map, bstr0(input)));
assert_true(mp_chmap_from_str(&expected_map, bstr0(expected_selection)));
mp_chmap_sel_add_map(&s, &a);
assert_true(mp_chmap_sel_fallback(&s, &b));
assert_string_equal(mp_chmap_to_str(&b), "7.1");
for (int n = 0; layouts[n]; n++) {
struct mp_chmap tmp;
assert_true(mp_chmap_from_str(&tmp, bstr0(layouts[n])));
int count = s.num_chmaps;
mp_chmap_sel_add_map(&s, &tmp);
assert_true(s.num_chmaps > count); // assure validity and max. count
}
assert_true(mp_chmap_sel_fallback(&s, &input_map));
// We convert expected_map to a chmap and then back to a string to avoid
// problems with ambiguous layouts.
assert_string_equal(mp_chmap_to_str(&input_map),
mp_chmap_to_str(&expected_map));
}
static void test_mp_chmap_sel_fallback_upmix(void **state) {
test_sel("5.1", "7.1", LAYOUTS("7.1"));
}
static void test_mp_chmap_sel_fallback_downmix(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap_sel s = {0};
mp_chmap_from_str(&a, bstr0("5.1"));
mp_chmap_from_str(&b, bstr0("7.1"));
mp_chmap_sel_add_map(&s, &a);
assert_true(mp_chmap_sel_fallback(&s, &b));
assert_string_equal(mp_chmap_to_str(&b), "5.1");
test_sel("7.1", "5.1", LAYOUTS("5.1"));
}
static void test_mp_chmap_sel_fallback_incompatible(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap_sel s = {0};
mp_chmap_from_str(&a, bstr0("7.1"));
mp_chmap_from_str(&b, bstr0("7.1(wide-side)"));
mp_chmap_sel_add_map(&s, &a);
assert_true(mp_chmap_sel_fallback(&s, &b));
assert_string_equal(mp_chmap_to_str(&b), "7.1");
test_sel("7.1(wide-side)", "7.1", LAYOUTS("7.1"));
}
static void test_mp_chmap_sel_fallback_prefer_compatible(void **state) {
struct mp_chmap a, b, c;
struct mp_chmap_sel s = {0};
mp_chmap_from_str(&a, bstr0("7.1"));
mp_chmap_from_str(&b, bstr0("5.1(side)"));
mp_chmap_from_str(&c, bstr0("7.1(wide-side)"));
mp_chmap_sel_add_map(&s, &a);
mp_chmap_sel_add_map(&s, &b);
assert_true(mp_chmap_sel_fallback(&s, &c));
assert_string_equal(mp_chmap_to_str(&b), "5.1(side)");
test_sel("7.1(wide-side)", "5.1(side)", LAYOUTS("7.1", "5.1(side)"));
}
static void test_mp_chmap_sel_fallback_prefer_closest_upmix(void **state) {
struct mp_chmap_sel s = {0};
char *maps[] = { "7.1", "5.1", "2.1", "stereo", "mono", NULL };
for (int i = 0; maps[i]; i++) {
struct mp_chmap m;
mp_chmap_from_str(&m, bstr0(maps[i]));
mp_chmap_sel_add_map(&s, &m);
}
struct mp_chmap c;
mp_chmap_from_str(&c, bstr0("3.1"));
assert_true(mp_chmap_sel_fallback(&s, &c));
assert_string_equal(mp_chmap_to_str(&c), "5.1");
test_sel("3.1", "5.1", LAYOUTS("7.1", "5.1", "2.1", "stereo", "mono"));
}
static void test_mp_chmap_sel_fallback_use_replacements(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap_sel s = {0};
test_sel("5.1", "7.1(rear)", LAYOUTS("7.1(rear)"));
}
mp_chmap_from_str(&a, bstr0("7.1(rear)"));
mp_chmap_from_str(&b, bstr0("5.1"));
static void test_mp_chmap_sel_fallback_works_on_alsa_chmaps(void **state) {
test_sel("5.1", "7.1(alsa)", LAYOUTS("7.1(alsa)"));
}
mp_chmap_sel_add_map(&s, &a);
assert_true(mp_chmap_sel_fallback(&s, &b));
assert_string_equal(mp_chmap_to_str(&b), "7.1(rear)");
static void test_mp_chmap_sel_fallback_mono_to_stereo(void **state) {
test_sel("mono", "stereo", LAYOUTS("stereo", "5.1"));
}
static void test_mp_chmap_sel_fallback_stereo_to_stereo(void **state) {
test_sel("stereo", "stereo", LAYOUTS("stereo", "5.1"));
}
static void test_mp_chmap_sel_fallback_no_downmix(void **state) {
test_sel("5.1(side)", "7.1(rear)", LAYOUTS("stereo", "7.1(rear)"));
}
static void test_mp_chmap_sel_fallback_minimal_downmix(void **state) {
test_sel("7.1", "fl-fr-lfe-fc-bl-br-flc-frc",
LAYOUTS("fl-fr-lfe-fc-bl-br-flc-frc", "3.0(back)"));
}
static void test_mp_chmap_sel_fallback_reject_unknown(void **state) {
@@ -89,9 +78,7 @@ static void test_mp_chmap_sel_fallback_reject_unknown(void **state) {
struct mp_chmap b;
struct mp_chmap_sel s = {0};
a.num = 2;
a.speaker[0] = MP_SPEAKER_ID_UNKNOWN0;
a.speaker[1] = MP_SPEAKER_ID_UNKNOWN0 + 1;
mp_chmap_set_unknown(&a, 2);
mp_chmap_from_str(&b, bstr0("5.1"));
@@ -100,51 +87,6 @@ static void test_mp_chmap_sel_fallback_reject_unknown(void **state) {
assert_string_equal(mp_chmap_to_str(&b), "5.1");
}
static void test_mp_chmap_sel_fallback_works_on_alsa_chmaps(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap_sel s = {0};
mp_chmap_from_str(&a, bstr0("7.1(alsa)"));
mp_chmap_from_str(&b, bstr0("5.1"));
mp_chmap_sel_add_map(&s, &a);
assert_true(mp_chmap_sel_fallback(&s, &b));
assert_string_equal(mp_chmap_to_str(&b), "7.1(alsa)");
}
static void test_mp_chmap_sel_fallback_mono_to_stereo(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap c;
struct mp_chmap_sel s = {0};
mp_chmap_from_str(&a, bstr0("stereo"));
mp_chmap_from_str(&b, bstr0("5.1"));
mp_chmap_from_str(&c, bstr0("mono"));
mp_chmap_sel_add_map(&s, &a);
mp_chmap_sel_add_map(&s, &b);
assert_true(mp_chmap_sel_fallback(&s, &c));
assert_string_equal(mp_chmap_to_str(&c), "stereo");
}
static void test_mp_chmap_sel_fallback_stereo_to_stereo(void **state) {
struct mp_chmap a;
struct mp_chmap b;
struct mp_chmap c;
struct mp_chmap_sel s = {0};
mp_chmap_from_str(&a, bstr0("stereo"));
mp_chmap_from_str(&b, bstr0("5.1"));
mp_chmap_from_str(&c, bstr0("stereo"));
mp_chmap_sel_add_map(&s, &a);
mp_chmap_sel_add_map(&s, &b);
assert_true(mp_chmap_sel_fallback(&s, &c));
assert_string_equal(mp_chmap_to_str(&c), "stereo");
}
int main(void) {
const UnitTest tests[] = {
unit_test(test_mp_chmap_sel_fallback_upmix),
@@ -153,10 +95,12 @@ int main(void) {
unit_test(test_mp_chmap_sel_fallback_prefer_compatible),
unit_test(test_mp_chmap_sel_fallback_prefer_closest_upmix),
unit_test(test_mp_chmap_sel_fallback_use_replacements),
unit_test(test_mp_chmap_sel_fallback_reject_unknown),
unit_test(test_mp_chmap_sel_fallback_works_on_alsa_chmaps),
unit_test(test_mp_chmap_sel_fallback_mono_to_stereo),
unit_test(test_mp_chmap_sel_fallback_stereo_to_stereo),
unit_test(test_mp_chmap_sel_fallback_no_downmix),
unit_test(test_mp_chmap_sel_fallback_minimal_downmix),
unit_test(test_mp_chmap_sel_fallback_reject_unknown),
};
return run_tests(tests);
}
+9 -2
View File
@@ -673,13 +673,20 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *m)
double ymul = (rgblev.max - rgblev.min) / (yuvlev.ymax - yuvlev.ymin);
double cmul = (rgblev.max - rgblev.min) / (yuvlev.cmid - yuvlev.cmin) / 2;
// Contrast scales the output value range (gain)
ymul *= params->contrast;
cmul *= params->contrast;
for (int i = 0; i < 3; i++) {
m->m[i][0] *= ymul;
m->m[i][1] *= cmul;
m->m[i][2] *= cmul;
// Set c so that Y=umin,UV=cmid maps to RGB=min (black to black)
// Set c so that Y=umin,UV=cmid maps to RGB=min (black to black),
// also add brightness offset (black lift)
m->c[i] = rgblev.min - m->m[i][0] * yuvlev.ymin
-(m->m[i][1] + m->m[i][2]) * yuvlev.cmid;
- (m->m[i][1] + m->m[i][2]) * yuvlev.cmid
+ params->brightness;
}
// Brightness adds a constant to output R,G,B.
+7
View File
@@ -673,6 +673,13 @@ static int config(struct vf_instance *vf, int width, int height,
return 0;
}
struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt);
if (width % desc.align_x || height % desc.align_y) {
MP_FATAL(vf, "VapourSynth does not allow unaligned/cropped video sizes.\n");
destroy_vs(vf);
return 0;
}
vf_rescale_dsize(&d_width, &d_height, width, height, vi->width, vi->height);
return vf_next_config(vf, vi->width, vi->height, d_width, d_height, flags, fmt);
+2 -2
View File
@@ -163,14 +163,14 @@ static struct mp_image *render(struct vf_instance *vf, struct mp_image *in,
status = vaMapBuffer(p->display, buffer, (void**)&param);
if (!check_error(vf, status, "vaMapBuffer()"))
break;
VAProcFilterParameterBufferDeinterlacing *filter_params;
status = vaMapBuffer(p->display, *(p->pipe.filters), (void**)&filter_params);
if (!check_error(vf, status, "vaMapBuffer()"))
break;
filter_params->flags = flags & VA_TOP_FIELD ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
vaUnmapBuffer(p->display, *(p->pipe.filters));
param->surface = in_id;
param->surface_region = NULL;
param->output_region = NULL;
+2 -1
View File
@@ -27,9 +27,10 @@ struct vo_cocoa_state;
int vo_cocoa_init(struct vo *vo);
void vo_cocoa_uninit(struct vo *vo);
int vo_cocoa_config_window(struct vo *vo, uint32_t flags, void *gl_ctx);
int vo_cocoa_config_window(struct vo *vo, uint32_t flags);
void vo_cocoa_set_current_context(struct vo *vo, bool current);
bool vo_cocoa_start_frame(struct vo *vo);
void vo_cocoa_swap_buffers(struct vo *vo);
int vo_cocoa_check_events(struct vo *vo);
int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg);
+23 -9
View File
@@ -35,10 +35,8 @@
#include "config.h"
#if HAVE_COCOA_APPLICATION
# include "osdep/macosx_application.h"
# include "osdep/macosx_application_objc.h"
#endif
#include "osdep/macosx_application.h"
#include "osdep/macosx_application_objc.h"
#include "options/options.h"
#include "video/out/vo.h"
@@ -109,6 +107,14 @@ static void with_cocoa_lock_on_main_thread(struct vo *vo, void(^block)(void))
});
}
static void with_cocoa_lock_on_main_thread_sync(struct vo *vo, void(^block)(void))
{
struct vo_cocoa_state *s = vo->cocoa;
dispatch_sync(dispatch_get_main_queue(), ^{
with_cocoa_lock(s, block);
});
}
static void queue_new_video_size(struct vo *vo, int w, int h)
{
struct vo_cocoa_state *s = vo->cocoa;
@@ -279,7 +285,7 @@ void vo_cocoa_uninit(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
with_cocoa_lock_on_main_thread(vo, ^{
with_cocoa_lock_on_main_thread_sync(vo, ^{
enable_power_management(s);
cocoa_uninit_light_sensor(s);
cocoa_rm_fs_screen_profile_observer(s);
@@ -462,13 +468,11 @@ static void create_ui(struct vo *vo, struct mp_rect *win, int geo_flags)
[view signalMousePosition];
s->adapter = adapter;
#if HAVE_COCOA_APPLICATION
cocoa_register_menu_item_action(MPM_H_SIZE, @selector(halfSize));
cocoa_register_menu_item_action(MPM_N_SIZE, @selector(normalSize));
cocoa_register_menu_item_action(MPM_D_SIZE, @selector(doubleSize));
cocoa_register_menu_item_action(MPM_MINIMIZE, @selector(performMiniaturize:));
cocoa_register_menu_item_action(MPM_ZOOM, @selector(performZoom:));
#endif
s->video = [[MpvVideoView alloc] initWithFrame:[s->view bounds]];
[s->video setWantsBestResolutionOpenGLSurface:YES];
@@ -546,7 +550,7 @@ void vo_cocoa_release_nsgl_ctx(struct vo *vo)
s->gl_ctx = nil;
}
int vo_cocoa_config_window(struct vo *vo, uint32_t flags, void *gl_ctx)
int vo_cocoa_config_window(struct vo *vo, uint32_t flags)
{
struct vo_cocoa_state *s = vo->cocoa;
with_cocoa_lock_on_main_thread(vo, ^{
@@ -632,13 +636,21 @@ static void draw_changes_after_next_frame(struct vo *vo)
}
}
bool vo_cocoa_start_frame(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
s->skip_swap_buffer = false;
return true;
}
void vo_cocoa_swap_buffers(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
if (s->skip_swap_buffer && !s->waiting_frame) {
s->skip_swap_buffer = false;
return;
s->pending_events |= VO_EVENT_EXPOSE;
} else {
[s->gl_ctx flushBuffer];
}
@@ -771,11 +783,13 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
*(double *)arg = vo->cocoa->screen_fps;
return VO_TRUE;
}
break;
case VOCTRL_GET_AMBIENT_LUX:
if (vo->cocoa->light_sensor != IO_OBJECT_NULL) {
*(int *)arg = vo->cocoa->last_lux;
return VO_TRUE;
}
break;
}
return VO_NOTIMPL;
}
+7 -1
View File
@@ -141,7 +141,7 @@ static bool config_window_cocoa(struct MPGLContext *ctx, int flags)
if (!ctx->gl->SwapInterval)
ctx->gl->SwapInterval = set_swap_interval;
vo_cocoa_config_window(ctx->vo, flags, p->ctx);
vo_cocoa_config_window(ctx->vo, flags);
return true;
}
@@ -153,6 +153,11 @@ static void releaseGlContext_cocoa(MPGLContext *ctx)
CGLReleaseContext(p->ctx);
}
static bool start_frame_cocoa(MPGLContext *ctx)
{
return vo_cocoa_start_frame(ctx->vo);
}
static void swapGlBuffers_cocoa(MPGLContext *ctx)
{
vo_cocoa_swap_buffers(ctx->vo);
@@ -169,6 +174,7 @@ void mpgl_set_backend_cocoa(MPGLContext *ctx)
ctx->config_window = config_window_cocoa;
ctx->releaseGlContext = releaseGlContext_cocoa;
ctx->swapGlBuffers = swapGlBuffers_cocoa;
ctx->start_frame = start_frame_cocoa;
ctx->vo_init = vo_cocoa_init;
ctx->register_resize_callback = vo_cocoa_register_resize_callback;
ctx->vo_uninit = vo_cocoa_uninit;
+4 -3
View File
@@ -114,9 +114,10 @@ typedef struct MPGLContext {
void (*register_resize_callback)(struct vo *vo,
void (*cb)(struct vo *vo, int w, int h));
// Optional activity state of context.
// If false, OpenGL renderers should not draw anything.
bool (*is_active)(struct MPGLContext *);
// Optional callback on the beginning of a frame. The frame will be finished
// with swapGlBuffers(). This returns false if use of the OpenGL context
// should be avoided.
bool (*start_frame)(struct MPGLContext *);
// For free use by the backend.
void *priv;
+2
View File
@@ -36,6 +36,8 @@
#include "gl_video.h"
#include "gl_lcms.h"
#include "osdep/io.h"
#if HAVE_LCMS2
#include <lcms2.h>
+16 -9
View File
@@ -107,6 +107,7 @@ struct texplane {
struct video_image {
struct texplane planes[4];
bool image_flipped;
bool needs_upload;
struct mp_image *mpi; // original input image
};
@@ -320,7 +321,7 @@ const struct gl_video_opts gl_video_opts_def = {
.npot = 1,
.dither_depth = -1,
.dither_size = 6,
.fbo_format = GL_RGBA,
.fbo_format = GL_RGBA16,
.sigmoid_center = 0.75,
.sigmoid_slope = 6.5,
.scaler = {
@@ -469,6 +470,7 @@ static void uninit_rendering(struct gl_video *p);
static void uninit_scaler(struct gl_video *p, struct scaler *scaler);
static void check_gl_features(struct gl_video *p);
static bool init_format(int fmt, struct gl_video *init);
static void gl_video_upload_image(struct gl_video *p);
#define GLSL(x) gl_sc_add(p->sc, #x "\n");
#define GLSLF(...) gl_sc_addf(p->sc, __VA_ARGS__)
@@ -2048,6 +2050,8 @@ void gl_video_render_frame(struct gl_video *p, int fbo, struct frame_timing *t)
}
if (vimg->mpi) {
gl_video_upload_image(p);
gl_sc_set_vao(p->sc, &p->vao);
if (p->opts.interpolation) {
@@ -2124,27 +2128,30 @@ static bool get_image(struct gl_video *p, struct mp_image *mpi)
return true;
}
void gl_video_skip_image(struct gl_video *p, struct mp_image *mpi)
void gl_video_set_image(struct gl_video *p, struct mp_image *mpi)
{
assert(mpi);
struct video_image *vimg = &p->image;
talloc_free(vimg->mpi);
vimg->mpi = mpi;
vimg->needs_upload = true;
p->osd_pts = mpi->pts;
}
void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
static void gl_video_upload_image(struct gl_video *p)
{
GL *gl = p->gl;
struct video_image *vimg = &p->image;
struct mp_image *mpi = vimg->mpi;
p->osd_pts = mpi->pts;
talloc_free(vimg->mpi);
vimg->mpi = mpi;
if (p->hwdec_active)
if (p->hwdec_active || !mpi || !vimg->needs_upload)
return;
vimg->needs_upload = false;
assert(mpi->num_planes == p->plane_count);
mp_image_t mpi2 = *mpi;
+1 -2
View File
@@ -83,8 +83,7 @@ bool gl_video_check_format(struct gl_video *p, int mp_format);
void gl_video_config(struct gl_video *p, struct mp_image_params *params);
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d);
void gl_video_skip_image(struct gl_video *p, struct mp_image *mpi);
void gl_video_upload_image(struct gl_video *p, struct mp_image *img);
void gl_video_set_image(struct gl_video *p, struct mp_image *img);
void gl_video_render_frame(struct gl_video *p, int fbo, struct frame_timing *t);
void gl_video_resize(struct gl_video *p, int vp_w, int vp_h,
struct mp_rect *src, struct mp_rect *dst,
+2 -2
View File
@@ -215,7 +215,7 @@ static int control(struct vo *vo, int *events, int request, void *data)
return r;
}
static bool is_active(struct MPGLContext *ctx)
static bool start_frame(struct MPGLContext *ctx)
{
struct vo_wayland_state *wl = ctx->vo->wayland;
return wl->frame.pending;
@@ -229,5 +229,5 @@ void mpgl_set_backend_wayland(MPGLContext *ctx)
ctx->vo_control = control;
ctx->vo_init = vo_wayland_init;
ctx->vo_uninit = vo_wayland_uninit;
ctx->is_active = is_active;
ctx->start_frame = start_frame;
}
+19 -7
View File
@@ -471,8 +471,10 @@ static void wait_vo(struct vo *vo, int64_t until_time)
pthread_mutex_unlock(&in->lock);
} else {
pthread_mutex_lock(&in->lock);
if (!in->need_wakeup)
mpthread_cond_timedwait(&in->wakeup, &in->lock, until_time);
if (!in->need_wakeup) {
struct timespec ts = mp_time_us_to_timespec(until_time);
pthread_cond_timedwait(&in->wakeup, &in->lock, &ts);
}
in->need_wakeup = false;
pthread_mutex_unlock(&in->lock);
}
@@ -586,7 +588,7 @@ static bool render_frame(struct vo *vo)
int64_t duration = in->frame_duration;
struct mp_image *img = in->frame_queued;
if (!img && (!in->vsync_timed || in->paused || pts <= 0))
if (!img && (!in->vsync_timed || in->paused))
goto nothing_done;
if (in->vsync_timed && !in->hasframe)
@@ -608,14 +610,22 @@ static bool render_frame(struct vo *vo)
if (!in->hasframe_rendered)
duration = -1; // disable framedrop
// if the clip and display have similar/identical fps, it's possible that
// If the clip and display have similar/identical fps, it's possible that
// we'll be very slightly late frequently due to timing jitter, or if the
// clip/container timestamps are not very accurate.
// so if we dropped the previous frame, keep dropping until we're aligned
// So if we dropped the previous frame, keep dropping until we're aligned
// perfectly, else, allow some slack (1 vsync) to let it settle into a rhythm.
// On low clip fps, we don't drop anyway and the slack logic doesn't matter.
// If the clip fps is more than ~5% above screen fps, we remove this slack
// and use "normal" logic to allow more regular drops of 1 frame at a time.
bool use_slack = duration > (0.95 * in->vsync_interval);
in->dropped_frame = duration >= 0 &&
use_slack ?
((in->dropped_frame && end_time < next_vsync) ||
(end_time < prev_vsync)); // hard threshold - 1 vsync late
(end_time < prev_vsync)) // hard threshold - 1 vsync late
:
end_time < next_vsync; // normal frequent drops
in->dropped_frame &= !(vo->driver->caps & VO_CAP_FRAMEDROP);
in->dropped_frame &= (vo->global->opts->frame_dropping & 1);
@@ -651,7 +661,7 @@ static bool render_frame(struct vo *vo)
MP_STATS(vo, "start video");
if (in->vsync_timed) {
if (vo->driver->draw_image_timed) {
struct frame_timing t = (struct frame_timing) {
.pts = pts,
.next_vsync = next_vsync,
@@ -961,6 +971,8 @@ void vo_event(struct vo *vo, int event)
pthread_mutex_lock(&in->lock);
if ((in->queued_events & event & VO_EVENTS_USER) != (event & VO_EVENTS_USER))
mp_input_wakeup(vo->input_ctx);
if (event)
wakeup_locked(vo);
in->queued_events |= event;
in->internal_events |= event;
pthread_mutex_unlock(&in->lock);
-1
View File
@@ -128,7 +128,6 @@ struct voctrl_get_equalizer_args {
#define VO_NOTAVAIL -2
#define VO_NOTIMPL -3
#define VOFLAG_FLIPPING 0x08
#define VOFLAG_HIDDEN 0x10 //< Use to create a hidden window
#define VOFLAG_GL_DEBUG 0x40 // Hint to request debug OpenGL context
#define VOFLAG_ALPHA 0x80 // Hint to request alpha framebuffer
+17 -3
View File
@@ -475,6 +475,10 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
mp_image_params_guess_csp(&p->sws->dst);
mp_image_set_params(p->cur_frame, &p->sws->dst);
struct modeset_buf *buf = p->dev->bufs;
memset(buf[0].map, 0, buf[0].size);
memset(buf[1].map, 0, buf[1].size);
if (mp_sws_reinit(p->sws) < 0)
return -1;
@@ -487,12 +491,13 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
struct priv *p = vo->priv;
if (p->active) {
struct mp_image src = *mpi;
struct mp_rect src_rc = p->src;
src_rc.x0 = MP_ALIGN_DOWN(src_rc.x0, mpi->fmt.align_x);
src_rc.y0 = MP_ALIGN_DOWN(src_rc.y0, mpi->fmt.align_y);
mp_image_crop_rc(mpi, src_rc);
mp_sws_scale(p->sws, p->cur_frame, mpi);
osd_draw_on_image(vo->osd, p->osd, mpi ? mpi->pts : 0, 0, p->cur_frame);
mp_image_crop_rc(&src, src_rc);
mp_sws_scale(p->sws, p->cur_frame, &src);
osd_draw_on_image(vo->osd, p->osd, src.pts, 0, p->cur_frame);
struct modeset_buf *front_buf = &p->dev->bufs[p->dev->front_buf];
int32_t shift = (p->device_w * p->y + p->x) * 4;
@@ -607,9 +612,18 @@ static int control(struct vo *vo, uint32_t request, void *data)
{
struct priv *p = vo->priv;
switch (request) {
case VOCTRL_SCREENSHOT_WIN:
*(struct mp_image**)data = mp_image_new_copy(p->cur_frame);
return VO_TRUE;
case VOCTRL_REDRAW_FRAME:
draw_image(vo, p->last_input);
return VO_TRUE;
case VOCTRL_GET_PANSCAN:
return VO_TRUE;
case VOCTRL_SET_PANSCAN:
if (vo->config_ok)
reconfig(vo, vo->params, 0);
return VO_TRUE;
}
return VO_NOTIMPL;
}
+17 -18
View File
@@ -76,7 +76,7 @@ struct gl_priv {
char *backend;
int vo_flipped;
bool frame_started;
int frames_rendered;
unsigned int prev_sgi_sync_count;
@@ -124,8 +124,11 @@ static void flip_page(struct vo *vo)
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
if (p->glctx->is_active && !p->glctx->is_active(p->glctx))
if (!p->frame_started) {
vo_increment_drop_count(vo, 1);
return;
}
p->frame_started = false;
mpgl_lock(p->glctx);
@@ -171,19 +174,17 @@ static void draw_image_timed(struct vo *vo, mp_image_t *mpi,
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
if (p->glctx->is_active && !p->glctx->is_active(p->glctx)) {
if (mpi)
gl_video_skip_image(p->renderer, mpi);
return;
}
if (p->vo_flipped)
mp_image_vflip(mpi);
mpgl_lock(p->glctx);
if (mpi)
gl_video_upload_image(p->renderer, mpi);
gl_video_set_image(p->renderer, mpi);
if (p->glctx->start_frame && !p->glctx->start_frame(p->glctx)) {
mpgl_unlock(p->glctx);
return;
}
p->frame_started = true;
gl_video_render_frame(p->renderer, 0, t);
// The playloop calls this last before waiting some time until it decides
@@ -236,8 +237,6 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
gl_video_config(p->renderer, params);
p->vo_flipped = !!(flags & VOFLAG_FLIPPING);
mpgl_unlock(p->glctx);
return 0;
@@ -388,11 +387,11 @@ static int control(struct vo *vo, uint32_t request, void *data)
request_hwdec_api(p, data);
return true;
case VOCTRL_REDRAW_FRAME:
if (p->glctx->is_active && !p->glctx->is_active(p->glctx))
return true;
mpgl_lock(p->glctx);
gl_video_render_frame(p->renderer, 0, NULL);
if (!(p->glctx->start_frame && !p->glctx->start_frame(p->glctx))) {
p->frame_started = true;
gl_video_render_frame(p->renderer, 0, NULL);
}
mpgl_unlock(p->glctx);
return true;
case VOCTRL_SET_COMMAND_LINE: {
+2 -1
View File
@@ -328,7 +328,7 @@ int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h)
pthread_mutex_unlock(&ctx->lock);
if (mpi)
gl_video_upload_image(ctx->renderer, mpi);
gl_video_set_image(ctx->renderer, mpi);
gl_video_render_frame(ctx->renderer, fbo, NULL);
@@ -542,6 +542,7 @@ static int preinit(struct vo *vo)
}
p->ctx->active = vo;
p->ctx->reconfigured = true;
p->ctx->update_new_opts = true;
copy_vo_opts(vo);
pthread_mutex_unlock(&p->ctx->lock);
+89 -22
View File
@@ -30,6 +30,8 @@
#include <libavutil/rational.h>
#include "osdep/atomics.h"
#include "common/common.h"
#include "common/msg.h"
#include "options/m_config.h"
@@ -57,6 +59,7 @@ struct osd_part {
struct priv {
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_ELEMENT_HANDLE_T window;
DISPMANX_RESOURCE_HANDLE_T window_back;
DISPMANX_UPDATE_HANDLE_T update;
uint32_t w, h;
@@ -72,6 +75,8 @@ struct priv {
// for RAM input
MMAL_POOL_T *swpool;
atomic_bool update_display;
int background_layer;
int video_layer;
int osd_layer;
@@ -239,6 +244,64 @@ static void resize(struct vo *vo)
MP_WARN(vo, "could not set video rectangle\n");
}
static int update_display_size(struct vo *vo)
{
struct priv *p = vo->priv;
uint32_t n_w = 0, n_h = 0;
if (graphics_get_display_size(0, &n_w, &n_h) < 0) {
MP_FATAL(vo, "Could not get display size.\n");
return -1;
}
if (p->w == n_w && p->h == n_h)
return 0;
p->w = n_w;
p->h = n_h;
MP_VERBOSE(vo, "Display size: %dx%d\n", p->w, p->h);
if (p->window)
vc_dispmanx_element_remove(p->update, p->window);
if (p->window_back)
vc_dispmanx_resource_delete(p->window_back);
p->window = 0;
p->window_back = 0;
VC_IMAGE_TYPE_T format = VC_IMAGE_ARGB8888; // assuming RPI is always LE
p->window_back = vc_dispmanx_resource_create(format, 1 | (4 << 16), 1,
&(int32_t){0});
if (!p->window_back) {
MP_ERR(vo, "Could not create background bitmap.\n");
return -1;
}
uint32_t px = 0;
VC_RECT_T rc = {.width = 1, .height = 1};
vc_dispmanx_resource_write_data(p->window_back, format, 4, &px, &rc);
// Use the whole screen.
VC_RECT_T dst = {.width = p->w, .height = p->h};
VC_RECT_T src = {.width = 1 << 16, .height = 1 << 16};
VC_DISPMANX_ALPHA_T alpha = {
.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
.opacity = 0xFF,
};
p->window = vc_dispmanx_element_add(p->update, p->display, p->background_layer,
&dst, p->window_back, &src,
DISPMANX_PROTECTION_NONE, &alpha, 0, 0);
if (!p->window) {
MP_FATAL(vo, "Could not add DISPMANX element.\n");
return -1;
}
vc_dispmanx_update_submit_sync(p->update);
p->update = vc_dispmanx_update_start(10);
return 0;
}
static void flip_page(struct vo *vo)
{
struct priv *p = vo->priv;
@@ -466,19 +529,43 @@ static int control(struct vo *vo, uint32_t request, void *data)
case VOCTRL_SCREENSHOT_WIN:
*(struct mp_image **)data = take_screenshot(vo);
return VO_TRUE;
case VOCTRL_CHECK_EVENTS:
if (atomic_load(&p->update_display)) {
atomic_store(&p->update_display, false);
update_display_size(vo);
if (p->renderer_enabled)
resize(vo);
}
return VO_TRUE;
}
return VO_NOTIMPL;
}
static void tv_callback(void *callback_data, uint32_t reason, uint32_t param1,
uint32_t param2)
{
struct vo *vo = callback_data;
struct priv *p = vo->priv;
atomic_store(&p->update_display, true);
vo_wakeup(vo);
}
static void uninit(struct vo *vo)
{
struct priv *p = vo->priv;
vc_tv_unregister_callback_full(tv_callback, vo);
talloc_free(p->next_image);
wipe_osd(vo);
if (p->window)
vc_dispmanx_element_remove(p->update, p->window);
if (p->window_back)
vc_dispmanx_resource_delete(p->window_back);
if (p->update)
vc_dispmanx_update_submit_sync(p->update);
@@ -521,30 +608,10 @@ static int preinit(struct vo *vo)
goto fail;
}
if (graphics_get_display_size(0, &p->w, &p->h) < 0) {
MP_FATAL(vo, "Could not get display size.\n");
if (update_display_size(vo) < 0)
goto fail;
}
MP_VERBOSE(vo, "Display size: %dx%d\n", p->w, p->h);
// Just use the whole screen.
VC_RECT_T dst = {.width = p->w, .height = p->h};
VC_RECT_T src = {.width = p->w << 16, .height = p->h << 16};
VC_DISPMANX_ALPHA_T alpha = {
.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
.opacity = 0xFF,
};
p->window = vc_dispmanx_element_add(p->update, p->display, p->background_layer,
&dst, 0, &src, DISPMANX_PROTECTION_NONE,
&alpha, 0, 0);
if (!p->window) {
MP_FATAL(vo, "Could not add DISPMANX element.\n");
goto fail;
}
vc_dispmanx_update_submit_sync(p->update);
p->update = vc_dispmanx_update_start(10);
vc_tv_register_callback(tv_callback, vo);
return 0;
Loaded 100 of 109 files, more files were not shown because too many files have changed in this diff. Show more