Compare commits

...
189 Commits
Author SHA1 Message Date
Martin Herkt 5b7d0fbab3 Release 0.12.0 2015-10-29 03:49:43 +01:00
Martin Herkt ec567d8a77 Merge branch 'master' into release/current 2015-10-29 02:56:49 +01:00
wm4 33489feca8 player: raise display sync desync tolerance
Bump it to 80, and 2 vsyncs. This is another measure against vsync
jitter. Admittedly this is a bit simplistic (and we should probably
estimate a stable estimated vsync phase instead), but for now this will
do.
2015-10-28 23:57:27 +01:00
wm4 ce82d88215 player: reset AO stats on pause and other discontinuities
It's annoying.
2015-10-28 23:57:24 +01:00
wm4 d1ad0815fe player: simplify display-adrop mode safeguard
It's not needed, because the additional data is not appended, but is the
total size of the audio buffer. The maximum size is the static audio
drop size (or twice, if the audio is duplicated).
2015-10-28 23:57:24 +01:00
wm4 fc3f1e7c54 player: minor refactor for A/V diff computation
Calculate the A/V difference directly in the display sync code, instead
of the awkward current way, which reuses the fields for audio sync.

We still set time_frame, because it makes falling back to audio sync
somewhat smoother.
2015-10-28 23:57:24 +01:00
wm4 466658ee7e player: fix display sync A/V difference estimation on drops
When dropping or repeating frames, we essentially influence when the
frame after the next frame will be shown, not the next frame. This led
to dropping/repeating frames 2 times, because the A/V difference had a
delay of one frame. Compensate it with the expected value.
2015-10-28 23:57:24 +01:00
wm4 cf18922d19 sub: remove use of semi-deprecated libass field
In newer libass version, this does nothing, and will be removed on the
next API/ABI bump.
2015-10-28 23:49:13 +01:00
wm4 3c081dfd93 Replace deprecated av_free_packet() calls
av_free_packet() got finally deprecated. Use av_packet_unref() instead,
which has almost the same semantics, has existed for a while, and is
available in all FFmpeg and Libav versions we support.
2015-10-28 23:48:56 +01:00
wm4 a135c9cffc demux_mkv: fix cluster skip with duration probing
The start time probing essentially broke it.
2015-10-27 20:57:11 +01:00
wm4 f891b24cb5 vo: kill non-working missed frame detection
This was not very reliable.

In the normal vo_opengl case, this didn't deal well enough with vsync
jitter. Vsync timings can jitter quite extremely, up to a whole vsync
duration, in which case the "missed" frame counter keeps growing, even
though nothing is wrong. This behavior also messes up the A/V difference
calculation, but as long as it's within tolerance, it won't provoke
extra frame dropping/repeating. Real misses are harder to detect, and I
might add such detection later.

In the vo_opengl_cb case, this was additionally broken due to the
asynchronity between renderer and VO threads.
2015-10-27 20:57:04 +01:00
wm4 70aa3b04f8 player: disable total-avsync-change update in display-sync mode
The total-avsync-change property made no sense in display-sync mode (in
addition to making not all that much sense in general).
2015-10-27 20:56:58 +01:00
wm4 c24921d56b player: fix display-sync A/V calculation on high playback speeds
This is all kinds of stupid - update_avsync_after_frame() will multiply
this value with the speed at a later point, and we only update this
field for this function. (This should be refactored.)
2015-10-27 20:56:49 +01:00
wm4 aaec2aba38 player: add audio drop/duplicate mode
Not very robust in the moment.
2015-10-27 20:56:46 +01:00
wm4 3b95dd47d5 player: simplify audio sync pts calculation
This was done for symmetry with adjust_sync(). But mpctx->delay is
always 0 at this point, so prefer slightly simpler code.
2015-10-27 20:56:39 +01:00
wm4 555ecbb70e demux_mkv: fix duration probing for files with non-0 start time
When using --demuxer-mkv-probe-video-duration=full and the file did not
start at timestamp 0, the reported duration was still wrong.
2015-10-26 18:21:31 +01:00
wm4 919707efb7 ao_coreaudio_exclusive: check for maximum channel count
Until recently, the channel layout code happened to catch this, but now
an explicit check is needed. Otherwise, it'd try to pad the missing
channels with NA in the channel map fallback code.
2015-10-26 16:00:24 +01:00
wm4 c1de8cdc38 client API: change error string if playback fails completely
It can print this if AO/VO initialization fails, which makes the wording
a lie. Change it to something more diplomatically safe.
2015-10-26 15:55:40 +01:00
wm4 0cc440f291 ao_coreaudio_exclusive: fallback to stereo on unknown channel layouts
This is intended for the case when CoreAudio returns only unknown
channel layouts, or no channel layout matches the number of channels the
CoreAudio device forces. Assume that outputting stereo or mono to the
first channels is safe, and that it's better than outputting nothing.

It's notable that XBMC/kodi falls back to a static channel layout in
this case. For some messed up reason, the layout it uses happens to
match with the channel order in ALSA's/mpv's "7.1(alsa)" layout.
2015-10-26 15:55:11 +01:00
wm4 0524907c18 ao_coreaudio_chmap: minor refactor
Share some code between ca_init_chmap() and ca_get_active_chmap(), which
also makes it look slightly nicer. No functional changes, other than the
additional log message.
2015-10-26 15:55:01 +01:00
wm4 c971fefd41 ao_coreaudio_chmap: allow stereo as fallback; avoid mono fallback
If no channel layouts were determined (which can actually happen with
some "strange" devices), the selection code was falling back to mono,
because mono is always added as a fallback. This doesn't seem quite
right.

Allow a fallback to stereo too, if no channel layout could be retrieved
at all. So we always assume that mono and stereo work, if no other
layouts are available.

(I still don't know what the CoreAudio stereo layout is supposed to do.
It could be used to swap left and right channels. It could also be used
to pad/move the channels, but I have never seen that. And it can be set
to non-stereo channels, which breaks mpv. Whatever.)
2015-10-26 15:54:45 +01:00
wm4 9ed289ef90 ao_coreaudio: fix another minor memory leak
How stupid, even the cleanup gotos were already there.
2015-10-26 15:54:36 +01:00
wm4 f3a003e550 audio: bump maximum number of channels to 16
The main reason is that ao_coreaudio_exclusive needs this for some OSX
devices. They want packed audio, and special-casing this in the
coreaudio code would be too much of a pain.

The maximum of channels we can support is 64 (because FFmpeg uses 64 bit
masks for channel layouts), but since struct mp_audio can get pretty
big (has static allocations of 2 pointers for each channel for planar
mode), it's less wasteful to stay lower for now.
2015-10-26 15:54:19 +01:00
wm4 48c2e9d67d audio: use AVFrames with more than 8 channels correctly
Requires messy dealing with the extended_ fields.

Don't bother with af_lavfi and ao_lavc for now. There are probably no
valid use-cases for these.
2015-10-26 15:54:00 +01:00
wm4 0ffaf653a2 af_lavrresample: make planarization pass work with >8 channels
av_get_default_channel_layout() fails with channel counts larger than 8.
The channel layout doesn't need to make sense, so pick an arbitrary
fallback.

libswresample also has options for setting the channel counts directly,
but better not introduce new concepts in the code. Also, libavresample
doesn't have these options.
2015-10-26 15:53:47 +01:00
wm4 76d1b430b0 audio: improve mp_chmap_to_lavc_unchecked() unknown chmap behavior
Change it so that it will always return a bitmask with the correct
number of channels set if an unknown channel map is passed. This didn't
work for channel counts larger than 8, as there are not any standard
channel layouts defined with more than 8 channels (both in mpv and
FFmpeg). Instead, it returned 0.

This will help when raising the maximum allowed channel count in mpv.
Some code in af_lavrresample relies on it, more or less.

One change is that unknown channel maps won't result in lavc standard
channel layouts anymore, just a set of random speakers. This should be
fine, as the caller of mp_chmap_to_lavc_unchecked() should handle these
cases. For mp_chmap_reorder_to_lavc() this is not so clear anymore, but
should also be ok.

For normal channel maps, simply dropping NA channels is still the
correct and wanted behavior.

Currently, the mpv maximum channel count is 8. This commit is
preparation for raising this limit.
2015-10-26 15:52:21 +01:00
wm4 ec27d573f4 audio: always log channel maps before determining final map
Until now, this was done only in debug verbosity, while some AOs logged
equivalent information in verbose mode. Clean this up.
2015-10-26 15:52:08 +01:00
wm4 72d3c5ef00 ao_coreaudio: fix potential UB in error cases
mNumberChannelDescriptions being 0 is pretty much an error, but if it
can happen, then the code checking the chmap below will trigger UB, as
chmap is not initialized at all.

Also, simplify the code a little: we never change the number of
channels, so this is just fine.
2015-10-26 15:51:59 +01:00
wm4 81109dcbb6 ao_coreaudio_chmap: add more logging 2015-10-26 15:51:50 +01:00
wm4 fa510bd00c af: prevent endless loop when removing filters due to spdif
This code removes filters which can not take spdif inout. This was made
so that PCM filters are transparently dropped in spdif mode.

This entered an endless loop with:

   --af=lavcac3enc:::2 --audio-channels=5.1

The forced number of output channels is incompatible with spdif. It's
trying to insert af_lavrresample as conversion filter to compensate for
it. Of course this doesn't work, which triggers the PCM filter removal.
Then it goes on normally - since the new state is exactly as before, it
will try the same thing again, forever.

Fix by reusing the retry counter, which is a very dumb but very
effective measure against these cases of filter negotiation failure. We
could try to be more clever (for example, if the removed filter is a
conversion filter, we can be sure this won't work, and error out
immediately). But better keep it simple and robust.
2015-10-26 15:51:26 +01:00
wm4 c21c26472c ao_alsa: log format probing in verbose mode
And also remove a redundant log message. (We can tell from the following
probe or error message whether or not the format test is successful.)
2015-10-25 20:09:38 +01:00
Rodger Combs d6e7190836 vd_lavc: make software decoding fallback an option 2015-10-25 15:21:11 +01:00
wm4 d1a46c2c32 options: remove --use-text-osd 2015-10-24 19:09:35 +02:00
Ricardo Constantino a02f3a5dd4 ytdl: disable --all-subs if "sub-lang" is in raw-options
Defaults stay the same (--all-subs is used if sub-lang wasn't used.)
Don't forget to also add "write-sub=" if using sub-lang or else it won't
work.
2015-10-24 17:30:22 +02:00
Bin Jin 17b4fb02b3 vo_opengl: remove source shader leftover
The source shader was removed after deband was introduced.
2015-10-24 17:11:02 +02:00
wm4 252dcdcc99 sd_lavc: take care of AVPicture deprecation 2015-10-23 20:14:08 +02:00
Niklas Haas 97fc4f4a85 vo_opengl: always cache to an FBO when not interpolating
This speeds up redraws considerably (improving eg. <60 Hz material on a 60 Hz
monitor with display-sync active, or redraws while paused), but slightly
slows down the worst case (eg. video FPS = display FPS).
2015-10-23 19:51:20 +02:00
Niklas Haas ad6e7c31df vo: expose frame->num_vsyncs to the VO backend
It's not clear why this was originally hidden, but the information is
useful for allowing the VO backend to make decisions about caching.
2015-10-23 19:51:20 +02:00
James Ross-Gowan bf6b981367 w32_common: disable IME
The IME is not useful for key-bindings. Handle the base ASCII chars
instead and don't show the IME window. For the sake of libmpv users, the
IME should only be disabled on mpv's GUI thread and not application-
wide.

No IME on the GUI thread should also mean that VK_PROCESSKEY will never
have to be handled, so the logic for that can be removed as well.
2015-10-23 17:55:47 +02:00
wm4 72ded5ccef vo_opengl: wayland: use a more standard symbol
They're the same, but EGL_CONTEXT_MAJOR_VERSION_KHR technically is an
extension, while EGL_CONTEXT_CLIENT_VERSION is the standardized alias.
2015-10-23 16:09:58 +02:00
wm4 0344abd67a vo_opengl: vaapi: fix compilation failure on older systems
Older systems have certain EGL extension definitions missing. We
redefine them to make the build system easier, and because it's trivial.
But we forgot to define the EGL_LINUX_DMA_BUF_EXT identifier. (I hope
it's the only missing one.)
2015-10-23 15:56:17 +02:00
wm4 56fefde7e2 command: make bitrate properties work correctly for external tracks 2015-10-23 14:58:01 +02:00
wm4 955c6843b6 command: do not return 0 for bitrates if unknown
This makes the bitrate properties unavailable, instead of
returning 0 when:

1. No track is selected, or
2. Not enough packets have been read to have a bitrate estimate yet
2015-10-23 14:53:19 +02:00
wm4 d1528e51d5 player: offset chapter display by start time
Some mkv files can have this. The chapter times are still timestamps
(and thus not affected by the start time), but it misplaces the OSD
chapter ticks.
2015-10-23 12:14:17 +02:00
wm4 53c720d412 vo_opengl_cb: fix passing through some video equalizer properties
The equalizer code as it exists in vo_opengl works perfectly fine. The
situation in vo_opengl_cb is pretty different. The playback thread can't
communicate with the renderer thread synchronously (essentially to give
the API user more flexibility). So the equalizer communication has to be
done in an asynchronous way too.

There were two problems. First, the eq capabilities can change with the
pixel format, and the renderer initializes them on config only. This
means equalizers were disabled on the first config run, and options like
--video-output-levels or --brightness would not work. So we just
initialize the caps with a known superset. The player will not correctly
indicate when setting an eq doesn't work, but we're fine with it, as it
is a relatively cosmetic issue.

Second, it copied back the eq settings in the "wrong" moment (what
for?), which overwrote the settings in some cases.

Third, the eq was not reset correctly on vo init. This is needed to make
it behave the same as vo_opengl.
2015-10-23 12:09:14 +02:00
wm4 878f12885b client API: fix typo and wording in a comment 2015-10-22 19:36:38 +02:00
wm4 0a1a5707bf demux: cosmetics: remove indirection
Let's not waste precious lines.
2015-10-22 01:26:34 +02:00
wm4 dd08018e9e sub: adjust behavior on mismatching video/subtitle aspect mismatch
If the aspect ratio of the video resolution and the subtitle resolution
(the implied subtitle coordinate system) mismatch, the subtitles
obviously can't be overlayed over the video perfectly. Either you get
video that can't be covered by subtitles, or the subtitles could go
beyond the video. We don't want to stretch the subtitle to compensate
for the aspect ratio, because it would look terrible.

Until now, mpv used to fit the subtitle rectangle into the video
rectangle (letterboxing/pillarboxing). This looks odd with some sample
files with subtitle canvas being wider than the video. Also, mpc-hc
displays them in a better way. vlc stretches them, which looks bad.
While you probably can't win this game with all those broken files
around, pick the mpc-hc method to handle this.
2015-10-21 23:07:39 +02:00
wm4 56d04c6570 input: rename recently added HALF_SPACE
There was a complaint that the naming is inaccurate. That's probably
right. Just use the official name instead, which is a bit clunky, but
surely correct.
2015-10-21 22:25:30 +02:00
wm4 96eb480299 ao_coreaudio_exclusive: fix build
"Let's apply cosmetic last minute changes without testing them."
2015-10-21 22:18:41 +02:00
wm4 14bb3d06a2 input: add key name for U+3000 IDEOGRAPHIC SPACE
Deserves its own name, because just like SPACE it's a printable
character, but invisible.

Fixes #2349... I think.
2015-10-21 21:57:59 +02:00
wm4 1a1ac76d2a sd_lavc: extend subtitle resolution if images go outside
Helps with broken vobsubs, which have an incorrect resolution header
set.

So we just extend the subtitle resolution to the video size, if the
video size is larger. This helps somewhat with readability, or makes
them visible at all. It should be a pretty safe change, because normally
no sub pictures are supposed to go outside of the area. It should make a
difference with broken files only.

The sample in question had a video resolution of 1888x1072, and a
subtitle resolution of 720x480. Note that always using video resolution
as subtitle resolution would break other files.
2015-10-21 21:33:02 +02:00
wm4 d93a9be656 ao_coreaudio: do not accept unknown channel layouts
Coreaudio gives us a channel map with all entries set to
kAudioChannelLabel_Unknown. This is translated to a mpv channel map with
all channels set to NA, which has special meaning: it's an "unknown"
channel map, which acts as wildcard and can be converted from/to any
channel layout. Not really what we want.

I've got this with USB audio, playing stereo. The multichannel layout
consisted of 2 unknown channels, while the stereo channel map was
stereo (as expected).

Note that channel maps with _some_ NA entries are not affected by this,
and must still work.
2015-10-21 18:57:03 +02:00
wm4 dda16ee1fb ao_coreaudio_exclusive: deal with devices return different channel count
If the device returns an unexpected number of channels instead of the
requested count on init, don't immediately error out. Instead, look if
there's a channel map with the given number of channels.

If there isn't, still error out, because we don't want to guess the
channel layout.
2015-10-21 18:54:48 +02:00
wm4 78112c8582 ao_coreaudio: avoid unnecessary format changes
Not particularly important; just being nice and potentially avoiding
problems caused by format setting.
2015-10-21 18:54:36 +02:00
wm4 ff778f6d68 ao_coreaudio: log current format before setting new format 2015-10-21 18:53:50 +02:00
wm4 cee9aeaf6b ao_coreaudio: fix some minor memory leaks 2015-10-21 18:53:34 +02:00
Niklas Haas eb66038d4f vo_opengl: make the default debanding settings less excessive
It's great that the new algorithm supports multiple placebo iterations
and all, but it's really not necessary and hurts performance in the
general case for the sake of the 0.1% that actually pause the screen
and look for minute differences.

Signed-off-by: wm4 <wm4@nowhere>
2015-10-21 11:32:31 +02:00
Joschka Tillmanns 1ee8ce75f1 options: add support for client certificate authentication
Client certificates are supported by ffmpeg as documented here:

  > https://www.ffmpeg.org/ffmpeg-protocols.html#tls

Signed-off-by: wm4 <wm4@nowhere>
2015-10-20 22:55:27 +02:00
bitingsock 0121d00478 TOOLS/autoload: avoid throwing an error when playing e.g. youtube
Signed-off-by: wm4 <wm4@nowhere>
2015-10-20 12:33:57 +02:00
wm4 e157d005ba ao_coreaudio: raise timeout for change-physical-format
Reportedly fixes operation with "USB connected Parasound ZDAC v.2". (OSX
and USB audio sure is not nice at all.)

This might be perceived as hang by some users, so it's quite possible
that this will have to be adjusted again somehow.

Fixes #2409.
2015-10-20 00:25:34 +02:00
Ricardo Vieira 251107076b Revert "vo_wayland: define opaque region"
This reverts commit c10fb4ce9f.

This is already done in vo_wayland.c:resize,324 doing it here makes the window bigger before the video resizes showing a black area while dragging the border.
2015-10-20 00:15:07 +02:00
wm4 750c29766f player: be slightly less prone to framedrop in display sync mode
1 to 2 frames desync is still tolerable, and will be quickly compensated
(if everything works).
2015-10-19 23:45:43 +02:00
wm4 b0b67cdf5d player: do not use copysign()
Apparently this function caused weird problems to me. I have no idea
why. The usage of the function looks perfectly fine to me, and even
rounding issues can be excluded. In any case, getting rid of this solved
my problem, and makes the code actually more readable.
2015-10-19 23:44:50 +02:00
wm4 50f8548b2f vd_lavc: attempt to fallback from hwdec before anything is decoded
The previous commit moved the av_frame_unref() after the got_picture
check. This accidentally also deferred the software fallback
reinitialization to until a software picture was decoded (instead of the
exact time of the fallback), which is not ideal.

Just rely on the fact that calling av_frame_unref() on a frame is ok
even if nothing was decoded.
2015-10-19 18:19:57 +02:00
wm4 0ab6031d76 vd_lavc: continue decoding properly after decoding failure
Commit 12cd48a8 started setting the hwdec_failed field even if hwdec was
not active, and because it also checked this field even if hwdec was not
active, broke decoding forever.

Fix this, and also avoid a memory leak or API misuse by releasing the
decoded picture. Passing an unreleased frame to the decoder has as far
as I know no defined effects.
2015-10-19 17:49:30 +02:00
wm4 667b968939 demux_lavf: always copy codec headers
If this is not done, libavformat could change the headers while
demuxing, all while the decoder thread reads these fields during
initialization.
2015-10-19 15:27:42 +02:00
wm4 e1128c8b28 video: pass through libavformat has_b_frames field
This fixes initial decoding of some samples. See #1341.

According to Libav devs, this should be considered a libavcodec bug, but
as it's hard to fix, here we go.
2015-10-19 15:00:21 +02:00
wm4 e3de309804 vo_opengl: support all kinds of GBRP formats
Adds support for AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, and
AV_PIX_FMT_GBRAP16.

(Not that it matters, because nobody uses these anyway.)
2015-10-18 18:37:24 +02:00
wm4 9ca312b4b1 demux: remove demux_add_packet() return value 2015-10-17 14:27:55 +02:00
wm4 d27d91715f build: remove explicit checks for VPP
This was once done when old versions of libva without VPP had to be
supported. Some parts of it were removed earlier already.
2015-10-17 14:25:09 +02:00
wm4 0eb45343ca vaapi: drop non-existing FourCC
This VA_FOURCC isn't even defined by latest drivers, so I'm just
assuming it doesn't exist and never existed. For planar 4:2:0,
VA_FOURCC_YV12 is normally preferred, and there's even a VA_FOURCC_IYUV
for 4:2:0 with unswapped planes.
2015-10-17 14:20:53 +02:00
wm4 7e7ef2f01d build: bump required libva version
0.34 and 0.35 don't have the buffer API, such as vaAcquireBufferHandle.
This is only needed for the EGL interop, but why bother staying
compatible for such old things (0.36 was released over a year ago).

We also can drop some minor compatibility ifdeffery.
2015-10-17 14:17:49 +02:00
wm4 76bfd5b4a2 demux_mkv: probe start time
MKV files can very well start with timestamps other than 0. While mpv
has support for such files in general, and demux_lavf enables this
feature, demux_mkv didn't export a start time.

Implement this by simply reading the first cluster timestamp. This in
turn is done by reading 1 block. While we don't need the block for this
prupose at all, it's the easiest way to get the cluster timestamp read
correctly without code duplication. In theory this could be wrong, and
a packet could start at a much later time, but in practice this won't
happen.

This commit also adds an option to disable this feature. It's not
documented because nobody should use it. (But I happen to have a need
for this.)
2015-10-16 17:11:44 +02:00
wm4 8d414e2fe7 command: make time properties unavailable if timestamp is unknown
Let's hope this doesn't confuse client API users too much. It's still
the best solution to get rid of corner cases where it actually return
the wrong timestamp on start, and then suddenly jump.
2015-10-16 16:16:10 +02:00
wm4 2483dab54d TOOLS/stats-conv: rewrite for pygtgraph
matplotlib is pathetically slow, which makes using stats-conv.py to view
dumps longer than a few seconds a huge pain.

pyqtgraph is slightly faster than matplotlib. Other than that, it seems
to be worse in every aspect (at least for plotting), but such is life.
2015-10-15 23:07:03 +02:00
wm4 3a7a2385df vo_opengl_cb: fix pausing and seeking if interpolation is enabled
When seeking, the current frame will have the wrong timestamp, until the
seek is done and a new frame from the seek target is shown. We still use
the "old" frame for redrawing during seeks. This frame has to be
explicitly marked with still=true in order not to confuse the
interpolation queue. If this is not done, it will ignore frames until a
frame with approximately the same timestamp as the "old" frame is
reached. (Does this mean interpolation handles timestamp resets
incorrectly? I have no idea.)

Of course we also have to clear possibly queued frames on seeks.

Also, in pausing, explicitly let the frame redraw.
2015-10-14 20:38:30 +02:00
wm4 3274fabeb3 player: fix an adjustment in display sync mode
This adjustment is supposed to improve the audio speed calculation in
case of unexpected desync. The flipped sign made it actually worse,
although the total impact of this bug was very minor.
2015-10-14 18:53:00 +02:00
wm4 e0f8d79772 af_lavrresample: fix unintended audio drift when setting playback speed
Small adjustments to the playback speed use swr_set_compensation()
to stretch the audio as it is required. But since large adjustments
are now handled by actually reinitializing libswresample, the small
adjustments get rounded off completely with typical frame sizes.

Compensate for this by accounting for the rounding error and keeping
track of fractional samples that should have been output to achieve
the correct ratio.

This fixes display sync mode behavior, which requires these adjustments
to be relatively accurate.
2015-10-14 18:51:12 +02:00
wm4 da496ae2fe msg: remove the useless trailing comment from stats dumping
The origin of the stats line was added as a comment (starting with '#').
It was useless and just blowing up file sizes.
2015-10-14 18:50:58 +02:00
wm4 184426175f player: fix inverted condition
Simple oversight which made it not work at all.

How did this ever work, and if it was never tested, then why did it work
when fixing this oversight?
2015-10-13 22:09:13 +02:00
wm4 1f9c4f19cf vo_opengl: x11egl: fix confused error status codes
This is all kinds of wonderfully stupid.
2015-10-12 22:10:11 +02:00
wm4 8b291aff96 vo_opengl: x11egl: reject nvidia drivers when autoprobing
Newer nVidia drivers support EGL, but they seem to work badly,
apparently don't support some needed features or not in a form we want
(such as swap control), and vdpau interop is not available. Disable it
by default, because I'm tired of explaining this issue.

Can be reverted as soon as nVidia release working drivers.
2015-10-12 21:30:13 +02:00
wm4 8d004f07a4 vd_lavc: work around libavcodec nonsense causing hwdec init failure
The libavcodec h264 decoder contains some idiotic code with unknown
purpose (no sample or explanation known that necessitates its
existence), that causes the AVCodecContext.get_format callback to be
invoked at a time when hwaccels can't be initialized. By definition, the
get_format callback is supposed to initialize hwaccels (another idiotic
thing now part of the API, but different story). This causes hwdec
initialization sometimes to fail (WolfensteinTwitch.mp4): the first
get_format callback will mark it as failed, so the second get_format
(the "proper" normal one) will not bother restoring the state, and hwdec
init fails.

While this should be fixed in libavcodec (good luck with that), it's
quite easy to workaround.
2015-10-12 21:24:25 +02:00
wm4 14a2993796 demux_mkv: do not return subtitle packets that end before seek target
This affects the subtitle preroll mode during seeking. It could matter
somewhat with insane files with ten-thousands of subtitle events, which
now seem to pop up, and will avoid packet queue overflow.
2015-10-12 21:19:43 +02:00
wm4 3804376ccc af_lavrresample: reinit resampler on large speed changes
swr/avresample_set_compensation() was made for small speed adjustments.
Non-documentation says it should be used for changes not larger than 1%,
so reinitialize the sampler if the change is larger than that.
2015-10-12 21:12:05 +02:00
ChrisK2 bddd1e9e3b ytdl: Set a proper label for external audio tracks 2015-10-11 20:52:11 +02:00
wm4 9e7069fde2 vd_lavc: refuse to initialize vaapi with unknown profiles
Bad idea, although I'm not sure how harmful it actually was.

Although this is common code, only the vaapi hwaccel still uses it.
2015-10-11 18:48:02 +02:00
wm4 94b6a1054e cocoa: set application policy before creating window
This fixes a regression since commit f4d62da8. The original code run
vo_cocoa_config_window() once without creating the window, which had the
effect that the last part of the function was run at least once before
the actual window was created. Fix the regression by moving it to before
the window is created.

The regression itself is hard to describe. One test case: start mpv from
a fullscreened terminal window. It should switch to another desktop,
with the mpv window visible. This didn't happen anymore.
2015-10-11 16:19:08 +02:00
wm4 d714c8380a DOCS/client_api_examples/README: add qt_opengl
And also adjust the documentation for the other Qt examples to avoid
redundancy.

While we're at it, move the simple example to the top.
2015-10-11 14:18:52 +02:00
wm4 b7ba2e2c57 DOCS/client_api_examples/qt_opengl: fix uninit
mpv_opengl_cb_uninit_gl() still needs the OpenGL context. It makes calls
to free OpenGL objects. Strictly speaking, this is probably unnecessary,
because the OpenGL context is destroyed afterwards (implicitly freeing
all related objects). But mpv_opengl_cb_uninit_gl() does not require the
destruction of the OpenGL context, and thus has to free resources
manually.

It's also true that OpenGL normally simply ignores API calls (or returns
errors) if no context is set, but doing it properly is cleaner.

That makeCurrent() can be called in the destructor is explicitly allowed
and recommended for freeing GL resources in the Qt docs.

This fixes a mpv error message on exit.
2015-10-11 14:11:12 +02:00
wang-bin 52de5ea6ad DOCS/client_api_examples: add qt widget + opengl-cb example 2015-10-11 13:58:09 +02:00
ChrisK2 78caf6ae86 ytdl: Remove DASH hacks, use DASH by default
Thanks to rcombs, ffmpeg now properly supports DASH and we can
remove our hacks for it and use it by default whenever
available. If you don't like this for whatever reason, you
can get the "normal" streams back with --ytdl-format=best .

Closes #579
Closes #1321
Closes #2359
2015-10-11 00:35:35 +02:00
wm4 46c499d02a DOCS/client_api_examples/README: rewrite
The new one is much more detailed.

Also add part of it to the libmpv doxygen.
2015-10-10 15:44:27 +02:00
wm4 dbbde6161d player: fix missed wakeup on video EOF
If video EOF happens during playback restart, and audio is syncing, and
the demuxer packet queue overflows (i.e. no new packets will be read),
then it could happen that the player accidentally enters sleeping, and
continues playing anything only after e.g. user input wakes it up.
2015-10-09 15:53:02 +02:00
wm4 a62dcdd5f4 manpage: font options do not support fontconfig patterns anymore
libass 0.13.0 breaks this due to removal of fontconfig from its core
(instead, fontconfig is one possible backend, and pattern lookup is
apparently not possible anymore).
2015-10-09 00:03:19 +02:00
wm4 f7124be091 audio: add AO deviation logging
Pretty dumb (and doesn't handle pausing or other discontinuities), but
at least somewhat idiot-proof.
2015-10-08 23:20:33 +02:00
wm4 6499224888 vo: log deviation from ideal vsync interval 2015-10-08 22:06:15 +02:00
wm4 252d5b319a demux_subreader: participate in probing only on Libav
FFmpeg supports all formats the old subreader code does, and is better
at it. On the other hand, subreader.c's probing is bad and can lead to
false positives easily.
2015-10-08 19:59:49 +02:00
wm4 280251656c af_lavrresample: use libswsresample dynamic rate adjustment feature
swr_set_compensation() changes the apparent sample rate on the fly (who
would have guessed). It is thus very well-suited for adjusting audio
speed on the fly during playback (like needed by the display-sync mode).
It skips the relatively slow resampler reinitialization.

If this doesn't work (libswresample soxr backend), then fall back to the
old method.
2015-10-07 21:54:45 +02:00
wm4 aa796c23db vo_xv: fix crash with --wid
Fixes #2386.

Reminder that you should not use this crap-VO.
2015-10-07 13:49:29 +02:00
wm4 0a41c6f0ec audio: make spdif re-probe from normal decoding work
The previous commit handled not falling back to normal decoding if the
AO was reloaded (I think...), and this tries to re-engage spdif pass-
through if it was previously falling back to normal decoding (e.g.
because it temporarily switched to an audio device incapable of
passthrough).
2015-10-06 20:21:29 +02:00
wm4 66aa54d319 audio: re-probe spdif if AO is reloaded
Makes the spdif automagic work better on audio hotplugging.
2015-10-06 19:59:02 +02:00
wm4 288eaacd85 demux: don't attempt to open a demuxer after abort signal was given
demux_open() kept trying to fallback to other demuxers when opening was
cancelled. This was not really a problem, but it was stupid.
2015-10-06 18:19:20 +02:00
wm4 ecb776f88e player: make stop command actually stop
The stop command didn't always stop. In this case, opening a HLS URL and
then sending "stop" during loading would actually make it fallback to
parsing it as a playlist, and then continued to play the playlist items.
(This corner case makes several unfortunate factors come together to
produce this really odd behavior.)

Another issue is that the "stop" was not always explicitly set. This
could be a problem when sending several commands at once. Only the
"quit" command should have priority over the "stop" command, so this is
still checked.
2015-10-06 18:19:20 +02:00
wm4 1c593f1497 README: link to Copyright instead of LICENSE file
The Copyright file explains the whole license mess. The earlier change
was apparently confusing, because the link reading "details" merely
linked to the GPLv2 license instead of explaining anything. In fact, I
meant to link to the Copyright file in the first place.
2015-10-06 18:19:20 +02:00
wm4 b4804a4b26 video: fix base for --no-correct-pts
Use the first encountered packet PTS/DTS as base, instead of the last
one. This does not add the amount of frames buffered in the codec to the
PTS offset, and thus is better.

Also, don't add the frame time if there was no decoded frame yet. The
first frame should obviously have the timestamp of the first packet
(going by this heuristic).
2015-10-06 18:19:20 +02:00
wm4 5015759334 video: increase maximum number of buffered AVI pts samples
While b-frame reordering limits the maximum required number to around
16, the number of additionally buffered frames can be much higher.

Guess when this actually matters? (For the libavcodec MMAL wrapper.)
2015-10-06 18:19:20 +02:00
wm4 3c292395ca video: don't sort AVI pts samples
It's obviously not needed, and only an artifact of the old PTS
determination code.
2015-10-06 18:19:20 +02:00
wm4 8e654d3f78 video: remove user-controllable PTS sorting (--pts-association-mode)
Useless. Sometimes it might be useful to make some extremely broken
files work, but on the other hand --no-correct-pts is sufficient for
these cases.

While we still need some of the code for AVI, the "auto" mode in
particular inflated the size of the code.
2015-10-06 18:19:20 +02:00
wm4 0e245b3752 video: disable framedrop if avi-style timestamps are used
This can't be handled correctly at all. Other cases when the decoder
might drop a frame (such as completely failing to decode a frame) will
shift timestamps by a frame, and it can't be avoided.

While we could maybe find a better way to handle this with libavcodec's
main decoders, this seems to be much harder if it should work with
certain HW decoders, which don't passthrough the DTS field (such as
MMAL). Another problem are .avi files with b-frames. So just leave it
as it is.
2015-10-06 18:18:57 +02:00
ChrisK2 6fb926a560 ytdl: Remove version check and minor cleanup
Closes #2370
2015-10-06 17:06:11 +02:00
Kevin Mitchell 8f33c65fe0 ao_alsa: add debug messages for format search 2015-10-06 02:24:36 -07:00
Kevin Mitchell beae60bcd5 ao_alsa: fix failure to find any sampleformat
Set format to invalid after each failed test. This way the final check
for valid format will actually fail if no formats work.
2015-10-06 02:24:36 -07:00
wm4 29e42b78c0 README: clarify license statement
Fixes #2382.
2015-10-06 09:28:38 +02:00
wm4 54fbda2ba4 audio: add option for falling back to ao_null
The manpage entry explains this.

(Maybe this option could be always enabled and removed. I don't quite
remember what valid use-cases there are for just disabling audio
entirely, other than that this is also needed for audio decoder init
failure.)
2015-10-05 19:12:23 +02:00
wm4 e694d67366 ao: rework audio output driver probing
Make the code a bit more uniform. Always build a "dummy" audio output
list before probing, which means that opening preferred devices and
pure auto-probing is done with the same code. We can drop the second
ao_init() call.

This also makes the next commit easier, which wants to selectively
fallback to ao_null. This could have been implemented by passing a
different requested audio output list (instead of reading it from
MPOptions), but I think it's better if this rather special feature
is handled internally in the AO code. This also makes sure the AO
code can handle its own options (such as the audio output list) in
a self-contained way.
2015-10-05 19:10:22 +02:00
wm4 6890de958d manpage: edit recommended VO remarks 2015-10-04 20:26:12 +02:00
wm4 c855ab5624 player: add wav to list of external audio file extensions
Fixes #2378.
2015-10-04 19:48:58 +02:00
wm4 3ccac74de2 video: remove codec delay estimation
This was used only by the timestamp sorting code, which is a fallback
for avi files (as well as avi-muxed mkv files). This was supposed to
prevent accumulating timestamps in case the decoder consumes more
packets than it outputs frames (i.e. frames are dropped). This didn't
work very well (timestamps could be off by a large amount), the
estimation of the delay was fragile, and the interdependencies with the
decoder were annoying, so kill it.
2015-10-03 22:10:44 +02:00
wm4 ee283843fa video: cosmetics: remove trailing whitespace 2015-10-03 21:21:27 +02:00
wm4 291f301c10 video/out: remove an unused parameter
This parameter has been unused for years (the last flag was removed in
commit d658b115). Get rid of it.

This affects the general VO API, as well as the vo_opengl backend API,
so it touches a lot of files.

The VOFLAGs are still used to control OpenGL context creation, so move
them to the OpenGL backend code.
2015-10-03 18:20:16 +02:00
wm4 e448e10fd7 vo: change some defines to enums
Why not.
2015-10-02 18:49:35 +02:00
wm4 e72ca08554 vo_opengl: drop old backend API 2015-10-02 18:49:35 +02:00
wm4 e87f705497 vo_opengl: rpi: switch to new internal API 2015-10-02 18:33:09 +02:00
wm4 93db4233af win32: cleanup: remove some unneeded things 2015-10-02 18:14:00 +02:00
wm4 fe993a6712 vo_opengl: w32: switch to new internal API 2015-10-02 18:10:58 +02:00
wm4 69bc7e34b9 vo_opengl: refactor DwmFlush crap
Get it out of the way in the common code. MPGLContext.dwm_flush_opt can
be removed as well as soon as the option system gets overhauled.
2015-10-02 17:59:05 +02:00
Emmanuel Gil Peyrot a9ed9e329c vo_opengl: remove leftover variable from vaglx in vaegl
This was preventing compilation on systems without X11 headers.
2015-10-02 03:49:02 +01:00
Emmanuel Gil Peyrot 8a21cb1cd3 vo: fix compilation failure when vaapi is enabled and x11 disabled
This was previously trying to use the video_output_vaapi symbol despite
vo_vaapi.c being guarded by the vaapi-x11 option.
2015-10-02 03:21:51 +01:00
wm4 bd87598af9 vo_opengl: wayland: switch to new internal API 2015-10-01 22:57:02 +02:00
wm4 f4d62da8f0 vo_opengl: cocoa: switch to new internal API 2015-10-01 22:42:25 +02:00
wm4 ae7212963e cue: read more metadata
Make handling of metadata slightly more generic, and add reading of the
"PERFORMER" fields. There are some more fields, but for now let's leave
it at this.

TRACK-specific PERFORMER fields have to be read from the per-chapter
metadata (somewhat obscure).

Fixes #2328.
2015-10-01 21:57:35 +02:00
wm4 24f34c9e8e player: print tags under different log prefix
A minor, but apparently common feature request. Fixes #2360.
2015-10-01 21:10:59 +02:00
wm4 98c4ab6d13 vo_opengl: make sw suboption work without explicit backend selection
You needed to select a GL backend with the backend suboption. This was
confusing.

Fixes #2361.
2015-10-01 20:57:29 +02:00
wm4 4a07205963 vo_opengl: debanding requires GLSL 1.30
We have to disable it, or shader compilation will fail.

Fixes #2362.
2015-10-01 20:44:39 +02:00
wm4 7c5f41ff5f x11: separate window creation and configuration
This gets rid of an old hack, VOFLAG_HIDDEN. Although handling of it has
been sane for a while, it used to cause much pain, and is still
unintuitive and weird even today.

The main reason for this hack is that OpenGL selects a X11 Visual for
you, and you're supposed to use this Visual when creating the X window
for the OpenGL context. Which means the X window can't be created early
in the common X11 init code, but the OpenGL code needs to do something
before that. API-wise you need separate functions for X11 init and X11
window creation. The VOFLAG_HIDDEN hack conflated window creation and
the entrypoint for resizing on video resolution change into one
function, vo_x11_config_vo_window(). This required all platform backends
to handle this flag, even if they didn't need this mechanism.

Wayland still uses this for minor reasons (alpha support?), so the
wayland backend must be changed before the flag can be entirely removed.
2015-09-30 23:31:34 +02:00
wm4 a2a2cdb5bc vo_opengl: cosmetics: coding style 2015-09-30 23:05:42 +02:00
wm4 41bf41e416 vo_opengl: do not reset video queue when changing video equalizer
If interpolation is enabled, then this causes heavy artifacts if done
while unpaused. It's preferable to allow a latency of a few frames for
the change to take full effect instead. If this is done paused, the
frame is fully redrawn anyway.
2015-09-30 22:59:34 +02:00
wm4 ebb43f5176 Revert "vo_x11: remove this video output"
This reverts commit d11184a256.

Unfortunately, there was a lot of unexpected resistance.

Do note that this is still extremely slow, crappy, etc.

Note that vo_x11.c was further edited. Compared to the removed vo_x11.c,
an additional ~200 lines of code was removed in order to simplify it. I
tried to strip it down as much as possible. In particular, support for
odd non-32 bit formats (24, 16, 15, 8 bit) is dropped.

Closes #2300.
2015-09-30 22:52:22 +02:00
wm4 aff6e8e8da stream: minor cleanup to verbose logging
Don't print the URL that is opened twice. stream.c and stream_lavf.c
each printed it once. Remove the logging from stream_lavf.c, and move
the log call to a more interesting point.
2015-09-30 22:51:37 +02:00
ChrisK2 1b7e8ff6c5 ytdl: Don't override user-set format in no-video mode 2015-09-30 22:28:01 +02:00
wm4 739452361f manpage: adjustments to hwdec remarks 2015-09-29 21:14:56 +02:00
wm4 ee63c9c210 video: replace vf_format outputlevels option with global option
The vf_format suboption is replaced with --video-output-levels (a global
option and property). In particular, the parameter is removed from
mp_image_params. The mechanism is moved to the "video equalizer", which
also handles common video output customization like brightness and
contrast controls.

The new code is slightly cleaner, and the top-level option is slightly
more user-friendly than as vf_format sub-option.
2015-09-29 21:12:26 +02:00
wm4 b4491c00c4 Take care of libavcodec convergence_duration deprecation
This AVPacket field was a hack against the fact that the duration field
was merely an int (too small for things like subtitle durations). Newer
libavcodec drops this field and makes duration 64 bit.
2015-09-29 18:43:28 +02:00
wm4 12cd48a8a9 Revert "vd_lavc: do not abort hardware decoding on errors"
This essentially reverts commit 009dfbe3. FFmpeg VideoToolbox support
is being wacky, and can cause major issues, such as not being able
to decode a single frame. (E.g. by playing a .ts file. This should be
fixed in FFmpeg eventually.)

This is not a straight revert of the commit; just a functional one. We
keep the slightly simpler code structure.
2015-09-28 22:31:47 +02:00
wm4 31316e9ca0 vo_opengl: videotoolbox: cleanups
Get rid of the VDA specifics like naming or ancient pixel formats.
2015-09-28 22:11:04 +02:00
wm4 853fe788f8 vo_opengl: rename hwdec_vda.c to hwdec_osx.c
It doesn't deal with VDA at all anymore. Rename it to hwdec_osx.c. Not
using hwdec_videotoolbox.c, because that would give it the longest
source path in this project yet. (Also, this code isn't even
VideoToolox-specific, other than the name of the pixel format used.)
2015-09-28 22:03:14 +02:00
wm4 1dd7b7bddc video: remove VDA support
VideoToolbox is preferred. Now that FFmpeg released 2.8, there's no
reason to support VDA anymore. In fact, we had a bug that made VDA not
useable with older FFmpeg versions in some newer mpv releases.

VideoToolbox is supported even on slightly older OSX versions, and if
not, you still can run mpv without hw decoding.
2015-09-28 22:03:14 +02:00
wm4 15ef9f9ee6 vd_lavc: remove some ancient cargo-culting
Definitely not needed anymore, and fixes a crash in some weird corner-
cases.

The extradata freeing is apparently still needed, though. (Because a
codec context can be opened again, which makes no sense, but ok.)
2015-09-28 22:03:14 +02:00
wm4 ad2ab5893e ao_alsa: improve handling of device disconnection
This can happen with USB audio. There was already code for this, but
something in mpv and ALSA changed - and now the old code is not
necessarily triggered anymore. It probably depends on the exact
situation.
2015-09-28 22:03:14 +02:00
wm4 144571da9b ao_coreaudio_utils: fix error handling in device listing code
This could sometimes cause crashes in hotplug events. (Apparently in
cases when CoreAudio changes its state asynchronously, or such.)

CA_GET_STR() does not set the string if there was an error, so errors
have to be strictly checked before using it.
2015-09-28 22:03:14 +02:00
wm4 8aa8417aa3 vo_opengl: vaapi: add Wayland support
Pretty trivial with the new EGL interop.

Fixes #478.
2015-09-27 21:38:45 +02:00
wm4 1fa674c109 vo_opengl: refactor EGL context information callback
Move the ugliness from x11egl.c to common.c, so that the ugliness
doesn't have to be duplicated in wayland.c.
2015-09-27 21:34:11 +02:00
wm4 710872bc22 vaapi: remove dependency on X11
There are at least 2 ways of using VAAPI without X11 (Wayland, DRM).
Remove the X11 requirement from the decoder part and the EGL interop.
This will be used by a following commit, which adds Wayland support.

The worst about this is the decoder part, which includes a bad hack for
using the decoder without any VO interop (also known as "vaapi-copy"
mode). Separate the X11 parts so that they're self-contained. For the
EGL interop code we do something similar (it's kept slightly simpler,
because it essentially only has to translate between our silly
MPGetNativeDisplay abstraction and the vaGetDisplay...() call).
2015-09-27 21:33:15 +02:00
wm4 1ff32236fa manpage: fix broken example
Fixes #2353.
2015-09-27 19:21:37 +02:00
wm4 2a7811176c vo_opengl: vaapi: provide symbols for missing extensions
We also could just check at build time, but since it's not much, just
redefine them inline if not present.
2015-09-27 16:25:03 +02:00
wm4 2e5df94f0f vo_opengl: vaapi: redo how EGL extensions are loaded
It looks like my hope that we can unconditionally include EGL headers in
the OpenGL code is not coming true, because OSX does not support EGL at
all. So I prefer loading the VAAPI EGL/GL specific extensions manually,
because it's less of a mess. Partially reverts commit d47dff3f.
2015-09-27 16:18:06 +02:00
wm4 0c494c238a vo_opengl: rpi: fix EGL comment
While EGL 1.4 seemed a bit ambiguous about this to me, it actually says
quite clearly that core functions are not supported with
eglGetProcAddress() in the following paragraph.
2015-09-27 16:07:18 +02:00
wm4 375886c777 vo_opengl: probe for EGL by default
Normally, we prefer GLX on X11. But for the VAAPI EGL interop, we
obviously want EGL. Since nvidia does not provide EGL with desktop GL
yet, we can leave it to the autoprobing. Just make sure some failure
messages don't unnecessarily show up in the nvidia case.

This breaks VAAPI GLX interop by default, but I don't care much. If
you use --hwdec=auto (which you should if you want hw decoding), this
should fallback to vaapi-copy instead.
2015-09-26 20:52:10 +02:00
wm4 0aa548457f vo_opengl: x11egl: cleanup uninit path
Get rid of the config_window_x11_egl() indirection.
2015-09-26 20:52:10 +02:00
wm4 e0cb65e8ac vo_opengl: vaapi: probe the surface format
Probe the surface format, and check whether it's really something we
support. This also does a complete check whether the EGL interop works
at all (the only way to find this out is actually running this code).
Also, support YV12. Under some circumstances, vaapi (with Intel
drivers) can be made to use this format.

Unfortunately, the Intel drivers show some very weird behavior, which
is hopefully a bug. insane_hack() provides a very evil workaround (see
comments). A proper solution might be passing the hw format as part of
mp_image_params, but as long as hw surfaces appear to be able to change
the format on the fly, attempting this is probably not worth the extra
complexity and likely fragility. The hack allows us to pretend that
there is sane behavior for now.
2015-09-26 20:52:10 +02:00
wm4 6875e6a779 wscript: add missing entry to help output
Fixes #2344.
2015-09-25 20:50:04 +02:00
wm4 ac5538c7df vaapi: use GPU memcpy for reading back from HW surface
This makes it much faster if the surface is really mapped from GPU
memory. It's slightly slower than system memcpy if used on system
memory. We don't really know definitely in which type of memory
it's located, so we use the GPU memcpy in all cases.

Fixes #2317.
2015-09-25 19:18:16 +02:00
wm4 0ae8aebb89 video: refactor GPU memcpy usage
Make the GPU memcpy from the dxva2 code generally useful to other parts
of the player.

We need to check at configure time whether SSE intrinsics work at all.
(At least in this form, they won't work on clang, for example. It also
won't work on non-x86.)

Introduce a mp_image_copy_gpu(), and make the dxva2 code use it. Do some
awkward stuff to share the existing code used by mp_image_copy(). I'm
hoping that FFmpeg will sooner or later provide a function like this, so
we can remove most of this again. (There is a patch, bit it's stuck in
limbo since forever.)

All this is used by the following commit.
2015-09-25 19:18:16 +02:00
Philip Langdale 361040f9d9 vd_lavc: Fix recovery from vdpau preemption
Flushing buffers, and thereby triggering decoder reinitialisation
needs to happen before attempting, and failing, to decode.
2015-09-25 17:29:44 +02:00
wm4 d2281935b3 vo_rpi, wayland: fix build
Broken by commit d47dff3f. If something is going to include EGL.h,
header_fixes.h has to know. This definitely affected vo_rpi, and
probably affects wayland builds (with x11egl didabled) as well.
2015-09-25 16:02:15 +02:00
wm4 0a6c334b59 vo_opengl: vaapi: undo vaAcquireBufferHandle() correctly on error
Checking and resetting the VAImage.buf field is non-sense, even if it
happened to work out in the normal case. buf is actually freed when
vaDestroyImage() is called (not quite intuitive), and we need an extra
field to know whether vaReleaseBufferHandle() has to be called.
2015-09-25 12:14:19 +02:00
wm4 38b747bb67 vaapi: cosmetics, minor fixes
Printing "Using vaDeriveImage()" every frame is too verbose, so raise
the log level.

mp_image strides are in int and not unsigned int; fix this. It's not
like it actually matters, though.

Finish a comment.
2015-09-25 12:10:43 +02:00
wm4 993bee38ca vo_opengl: vaapi: handle YV12 correctly
This specific FourCC has its planes swapped compared to FFmpeg yuv420p.
2015-09-25 12:07:20 +02:00
wm4 0b87bf9b72 vo_opengl: vaapi: document DRM fourcc upstream defines
Add the upstream symbolic names as comments. Normally, these should be
defined in libdrm's drm_fourcc.h header. But DRM_FORMAT_R8 and
DRM_FORMAT_GR88 are not defined anywhere, except in the kernel userland
headers of Linux 4.3 (!). We don't want mpv to depend on bleeding-edge
Linux kernel headers, so this will have to do.

Also, just for completeness, add fourccs for the 3 and 4 channel
formats. I didn't manage to test them, though.
2015-09-25 12:03:36 +02:00
wm4 456366b63b vo_opengl: vaapi: use dummy image to determine plane layout
Reduces the amount of hardcoded assumptions about the layout
drastically. (Now adding yuv420 support would be just adjusting an if,
if you ignore the other problems, such as determining the hw format at
all early enough.)
2015-09-25 10:22:10 +02:00
wm4 ec356d3efe vo_opengl: vaapi: remove unnecessary loop
Not sure what I was thinking.
2015-09-25 10:03:17 +02:00
wm4 5786d07450 vo_opengl: vaapi: fix cleanup
Don't call eglDestroyImageKHR() on the same ID possibly more than once.

Clear the image reference on termination, or we would leak up to 1 image
per VO recreation.
2015-09-25 10:02:54 +02:00
wm4 8d8a2045bd vo_opengl: support new VAAPI EGL interop
Should work much better than the old GLX interop code. Requires Mesa 11,
and explicitly selecting the X11 EGL backend with:

    --vo=opengl:backend=x11egl

Should it turn out that the new interop works well, we will try to
autodetect EGL by default.

This code still uses some bad assumptions, like expecting surfaces to be
in NV12. (This is probably ok, because virtually all HW will use this
format. But we should at least check this on init or so, instead of
failing to render an image if our assumption doesn't hold up.)

This repo was a lot of help: https://github.com/gbeauchesne/ffvademo
The kodi code was also helpful (the magic FourCC it uses for
EGL_LINUX_DRM_FOURCC_EXT are nowhere documented, and
EGL_IMAGE_INTERNAL_FORMAT_EXT as used in ffvademo does
not actually exist).

(This is the 3rd VAAPI GL interop that was implemented in this player.)
2015-09-25 00:26:19 +02:00
wm4 0e9cfa6b64 vo_opengl: add mechanism to retrieve Display from EGL context
The VAAPI EGL interop code will need access to the X11 Display. While
GLX could return it from the current GLX context, EGL has no such
mechanism. (At least no standard one supported by all implementations.)
So mpv makes up such a mechanism.

For internal purposes, this is very rather awkward solution, but it's
needed for libmpv anyway.
2015-09-25 00:20:11 +02:00
wm4 d47dff3faa vo_opengl: load certain EGL extensions needed for VAAPI EGL interop
These extensions use a bunch of EGL types, so we need to include the EGL
headers in common.h to use our GL function loader with this.

In the future, we should probably require presence of the EGL headers to
reduce the hacks. This might be not so simple at least with OSX, so for
now this has to do.
2015-09-25 00:19:58 +02:00
wm4 b81d9c79a8 vo_opengl: enable X11 EGL backend by default
Originally, this was disabled, because it was useless and I was afraid
it could possibly break autodetection and proper fallback.
2015-09-24 23:56:55 +02:00
wm4 57831d52dc vo_opengl: actually set hardware decoder mapped texture format
Surfaces used by hardware decoding formats can be mapped exactly like a
specific software pixel format, e.g. RGBA or NV12. p->image_params is
supposed to be set to this format, but it wasn't.

(How did this ever work?)

Also, setting params->imgfmt in the hwdec interop drivers is pointless
and redundant. (Change them to asserts, because why not.)
2015-09-24 23:48:57 +02:00
wm4 b14c9eb748 client API: rename GL_MP_D3D_interfaces
This is a pseudo-OpenGL extension for letting libmpv query native
windowing system handles from the API user. (It uses the OpenGL
extension mechanism because I'm lazy. In theory it would be nicer to let
the user pass them with mpv_opengl_cb_init_gl(), but this would require
a more intrusive API change to extend its argument list.)

The naming of the extension and associated function was unnecessarily
Windows specific (using "D3D"), even though it would work just fine for
other platforms. So deprecate the old names and introduce new ones. The
old ones still work.
2015-09-24 21:07:37 +02:00
wm4 cb1c072534 vo_opengl: remove sharpen scalers, add sharpen sub-option
This turns the old scalers (inherited from MPlayer) into a pre-
processing step (after color conversion and before scaling). The code
for the "sharpen5" scaler is reused for this.

The main reason MPlayer implemented this as scalers was perhaps because
FBOs were too expensive, and making it a scaler allowed to implement
this in 1 pass. But unsharp masking is not really a scaler, and I would
guess the result is more like combining bilinear scaling and unsharp
masking.
2015-09-23 22:43:27 +02:00
wm4 c17ff1703a vo_opengl: move deband_opts declaration to where it's used
At least one thing the current option code can do right.
2015-09-23 22:21:59 +02:00
wm4 65ad85790a vo_opengl: remove unsued chroma_location field
This was redundant to forcing the value with vf_format, so the vo_opengl
sub-option was removed. This field is just a leftover.
2015-09-23 22:16:36 +02:00
wm4 17cd6798a6 vo_opengl: move shader file caching to video.c
It's just about loading and cachign small files, not does not
necessarily have anything to do with shaders. Move it to video.c where
it's used.
2015-09-23 22:13:03 +02:00
wm4 d8d4e18835 player: fix another --force-window bug
Will this shit ever actually work?

Fixes #2339.
2015-09-23 22:03:11 +02:00
wm4 009dfbe3b6 vd_lavc: do not abort hardware decoding on errors
Usually, libavcodec ignores errors reported by the hardware decoding
API, so it's not like we can actually escape if the hardware is somehow
acting up.

For normal fallback purposes, or if parts of the hw decoding API which
we actually check fails, we do this by setting and checking the
hwdec_failed flag anyway.
2015-09-23 20:37:47 +02:00
wm4 2ed9370bd6 vf_vavpp: allocate output surfaces with the same size as input
This can happen if the hw decoder allocates padded surfaces (e.g.
mod16), but the VPP output surface was allocated with the exact size.
Apparently VPP requires matching input and output sizes, or it will add
artifacts. In this case, it added mirrored pixels to the bottom few
pixels.

Note that the previous commit should have fixed this. But it didn't
work, while this commit does.

Fixes #2320.
2015-09-23 14:20:50 +02:00
wm4 e0c005cb75 va_vavpp: set input/output processing region
If not set, VPP will use the whole surface. This is a problem if the
surfaces are padded, and especially if the surfaces are padded by
different amounts.

This is an attempt to fix #2320, but it appears to do nothing at all.
2015-09-23 14:20:50 +02:00
wm4 4d6c1be7b6 vd_lavc: minor cleanup to hwdec fallback code
The comment was largely outdated, and described the old situation when
we used a "violent" fallback by making get_buffer2 fail completely.

Also, for the case when the hw decoder initialization succeeded (in
get_format), but get_buffer2 for some reason requests something
unexpected, we also can fallback more gracefully and in the same way.
2015-09-23 14:20:50 +02:00
151 changed files with 3249 additions and 1596 deletions

No files matched your search

+5
View File
@@ -32,7 +32,12 @@ API changes
::
--- mpv 0.12.0 ---
1.20 - deprecate "GL_MP_D3D_interfaces"/"glMPGetD3DInterface", and introduce
"GL_MP_MPGetNativeDisplay"/"glMPGetNativeDisplay" (this is a
backwards-compatible rename)
--- mpv 0.11.0 ---
--- mpv 0.10.0 ---
1.19 - add "GL_MP_D3D_interfaces" pseudo extension to make it possible to
use DXVA2 in OpenGL fullscreen mode in some situations
- mpv_request_log_messages() now accepts "terminal-default" as parameter
+99 -20
View File
@@ -1,35 +1,114 @@
Client API examples
===================
# Client API examples
All these examples use the mpv client API through libmpv.
cocoa
-----
## Where are the docs?
The libmpv C API is documented directly in the header files (on normal Unix
systems, this is in `/usr/include/mpv/client.h`.
libmpv merely gives you access to mpv's command interface, which is documented
here:
* Options (`mpv_set_option()` and friends): http://mpv.io/manual/master/#options
* Commands (`mpv_command()` and friends): http://mpv.io/manual/master/#list-of-input-commands
* Properties (`mpv_set_property()` and friends): http://mpv.io/manual/master/#properties
Essentially everything is done with them, including loading a file, retrieving
playback progress, and so on.
## Methods of embedding the video window
All of these examples concentrate on how to integrate mpv's video renderers
with your own GUI. This is generally the hardest part. libmpv enforces a
somewhat efficient video output method, rather than e.g. returning a RGBA
surface in memory for each frame. The latter would be prohibitively inefficient,
because it would require conversion on the CPU. The goal is also not requiring
the API users to reinvent their own video rendering/scaling/presentation
mechanisms.
There are currently 2 methods of embedding video.
### Native window embedding
This uses the platform's native method of nesting multiple windows. For example,
Linux/X11 can nest a window from a completely different process. The nested
window can redraw contents on its own, and receive user input if the user
interacts with this window.
libmpv lets you specify a parent window for its own video window via the `wid`
option. Then libmpv will create its window with your window as parent, and
render its video inside of it.
This method is highly OS-dependent. Some behavior is OS-specific. There are
problems with focusing on X11 (the ancient X11 focus policy mismatches with
that of modern UI toolkits - it's normally worked around, but this is not
easily possible with raw window embedding). It seems to have stability problems
on OSX when using the Qt toolkit.
### OpenGL embedding
This method lets you use libmpv's OpenGL renderer directly. You create an
OpenGL context, and then use `mpv_opengl_cb_draw()` to render the video on
each frame.
This is more complicated, because libmpv will work directly on your own OpenGL
state. It's also not possible to have mpv automatically receive user input.
You will have to simulate this with the `mouse`/`keypress`/`keydown`/`keyup`
commands.
You also get much more flexibility. For example, you can actually render your
own OSD on top of the video, something that is not possible with raw window
embedding.
### Which one to use?
Due to the various platform-specific behavior and problems (in particular on
OSX), OpenGL embedding is recommended. If you're not comfortable with requiring
OpenGL, or want to support "direct" video output such as vdpau (which might
win when it comes to performance and energy-saving), you should probably
support both methods if possible.
## List of examples
### simple
Very primitive terminal-only example. Shows some most basic API usage.
### cocoa
Shows how to embed the mpv video window in Objective-C/Cocoa.
qt
--
### cocoa-openglcb
Similar to the cocoa sample, but shows how to integrate mpv's OpenGL renderer
using libmpv's opengl-cb API. Since it does not require complicated interaction
with Cocoa elements from different libraries, it's more robust.
### qt
Shows how to embed the mpv video window in Qt (using normal desktop widgets).
qml
---
### qt_opengl
Shows how to use mpv's OpenGL video renderer in QtQuick2 with QML.
Shows how to use mpv's OpenGL video renderer in Qt. This uses the opengl-cb API
for video. Since it does not rely on embedding "foreign" native Windows, it's
usually more robust, potentially faster, and it's easier to control how your
GUI interacts with the video. You can do your own OpenGL rendering on top of
the video as well.
qml_direct
----------
### qml
Shows how to use mpv's OpenGL video renderer in QtQuick2 with QML. Uses the
opengl-cb API for video. Since the video is a normal QML element, it's trivial
to create OSD overlays with QML-native graphical elements as well.
### qml_direct
Alternative example, which typically avoids a FBO indirection. Might be
slightly faster, but is less flexible and harder to use.
slightly faster, but is less flexible and harder to use. In particular, the
video is not a normal QML element. Uses the opengl-cb API for video.
sdl
---
### sdl
Show how to embed the mpv OpenGL renderer in SDL.
simple
------
Very primitive terminal-only example. Shows some most basic API usage.
Show how to embed the mpv OpenGL renderer in SDL. Uses the opengl-cb API for
video.
+1 -1
View File
@@ -50,7 +50,7 @@ Item {
text: "Make video look like on a Smart TV"
onClicked: {
if (checkbox.checked) {
renderer.command(["vo_cmdline", "scale=sharpen3:scale-param1=5.0"])
renderer.command(["vo_cmdline", "sharpen=5.0"])
} else {
renderer.command(["vo_cmdline", ""])
}
@@ -0,0 +1,13 @@
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Qt sets the locale in the QApplication constructor, but libmpv requires
// the LC_NUMERIC category to be set to "C", so change it back.
setlocale(LC_NUMERIC, "C");
MainWindow w;
w.show();
return a.exec();
}
@@ -0,0 +1,53 @@
#include "mainwindow.h"
#include "mpvwidget.h"
#include <QPushButton>
#include <QSlider>
#include <QLayout>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
m_mpv = new MpvWidget(this);
m_slider = new QSlider();
m_slider->setOrientation(Qt::Horizontal);
m_openBtn = new QPushButton("Open");
m_playBtn = new QPushButton("Pause");
QHBoxLayout *hb = new QHBoxLayout();
hb->addWidget(m_openBtn);
hb->addWidget(m_playBtn);
QVBoxLayout *vl = new QVBoxLayout();
vl->addWidget(m_mpv);
vl->addWidget(m_slider);
vl->addLayout(hb);
setLayout(vl);
connect(m_slider, SIGNAL(sliderMoved(int)), SLOT(seek(int)));
connect(m_openBtn, SIGNAL(clicked()), SLOT(openMedia()));
connect(m_playBtn, SIGNAL(clicked()), SLOT(pauseResume()));
connect(m_mpv, SIGNAL(positionChanged(int)), m_slider, SLOT(setValue(int)));
connect(m_mpv, SIGNAL(durationChanged(int)), this, SLOT(setSliderRange(int)));
}
void MainWindow::openMedia()
{
QString file = QFileDialog::getOpenFileName(0, "Open a video");
if (file.isEmpty())
return;
m_mpv->command(QStringList() << "loadfile" << file);
}
void MainWindow::seek(int pos)
{
m_mpv->command(QVariantList() << "seek" << pos << "absolute");
}
void MainWindow::pauseResume()
{
const bool paused = m_mpv->getProperty("pause").toBool();
m_mpv->setProperty("pause", !paused);
}
void MainWindow::setSliderRange(int duration)
{
const int time0 = m_mpv->getProperty("time-start").toInt();
m_slider->setRange(time0, time0+duration);
}
@@ -0,0 +1,27 @@
#ifndef MainWindow_H
#define MainWindow_H
#include <QtWidgets/QWidget>
class MpvWidget;
class QSlider;
class QPushButton;
class MainWindow : public QWidget
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
public Q_SLOTS:
void openMedia();
void seek(int pos);
void pauseResume();
private Q_SLOTS:
void setSliderRange(int duration);
private:
MpvWidget *m_mpv;
QSlider *m_slider;
QPushButton *m_openBtn;
QPushButton *m_playBtn;
};
#endif // MainWindow_H
@@ -0,0 +1,129 @@
#include "mpvwidget.h"
#include <stdexcept>
#include <QtGui/QOpenGLContext>
#include <QtCore/QMetaObject>
static void wakeup(void *ctx)
{
QMetaObject::invokeMethod((MpvWidget*)ctx, "on_mpv_events", Qt::QueuedConnection);
}
static void *get_proc_address(void *ctx, const char *name) {
Q_UNUSED(ctx);
QOpenGLContext *glctx = QOpenGLContext::currentContext();
if (!glctx)
return NULL;
return (void *)glctx->getProcAddress(QByteArray(name));
}
MpvWidget::MpvWidget(QWidget *parent, Qt::WindowFlags f)
: QOpenGLWidget(parent, f)
{
mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
if (!mpv)
throw std::runtime_error("could not create mpv context");
mpv_set_option_string(mpv, "terminal", "yes");
mpv_set_option_string(mpv, "msg-level", "all=v");
if (mpv_initialize(mpv) < 0)
throw std::runtime_error("could not initialize mpv context");
// Make use of the MPV_SUB_API_OPENGL_CB API.
mpv::qt::set_option_variant(mpv, "vo", "opengl-cb");
// Request hw decoding, just for testing.
mpv::qt::set_option_variant(mpv, "hwdec", "auto");
mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB);
if (!mpv_gl)
throw std::runtime_error("OpenGL not compiled in");
mpv_opengl_cb_set_update_callback(mpv_gl, MpvWidget::on_update, (void *)this);
connect(this, SIGNAL(frameSwapped()), SLOT(swapped()));
mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
mpv_set_wakeup_callback(mpv, wakeup, this);
}
MpvWidget::~MpvWidget()
{
makeCurrent();
if (mpv_gl)
mpv_opengl_cb_set_update_callback(mpv_gl, NULL, NULL);
// Until this call is done, we need to make sure the player remains
// alive. This is done implicitly with the mpv::qt::Handle instance
// in this class.
mpv_opengl_cb_uninit_gl(mpv_gl);
}
void MpvWidget::command(const QVariant& params)
{
mpv::qt::command_variant(mpv, params);
}
void MpvWidget::setProperty(const QString& name, const QVariant& value)
{
mpv::qt::set_property_variant(mpv, name, value);
}
QVariant MpvWidget::getProperty(const QString &name) const
{
return mpv::qt::get_property_variant(mpv, name);
}
void MpvWidget::initializeGL()
{
int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL);
if (r < 0)
throw std::runtime_error("could not initialize OpenGL");
}
void MpvWidget::paintGL()
{
mpv_opengl_cb_draw(mpv_gl, QOpenGLContext::currentContext()->defaultFramebufferObject(), width(), -height());
}
void MpvWidget::swapped()
{
mpv_opengl_cb_report_flip(mpv_gl, 0);
}
void MpvWidget::on_mpv_events()
{
// Process all events, until the event queue is empty.
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE) {
break;
}
handle_mpv_event(event);
}
}
void MpvWidget::handle_mpv_event(mpv_event *event)
{
switch (event->event_id) {
case MPV_EVENT_PROPERTY_CHANGE: {
mpv_event_property *prop = (mpv_event_property *)event->data;
if (strcmp(prop->name, "time-pos") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double *)prop->data;
Q_EMIT positionChanged(time);
}
} else if (strcmp(prop->name, "duration") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double *)prop->data;
Q_EMIT durationChanged(time);
}
}
break;
}
default: ;
// Ignore uninteresting or unknown events.
}
}
void MpvWidget::on_update(void *ctx)
{
QMetaObject::invokeMethod((MpvWidget*)ctx, "update");
}
@@ -0,0 +1,38 @@
#ifndef PLAYERWINDOW_H
#define PLAYERWINDOW_H
#include <QtWidgets/QOpenGLWidget>
#include <mpv/client.h>
#include <mpv/opengl_cb.h>
#include <mpv/qthelper.hpp>
class MpvWidget Q_DECL_FINAL: public QOpenGLWidget
{
Q_OBJECT
public:
MpvWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
~MpvWidget();
void command(const QVariant& params);
void setProperty(const QString& name, const QVariant& value);
QVariant getProperty(const QString& name) const;
QSize sizeHint() const { return QSize(480, 270);}
Q_SIGNALS:
void durationChanged(int value);
void positionChanged(int value);
protected:
void initializeGL() Q_DECL_OVERRIDE;
void paintGL() Q_DECL_OVERRIDE;
private Q_SLOTS:
void swapped();
void on_mpv_events();
private:
void handle_mpv_event(mpv_event *event);
static void on_update(void *ctx);
mpv::qt::Handle mpv;
mpv_opengl_cb_context *mpv_gl;
};
#endif // PLAYERWINDOW_H
@@ -0,0 +1,13 @@
CONFIG -= app_bundle
QT += widgets
QT_CONFIG -= no-pkg-config
CONFIG += link_pkgconfig debug
PKGCONFIG += mpv
HEADERS = \
mpvwidget.h \
mainwindow.h
SOURCES = main.cpp \
mpvwidget.cpp \
mainwindow.cpp
+11
View File
@@ -19,6 +19,17 @@ Interface changes
::
--- mpv 0.12.0 ---
- remove --use-text-osd (useless; fontconfig isn't a requirement anymore,
and text rendering is also lazily initialized)
- some time properties (at least "playback-time", "time-pos",
"time-remaining", "playtime-remaining") now are unavailable if the time
is unknown, instead of just assuming that the internal playback position
is 0
- add --audio-fallback-to-null option
- replace vf_format outputlevels suboption with "video-output-levels" global
property/option; also remove "colormatrix-output-range" property
- vo_opengl: remove sharpen3/sharpen5 scale filters, add sharpen sub-option
--- mpv 0.11.0 ---
- add "af-metadata" property
--- mpv 0.10.0 ---
+1 -1
View File
@@ -164,7 +164,7 @@ Available filters are:
.. admonition:: Examples
``mpv --af=channels=4:[0-1,1-0,0-2,1-3] media.avi``
``mpv --af=channels=4:[0-1,1-0,2-2,3-3] media.avi``
Would change the number of channels to 4 and set up 4 routes that
swap channel 0 and channel 1 and leave channel 2 and 3 intact.
Observe that if media containing two channels were played back,
+2 -5
View File
@@ -1171,9 +1171,6 @@ Property list
is loaded, or when switching ordered chapter segments. This is because
the same underlying code is used for seeking and resyncing.)
``pts-association-mode`` (RW)
See ``--pts-association-mode``.
``hr-seek`` (RW)
See ``--hr-seek``.
@@ -1260,8 +1257,8 @@ Property list
``colormatrix-input-range`` (R)
See ``colormatrix``.
``colormatrix-output-range`` (R)
See ``colormatrix``.
``video-output-levels`` (RW)
See ``--video-output-levels``,
``colormatrix-primaries`` (R)
See ``colormatrix``.
+67 -36
View File
@@ -456,16 +456,13 @@ Program Behavior
If the script can't do anything with an URL, it will do nothing.
(Note: this is the replacement for the now removed libquvi support.)
``--ytdl-format=<best|worst|mp4|webm|...>``
Video format/quality that is directly passed to youtube-dl. The possible
values are specific to the website and the video, for a given url the
available formats can be found with the command
``youtube-dl --list-formats URL``. See youtube-dl's documentation for
available aliases. To use experimental DASH support for youtube, use
``bestvideo+bestaudio``.
(Default: ``best``)
available aliases.
(Default: youtube-dl's default, currently ``bestvideo+bestaudio/best``)
``--ytdl-raw-options=<key>=<value>[,<key>=<value>[,...]]``
Pass arbitrary options to youtube-dl. Parameter and argument should be
@@ -567,12 +564,11 @@ Video
:no: always use software decoding (default)
:auto: see below
:vdpau: requires ``--vo=vdpau`` or ``--vo=opengl`` (Linux only)
:vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux with Intel GPUs only)
:vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux only)
:vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only)
:vda: requires ``--vo=opengl`` (OS X only)
:videotoolbox: requires ``--vo=opengl`` (newer OS X only)
:videotoolbox: requires ``--vo=opengl`` (OS X 10.8 and up only)
:dxva2-copy: copies video back to system RAM (Windows only)
:rpi: requires ``--vo=rpi`` (Raspberry Pi only - default if available)
:rpi: requires ``--vo=rpi`` (Raspberry Pi only - default if available)
``auto`` tries to automatically enable hardware decoding using the first
available method. This still depends what VO you are using. For example,
@@ -581,6 +577,12 @@ Video
work, it will always fall back to software decoding, instead of trying the
next method (might matter on some Linux systems).
The ``vaapi`` mode, if used with ``--vo=opengl``, requires Mesa 11 and most
likely works with Intel GPUs only. It also requires the opengl EGL backend
(automatically used if available). You can also try the old GLX backend by
forcing it with ``--vo=opengl:backend=x11``, but the vaapi/GLX interop is
said to be slower than ``vaapi-copy``.
The ``vaapi-copy`` mode allows you to use vaapi with any VO. Because
this copies the decoded video back to system RAM, it's likely less efficient
than the ``vaapi`` mode.
@@ -775,6 +777,26 @@ Video
For audio-only playback, any value greater than 0 will quit playback
immediately after initialization. The value 0 works as with video.
``--video-output-levels=<outputlevels>``
RGB color levels used with YUV to RGB conversion. Normally, output devices
such as PC monitors use full range color levels. However, some TVs and
video monitors expect studio RGB levels. Providing full range output to a
device expecting studio level input results in crushed blacks and whites,
the reverse in dim gray blacks and dim whites.
Not all VOs support this option. Some will silently ignore it.
Available color ranges are:
:auto: automatic selection (equals to full range) (default)
:limited: limited range (16-235 per component), studio levels
:full: full range (0-255 per component), PC levels
.. note::
It is advisable to use your graphics driver's color range option
instead, if available.
``--hwdec-codecs=<codec1,codec2,...|all>``
Allow hardware decoding for a given list of codecs only. The special value
``all`` always allows all codecs.
@@ -801,6 +823,10 @@ Video
The result is most likely broken decoding, but may also help if the
detected or reported profiles are somehow incorrect.
``--vd-lavc-software-fallback=<yes|no>``
Fallback to software decoding if the hardware-accelerated decoder fails
(default: yes).
``--vd-lavc-bitexact``
Only use bit-exact algorithms in all decoding steps (for codec testing).
@@ -892,6 +918,14 @@ Audio
Currently not implemented for most AOs.
``--audio-fallback-to-null=<yes|no>``
If no audio device can be opened, behave as if ``--ao=null`` was given. This
is useful in combination with ``--audio-device``: instead of causing an
error if the selected device does not exist, the client API user (or a
Lua script) could let playback continue normally, and check the
``current-ao`` and ``audio-device-list`` properties to make high-level
decisions about how to continue.
``--ao=<driver1[:suboption1[=value]:...],driver2,...[,]>``
Specify a priority list of audio output drivers to be used. For
interactive use one would normally specify a single one to use, but in
@@ -2441,14 +2475,14 @@ OSD
``--osd-duration=<time>``
Set the duration of the OSD messages in ms (default: 1000).
``--osd-font=<pattern>``, ``--sub-text-font=<pattern>``
``--osd-font=<name>``, ``--sub-text-font=<name>``
Specify font to use for OSD and for subtitles that do not themselves
specify a particular font. The default is ``sans-serif``.
.. admonition:: Examples
- ``--osd-font='Bitstream Vera Sans'``
- ``--osd-font='Bitstream Vera Sans:style=Bold'`` (fontconfig pattern)
- ``--osd-font='MS Comic Sans'``
.. note::
@@ -2456,6 +2490,9 @@ OSD
options) are ignored when ASS-subtitles are rendered, unless the
``--no-sub-ass`` option is specified.
This used to support fontconfig patterns. Starting with libass 0.13.0,
this stopped working.
``--osd-font-size=<size>``, ``--sub-text-font-size=<size>``
Specify the OSD/sub font size. The unit is the size in scaled pixels at a
window height of 720. The actual pixel size is scaled with the window
@@ -2636,17 +2673,6 @@ OSD
Default: 0.
``--use-text-osd=<yes|no>``
Disable text OSD rendering completely. (This includes the complete OSC as
well.) This is mostly useful for avoiding loading fontconfig in situations
where fontconfig does not behave well, and OSD is unused - this could for
example allow GUI programs using libmpv to workaround fontconfig issues.
Note that selecting subtitles of any kind still initializes fontconfig.
Default: ``no``.
Screenshot
----------
@@ -3245,6 +3271,13 @@ Network
Verify peer certificates when using TLS (e.g. with ``https://...``).
(Silently fails with older FFmpeg or Libav versions.)
``--tls-cert-file``
A file containing a certificate to use in the handshake with the
peer.
``--tls-key-file``
A file containing the private key for the certificate.
``--referrer=<string>``
Specify a referrer path or URL for HTTP requests.
@@ -3430,6 +3463,11 @@ Miscellaneous
:display-vdrop: Drop or repeat video frames to compensate desyncing
video. (Although it should have the same effects as
``audio``, the implementation is very different.)
:display-adrop: Drop or repeat audio data to compensate desyncing
video. See ``--video-sync-adrop-size``. This mode will
cause severe audio artifacts if the real monitor
refresh rate is too different from the reported or
forced rate.
:display-desync: Sync video to display, and let audio play on its own.
:desync: Sync video according to system clock, and let audio play
on its own.
@@ -3461,6 +3499,13 @@ Miscellaneous
frame dropping due to the audio "overshooting" and skipping multiple video
frames before the sync logic can react.
``--video-sync-adrop-size=<value``
For the ``--video-sync=display-adrop`` mode. This mode duplicates/drops
audio data to keep audio in sync with video. To avoid audio artifacts on
jitter (which would add/remove samples all the time), this is done in
relatively large, fixed units, controlled by this option. The unit is
seconds.
``--mf-fps=<value>``
Framerate used when decoding from multiple PNG or JPEG files with ``mf://``
(default: 1).
@@ -3502,20 +3547,6 @@ Miscellaneous
.. warning:: Using realtime priority can cause system lockup.
``--pts-association-mode=<decode|sort|auto>``
Select the method used to determine which container packet timestamp
corresponds to a particular output frame from the video decoder. Normally
you should not need to change this option.
:decoder: Use decoder reordering functionality. Unlike in classic MPlayer
and mplayer2, this includes a DTS fallback. (Default.)
:sort: Maintain a buffer of unused pts values and use the lowest value
for the frame.
:auto: Try to pick a working mode from the ones above automatically.
You can also try to use ``--no-correct-pts`` for files with completely
broken timestamps.
``--force-media-title=<string>``
Force the contents of the ``media-title`` property to this value. Useful
for scripts which want to set a title, without overriding the user's
-20
View File
@@ -259,26 +259,6 @@ Available filters are:
:limited: limited range (16-235 for luma, 16-240 for chroma)
:full: full range (0-255 for both luma and chroma)
``<outputlevels>``
RGB color levels used with YUV to RGB conversion. Normally, output devices
such as PC monitors use full range color levels. However, some TVs and
video monitors expect studio RGB levels. Providing full range output to a
device expecting studio level input results in crushed blacks and whites,
the reverse in dim gray blacks and dim whites.
The same limitations as with ``<colormatrix>`` apply.
Available color ranges are:
:auto: automatic selection (equals to full range) (default)
:limited: limited range (16-235 per component), studio levels
:full: full range (0-255 per component), PC levels
.. note::
It is advisable to use your graphics driver's color range option
instead, if available.
``<primaries>``
RGB primaries the source file was encoded with. Normally this should be set
in the file header, but when playing broken or mistagged files this can be
+28 -19
View File
@@ -20,13 +20,10 @@ normal driver parameters.
See ``--vo=help`` for a list of compiled-in video output drivers.
The recommended output drivers are ``--vo=vdpau`` and ``--vo=opengl-hq``.
All other drivers are just for compatibility or special purposes.
.. admonition:: Example
``--vo=opengl,xv,``
Try the ``opengl`` driver, then the ``xv`` driver, then others.
The recommended output driver is ``--vo=opengl-hq``. All other drivers are
for compatibility or special purposes. By default, ``--vo=opengl`` is used,
but if that appears not to work, it fallback to other drivers (in the same
order as listed by ``--vo=help``).
Available video output drivers are:
@@ -75,6 +72,12 @@ Available video output drivers are:
not responding quickly enough if video FPS is close to or higher than
the display refresh rate.
``x11`` (X11 only)
Shared memory video output driver without hardware acceleration that works
whenever X11 is present.
.. note:: This is a fallback only, and should not be normally used.
``vdpau`` (X11 only)
Uses the VDPAU interface to display and optionally also decode video.
Hardware decoding is used with ``--hwdec=vdpau``.
@@ -375,10 +378,6 @@ Available video output drivers are:
Scale parameter (``t``). Increasing this makes the result blurrier.
Defaults to 1.
sharpen3, sharpen5
Sharpening strength. Increasing this makes the image sharper but
adds more ringing and aliasing. Defaults to 0.5.
oversample
Minimum distance to an edge before interpolation is used. Setting
this to 0 will always interpolate edges, whereas setting it to 0.5
@@ -408,8 +407,8 @@ Available video output drivers are:
between 0.0 and 1.0. The default value of 0.0 disables antiringing
entirely.
Note that this doesn't affect the special filters ``bilinear``,
``bicubic_fast`` or ``sharpen``.
Note that this doesn't affect the special filters ``bilinear`` and
``bicubic_fast``.
``scale-window=<window>``
(Advanced users only) Choose a custom windowing function for the kernel.
@@ -612,11 +611,8 @@ Available video output drivers are:
``deband-iterations=<1..16>``
The number of debanding steps to perform per sample. Each step reduces
a bit more banding, but takes time to compute. Note that the strength
of each step falls off very quickly, so high numbers are practically
useless. (Default 4)
If the performance hit of debanding is too great, you can reduce this
to 2 or 1 with marginal visual quality loss.
of each step falls off very quickly, so high numbers (>4) are
practically useless. (Default 1)
``deband-threshold=<0..4096>``
The debanding filter's cut-off threshold. Higher numbers increase the
@@ -626,7 +622,10 @@ Available video output drivers are:
``deband-range=<1..64>``
The debanding filter's initial radius. The radius increases linearly
for each iteration. A higher radius will find more gradients, but
a lower radius will smooth more aggressively. (Default 8)
a lower radius will smooth more aggressively. (Default 16)
If you increase the ``deband-iterations``, you should probably
decrease this to compensate.
``deband-grain=<0..4096>``
Add some extra noise to the image. This significantly helps cover up
@@ -645,6 +644,16 @@ Available video output drivers are:
The slope of the sigmoid curve used for ``sigmoid-upscaling``, must
be a float between 1.0 and 20.0. Defaults to 6.5 if not specified.
``sharpen=<value>``
If set to a value other than 0, enable an unsharp masking filter.
Positive values will sharpen the image (but add more ringing and
aliasing). Negative values will blur the image. If your GPU is powerful
enough, consider alternatives like the ``ewa_lanczossharp`` scale
filter, or the ``scale-blur`` sub-option.
(This feature is the replacement for the old ``sharpen3`` and
``sharpen5`` scalers.)
``glfinish``
Call ``glFinish()`` before and after swapping buffers (default: disabled).
Slower, but might help getting better results when doing framedropping.
+2 -2
View File
@@ -187,7 +187,7 @@ only if discretion is required.
[windows_compilation]: https://github.com/mpv-player/mpv/blob/master/DOCS/compile-windows.md
[mplayer-changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/mplayer-changes.rst
## License
## License
[GPLv2](https://github.com/mpv-player/mpv/blob/master/LICENSE)
Mostly GPLv2 or later. See [details.](https://github.com/mpv-player/mpv/blob/master/Copyright)
+88
View File
@@ -1,3 +1,91 @@
Release 0.12.0
==============
NOTE: This release changes the default format for youtube-dl and removes some
workarounds related to MPEG DASH support. However, the required changes to
FFmpeg code are not in any FFmpeg release yet (as of 2015-10-29), so for now,
playing DASH streams requires using FFmpeg git master. You can work around
this by using the --ytdl-format=best option.
Features
--------
New
~~~
- vo_opengl: support new VAAPI EGL interop (requires Mesa 11)
- vo_opengl: vaapi: add Wayland support
- bring back the x11 video output
- vo_opengl: support all kinds of GBRP formats
Removed
~~~~~~~
- video: remove VDA support (VideoToolbox is preferred)
Behavior
--------
- vo_opengl: enable X11 EGL backend by default (disabled for NVIDIA due to driver bugs)
- ytdl: don't override user-set format in no-video mode
- sub: adjust behavior on mismatching video/subtitle aspect ratio
Options and Commands
--------------------
Added
~~~~~
- audio: add option for falling back to ao_null
- options: add support for client certificate authentication
- input: add key name for U+3000 IDEOGRAPHIC SPACE
- player: add audio drop/duplicate mode to video-sync
Changed
~~~~~~~
- vo_opengl: remove sharpen scalers, add sharpen sub-option
- vo_opengl: make sw suboption work without explicit backend selection
- command: make time properties unavailable if timestamp is unknown
- command: do not return 0 for bitrate if unknown (make property unavailable instead)
- vo_opengl: make the default debanding settings less excessive
- ytdl: disable --all-subs if "sub-lang" is in raw-options
Removed
~~~~~~~
- video: remove user-controllable PTS sorting (--pts-association-mode)
Fixes and Minor Enhancements
----------------------------
- player: fix another --force-window bug
- player: add wav to list of external audio file extensions
- ao_alsa: fix failure to find any sample format
- player: make stop command actually stop in all cases
- audio: various fixes related to audio device hotplugging
- vo_xv: fix crash with --wid
- ytdl: Remove DASH hacks, use DASH by default
- player: be slightly less prone to framedrop in display sync mode
- sd_lavc: extend subtitle resolution if images go outside video frame
- player: offset chapter display by start time
- command: make bitrate properties work correctly for external tracks
- w32_common: disable IME
- player: fix display-sync A/V calculation on high playback speeds
- player: fix display sync A/V difference estimation on drops
- player: raise display sync desync tolerance
This listing is not complete. Check DOCS/client-api-changes.rst for a history
of changes to the client API. A complete changelog can be seen by running
`git log v0.11.0..v0.12.0` in the git repository or by visiting either
https://github.com/mpv-player/mpv/compare/v0.11.0...v0.12.0 or
http://git.srsfckn.biz/mpv/log/?qt=range&q=v0.11.0..v0.12.0
Release 0.11.0
==============
+6 -1
View File
@@ -30,7 +30,12 @@ function add_files_at(index, files)
end
function get_extension(path)
return string.match(path, "%.([^%.]+)$" )
match = string.match(path, "%.([^%.]+)$" )
if match == nil then
return "nomatch"
else
return match
end
end
table.filter = function(t, iter)
+23 -8
View File
@@ -610,12 +610,13 @@ define_yes_no $_vdpau HAVE_VDPAU_HWACCEL
check_pkg_config "VAAPI" $_vaapi VAAPI 'libva >= 0.32.0 libva-x11 >= 0.32.0'
_vaapi=$(defretval)
define_yes_no $_vaapi HAVE_VAAPI_HWACCEL
define_yes_no $_vaapi HAVE_VAAPI_X11
_vaapi_wayland=no
if test "$_vaapi" = yes ; then
check_pkg_config "VAAPI VPP" auto VAAPI_VPP 'libva >= 0.34.0'
else
check_yes_no no VAAPI_VPP
_vaapi_wayland=auto
fi
check_pkg_config "VAAPI Wayland" $_vaapi_wayland VAAPI_WAYLAND 'libva-wayland >= 0.34.0'
check_pkg_config "Xinerama" $_xinerama XINERAMA 'xinerama'
@@ -703,6 +704,11 @@ _vaapi_glx=no
(test "$_gl_x11" = yes && test "$_vaapi" = yes) && _vaapi_glx=auto
check_pkg_config "VAAPI with OpenGL/X11" $_vaapi_glx VAAPI_GLX 'libva-glx >= 0.32.0'
_vaapi_x_egl=no
(test "$_gl_x11_egl" = yes && test "$_vaapi" = yes) && _vaapi_x_egl=yes
check_yes_no $_vaapi_x_egl VAAPI_X_EGL
check_yes_no $_vaapi_x_egl VAAPI_EGL
check_pkg_config "SDL 2.0" $_sdl2 SDL2 'sdl2'
check_statement_libs "OSS Audio" $_ossaudio OSS_AUDIO $_soundcard_header "int x = SNDCTL_DSP_SETFRAGMENT;"
@@ -804,6 +810,18 @@ api_statement_check \
libavutil/pixdesc.h \
'AVComponentDescriptor d; int x = d.depth'
api_statement_check \
"libavcodec 64 bit AVPacket.duration" \
HAVE_AV_AVPACKET_INT64_DURATION \
libavcodec/avcodec.h \
'int x[(int)sizeof(((AVPacket){0}).duration) - 7]'
api_statement_check \
"libavcodec AVSubtitleRect AVPicture removal" \
HAVE_AV_SUBTITLE_NOPICT \
libavcodec/avcodec.h \
'AVSubtitleRect r = {.linesize={0}}'
check_pkg_config "libavfilter" $_libavfilter LIBAVFILTER 'libavfilter >= 5.0.0'
check_pkg_config "libavdevice" $_libavdevice LIBAVDEVICE 'libavdevice >= 55.0.0'
@@ -926,10 +944,6 @@ cat > $TMPC << EOF
for platforms not supported by this configure script */
#define HAVE_BSD_FSTATFS 0
#define HAVE_LINUX_FSTATFS 1
#define HAVE_VDA_AV_VDA_ALLOC_CONTEXT 0
#define HAVE_VDA_HWACCEL 0
#define HAVE_VDA_LIBAVCODEC_REFCOUNTING 0
#define HAVE_VDA_GL 0
#define HAVE_GL_COCOA 0
#define HAVE_COCOA 0
#define HAVE_COCOA_APPLICATION 0
@@ -958,7 +972,8 @@ cat > $TMPC << EOF
#define HAVE_DRM 0
#define HAVE_VIDEOTOOLBOX_HWACCEL 0
#define HAVE_VIDEOTOOLBOX_GL 0
#define HAVE_VIDEOTOOLBOX_VDA_GL 0
#define HAVE_SSE4_INTRINSICS 1
#define HAVE_C11_TLS 1
#ifdef __OpenBSD__
#define DEFAULT_CDROM_DEVICE "/dev/rcd0c"
+5 -2
View File
@@ -88,11 +88,13 @@ SOURCES-$(VDPAU) += video/vdpau.c video/vdpau_mixer.c \
SOURCES-$(VDPAU_GL_X11) += video/out/opengl/hwdec_vdpau.c
SOURCES-$(VAAPI) += video/out/vo_vaapi.c \
video/decode/vaapi.c \
video/filter/vf_vavpp.c \
video/vaapi.c
SOURCES-$(VAAPI_VPP) += video/filter/vf_vavpp.c
SOURCES-$(VAAPI_GLX) += video/out/opengl/hwdec_vaglx.c
SOURCES-$(VAAPI_X_EGL) += video/out/opengl/hwdec_vaegl.c
SOURCES-$(XV) += video/out/x11_common.c video/out/vo_xv.c
SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c
SOURCES-$(XV) += video/out/vo_xv.c
SOURCES-$(WAYLAND) += video/out/vo_wayland.c \
video/out/wayland_common.c \
video/out/wayland/buffer.c \
@@ -233,6 +235,7 @@ SOURCES = audio/audio.c \
ta/ta_talloc.c \
video/csputils.c \
video/fmt-conversion.c \
video/gpu_memcpy.c \
video/image_writer.c \
video/img_format.c \
video/mp_image.c \
+26 -14
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import matplotlib.pyplot as plot
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import sys
import re
@@ -38,8 +39,8 @@ Currently, the following event types are supported:
class G:
events = {}
start = None
# http://matplotlib.org/api/markers_api.html#module-matplotlib.markers
markers = ["o", "8", "s", "p", "*", "h", "+", "x", "D"]
markers = ["o", "s", "t", "d"]
curveno = 0
def find_marker():
if len(G.markers) == 0:
@@ -128,20 +129,31 @@ for e, index in zip(G.sevents, range(len(G.sevents))):
else:
e.vals = [(x, y * (m - index) / m) for (x, y) in e.vals]
fig = plot.figure()
fig.hold(True)
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
app = QtGui.QApplication([])
win = pg.GraphicsWindow()
#win.resize(1500, 900)
ax = [None, None]
plots = 2 if hasval else 1
ax[0] = fig.add_subplot(plots, 1, 1)
ax[0] = win.addPlot()
if hasval:
ax[1] = fig.add_subplot(plots, 1, 2, sharex=ax[0])
legends = [[], []]
win.nextRow()
ax[1] = win.addPlot()
ax[1].setXLink(ax[0])
for cur in ax:
if cur is not None:
cur.addLegend(offset = (-1, 1))
for e in G.sevents:
cur = ax[1 if e.type == "value" else 0]
pl, = cur.plot([x for x,y in e.vals], [y for x,y in e.vals], label=e.name)
args = {'name': e.name,'antialias':True}
if e.type == "event-signal":
plot.setp(pl, marker = e.marker, linestyle = "None")
for cur in ax:
if cur is not None:
cur.legend()
plot.show()
args['symbol'] = e.marker
args['pen'] = None
else:
args['pen'] = pg.mkPen(pg.intColor(G.curveno), width=0)
G.curveno += 1
n = cur.plot([x for x,y in e.vals], [y for x,y in e.vals], **args)
QtGui.QApplication.instance().exec_()
+1 -1
View File
@@ -1 +1 @@
0.11.0
0.12.0
+7 -5
View File
@@ -323,21 +323,23 @@ struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe)
}
// If we can't handle the format (e.g. too many channels), bail out.
if (!mp_audio_config_valid(new) || avframe->nb_extended_buf)
if (!mp_audio_config_valid(new))
goto fail;
for (int n = 0; n < AV_NUM_DATA_POINTERS; n++) {
if (!avframe->buf[n])
for (int n = 0; n < AV_NUM_DATA_POINTERS + avframe->nb_extended_buf; n++) {
AVBufferRef *buf = n < AV_NUM_DATA_POINTERS ? avframe->buf[n]
: avframe->extended_buf[n - AV_NUM_DATA_POINTERS];
if (!buf)
break;
if (n >= MP_NUM_CHANNELS)
goto fail;
new->allocated[n] = av_buffer_ref(avframe->buf[n]);
new->allocated[n] = av_buffer_ref(buf);
if (!new->allocated[n])
goto fail;
}
for (int n = 0; n < new->num_planes; n++)
new->planes[n] = avframe->data[n];
new->planes[n] = avframe->extended_data[n];
new->samples = avframe->nb_samples;
return new;
+9
View File
@@ -119,6 +119,15 @@ void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples)
mp_audio_fill_silence(ab->buffer, 0, samples);
}
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples)
{
assert(samples >= 0 && samples <= ab->buffer->samples);
int oldlen = ab->buffer->samples;
ab->buffer->samples += samples;
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
mp_audio_copy(ab->buffer, oldlen, ab->buffer, oldlen - samples, samples);
}
// Get the start of the current readable buffer.
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa)
{
+1
View File
@@ -35,6 +35,7 @@ void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples
void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa);
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa);
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_clear(struct mp_audio_buffer *ab);
+10 -2
View File
@@ -298,12 +298,18 @@ void mp_chmap_remove_useless_channels(struct mp_chmap *map,
// 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.
// Also, "unknown" channel maps are translated to non-sense channel
// maps with the same number of channels.
uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src)
{
// lavc has no concept for unknown layouts yet, so pick a default
struct mp_chmap t = *src;
if (t.num > 64)
return 0;
// lavc has no concept for unknown layouts yet, so pick something that does
// the job of signaling the number of channels, even if it makes no sense
// as a proper layout.
if (mp_chmap_is_unknown(&t))
mp_chmap_from_channels(&t, t.num);
return t.num == 64 ? (uint64_t)-1 : (1ULL << t.num) - 1;
uint64_t mask = 0;
for (int n = 0; n < t.num; n++) {
if (t.speaker[n] < 64) // ignore MP_SPEAKER_ID_NA etc.
@@ -359,6 +365,8 @@ bool mp_chmap_is_lavc(const struct mp_chmap *src)
return true;
}
// Warning: for "unknown" channel maps, this returns something that may not
// make sense. Invalid channel maps are not changed.
void mp_chmap_reorder_to_lavc(struct mp_chmap *map)
{
if (!mp_chmap_is_valid(map))
+1 -1
View File
@@ -22,7 +22,7 @@
#include <stdbool.h>
#include "misc/bstr.h"
#define MP_NUM_CHANNELS 8
#define MP_NUM_CHANNELS 16
// Speaker a channel can be assigned to.
// This corresponds to WAVEFORMATEXTENSIBLE channel mask bit indexes.
+22
View File
@@ -20,6 +20,7 @@
#include <limits.h>
#include "common/common.h"
#include "common/msg.h"
#include "chmap_sel.h"
static const struct mp_chmap speaker_replacements[][2] = {
@@ -357,3 +358,24 @@ bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
}
return map->num > 0;
}
// Print the set of allowed channel layouts.
void mp_chmal_sel_log(const struct mp_chmap_sel *s, struct mp_log *log, int lev)
{
if (!mp_msg_test(log, lev))
return;
for (int i = 0; i < s->num_chmaps; i++)
mp_msg(log, lev, " - %s\n", mp_chmap_to_str(&s->chmaps[i]));
for (int i = 0; i < MP_SPEAKER_ID_COUNT; i++) {
if (!s->speakers[i])
continue;
struct mp_chmap l = {.num = 1, .speaker = { i }};
mp_msg(log, lev, " - #%s\n",
i == MP_SPEAKER_ID_FC ? "fc" : mp_chmap_to_str_hr(&l));
}
if (s->allow_waveext)
mp_msg(log, lev, " - waveext\n");
if (s->allow_any)
mp_msg(log, lev, " - anything\n");
}
+3
View File
@@ -45,4 +45,7 @@ bool mp_chmap_sel_fallback(const struct mp_chmap_sel *s, struct mp_chmap *map);
bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
int num);
struct mp_log;
void mp_chmal_sel_log(const struct mp_chmap_sel *s, struct mp_log *log, int lev);
#endif
+1 -1
View File
@@ -30,7 +30,7 @@ struct dec_audio {
struct mp_log *log;
struct MPOpts *opts;
struct mpv_global *global;
bool spdif_passthrough;
bool spdif_passthrough, spdif_failed;
const struct ad_functions *ad_driver;
struct sh_stream *header;
struct af_stream *afilter;
+2 -1
View File
@@ -461,7 +461,8 @@ static int af_reinit(struct af_stream *s)
struct af_instance *aft = af->prev;
af_remove(s, af);
af = aft->next;
break;
retry++;
continue;
}
}
goto negotiate_error;
+1 -1
View File
@@ -146,7 +146,7 @@ static void uninit(struct af_instance* af)
af_ac3enc_t *s = af->priv;
if (s) {
av_free_packet(&s->pkt);
av_packet_unref(&s->pkt);
if(s->lavc_actx) {
avcodec_close(s->lavc_actx);
av_free(s->lavc_actx);
+5 -3
View File
@@ -195,6 +195,10 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (af_to_avformat(in->format) == AV_SAMPLE_FMT_NONE)
mp_audio_set_format(in, AF_FORMAT_FLOAT);
// Removing this requires fixing AVFrame.data vs. AVFrame.extended_data
if (in->channels.num > AV_NUM_DATA_POINTERS)
return AF_ERROR;
if (!mp_chmap_is_lavc(&in->channels))
mp_chmap_reorder_to_lavc(&in->channels); // will always work
@@ -211,7 +215,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
mp_chmap_from_lavc(&out_cm, l_out->channel_layout);
mp_audio_set_channels(out, &out_cm);
if (!mp_audio_config_valid(out))
if (!mp_audio_config_valid(out) || out->channels.num > AV_NUM_DATA_POINTERS)
return AF_ERROR;
p->timebase_out = l_out->time_base;
@@ -349,8 +353,6 @@ static int af_open(struct af_instance *af)
af->uninit = uninit;
af->filter_frame = filter_frame;
af->filter_out = filter_out;
// Removing this requires fixing AVFrame.data vs. AVFrame.extended_data
assert(MP_NUM_CHANNELS <= AV_NUM_DATA_POINTERS);
return AF_OK;
}
+41 -13
View File
@@ -49,6 +49,7 @@
#define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \
swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples)
#define avresample_set_channel_mapping swr_set_channel_mapping
#define avresample_set_compensation swr_set_compensation
#else
#error "config.h broken or no resampler found"
#endif
@@ -90,6 +91,8 @@ struct af_resample {
int out_rate;
int out_format;
struct mp_chmap out_channels;
double missing_samples; // fractional samples not yet output
};
#if HAVE_LIBAVRESAMPLE
@@ -223,6 +226,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
s->out_channels= out->channels;
s->in_channels = in->channels;
s->missing_samples = 0;
av_opt_set_int(s->avrctx, "filter_size", s->opts.filter_size, 0);
av_opt_set_int(s->avrctx, "phase_shift", s->opts.phase_shift, 0);
av_opt_set_int(s->avrctx, "linear_interp", s->opts.linear, 0);
@@ -304,14 +309,15 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
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);
// Just needs the correct number of channels for deplanarization.
struct mp_chmap fake_chmap;
mp_chmap_set_unknown(&fake_chmap, map_out.num);
uint64_t fake_out_ch_layout = mp_chmap_to_lavc_unchecked(&fake_chmap);
if (!fake_out_ch_layout)
goto 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->out_rate, 0);
@@ -386,14 +392,6 @@ static int control(struct af_instance *af, int cmd, void *arg)
return AF_OK;
case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
s->playback_speed = *(double *)arg;
int new_rate = rate_from_speed(s->in_rate_af, s->playback_speed);
if (new_rate != s->in_rate && s->avrctx && af->fmt_out.format) {
// Before reconfiguring, drain the audio that is still buffered
// in the resampler.
af->filter_frame(af, NULL);
// Reinitialize resampler.
configure_lavrr(af, &af->fmt_in, &af->fmt_out, false);
}
return AF_OK;
}
case AF_CONTROL_RESET:
@@ -455,7 +453,7 @@ static void reorder_planes(struct mp_audio *mpa, int *reorder,
}
}
static int filter(struct af_instance *af, struct mp_audio *in)
static int filter_resample(struct af_instance *af, struct mp_audio *in)
{
struct af_resample *s = af->priv;
@@ -516,6 +514,36 @@ error:
return -1;
}
static int filter(struct af_instance *af, struct mp_audio *in)
{
struct af_resample *s = af->priv;
int new_rate = rate_from_speed(s->in_rate_af, s->playback_speed);
bool need_reinit = fabs(new_rate / (double)s->in_rate - 1) > 0.01;
if (!need_reinit && s->avrctx) {
double speed_factor = s->playback_speed * s->in_rate_af / s->in_rate;
int in_samples = in ? in->samples : 0;
double wanted_samples = in_samples / speed_factor + s->missing_samples;
int wanted_samples_i = lrint(wanted_samples);
s->missing_samples = wanted_samples - wanted_samples_i;
if (avresample_set_compensation(s->avrctx,
(wanted_samples_i - in_samples) * s->out_rate / s->in_rate,
wanted_samples_i * s->out_rate / s->in_rate) < 0)
need_reinit = true;
}
if (need_reinit && new_rate != s->in_rate) {
// Before reconfiguring, drain the audio that is still buffered
// in the resampler.
filter_resample(af, NULL);
// Reinitialize resampler.
configure_lavrr(af, &af->fmt_in, &af->fmt_out, false);
}
return filter_resample(af, in);
}
static int af_open(struct af_instance *af)
{
struct af_resample *s = af->priv;
+52 -49
View File
@@ -240,6 +240,7 @@ static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev)
}
struct ao *ao_init_best(struct mpv_global *global,
bool ao_null_fallback,
struct input_ctx *input_ctx,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels)
@@ -248,58 +249,67 @@ struct ao *ao_init_best(struct mpv_global *global,
void *tmp = talloc_new(NULL);
struct mp_log *log = mp_log_new(tmp, global->log, "ao");
struct ao *ao = NULL;
struct m_obj_settings *ao_list = opts->audio_driver_list;
struct m_obj_settings *ao_list = NULL;
int ao_num = 0;
for (int n = 0; opts->audio_driver_list && opts->audio_driver_list[n].name; n++)
MP_TARRAY_APPEND(tmp, ao_list, ao_num, opts->audio_driver_list[n]);
bool forced_dev = false;
char *pref_ao, *pref_dev;
split_ao_device(tmp, opts->audio_device, &pref_ao, &pref_dev);
if (!(ao_list && ao_list[0].name) && pref_ao) {
if (!ao_num && pref_ao) {
// Reuse the autoselection code
ao_list = talloc_zero_array(tmp, struct m_obj_settings, 2);
ao_list[0].name = pref_ao;
MP_TARRAY_APPEND(tmp, ao_list, ao_num,
(struct m_obj_settings){.name = pref_ao});
forced_dev = true;
}
if (ao_list && ao_list[0].name) {
for (int n = 0; ao_list[n].name; n++) {
if (strlen(ao_list[n].name) == 0)
goto autoprobe;
mp_verbose(log, "Trying preferred audio driver '%s'\n",
ao_list[n].name);
char *dev = NULL;
if (pref_ao && strcmp(ao_list[n].name, pref_ao) == 0)
dev = pref_dev;
if (dev)
mp_verbose(log, "Using preferred device '%s'\n", dev);
ao = ao_init(false, global, input_ctx, encode_lavc_ctx,
samplerate, format, channels, dev,
ao_list[n].name, ao_list[n].attribs);
if (ao)
goto done;
mp_err(log, "Failed to initialize audio driver '%s'\n",
ao_list[n].name);
if (forced_dev) {
mp_err(log, "This audio driver/device was forced with the "
"--audio-device option.\n"
"Try unsetting it.\n");
}
bool autoprobe = ao_num == 0;
// Something like "--ao=a,b," means do autoprobing after a and b fail.
if (ao_num && strlen(ao_list[ao_num - 1].name) == 0) {
ao_num -= 1;
autoprobe = true;
}
if (autoprobe) {
for (int n = 0; audio_out_drivers[n]; n++) {
const struct ao_driver *driver = audio_out_drivers[n];
if (driver == &audio_out_null)
break;
MP_TARRAY_APPEND(tmp, ao_list, ao_num,
(struct m_obj_settings){.name = (char *)driver->name});
}
goto done;
}
autoprobe: ;
// now try the rest...
for (int i = 0; audio_out_drivers[i]; i++) {
const struct ao_driver *driver = audio_out_drivers[i];
if (driver == &audio_out_null)
break;
ao = ao_init(true, global, input_ctx, encode_lavc_ctx, samplerate,
format, channels, NULL, (char *)driver->name, NULL);
if (ao_null_fallback) {
MP_TARRAY_APPEND(tmp, ao_list, ao_num,
(struct m_obj_settings){.name = "null"});
}
for (int n = 0; n < ao_num; n++) {
struct m_obj_settings *entry = &ao_list[n];
bool probing = n + 1 != ao_num;
mp_verbose(log, "Trying audio driver '%s'\n", entry->name);
char *dev = NULL;
if (pref_ao && pref_dev && strcmp(entry->name, pref_ao) == 0) {
dev = pref_dev;
mp_verbose(log, "Using preferred device '%s'\n", dev);
}
ao = ao_init(probing, global, input_ctx, encode_lavc_ctx,
samplerate, format, channels, dev,
entry->name, entry->attribs);
if (ao)
goto done;
break;
if (!probing)
mp_err(log, "Failed to initialize audio driver '%s'\n", entry->name);
if (dev && forced_dev) {
mp_err(log, "This audio driver/device was forced with the "
"--audio-device option.\nTry unsetting it.\n");
}
}
done:
talloc_free(tmp);
return ao;
}
@@ -411,18 +421,11 @@ void ao_hotplug_event(struct ao *ao)
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map)
{
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 (%s)\n", i, mp_chmap_to_str(&c),
mp_chmap_to_str_hr(&c));
}
}
MP_VERBOSE(ao, "Channel layouts:\n");
mp_chmal_sel_log(s, ao->log, MSGL_V);
bool r = mp_chmap_sel_adjust(s, map);
if (r) {
MP_DBG(ao, "result: %s (%s)\n", mp_chmap_to_str(map),
mp_chmap_to_str_hr(map));
}
if (r)
MP_VERBOSE(ao, "result: %s\n", mp_chmap_to_str(map));
return r;
}
+1
View File
@@ -72,6 +72,7 @@ struct encode_lavc_context;
struct mp_audio;
struct ao *ao_init_best(struct mpv_global *global,
bool ao_null_fallback,
struct input_ctx *input_ctx,
struct encode_lavc_context *encode_lavc_ctx,
int samplerate, int format, struct mp_chmap channels);
+31 -10
View File
@@ -50,6 +50,7 @@
struct priv {
snd_pcm_t *alsa;
bool device_lost;
snd_pcm_format_t alsa_fmt;
int can_pause;
snd_pcm_sframes_t prepause_frames;
@@ -83,6 +84,21 @@ struct priv {
MP_WARN(ao, "%s: %s\n", (message), snd_strerror(err)); \
} while (0)
// Common code for handling ENODEV, which happens if a device gets "lost", and
// can't be used anymore. Returns true if alsa_err is not ENODEV.
static bool check_device_present(struct ao *ao, int alsa_err)
{
struct priv *p = ao->priv;
if (alsa_err != -ENODEV)
return true;
if (!p->device_lost) {
MP_WARN(ao, "Device lost, trying to recover...\n");
ao_request_reload(ao);
p->device_lost = true;
}
return false;
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct priv *p = ao->priv;
@@ -312,9 +328,9 @@ static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
if (mp_chmap_is_valid(&entry)) {
if (maps[i]->type == SND_CHMAP_TYPE_VAR)
mp_chmap_reorder_norm(&entry);
MP_VERBOSE(ao, "Got supported channel map: %s (type %s)\n",
mp_chmap_to_str(&entry),
snd_pcm_chmap_type_name(maps[i]->type));
MP_DBG(ao, "Got supported channel map: %s (type %s)\n",
mp_chmap_to_str(&entry),
snd_pcm_chmap_type_name(maps[i]->type));
mp_chmap_sel_add_map(&chmap_sel, &entry);
} else {
char tmp[128];
@@ -462,16 +478,20 @@ static int init_device(struct ao *ao, bool second_try)
err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to get initial parameters");
bool found_format = false;
int try_formats[AF_FORMAT_COUNT];
af_get_best_sample_formats(ao->format, try_formats);
for (int n = 0; try_formats[n]; n++) {
ao->format = try_formats[n];
p->alsa_fmt = find_alsa_format(ao->format);
if (snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt) >= 0)
p->alsa_fmt = find_alsa_format(try_formats[n]);
MP_VERBOSE(ao, "trying format %s\n", af_fmt_to_str(try_formats[n]));
if (snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt) >= 0) {
ao->format = try_formats[n];
found_format = true;
break;
}
}
if (!ao->format) {
if (!found_format) {
MP_ERR(ao, "Can't find appropriate sample format.\n");
goto alsa_error;
}
@@ -730,6 +750,8 @@ static int get_space(struct ao *ao)
snd_pcm_status_alloca(&status);
err = snd_pcm_status(p->alsa, status);
if (!check_device_present(ao, err))
goto alsa_error;
CHECK_ALSA_ERROR("cannot get pcm status");
unsigned space = snd_pcm_status_get_avail(status);
@@ -856,9 +878,8 @@ static int play(struct ao *ao, void **data, int samples, int flags)
if (res == -EINTR || res == -EAGAIN) { /* retry */
res = 0;
} else if (res == -ENODEV) {
MP_WARN(ao, "Device lost, trying to recover...\n");
ao_request_reload(ao);
} else if (!check_device_present(ao, res)) {
goto alsa_error;
} else if (res < 0) {
if (res == -ESTRPIPE) { /* suspend */
resume_device(ao);
+12
View File
@@ -180,6 +180,8 @@ static void init_physical_format(struct ao *ao)
struct priv *p = ao->priv;
OSErr err;
void *tmp = talloc_new(NULL);
AudioStreamBasicDescription asbd;
ca_fill_asbd(ao, &asbd);
@@ -190,6 +192,8 @@ static void init_physical_format(struct ao *ao)
&streams, &n_streams);
CHECK_CA_ERROR("could not get number of streams");
talloc_steal(tmp, streams);
MP_VERBOSE(ao, "Found %zd substream(s).\n", n_streams);
for (int i = 0; i < n_streams; i++) {
@@ -204,6 +208,7 @@ static void init_physical_format(struct ao *ao)
if (!CHECK_CA_WARN("could not get number of stream formats"))
continue; // try next one
talloc_steal(tmp, formats);
uint32_t direction;
err = CA_GET(streams[i], kAudioStreamPropertyDirection, &direction);
@@ -232,6 +237,12 @@ static void init_physical_format(struct ao *ao)
&p->original_asbd);
CHECK_CA_WARN("could not get current physical stream format");
if (ca_asbd_equals(&p->original_asbd, &best_asbd)) {
MP_VERBOSE(ao, "Requested format already set, not changing.\n");
p->original_asbd.mFormatID = 0;
break;
}
if (!ca_change_physical_format_sync(ao, streams[i], best_asbd))
p->original_asbd = (AudioStreamBasicDescription){0};
break;
@@ -239,6 +250,7 @@ static void init_physical_format(struct ao *ao)
}
coreaudio_error:
talloc_free(tmp);
return;
}
+62 -27
View File
@@ -98,6 +98,9 @@ static AudioChannelLayout *ca_layout_to_custom_layout(struct ao *ao,
AudioChannelLayout *r;
OSStatus err;
if (tag == kAudioChannelLayoutTag_UseChannelDescriptions)
return l;
if (tag == kAudioChannelLayoutTag_UseChannelBitmap) {
uint32_t psize;
err = AudioFormatGetPropertyInfo(
@@ -109,7 +112,7 @@ static AudioChannelLayout *ca_layout_to_custom_layout(struct ao *ao,
kAudioFormatProperty_ChannelLayoutForBitmap,
sizeof(uint32_t), &l->mChannelBitmap, &psize, r);
CHECK_CA_ERROR("failed to convert channel bitmap to descriptions (get)");
} else if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) {
} else {
uint32_t psize;
err = AudioFormatGetPropertyInfo(
kAudioFormatProperty_ChannelLayoutForTag,
@@ -120,10 +123,11 @@ static AudioChannelLayout *ca_layout_to_custom_layout(struct ao *ao,
kAudioFormatProperty_ChannelLayoutForTag,
sizeof(AudioChannelLayoutTag), &l->mChannelLayoutTag, &psize, r);
CHECK_CA_ERROR("failed to convert channel tag to descriptions (get)");
} else {
r = l;
}
MP_VERBOSE(ao, "converted input channel layout:\n");
ca_log_layout(ao, MSGL_V, l);
return r;
coreaudio_error:
return NULL;
@@ -134,22 +138,20 @@ static bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
{
void *talloc_ctx = talloc_new(NULL);
MP_DBG(ao, "input channel layout:\n");
ca_log_layout(ao, MSGL_DEBUG, layout);
MP_VERBOSE(ao, "input channel layout:\n");
ca_log_layout(ao, MSGL_V, layout);
AudioChannelLayout *l = ca_layout_to_custom_layout(ao, talloc_ctx, layout);
if (!l)
goto coreaudio_error;
MP_VERBOSE(ao, "converted input channel layout:\n");
ca_log_layout(ao, MSGL_V, l);
if (l->mNumberChannelDescriptions > MP_NUM_CHANNELS) {
MP_VERBOSE(ao, "layout has too many descriptions (%u, max: %d)\n",
(unsigned) l->mNumberChannelDescriptions, MP_NUM_CHANNELS);
return false;
}
chmap->num = l->mNumberChannelDescriptions;
for (int n = 0; n < l->mNumberChannelDescriptions; n++) {
AudioChannelLabel label = l->mChannelDescriptions[n].mChannelLabel;
int speaker = ca_label_to_mp_speaker_id(label);
@@ -157,14 +159,13 @@ static bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
MP_VERBOSE(ao, "channel label=%u unusable to build channel "
"bitmap, skipping layout\n", (unsigned) label);
goto coreaudio_error;
} else {
chmap->speaker[n] = speaker;
chmap->num = n + 1;
}
chmap->speaker[n] = speaker;
}
talloc_free(talloc_ctx);
return chmap->num > 0;
MP_VERBOSE(ao, "mp chmap: %s\n", mp_chmap_to_str(chmap));
return mp_chmap_is_valid(chmap) && !mp_chmap_is_unknown(chmap);
coreaudio_error:
MP_VERBOSE(ao, "converted input channel layout (failed):\n");
ca_log_layout(ao, MSGL_V, layout);
@@ -234,34 +235,68 @@ coreaudio_error:
return r;
}
bool ca_init_chmap(struct ao *ao, AudioDeviceID device)
static void ca_retrieve_layouts(struct ao *ao, struct mp_chmap_sel *s,
AudioDeviceID device)
{
void *ta_ctx = talloc_new(NULL);
struct mp_chmap_sel chmap_sel = {.tmp = ta_ctx};
struct mp_chmap chmap = {0};
mp_chmap_sel_add_map(&chmap_sel, &(struct mp_chmap)MP_CHMAP_INIT_MONO);
struct mp_chmap chmap;
AudioChannelLayout *ml = ca_query_layout(ao, device, ta_ctx);
if (ml && ca_layout_to_mp_chmap(ao, ml, &chmap))
mp_chmap_sel_add_map(&chmap_sel, &chmap);
mp_chmap_sel_add_map(s, &chmap);
AudioChannelLayout *sl = ca_query_stereo_layout(ao, device, ta_ctx);
if (sl && ca_layout_to_mp_chmap(ao, sl, &chmap))
mp_chmap_sel_add_map(&chmap_sel, &chmap);
mp_chmap_sel_add_map(s, &chmap);
talloc_free(ta_ctx);
}
bool ca_init_chmap(struct ao *ao, AudioDeviceID device)
{
struct mp_chmap_sel chmap_sel = {0};
ca_retrieve_layouts(ao, &chmap_sel, device);
if (!chmap_sel.num_chmaps)
mp_chmap_sel_add_map(&chmap_sel, &(struct mp_chmap)MP_CHMAP_INIT_STEREO);
mp_chmap_sel_add_map(&chmap_sel, &(struct mp_chmap)MP_CHMAP_INIT_MONO);
if (!ao_chmap_sel_adjust(ao, &chmap_sel, &ao->channels)) {
MP_ERR(ao, "could not select a suitable channel map among the "
"hardware supported ones. Make sure to configure your "
"output device correctly in 'Audio MIDI Setup.app'\n");
goto coreaudio_error;
return false;
}
return true;
}
void ca_get_active_chmap(struct ao *ao, AudioDeviceID device, int channel_count,
struct mp_chmap *out_map)
{
// Apparently, we have to guess by looking back at the supported layouts,
// and I haven't found a property that retrieves the actual currently
// active channel layout.
struct mp_chmap_sel chmap_sel = {0};
ca_retrieve_layouts(ao, &chmap_sel, device);
// Use any exact match.
for (int n = 0; n < chmap_sel.num_chmaps; n++) {
if (chmap_sel.chmaps[n].num == channel_count) {
MP_VERBOSE(ao, "mismatching channels - fallback #%d\n", n);
*out_map = chmap_sel.chmaps[n];
return;
}
}
talloc_free(ta_ctx);
return true;
coreaudio_error:
talloc_free(ta_ctx);
return false;
// Fall back to stereo or mono, and fill the rest with silence. (We don't
// know what the device expects. We could use a larger default layout here,
// but let's not.)
mp_chmap_from_channels(out_map, MPMIN(2, channel_count));
out_map->num = channel_count;
for (int n = 2; n < out_map->num; n++)
out_map->speaker[n] = MP_SPEAKER_ID_NA;
MP_WARN(ao, "mismatching channels - falling back to %s\n",
mp_chmap_to_str(out_map));
}
+4
View File
@@ -20,6 +20,10 @@
#include <AudioToolbox/AudioToolbox.h>
struct mp_chmap;
bool ca_init_chmap(struct ao *ao, AudioDeviceID device);
void ca_get_active_chmap(struct ao *ao, AudioDeviceID device, int channel_count,
struct mp_chmap *out_map);
#endif
+10 -1
View File
@@ -300,6 +300,12 @@ static int init(struct ao *ao)
ca_print_asbd(ao, "virtual format", &p->stream_asbd);
if (p->stream_asbd.mChannelsPerFrame > MP_NUM_CHANNELS) {
MP_ERR(ao, "unsupported number of channels: %d > %d.\n",
p->stream_asbd.mChannelsPerFrame, MP_NUM_CHANNELS);
goto coreaudio_error;
}
int new_format = ca_asbd_to_mp_format(&p->stream_asbd);
// If both old and new formats are spdif, avoid changing it due to the
@@ -315,7 +321,10 @@ static int init(struct ao *ao)
ao->samplerate = p->stream_asbd.mSampleRate;
if (ao->channels.num != p->stream_asbd.mChannelsPerFrame) {
// We really expect that ca_init_chmap() fixes the layout to the HW's.
ca_get_active_chmap(ao, p->device, p->stream_asbd.mChannelsPerFrame,
&ao->channels);
}
if (!ao->channels.num) {
MP_ERR(ao, "number of channels changed, and unknown channel layout!\n");
goto coreaudio_error;
}
+13 -4
View File
@@ -51,7 +51,9 @@ static bool ca_is_output_device(struct ao *ao, AudioDeviceID dev)
size_t n_buffers;
AudioBufferList *buffers;
const ca_scope scope = kAudioDevicePropertyStreamConfiguration;
CA_GET_ARY_O(dev, scope, &buffers, &n_buffers);
OSStatus err = CA_GET_ARY_O(dev, scope, &buffers, &n_buffers);
if (err != noErr)
return false;
talloc_free(buffers);
return n_buffers > 0;
}
@@ -71,11 +73,16 @@ void ca_get_device_list(struct ao *ao, struct ao_device_list *list)
char *name;
char *desc;
err = CA_GET_STR(devs[i], kAudioDevicePropertyDeviceUID, &name);
if (err != noErr) {
MP_VERBOSE(ao, "skipping device %d, which has no UID\n", i);
talloc_free(ta_ctx);
continue;
}
talloc_steal(ta_ctx, name);
err = CA_GET_STR(devs[i], kAudioObjectPropertyName, &desc);
talloc_steal(ta_ctx, desc);
if (err != noErr)
desc = "Unknown";
desc = talloc_strdup(NULL, "Unknown");
talloc_steal(ta_ctx, desc);
ao_device_list_add(list, ao, &(struct ao_device_desc){name, desc});
talloc_free(ta_ctx);
}
@@ -498,6 +505,8 @@ bool ca_change_physical_format_sync(struct ao *ao, AudioStreamID stream,
err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &prev_format);
CHECK_CA_ERROR("can't get current physical format");
ca_print_asbd(ao, "format in use before switching:", &prev_format);
/* Install the callback. */
AudioObjectPropertyAddress p_addr = {
.mSelector = kAudioStreamPropertyPhysicalFormat,
@@ -516,7 +525,7 @@ bool ca_change_physical_format_sync(struct ao *ao, AudioStreamID stream,
/* The AudioStreamSetProperty is not only asynchronous,
* it is also not Atomic, in its behaviour. */
struct timespec timeout = mp_rel_time_to_timespec(0.5);
struct timespec timeout = mp_rel_time_to_timespec(2.0);
AudioStreamBasicDescription actual_format = {0};
while (1) {
err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &actual_format);
+3
View File
@@ -164,6 +164,9 @@ static int init(struct ao *ao)
ao->untimed = true;
if (ao->channels.num > AV_NUM_DATA_POINTERS)
goto fail;
pthread_mutex_unlock(&ao->encode_lavc_ctx->lock);
return 0;
+1 -3
View File
@@ -486,10 +486,8 @@ static bool search_channels(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat)
}
} else {
change_waveformat_channels(wformat, &entry);
if (try_format_exclusive(ao, wformat)) {
if (try_format_exclusive(ao, wformat))
mp_chmap_sel_add_map(&chmap_sel, &entry);
MP_VERBOSE(ao, "%s is supported\n", mp_chmap_to_str(&entry));
}
}
}
+1
View File
@@ -65,6 +65,7 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st)
avctx->block_align = st->block_align;
avctx->channel_layout = st->channel_layout;
avctx->bits_per_coded_sample = st->bits_per_coded_sample;
avctx->has_b_frames = st->has_b_frames;
}
// We merely pass-through our PTS/DTS as an int64_t; libavcodec won't use it.
+2 -4
View File
@@ -326,10 +326,8 @@ static void write_msg_to_buffers(struct mp_log *log, int lev, char *text)
static void dump_stats(struct mp_log *log, int lev, char *text)
{
struct mp_log_root *root = log->root;
if (lev == MSGL_STATS && root->stats_file) {
fprintf(root->stats_file, "%"PRId64" %s #%s\n", mp_time_us(), text,
log->verbose_prefix);
}
if (lev == MSGL_STATS && root->stats_file)
fprintf(root->stats_file, "%"PRId64" %s\n", mp_time_us(), text);
}
void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va)
+23 -9
View File
@@ -24,6 +24,7 @@
#include "misc/bstr.h"
#include "common/common.h"
#include "common/tags.h"
#include "cue.h"
@@ -37,6 +38,7 @@ enum cue_command {
CUE_TRACK,
CUE_INDEX,
CUE_TITLE,
CUE_PERFORMER,
};
static const struct {
@@ -51,7 +53,7 @@ static const struct {
{ CUE_UNUSED, "CDTEXTFILE" },
{ CUE_UNUSED, "FLAGS" },
{ CUE_UNUSED, "ISRC" },
{ CUE_UNUSED, "PERFORMER" },
{ CUE_PERFORMER, "PERFORMER" },
{ CUE_UNUSED, "POSTGAP" },
{ CUE_UNUSED, "PREGAP" },
{ CUE_UNUSED, "REM" },
@@ -160,17 +162,19 @@ bool mp_probe_cue(struct bstr data)
struct cue_file *mp_parse_cue(struct bstr data)
{
struct cue_file *f = talloc_zero(NULL, struct cue_file);
f->tags = talloc_zero(f, struct mp_tags);
data = skip_utf8_bom(data);
char *filename = NULL;
// Global metadata, and copied into new tracks.
struct cue_track proto_track = {0};
struct cue_track *cur_track = &proto_track;
struct cue_track *cur_track = NULL;
while (data.len) {
struct bstr param;
switch (read_cmd(&data, &param)) {
int cmd = read_cmd(&data, &param);
switch (cmd) {
case CUE_ERROR:
talloc_free(f);
return NULL;
@@ -179,19 +183,29 @@ struct cue_file *mp_parse_cue(struct bstr data)
f->num_tracks += 1;
cur_track = &f->tracks[f->num_tracks - 1];
*cur_track = proto_track;
cur_track->tags = talloc_zero(f, struct mp_tags);
break;
}
case CUE_TITLE:
cur_track->title = read_quoted(f, &param);
case CUE_PERFORMER: {
static const char *metanames[] = {
[CUE_TITLE] = "title",
[CUE_PERFORMER] = "performer",
};
struct mp_tags *tags = cur_track ? cur_track->tags : f->tags;
mp_tags_set_bstr(tags, bstr0(metanames[cmd]), param);
break;
}
case CUE_INDEX: {
int type = read_int_2(&param);
double time = read_time(&param);
if (type == 1) {
cur_track->start = time;
cur_track->filename = filename;
} else if (type == 0) {
cur_track->pregap_start = time;
if (cur_track) {
if (type == 1) {
cur_track->start = time;
cur_track->filename = filename;
} else if (type == 0) {
cur_track->pregap_start = time;
}
}
break;
}
+2 -1
View File
@@ -25,6 +25,7 @@
struct cue_file {
struct cue_track *tracks;
int num_tracks;
struct mp_tags *tags;
};
struct cue_track {
@@ -32,7 +33,7 @@ struct cue_track {
double start; // corresponds to INDEX 01
char *filename;
int source;
char *title;
struct mp_tags *tags;
};
bool mp_probe_cue(struct bstr data);
+13 -12
View File
@@ -307,13 +307,12 @@ const char *stream_type_name(enum stream_type type)
}
}
// Returns the same value as demuxer->fill_buffer: 1 ok, 0 EOF/not selected.
int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
{
struct demux_stream *ds = stream ? stream->ds : NULL;
if (!dp || !ds) {
talloc_free(dp);
return 0;
return;
}
struct demux_internal *in = ds->in;
pthread_mutex_lock(&in->lock);
@@ -330,7 +329,7 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
if (!ds->selected || in->seeking || drop) {
pthread_mutex_unlock(&in->lock);
talloc_free(dp);
return 0;
return;
}
dp->stream = stream->index;
@@ -371,7 +370,6 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
ds->in->wakeup_cb(ds->in->wakeup_cb_ctx);
pthread_cond_signal(&in->wakeup);
pthread_mutex_unlock(&in->lock);
return 1;
}
// Returns true if there was "progress" (lock was released temporarily).
@@ -430,10 +428,8 @@ static bool read_packet(struct demux_internal *in)
pthread_mutex_lock(&in->lock);
if (eof) {
for (int n = 0; n < in->d_buffer->num_streams; n++) {
struct demux_stream *ds = in->d_buffer->streams[n]->ds;
ds->eof = true;
}
for (int n = 0; n < in->d_buffer->num_streams; n++)
in->d_buffer->streams[n]->ds->eof = true;
// If we had EOF previously, then don't wakeup (avoids wakeup loop)
if (!in->last_eof) {
if (in->wakeup_cb)
@@ -924,7 +920,8 @@ static void demux_init_cuesheet(struct demuxer *demuxer)
if (f) {
for (int n = 0; n < f->num_tracks; n++) {
struct cue_track *t = &f->tracks[n];
demuxer_add_chapter(demuxer, t->title, t->start, -1);
int idx = demuxer_add_chapter(demuxer, "", t->start, -1);
mp_tags_merge(demuxer->chapters[idx].metadata, t->tags);
}
}
talloc_free(f);
@@ -938,6 +935,9 @@ static struct demuxer *open_given_type(struct mpv_global *global,
struct demuxer_params *params,
enum demux_check check)
{
if (mp_cancel_test(stream->cancel))
return NULL;
struct demuxer *demuxer = talloc_ptrtype(NULL, demuxer);
*demuxer = (struct demuxer) {
.desc = desc,
@@ -1392,10 +1392,11 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
case DEMUXER_CTRL_GET_BITRATE_STATS: {
double *rates = arg;
for (int n = 0; n < STREAM_TYPE_COUNT; n++)
rates[n] = 0;
rates[n] = -1;
for (int n = 0; n < in->d_user->num_streams; n++) {
struct demux_stream *ds = in->d_user->streams[n]->ds;
rates[ds->type] += MPMAX(0, ds->bitrate);
if (ds->selected && ds->bitrate >= 0)
rates[ds->type] = MPMAX(0, rates[ds->type]) + ds->bitrate;
}
return DEMUXER_CTRL_OK;
}
+1 -1
View File
@@ -242,7 +242,7 @@ typedef struct {
void free_demuxer(struct demuxer *demuxer);
void free_demuxer_and_stream(struct demuxer *demuxer);
int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp);
void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp);
struct demux_packet *demux_read_packet(struct sh_stream *sh);
int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt);
+15 -15
View File
@@ -38,7 +38,7 @@
#define PROBE_SIZE 512
struct priv {
bstr data;
struct cue_file *f;
};
static void add_source(struct timeline *tl, struct demuxer *d)
@@ -150,15 +150,8 @@ static void build_timeline(struct timeline *tl)
add_source(tl, tl->demuxer);
struct cue_file *f = mp_parse_cue(p->data);
if (!f) {
MP_ERR(tl, "CUE: error parsing input file!\n");
goto out;
}
talloc_steal(ctx, f);
struct cue_track *tracks = f->tracks;
size_t track_count = f->num_tracks;
struct cue_track *tracks = p->f->tracks;
size_t track_count = p->f->num_tracks;
if (track_count == 0) {
MP_ERR(tl, "CUE: no tracks found!\n");
@@ -224,10 +217,8 @@ static void build_timeline(struct timeline *tl)
};
chapters[i] = (struct demux_chapter) {
.pts = timeline[i].start,
.metadata = talloc_zero(tl, struct mp_tags),
.metadata = mp_tags_dup(tl, tracks[i].tags),
};
// might want to include other metadata here
mp_tags_set_str(chapters[i].metadata, "title", tracks[i].title);
starttime += duration;
}
@@ -261,9 +252,18 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check)
struct priv *p = talloc_zero(demuxer, struct priv);
demuxer->priv = p;
demuxer->fully_read = true;
p->data = stream_read_complete(s, demuxer, 1000000);
if (p->data.start == NULL)
bstr data = stream_read_complete(s, p, 1000000);
if (data.start == NULL)
return -1;
p->f = mp_parse_cue(data);
talloc_steal(p, p->f);
if (!p->f) {
MP_ERR(demuxer, "error parsing input file!\n");
return -1;
}
mp_tags_merge(demuxer->metadata, p->f->tags);
return 0;
}
+14 -5
View File
@@ -635,7 +635,10 @@ static void handle_stream(demuxer_t *demuxer, int i)
sh->ff_index = st->index;
sh->codec = mp_codec_from_av_codec_id(codec->codec_id);
sh->codec_tag = codec->codec_tag;
sh->lav_headers = codec;
sh->lav_headers = avcodec_alloc_context3(NULL);
if (!sh->lav_headers)
return;
mp_copy_lav_codec_headers(sh->lav_headers, codec);
if (st->disposition & AV_DISPOSITION_DEFAULT)
sh->default_track = true;
@@ -850,7 +853,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
AVPacket *pkt = &(AVPacket){0};
int r = av_read_frame(priv->avfc, pkt);
if (r < 0) {
av_free_packet(pkt);
av_packet_unref(pkt);
if (r == AVERROR(EAGAIN))
return 1;
if (r == AVERROR_EOF)
@@ -867,13 +870,13 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
AVStream *st = priv->avfc->streams[pkt->stream_index];
if (!demux_stream_is_selected(stream)) {
av_free_packet(pkt);
av_packet_unref(pkt);
return 1; // don't signal EOF if skipping a packet
}
struct demux_packet *dp = new_demux_packet_from_avpacket(pkt);
if (!dp) {
av_free_packet(pkt);
av_packet_unref(pkt);
return 1;
}
@@ -882,8 +885,10 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
if (pkt->dts != AV_NOPTS_VALUE)
dp->dts = pkt->dts * av_q2d(st->time_base);
dp->duration = pkt->duration * av_q2d(st->time_base);
#if !HAVE_AV_AVPACKET_INT64_DURATION
if (pkt->convergence_duration > 0)
dp->duration = pkt->convergence_duration * av_q2d(st->time_base);
#endif
dp->pos = pkt->pos;
dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY;
if (dp->pts != MP_NOPTS_VALUE) {
@@ -891,7 +896,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
} else if (dp->dts != MP_NOPTS_VALUE) {
priv->last_pts = dp->dts * AV_TIME_BASE;
}
av_free_packet(pkt);
av_packet_unref(pkt);
if (priv->format_hack.clear_filepos)
dp->pos = -1;
@@ -1074,6 +1079,10 @@ static void demux_close_lavf(demuxer_t *demuxer)
if (priv->pb)
av_freep(&priv->pb->buffer);
av_freep(&priv->pb);
for (int n = 0; n < priv->num_streams; n++) {
if (priv->streams[n])
avcodec_free_context(&priv->streams[n]->lav_headers);
}
talloc_free(priv);
demuxer->priv = NULL;
}
+57 -19
View File
@@ -149,6 +149,16 @@ typedef struct mkv_index {
uint64_t filepos; // position of the cluster which contains the packet
} mkv_index_t;
struct block_info {
uint64_t duration, discardpadding;
bool simple, keyframe;
uint64_t timecode;
mkv_track_t *track;
bstr data;
void *alloc;
int64_t filepos;
};
typedef struct mkv_demuxer {
int64_t segment_start, segment_end;
@@ -183,6 +193,8 @@ typedef struct mkv_demuxer {
bool index_has_durations;
bool eof_warning;
struct block_info tmp_block;
} mkv_demuxer_t;
#define OPT_BASE_STRUCT struct demux_mkv_opts
@@ -190,6 +202,7 @@ struct demux_mkv_opts {
int subtitle_preroll;
double subtitle_preroll_secs;
int probe_duration;
int probe_start_time;
int fix_timestamps;
};
@@ -200,12 +213,14 @@ const struct m_sub_options demux_mkv_conf = {
M_OPT_MIN, .min = 0),
OPT_CHOICE("probe-video-duration", probe_duration, 0,
({"no", 0}, {"yes", 1}, {"full", 2})),
OPT_FLAG("probe-start-time", probe_start_time, 0),
OPT_FLAG("fix-timestamps", fix_timestamps, 0),
{0}
},
.size = sizeof(struct demux_mkv_opts),
.defaults = &(const struct demux_mkv_opts){
.subtitle_preroll_secs = 1.0,
.probe_start_time = 1,
.fix_timestamps = 0,
},
};
@@ -219,7 +234,9 @@ const struct m_sub_options demux_mkv_conf = {
// (Subtitle packets added before first A/V keyframe packet is found with seek.)
#define NUM_SUB_PREROLL_PACKETS 500
static void probe_last_timestamp(struct demuxer *demuxer);
static void probe_last_timestamp(struct demuxer *demuxer, int64_t start_pos);
static void probe_first_timestamp(struct demuxer *demuxer);
static void free_block(struct block_info *block);
#define AAC_SYNC_EXTENSION_TYPE 0x02b7
static int aac_get_sample_rate_index(uint32_t sample_rate)
@@ -1884,8 +1901,9 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
add_coverart(demuxer);
demuxer->allow_refresh_seeks = true;
probe_first_timestamp(demuxer);
if (opts->demux_mkv->probe_duration)
probe_last_timestamp(demuxer);
probe_last_timestamp(demuxer, start_pos);
return 0;
}
@@ -2095,6 +2113,8 @@ static void mkv_seek_reset(demuxer_t *demuxer)
}
track->av_parser_codec = NULL;
}
free_block(&mkv_d->tmp_block);
}
// Copied from libavformat/matroskadec.c (FFmpeg 310f9dd / 2013-05-30)
@@ -2268,16 +2288,6 @@ static void mkv_parse_and_add_packet(demuxer_t *demuxer, mkv_track_t *track,
}
}
struct block_info {
uint64_t duration, discardpadding;
bool simple, keyframe;
uint64_t timecode;
mkv_track_t *track;
bstr data;
void *alloc;
int64_t filepos;
};
static void free_block(struct block_info *block)
{
free(block->alloc);
@@ -2389,8 +2399,12 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
if (mkv_d->a_skip_to_keyframe)
use_this_block &= keyframe;
} else if (track->type == MATROSKA_TRACK_SUBTITLE) {
if (!use_this_block && mkv_d->subtitle_preroll)
use_this_block = 1;
if (!use_this_block && mkv_d->subtitle_preroll) {
int64_t end_time = block_info->timecode + block_info->duration;
if (!block_info->duration)
end_time = INT64_MAX;
use_this_block = end_time > mkv_d->skip_to_timecode;
}
if (use_this_block) {
if (mkv_d->subtitle_preroll) {
mkv_d->subtitle_preroll--;
@@ -2522,6 +2536,12 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
stream_t *s = demuxer->stream;
if (mkv_d->tmp_block.alloc) {
*block = mkv_d->tmp_block;
mkv_d->tmp_block = (struct block_info){0};
return 1;
}
while (1) {
while (stream_tell(s) < mkv_d->cluster_end) {
int64_t start_filepos = stream_tell(s);
@@ -2847,10 +2867,9 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
demux_mkv_fill_buffer(demuxer);
}
static void probe_last_timestamp(struct demuxer *demuxer)
static void probe_last_timestamp(struct demuxer *demuxer, int64_t start_pos)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
int64_t old_pos = stream_tell(demuxer->stream);
if (!demuxer->seekable)
return;
@@ -2888,10 +2907,12 @@ static void probe_last_timestamp(struct demuxer *demuxer)
int64_t size = stream_get_size(demuxer->stream);
stream_seek(demuxer->stream, MPMAX(size - 10 * 1024 * 1024, 0));
if (ebml_resync_cluster(mp_null_log, demuxer->stream) < 0)
stream_seek(demuxer->stream, old_pos); // full scan otherwise
stream_seek(demuxer->stream, start_pos); // full scan otherwise
}
}
free_block(&mkv_d->tmp_block);
int64_t last_ts[STREAM_TYPE_COUNT] = {0};
while (1) {
struct block_info block;
@@ -2913,12 +2934,29 @@ static void probe_last_timestamp(struct demuxer *demuxer)
last_ts[STREAM_VIDEO] = mkv_d->cluster_tc;
if (last_ts[STREAM_VIDEO])
mkv_d->duration = last_ts[STREAM_VIDEO] / 1e9;
mkv_d->duration = last_ts[STREAM_VIDEO] / 1e9 - demuxer->start_time;
stream_seek(demuxer->stream, old_pos);
stream_seek(demuxer->stream, start_pos);
mkv_d->cluster_start = mkv_d->cluster_end = 0;
}
static void probe_first_timestamp(struct demuxer *demuxer)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
if (!demuxer->opts->demux_mkv->probe_start_time)
return;
struct block_info block;
if (read_next_block(demuxer, &block) > 0)
mkv_d->tmp_block = block;
demuxer->start_time = mkv_d->cluster_tc / 1e9;
if (demuxer->start_time > 0)
MP_VERBOSE(demuxer, "Start PTS: %f\n", demuxer->start_time);
}
static int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+7 -1
View File
@@ -758,6 +758,10 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check)
{
if (check > DEMUX_CHECK_REQUEST)
return -1;
#if LIBAVUTIL_VERSION_MICRO >= 100
if (check != DEMUX_CHECK_FORCE)
return -1;
#endif
if (!demuxer->params || !demuxer->params->expect_subtitle)
return -1;
@@ -800,7 +804,9 @@ static int d_fill_buffer(struct demuxer *demuxer)
struct priv *p = demuxer->priv;
struct demux_packet *dp = demux_packet_list_fill(p->pkts, p->num_pkts,
&p->current);
return demux_add_packet(p->sh, dp);
int have_packet = !!dp;
demux_add_packet(p->sh, dp);
return have_packet;
}
static void d_seek(struct demuxer *demuxer, double secs, int flags)
+1
View File
@@ -36,6 +36,7 @@ struct key_name {
static const struct key_name key_names[] = {
{ ' ', "SPACE" },
{ '#', "SHARP" },
{ 0x3000, "IDEOGRAPHIC_SPACE" },
{ MP_KEY_ENTER, "ENTER" },
{ MP_KEY_TAB, "TAB" },
{ MP_KEY_BACKSPACE, "BS" },
+20 -4
View File
@@ -49,13 +49,29 @@ extern "C" {
* 2) Using mpv as a library with mpv_create(). This basically allows embedding
* mpv in other applications.
*
* Documentation
* -------------
*
* The libmpv C API is documented directly in this header. Note that most
* actual interaction with this player is done through
* options/commands/properties, which can be accessed through this API.
* Essentially everything is done with them, including loading a file,
* retrieving playback progress, and so on.
*
* These are documented elsewhere:
* * http://mpv.io/manual/master/#options
* * http://mpv.io/manual/master/#list-of-input-commands
* * http://mpv.io/manual/master/#properties
*
* You can also look at the examples in DOCS/client_api_examples/.
*
* Event loop
* ----------
*
* In general, the API user should run an event loop in order to receive events.
* This even loop should call mpv_wait_event(), which will return once a new
* mpv client API is available. It should also be possible to integrate client
* API usage in other event loops (e.g. GUI toolkits) with the
* This event loop should call mpv_wait_event(), which will return once a new
* mpv client API is available. It is also possible to integrate client API
* usage in other event loops (e.g. GUI toolkits) with the
* mpv_set_wakeup_callback() function, and then polling for events by calling
* mpv_wait_event() with a 0 timeout.
*
@@ -198,7 +214,7 @@ extern "C" {
* relational operators (<, >, <=, >=).
*/
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 19)
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 20)
/**
* Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with.
+38 -10
View File
@@ -108,8 +108,36 @@ extern "C" {
* context must have been uninitialized. If this doesn't happen, undefined
* behavior will result.
*
* Special D3D interop considerations
* ----------------------------------
* Special windowing system interop considerations
* ------------------------------------------------
*
* In some cases, libmpv needs to have access to the windowing system's handles.
* This can be a pointer to a X11 "Display" for example. Usually this is needed
* only for hardware decoding.
*
* You can communicate these handles to libmpv by adding a pseudo-OpenGL
* extension "GL_MP_MPGetNativeDisplay" to the additional extension string when
* calling mpv_opengl_cb_init_gl(). The get_proc_address callback should resolve
* a function named "glMPGetNativeDisplay", which has the signature:
*
* void* GLAPIENTRY glMPGetNativeDisplay(const char* name)
*
* See below what names are defined. Usually, libmpv will use the native handle
* up until mpv_opengl_cb_uninit_gl() is called. If the name is not anything
* you know/expected, return NULL from the function.
*
* Windowing system interop on Linux
* ---------------------------------
*
* The new VAAPI OpenGL interop requires an EGL context. EGL provides no way
* to query the X11 Display associated to a specific EGL context, so this API
* is used to pass it through.
*
* glMPGetNativeDisplay("x11") should return a X11 "Display*", which then will
* be used to create the hardware decoder state. (On GLX, this is not needed.)
*
* Windowing system interop on MS win32
* ------------------------------------
*
* If OpenGL switches to fullscreen, most players give it access GPU access,
* which means DXVA2 hardware decoding in mpv won't work. This can be worked
@@ -117,14 +145,14 @@ extern "C" {
* create a decoder. The device can be either the real device used for display,
* or a "blank" device created before switching to fullscreen.
*
* You can do this by adding "GL_MP_D3D_interfaces" to the additional extension
* string when calling mpv_opengl_cb_init_gl(). The get_proc_address callback
* should resolve a function named "glMPGetD3DInterface", which has the
* signature: "void* __stdcall glMPGetD3DInterface(const char* name)". If
* name is "IDirect3DDevice9", it should return a IDirect3DDevice9 pointer
* (or NULL if not available). libmpv will release this interface when it is
* done with it (usually when mpv_opengl_cb_uninit_gl() is called). New
* interface names can be added in the future.
* You can provide glMPGetNativeDisplay as described in the previous section.
* If it is called with name set to "IDirect3DDevice9", it should return a
* IDirect3DDevice9 pointer (or NULL if not available). libmpv will release
* this interface when it is done with it.
*
* In previous libmpv releases, this used "GL_MP_D3D_interfaces" and
* "glMPGetD3DInterface". This is deprecated; use glMPGetNativeDisplay instead
* (the semantics are 100% compatible).
*/
/**
+10 -7
View File
@@ -84,7 +84,6 @@ const struct m_opt_choice_alternatives mp_hwdec_names[] = {
{"no", HWDEC_NONE},
{"auto", HWDEC_AUTO},
{"vdpau", HWDEC_VDPAU},
{"vda", HWDEC_VDA},
{"videotoolbox",HWDEC_VIDEOTOOLBOX},
{"vaapi", HWDEC_VAAPI},
{"vaapi-copy", HWDEC_VAAPI_COPY},
@@ -186,6 +185,8 @@ const m_option_t mp_opts[] = {
{"http", 3})),
OPT_FLAG("tls-verify", network_tls_verify, 0),
OPT_STRING("tls-ca-file", network_tls_ca_file, M_OPT_FILE),
OPT_STRING("tls-cert-file", network_tls_cert_file, M_OPT_FILE),
OPT_STRING("tls-key-file", network_tls_key_file, M_OPT_FILE),
OPT_DOUBLE("network-timeout", network_timeout, M_OPT_MIN, .min = 0),
// ------------------------- demuxer options --------------------
@@ -373,7 +374,6 @@ const m_option_t mp_opts[] = {
OPT_FLOATRANGE("osd-bar-w", osd_bar_w, 0, 1, 100),
OPT_FLOATRANGE("osd-bar-h", osd_bar_h, 0, 0.1, 50),
OPT_SUBSTRUCT("osd", osd_style, osd_style_conf, 0),
OPT_FLAG("use-text-osd", use_text_osd, CONF_GLOBAL),
OPT_SUBSTRUCT("sub-text", sub_text_style, sub_style_conf, 0),
OPT_FLAG("sub-clear-on-seek", sub_clear_on_seek, 0),
@@ -384,6 +384,7 @@ const m_option_t mp_opts[] = {
OPT_SETTINGSLIST("ao-defaults", ao_defs, 0, &ao_obj_list),
OPT_STRING("audio-device", audio_device, 0),
OPT_STRING("audio-client-name", audio_client_name, 0),
OPT_FLAG("audio-fallback-to-null", ao_null_fallback, 0),
OPT_CHOICE("force-window", force_vo, 0,
({"no", 0}, {"yes", 1}, {"immediate", 2})),
OPT_FLAG("ontop", vo.ontop, M_OPT_FIXED),
@@ -464,6 +465,8 @@ const m_option_t mp_opts[] = {
OPT_INTRANGE("contrast", gamma_contrast, 0, -100, 100),
OPT_INTRANGE("hue", gamma_hue, 0, -100, 100),
OPT_INTRANGE("gamma", gamma_gamma, 0, -100, 100),
OPT_CHOICE_C("video-output-levels", video_output_levels, 0,
mp_csp_levels_names),
OPT_FLAG("keepaspect", vo.keepaspect, 0),
OPT_FLAG("keepaspect-window", vo.keepaspect_window, 0),
@@ -519,14 +522,13 @@ const m_option_t mp_opts[] = {
// a-v sync stuff:
OPT_FLAG("correct-pts", correct_pts, 0),
OPT_CHOICE("pts-association-mode", user_pts_assoc_mode, 0,
({"auto", 0}, {"decoder", 1}, {"sort", 2})),
OPT_FLAG("initial-audio-sync", initial_audio_sync, 0),
OPT_CHOICE("video-sync", video_sync, 0,
({"audio", VS_DEFAULT},
{"display-resample", VS_DISP_RESAMPLE},
{"display-resample-vdrop", VS_DISP_RESAMPLE_VDROP},
{"display-resample-desync", VS_DISP_RESAMPLE_NONE},
{"display-adrop", VS_DISP_ADROP},
{"display-vdrop", VS_DISP_VDROP},
{"display-desync", VS_DISP_NONE},
{"desync", VS_NONE})),
@@ -534,6 +536,8 @@ const m_option_t mp_opts[] = {
M_OPT_MIN, .min = 0),
OPT_DOUBLE("video-sync-max-audio-change", sync_max_audio_change,
M_OPT_MIN | M_OPT_MAX, .min = 0, .max = 1),
OPT_DOUBLE("video-sync-adrop-size", sync_audio_drop_size,
M_OPT_MIN | M_OPT_MAX, .min = 0, .max = 1),
OPT_CHOICE("hr-seek", hr_seek, 0,
({"no", -1}, {"absolute", 0}, {"yes", 1}, {"always", 1})),
OPT_FLOAT("hr-seek-demuxer-offset", hr_seek_demuxer_offset, 0),
@@ -713,11 +717,10 @@ const struct MPOpts mp_default_opts = {
.sub_use_margins = 1,
.ass_scale_with_window = 0,
.sub_scale_with_window = 1,
.use_text_osd = 1,
#if HAVE_LUA
.lua_load_osc = 1,
.lua_load_ytdl = 1,
.lua_ytdl_format = "best",
.lua_ytdl_format = NULL,
.lua_ytdl_raw_options = NULL,
#endif
.auto_load_scripts = 1,
@@ -728,6 +731,7 @@ const struct MPOpts mp_default_opts = {
.hr_seek_framedrop = 1,
.sync_max_video_change = 1,
.sync_max_audio_change = 0.125,
.sync_audio_drop_size = 0.020,
.load_config = 1,
.position_resume = 1,
.stream_cache = {
@@ -752,7 +756,6 @@ const struct MPOpts mp_default_opts = {
.edition_id = -1,
.default_max_pts_correction = -1,
.correct_pts = 1,
.user_pts_assoc_mode = 1,
.initial_audio_sync = 1,
.frame_dropping = 1,
.term_osd = 2,
+5 -2
View File
@@ -81,6 +81,7 @@ typedef struct MPOpts {
struct m_obj_settings *audio_driver_list, *ao_defs;
char *audio_device;
char *audio_client_name;
int ao_null_fallback;
int force_vo;
int softvol;
float mixer_init_volume;
@@ -103,6 +104,7 @@ typedef struct MPOpts {
int gamma_contrast;
int gamma_saturation;
int gamma_hue;
int video_output_levels;
int stop_screensaver;
int cursor_autohide_delay;
@@ -142,11 +144,11 @@ typedef struct MPOpts {
int chapterrange[2];
int edition_id;
int correct_pts;
int user_pts_assoc_mode;
int initial_audio_sync;
int video_sync;
double sync_max_video_change;
double sync_max_audio_change;
double sync_audio_drop_size;
int hr_seek;
float hr_seek_demuxer_offset;
int hr_seek_framedrop;
@@ -233,7 +235,6 @@ typedef struct MPOpts {
char **sub_paths;
int sub_auto;
int audiofile_auto;
int use_text_osd;
int osd_bar_visible;
float osd_bar_align_x;
float osd_bar_align_y;
@@ -276,6 +277,8 @@ typedef struct MPOpts {
char **network_http_header_fields;
int network_tls_verify;
char *network_tls_ca_file;
char *network_tls_cert_file;
char *network_tls_key_file;
double network_timeout;
struct tv_params *tv_params;
+74 -6
View File
@@ -29,6 +29,7 @@
#include "common/encode.h"
#include "options/options.h"
#include "common/common.h"
#include "osdep/timer.h"
#include "audio/mixer.h"
#include "audio/audio.h"
@@ -153,6 +154,7 @@ void reset_audio_state(struct MPContext *mpctx)
mp_audio_buffer_clear(mpctx->ao_buffer);
mpctx->audio_status = mpctx->d_audio ? STATUS_SYNCING : STATUS_EOF;
mpctx->delay = 0;
mpctx->audio_stat_start = 0;
}
void uninit_audio_out(struct MPContext *mpctx)
@@ -260,11 +262,15 @@ void reinit_audio_chain(struct MPContext *mpctx)
}
if (!mpctx->ao) {
bool spdif_fallback = af_fmt_is_spdif(afs->output.format) &&
mpctx->d_audio->spdif_passthrough;
bool ao_null_fallback = opts->ao_null_fallback && !spdif_fallback;
mp_chmap_remove_useless_channels(&afs->output.channels,
&opts->audio_output_channels);
mp_audio_set_channels(&afs->output, &afs->output.channels);
mpctx->ao = ao_init_best(mpctx->global, mpctx->input,
mpctx->ao = ao_init_best(mpctx->global, ao_null_fallback, mpctx->input,
mpctx->encode_lavc_ctx, afs->output.rate,
afs->output.format, afs->output.channels);
@@ -283,10 +289,9 @@ void reinit_audio_chain(struct MPContext *mpctx)
if (!mpctx->ao) {
// If spdif was used, try to fallback to PCM.
if (af_fmt_is_spdif(afs->output.format) &&
mpctx->d_audio->spdif_passthrough)
{
if (spdif_fallback) {
mpctx->d_audio->spdif_passthrough = false;
mpctx->d_audio->spdif_failed = true;
if (!audio_init_best_codec(mpctx->d_audio))
goto init_error;
reset_audio_state(mpctx);
@@ -400,11 +405,31 @@ static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags
if (played > 0) {
mpctx->shown_aframes += played;
mpctx->delay += played / real_samplerate;
mpctx->written_audio += played / (double)out_format.rate;
return played;
}
return 0;
}
static void dump_audio_stats(struct MPContext *mpctx)
{
if (!mp_msg_test(mpctx->log, MSGL_STATS))
return;
if (mpctx->audio_status != STATUS_PLAYING || !mpctx->ao || mpctx->paused) {
mpctx->audio_stat_start = 0;
return;
}
double delay = ao_get_delay(mpctx->ao);
if (!mpctx->audio_stat_start) {
mpctx->audio_stat_start = mp_time_us();
mpctx->written_audio = delay;
}
double current_audio = mpctx->written_audio - delay;
double current_time = (mp_time_us() - mpctx->audio_stat_start) / 1e6;
MP_STATS(mpctx, "value %f ao-dev", current_audio - current_time);
}
// Return the number of samples that must be skipped or prepended to reach the
// target audio pts after a seek (for A/V sync or hr-seek).
// Return value (*skip):
@@ -441,7 +466,7 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
if (mpctx->video_status < STATUS_READY)
return false; // wait until we know a video PTS
if (mpctx->video_next_pts != MP_NOPTS_VALUE)
sync_pts = mpctx->video_next_pts - (opts->audio_delay - mpctx->delay);
sync_pts = mpctx->video_next_pts - opts->audio_delay;
} else if (mpctx->hrseek_active) {
sync_pts = mpctx->hrseek_pts;
}
@@ -468,11 +493,23 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
struct MPOpts *opts = mpctx->opts;
struct dec_audio *d_audio = mpctx->d_audio;
dump_audio_stats(mpctx);
if (mpctx->ao && ao_query_and_reset_events(mpctx->ao, AO_EVENT_RELOAD)) {
ao_reset(mpctx->ao);
uninit_audio_out(mpctx);
if (d_audio)
if (d_audio) {
if (mpctx->d_audio->spdif_failed) {
mpctx->d_audio->spdif_failed = false;
mpctx->d_audio->spdif_passthrough = true;
if (!audio_init_best_codec(mpctx->d_audio)) {
MP_ERR(mpctx, "Error reinitializing audio.\n");
error_on_track(mpctx, mpctx->current_track[0][STREAM_AUDIO]);
return;
}
}
mpctx->audio_status = STATUS_SYNCING;
}
}
if (!d_audio)
@@ -516,6 +553,20 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
playsize = MPMAX(1, playsize + skip); // silence will be prepended
}
int skip_duplicate = 0; // >0: skip, <0: duplicate
if (mpctx->display_sync_active && opts->video_sync == VS_DISP_ADROP &&
fabs(mpctx->last_av_difference) >= opts->sync_audio_drop_size &&
mpctx->audio_status == STATUS_PLAYING)
{
int samples = ceil(opts->sync_audio_drop_size * play_samplerate);
int align = af_format_sample_alignment(out_format.format);
samples = (samples + align / 2) / align * align;
skip_duplicate = mpctx->last_av_difference >= 0 ? -samples : samples;
playsize = MPMAX(playsize, samples);
}
int status = AD_OK;
bool working = false;
if (playsize > mp_audio_buffer_samples(mpctx->ao_buffer)) {
@@ -563,6 +614,21 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
end_sync = true;
}
if (skip_duplicate) {
int max = mp_audio_buffer_samples(mpctx->ao_buffer);
if (abs(skip_duplicate) > max)
skip_duplicate = skip_duplicate >= 0 ? max : -max;
mpctx->last_av_difference += skip_duplicate / play_samplerate;
if (skip_duplicate >= 0) {
mp_audio_buffer_skip(mpctx->ao_buffer, skip_duplicate);
MP_STATS(mpctx, "drop-audio");
} else {
mp_audio_buffer_duplicate(mpctx->ao_buffer, -skip_duplicate);
MP_STATS(mpctx, "duplicate-audio");
}
MP_VERBOSE(mpctx, "audio skip_duplicate=%d\n", skip_duplicate);
}
if (mpctx->audio_status == STATUS_SYNCING) {
if (end_sync)
mpctx->audio_status = STATUS_FILLING;
@@ -617,6 +683,8 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
assert(played >= 0 && played <= data.samples);
mp_audio_buffer_skip(mpctx->ao_buffer, played);
dump_audio_stats(mpctx);
mpctx->audio_status = STATUS_PLAYING;
if (audio_eof && !playsize) {
mpctx->audio_status = STATUS_DRAINING;
+1 -1
View File
@@ -1601,7 +1601,7 @@ static const char *const err_table[] = {
[-MPV_ERROR_LOADING_FAILED] = "loading failed",
[-MPV_ERROR_AO_INIT_FAILED] = "audio output initialization failed",
[-MPV_ERROR_VO_INIT_FAILED] = "audio output initialization failed",
[-MPV_ERROR_NOTHING_TO_PLAY] = "no audio or video data found",
[-MPV_ERROR_NOTHING_TO_PLAY] = "no audio or video data played",
[-MPV_ERROR_UNKNOWN_FORMAT] = "unrecognized file format",
[-MPV_ERROR_UNSUPPORTED] = "not supported",
[-MPV_ERROR_NOT_IMPLEMENTED] = "operation not implemented",
+22 -11
View File
@@ -484,6 +484,9 @@ static int mp_property_stream_end(void *ctx, struct m_property *prop,
// Assumes prop is the type of the actual property.
static int property_time(int action, void *arg, double time)
{
if (time == MP_NOPTS_VALUE)
return M_PROPERTY_UNAVAILABLE;
const struct m_option time_type = {.type = CONF_TYPE_TIME};
switch (action) {
case M_PROPERTY_GET:
@@ -652,6 +655,9 @@ static bool time_remaining(MPContext *mpctx, double *remaining)
double len = get_time_length(mpctx);
double playback = get_playback_time(mpctx);
if (playback == MP_NOPTS_VALUE)
return false;
*remaining = len - playback;
return len >= 0;
@@ -1611,7 +1617,7 @@ static int mp_property_audio_device(void *ctx, struct m_property *prop,
struct ao_device_list *list = ao_hotplug_get_device_list(cmd->hotplug);
for (int n = 0; n < list->num_devices; n++) {
struct ao_device_desc *dev = &list->devices[n];
if (dev->name && strcmp(dev->name, mpctx->opts->audio_device)) {
if (dev->name && strcmp(dev->name, mpctx->opts->audio_device) == 0) {
*(char **)arg = talloc_strdup(NULL, dev->desc ? dev->desc : "?");
return M_PROPERTY_OK;
}
@@ -2370,18 +2376,19 @@ static int mp_property_framedrop(void *ctx, struct m_property *prop,
static int mp_property_video_color(void *ctx, struct m_property *prop,
int action, void *arg)
{
const char *name = prop->priv ? prop->priv : prop->name;
MPContext *mpctx = ctx;
if (!mpctx->d_video)
return M_PROPERTY_UNAVAILABLE;
switch (action) {
case M_PROPERTY_SET: {
if (video_set_colors(mpctx->d_video, prop->name, *(int *) arg) <= 0)
if (video_set_colors(mpctx->d_video, name, *(int *) arg) <= 0)
return M_PROPERTY_UNAVAILABLE;
break;
}
case M_PROPERTY_GET:
if (video_get_colors(mpctx->d_video, prop->name, (int *)arg) <= 0)
if (video_get_colors(mpctx->d_video, name, (int *)arg) <= 0)
return M_PROPERTY_UNAVAILABLE;
// Write new value to option variable
mp_property_generic_option(mpctx, prop, M_PROPERTY_SET, arg);
@@ -2440,8 +2447,6 @@ static int property_imgparams(struct mp_image_params p, int action, void *arg)
SUB_PROP_STR(m_opt_choice_str(mp_csp_names, p.colorspace))},
{"colorlevels",
SUB_PROP_STR(m_opt_choice_str(mp_csp_levels_names, p.colorlevels))},
{"outputlevels",
SUB_PROP_STR(m_opt_choice_str(mp_csp_levels_names, p.outputlevels))},
{"primaries",
SUB_PROP_STR(m_opt_choice_str(mp_csp_prim_names, p.primaries))},
{"gamma",
@@ -3082,11 +3087,18 @@ static int mp_property_packet_bitrate(void *ctx, struct m_property *prop,
int type = (uintptr_t)prop->priv & ~0x100;
bool old = (uintptr_t)prop->priv & 0x100;
if (!mpctx->demuxer)
struct demuxer *demuxer = NULL;
if (mpctx->current_track[0][type])
demuxer = mpctx->current_track[0][type]->demuxer;
if (!demuxer)
demuxer = mpctx->demuxer;
if (!demuxer)
return M_PROPERTY_UNAVAILABLE;
double r[STREAM_TYPE_COUNT];
if (demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_BITRATE_STATS, &r) < 1)
if (demux_control(demuxer, DEMUXER_CTRL_GET_BITRATE_STATS, &r) < 1)
return M_PROPERTY_UNAVAILABLE;
if (r[type] < 0)
return M_PROPERTY_UNAVAILABLE;
// r[type] is in bytes/second -> bits
@@ -3406,7 +3418,6 @@ static const struct m_property mp_properties[] = {
{"demuxer-cache-idle", mp_property_demuxer_cache_idle},
{"cache-buffering-state", mp_property_cache_buffering},
{"paused-for-cache", mp_property_paused_for_cache},
{"pts-association-mode", mp_property_generic_option},
{"hr-seek", mp_property_generic_option},
{"clock", mp_property_clock},
{"seekable", mp_property_seekable},
@@ -3453,6 +3464,8 @@ static const struct m_property mp_properties[] = {
{"contrast", mp_property_video_color},
{"saturation", mp_property_video_color},
{"hue", mp_property_video_color},
{"video-output-levels", mp_property_video_color,
.priv = (void *)"output-levels"},
{"panscan", panscan_property_helper},
{"video-zoom", panscan_property_helper},
{"video-align-x", panscan_property_helper},
@@ -3563,7 +3576,6 @@ static const struct m_property mp_properties[] = {
M_PROPERTY_ALIAS("sub", "sid"),
M_PROPERTY_ALIAS("colormatrix", "video-params/colormatrix"),
M_PROPERTY_ALIAS("colormatrix-input-range", "video-params/colorlevels"),
M_PROPERTY_ALIAS("colormatrix-output-range", "video-params/outputlevels"),
M_PROPERTY_ALIAS("colormatrix-primaries", "video-params/primaries"),
M_PROPERTY_ALIAS("colormatrix-gamma", "video-params/gamma"),
@@ -3734,7 +3746,6 @@ static const struct property_osd_display {
{ "chapter", .seek_msg = OSD_SEEK_INFO_CHAPTER_TEXT,
.seek_bar = OSD_SEEK_INFO_BAR },
{ "edition", .seek_msg = OSD_SEEK_INFO_EDITION },
{ "pts-association-mode", "PTS association mode" },
{ "hr-seek", "hr-seek" },
{ "speed", "Speed" },
{ "clock", "Clock" },
@@ -4590,7 +4601,7 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
case MP_CMD_STOP:
playlist_clear(mpctx->playlist);
if (!mpctx->stop_play)
if (mpctx->stop_play != PT_QUIT)
mpctx->stop_play = PT_STOP;
break;
+3 -5
View File
@@ -286,10 +286,6 @@ void mp_write_watch_later_conf(struct MPContext *mpctx)
goto exit;
}
double pos = get_current_time(mpctx);
if (pos == MP_NOPTS_VALUE)
goto exit;
mp_mk_config_dir(mpctx->global, MP_WATCH_LATER_CONF);
conffile = mp_get_playback_resume_config_filename(mpctx, filename);
@@ -307,7 +303,9 @@ void mp_write_watch_later_conf(struct MPContext *mpctx)
write_name[n] = (unsigned char)filename[n] < 32 ? '_' : filename[n];
fprintf(file, "# %s\n", write_name);
}
fprintf(file, "start=%f\n", pos);
double pos = get_current_time(mpctx);
if (pos != MP_NOPTS_VALUE)
fprintf(file, "start=%f\n", pos);
for (int i = 0; backup_properties[i]; i++) {
const char *pname = backup_properties[i];
char *val = NULL;
+5
View File
@@ -84,6 +84,7 @@ enum video_sync {
VS_DISP_RESAMPLE,
VS_DISP_RESAMPLE_VDROP,
VS_DISP_RESAMPLE_NONE,
VS_DISP_ADROP,
VS_DISP_VDROP,
VS_DISP_NONE,
VS_NONE,
@@ -92,6 +93,7 @@ enum video_sync {
#define VS_IS_DISP(x) ((x) == VS_DISP_RESAMPLE || \
(x) == VS_DISP_RESAMPLE_VDROP || \
(x) == VS_DISP_RESAMPLE_NONE || \
(x) == VS_DISP_ADROP || \
(x) == VS_DISP_VDROP || \
(x) == VS_DISP_NONE)
@@ -302,6 +304,9 @@ typedef struct MPContext {
double last_vo_pts;
// Video PTS, or audio PTS if video has ended.
double playback_pts;
// audio stats only
int64_t audio_stat_start;
double written_audio;
int last_chapter;
+2 -1
View File
@@ -19,7 +19,8 @@ static const char *const sub_exts[] = {"utf", "utf8", "utf-8", "idx", "sub", "sr
"js", "ass", "mks", "vtt", "sup", NULL};
static const char *const audio_exts[] = {"mp3", "aac", "mka", "dts", "flac",
"ogg", "m4a", "ac3", "opus", NULL};
"ogg", "m4a", "ac3", "opus", "wav",
NULL};
static bool test_ext_list(bstr ext, const char *const *list)
{
+5 -3
View File
@@ -198,10 +198,12 @@ void update_demuxer_properties(struct MPContext *mpctx)
continue;
}
}
struct mp_log *log = mp_log_new(NULL, mpctx->log, "!display-tags");
if (!had_output)
MP_INFO(mpctx, "File tags:\n");
MP_INFO(mpctx, " %s: %s\n", info->keys[n], info->values[n]);
mp_info(log, "File tags:\n");
mp_info(log, " %s: %s\n", info->keys[n], info->values[n]);
had_output = true;
talloc_free(log);
}
talloc_free(mpctx->filtered_tags);
mpctx->filtered_tags = info;
@@ -1095,7 +1097,7 @@ reopen_file:
}
open_demux_reentrant(mpctx);
if (!mpctx->master_demuxer)
if (!mpctx->master_demuxer || mpctx->stop_play)
goto terminate_playback;
mpctx->demuxer = mpctx->master_demuxer;
+46 -57
View File
@@ -3,8 +3,7 @@ local msg = require 'mp.msg'
local ytdl = {
path = "youtube-dl",
minver = "2015.02.23.1",
vercheck = nil,
searched = false
}
local function exec(args)
@@ -12,9 +11,9 @@ local function exec(args)
return ret.status, ret.stdout, ret
end
-- return if it was explicitly set on the command line
-- return true if it was explicitly set on the command line
local function option_was_set(name)
return mp.get_property_bool("option-info/" .. name .. "/set-from-commandline",
return mp.get_property_bool("option-info/" ..name.. "/set-from-commandline",
false)
end
@@ -51,41 +50,25 @@ local function append_rtmp_prop(props, name, value)
return props..name.."=\""..value.."\""
end
local function edl_escape(url)
return "%" .. string.len(url) .. "%" .. url
end
mp.add_hook("on_load", 10, function ()
local url = mp.get_property("stream-open-filename")
if (url:find("http://") == 1) or (url:find("https://") == 1)
or (url:find("ytdl://") == 1) then
-- check version of youtube-dl if not done yet
if (ytdl.vercheck == nil) then
-- check for youtube-dl in mpv's config dir
-- check for youtube-dl in mpv's config dir
if not (ytdl.searched) then
local ytdl_mcd = mp.find_config_file("youtube-dl")
if not (ytdl_mcd == nil) then
msg.verbose("found youtube-dl at: " .. ytdl_mcd)
ytdl.path = ytdl_mcd
end
msg.debug("checking ytdl version ...")
local es, version = exec({ytdl.path, "--version"})
if (es < 0) then
msg.warn("youtube-dl not found, not executable, or broken.")
ytdl.vercheck = false
elseif (version < ytdl.minver) then
msg.verbose("found youtube-dl version: " .. version)
msg.warn("Your version of youtube-dl is too old! "
.. "You need at least version '"..ytdl.minver
.. "', try running `youtube-dl -U`.")
ytdl.vercheck = false
else
msg.verbose("found youtube-dl version: " .. version)
ytdl.vercheck = true
end
end
if not (ytdl.vercheck) then
return
ytdl.searched = true
end
-- strip ytdl://
@@ -95,14 +78,18 @@ mp.add_hook("on_load", 10, function ()
local format = mp.get_property("options/ytdl-format")
local raw_options = mp.get_property_native("options/ytdl-raw-options")
local allsubs = true
local command = {
ytdl.path, "--no-warnings", "-J", "--flat-playlist", "--all-subs",
ytdl.path, "--no-warnings", "-J", "--flat-playlist",
"--sub-format", "ass/srt/best", "--no-playlist"
}
-- Checks if video option is "no", change options accordingly
if (mp.get_property("options/vid") == "no") then
-- Checks if video option is "no", change format accordingly,
-- but only if user didn't explicitly set one
if (mp.get_property("options/vid") == "no")
and not option_was_set("ytdl-format") then
format = "bestaudio/best"
msg.verbose("Video disabled. Only using audio")
end
@@ -117,6 +104,13 @@ mp.add_hook("on_load", 10, function ()
if (arg ~= "") then
table.insert(command, arg)
end
if (param == "sub-lang") and (arg ~= "") then
allsubs = false
end
end
if (allsubs == true) then
table.insert(command, "--all-subs")
end
table.insert(command, "--")
table.insert(command, url)
@@ -145,7 +139,8 @@ mp.add_hook("on_load", 10, function ()
msg.verbose("Got direct URL")
return
elseif not (json["_type"] == nil)
and ((json["_type"] == "playlist") or (json["_type"] == "multi_video")) then
and ((json["_type"] == "playlist")
or (json["_type"] == "multi_video")) then
-- a playlist
if (#json.entries == 0) then
@@ -159,13 +154,9 @@ mp.add_hook("on_load", 10, function ()
and (json.entries[1]["webpage_url"] == json["webpage_url"]) then
msg.verbose("multi-arc video detected, building EDL")
local playlist = "edl://"
for i, entry in pairs(json.entries) do
local urllength = string.len(entry.url)
playlist = playlist .. "%" .. urllength .. "%" .. entry.url .. ";"
playlist = playlist .. edl_escape(entry.url) .. ";"
end
msg.debug("EDL: " .. playlist)
@@ -177,7 +168,8 @@ mp.add_hook("on_load", 10, function ()
mp.set_property("stream-open-filename", playlist)
if not (json.title == nil) then
mp.set_property("file-local-options/force-media-title", json.title)
mp.set_property("file-local-options/force-media-title",
json.title)
end
else
@@ -206,21 +198,13 @@ mp.add_hook("on_load", 10, function ()
-- DASH?
if not (json["requested_formats"] == nil) then
msg.info("Using DASH, expect inaccurate duration.")
if not (json.duration == nil) then
msg.info("Actual duration: " .. mp.format_time(json.duration))
end
-- video url
streamurl = json["requested_formats"][1].url
-- audio url
mp.set_property("file-local-options/audio-file",
json["requested_formats"][2].url)
-- workaround for slow startup (causes inaccurate duration)
mp.set_property("file-local-options/demuxer-lavf-o",
"fflags=+ignidx")
mp.commandv("audio-add", json["requested_formats"][2].url,
"select", json["requested_formats"][2]["format_note"])
elseif not (json.url == nil) then
-- normal video
@@ -251,7 +235,7 @@ mp.add_hook("on_load", 10, function ()
end
if not (sub == nil) then
mp.commandv("sub_add", sub,
mp.commandv("sub-add", sub,
"auto", sub_info.ext, lang)
else
msg.verbose("No subtitle data/url for ["..lang.."]")
@@ -259,19 +243,24 @@ mp.add_hook("on_load", 10, function ()
end
end
-- set start and end time
-- set start time
if not (json.start_time == nil) then
msg.debug("setting start to: " .. json.start_time .. " secs")
mp.set_property("file-local-options/start",json.start_time)
msg.debug("Setting start to: " .. json.start_time .. " secs")
mp.set_property("file-local-options/start", json.start_time)
end
-- for rtmp
if not (json.play_path == nil) then
local rtmp_prop = append_rtmp_prop(nil, "rtmp_tcurl", streamurl)
rtmp_prop = append_rtmp_prop(rtmp_prop, "rtmp_pageurl", json.page_url)
rtmp_prop = append_rtmp_prop(rtmp_prop, "rtmp_playpath", json.play_path)
rtmp_prop = append_rtmp_prop(rtmp_prop, "rtmp_swfverify", json.player_url)
rtmp_prop = append_rtmp_prop(rtmp_prop, "rtmp_app", json.app)
local rtmp_prop = append_rtmp_prop(nil,
"rtmp_tcurl", streamurl)
rtmp_prop = append_rtmp_prop(rtmp_prop,
"rtmp_pageurl", json.page_url)
rtmp_prop = append_rtmp_prop(rtmp_prop,
"rtmp_playpath", json.play_path)
rtmp_prop = append_rtmp_prop(rtmp_prop,
"rtmp_swfverify", json.player_url)
rtmp_prop = append_rtmp_prop(rtmp_prop,
"rtmp_app", json.app)
mp.set_property("file-local-options/stream-lavf-o", rtmp_prop)
end
+1 -1
View File
@@ -466,7 +466,7 @@ int mp_initialize(struct MPContext *mpctx, char **options)
if (opts->consolecontrols && cas_terminal_owner(mpctx, mpctx))
terminal_setup_getch(mpctx->input);
if (handle_force_window(mpctx, false) < 0)
if (opts->force_vo == 2 && handle_force_window(mpctx, false) < 0)
return -1;
#if !defined(__MINGW32__)
+12 -3
View File
@@ -54,6 +54,14 @@ static void sadd_hhmmssff(char **buf, double time, bool fractions)
talloc_free(s);
}
// If time unknown (MP_NOPTS_VALUE), use 0 instead.
static void sadd_hhmmssff_u(char **buf, double time, bool fractions)
{
if (time == MP_NOPTS_VALUE)
time = 0;
sadd_hhmmssff(buf, time, fractions);
}
static void sadd_percentage(char **buf, int percent) {
if (percent >= 0)
*buf = talloc_asprintf_append(*buf, " (%d%%)", percent);
@@ -191,7 +199,7 @@ static void print_status(struct MPContext *mpctx)
saddf(&line, ": ");
// Playback position
sadd_hhmmssff(&line, get_playback_time(mpctx), mpctx->opts->osd_fractions);
sadd_hhmmssff_u(&line, get_playback_time(mpctx), mpctx->opts->osd_fractions);
double len = get_time_length(mpctx);
if (len >= 0) {
@@ -360,7 +368,8 @@ void set_osd_bar_chapters(struct MPContext *mpctx, int type)
} else {
int num = get_chapter_count(mpctx);
for (int n = 0; n < num; n++) {
double time = chapter_start_time(mpctx, n);
double time = chapter_start_time(mpctx, n) -
get_start_time(mpctx);
if (time >= 0) {
float pos = time / len;
MP_TARRAY_APPEND(mpctx, mpctx->osd_progbar.stops,
@@ -429,7 +438,7 @@ static void sadd_osd_status(char **buffer, struct MPContext *mpctx, int level)
*buffer = talloc_strdup_append(*buffer, text);
talloc_free(text);
} else {
sadd_hhmmssff(buffer, get_playback_time(mpctx), fractions);
sadd_hhmmssff_u(buffer, get_playback_time(mpctx), fractions);
if (level == 3) {
double len = get_time_length(mpctx);
if (len >= 0) {
+12 -9
View File
@@ -199,7 +199,8 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
break;
case MPSEEK_RELATIVE:
direction = seek.amount > 0 ? 1 : -1;
target_time = seek.amount + get_current_time(mpctx);
double cur = get_current_time(mpctx);
target_time = seek.amount + (cur == MP_NOPTS_VALUE ? 0 : cur);
break;
case MPSEEK_FACTOR: ;
double len = get_time_length(mpctx);
@@ -390,18 +391,20 @@ double get_time_length(struct MPContext *mpctx)
double get_current_time(struct MPContext *mpctx)
{
struct demuxer *demuxer = mpctx->demuxer;
if (!demuxer)
return 0;
if (mpctx->playback_pts != MP_NOPTS_VALUE)
return mpctx->playback_pts;
if (mpctx->last_seek_pts != MP_NOPTS_VALUE)
return mpctx->last_seek_pts;
return 0;
if (demuxer) {
if (mpctx->playback_pts != MP_NOPTS_VALUE)
return mpctx->playback_pts;
if (mpctx->last_seek_pts != MP_NOPTS_VALUE)
return mpctx->last_seek_pts;
}
return MP_NOPTS_VALUE;
}
double get_playback_time(struct MPContext *mpctx)
{
double cur = get_current_time(mpctx);
if (cur == MP_NOPTS_VALUE)
return cur;
double start = get_start_time(mpctx);
// During seeking, the time corresponds to the last seek time - apply some
// cosmetics to it.
@@ -917,7 +920,7 @@ int handle_force_window(struct MPContext *mpctx, bool force)
.w = w, .h = h,
.d_w = w, .d_h = h,
};
if (vo_reconfig(vo, &p, 0) < 0)
if (vo_reconfig(vo, &p) < 0)
goto err;
vo_control(vo, VOCTRL_RESTORE_SCREENSAVER, NULL);
vo_set_paused(vo, true);
+43 -23
View File
@@ -550,6 +550,9 @@ static void adjust_sync(struct MPContext *mpctx, double v_pts, double frame_time
change = max_change;
mpctx->delay += change;
mpctx->total_avsync_change += change;
if (mpctx->display_sync_active)
mpctx->total_avsync_change = 0;
}
// Make the frame at position 0 "known" to the playback logic. This must happen
@@ -748,8 +751,8 @@ static void update_avsync_before_frame(struct MPContext *mpctx)
}
}
// Update the A/V sync difference after a video frame has been shown.
static void update_avsync_after_frame(struct MPContext *mpctx)
// Update the A/V sync difference when a new video frame is being shown.
static void update_av_diff(struct MPContext *mpctx, double offset)
{
struct MPOpts *opts = mpctx->opts;
@@ -760,13 +763,12 @@ static void update_avsync_after_frame(struct MPContext *mpctx)
return;
double a_pos = playing_audio_pts(mpctx);
if (a_pos != MP_NOPTS_VALUE && mpctx->video_pts != MP_NOPTS_VALUE) {
mpctx->last_av_difference = a_pos - mpctx->video_pts
+ opts->audio_delay + offset;
}
mpctx->last_av_difference = a_pos - mpctx->video_pts + opts->audio_delay;
if (mpctx->time_frame > 0)
mpctx->last_av_difference += mpctx->time_frame * mpctx->video_speed;
if (a_pos == MP_NOPTS_VALUE || mpctx->video_pts == MP_NOPTS_VALUE) {
mpctx->last_av_difference = 0;
} else if (fabs(mpctx->last_av_difference) > 0.5 && !mpctx->drop_message_shown) {
if (fabs(mpctx->last_av_difference) > 0.5 && !mpctx->drop_message_shown) {
MP_WARN(mpctx, "%s", av_desync_help_text);
mpctx->drop_message_shown = true;
}
@@ -787,6 +789,7 @@ static void init_vo(struct MPContext *mpctx)
video_set_colors(d_video, "saturation", opts->gamma_saturation);
if (opts->gamma_hue != 1000)
video_set_colors(d_video, "hue", opts->gamma_hue);
video_set_colors(d_video, "output-levels", opts->video_output_levels);
mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL);
}
@@ -911,7 +914,7 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
bool resample = mode == VS_DISP_RESAMPLE || mode == VS_DISP_RESAMPLE_VDROP ||
mode == VS_DISP_RESAMPLE_NONE;
bool drop = mode == VS_DISP_VDROP || mode == VS_DISP_RESAMPLE ||
mode == VS_DISP_RESAMPLE_VDROP;
mode == VS_DISP_ADROP || mode == VS_DISP_RESAMPLE_VDROP;
drop &= (opts->frame_dropping & 1);
if (resample && using_spdif_passthrough(mpctx))
@@ -959,10 +962,11 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
// If we are too far ahead/behind, attempt to drop/repeat frames. In
// particular, don't attempt to change speed for them.
if (drop) {
// Tolerate some desync to avoid frame dropping due to jitter.
if (drop && fabs(av_diff) >= 0.080 && fabs(av_diff) / vsync >= 2)
drop_repeat = -av_diff / vsync; // round towards 0
av_diff -= drop_repeat * vsync;
}
av_diff += drop_repeat * vsync;
if (resample) {
double audio_factor = 1.0;
@@ -985,7 +989,7 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
if (av_diff * -mpctx->display_sync_drift_dir >= 0)
new = 0;
if (fabs(av_diff) > max_drift)
new = copysign(1, av_diff);
new = av_diff >= 0 ? 1 : -1;
if (mpctx->display_sync_drift_dir != new) {
MP_VERBOSE(mpctx, "Change display sync audio drift: %d\n", new);
mpctx->display_sync_drift_dir = new;
@@ -1022,16 +1026,21 @@ static void handle_display_sync_frame(struct MPContext *mpctx,
vo_increment_drop_count(vo, 1);
// Estimate the video position, so we can calculate a good A/V difference
// value with update_avsync_after_frame() later. This is used to estimate
// A/V drift.
mpctx->time_frame = 0;
// value below. This is used to estimate A/V drift.
double time_left = (vo_get_next_frame_start_time(vo) - mp_time_us()) / 1e6;
if (time_left >= 0)
mpctx->time_frame += time_left;
time_left = MPMAX(time_left, 0);
// We also know that the timing is (necessarily) off, because we have to
// align frame timings on the vsync boundaries. This is unavoidable, and
// for the sake of the video sync calculations we pretend it's perfect.
mpctx->time_frame -= mpctx->display_sync_error;
time_left -= mpctx->display_sync_error;
// Likewise, we know sync is off, but is going to be compensated.
time_left += drop_repeat * vsync;
mpctx->total_avsync_change = 0;
update_av_diff(mpctx, time_left);
// A bad guess, only needed when reverting to audio sync.
mpctx->time_frame = time_left;
mpctx->speed_factor_v = video_speed_correction;
@@ -1053,6 +1062,16 @@ done:
MPMAX(0, mpctx->display_sync_disable_counter - 1);
}
static void schedule_frame(struct MPContext *mpctx, struct vo_frame *frame)
{
handle_display_sync_frame(mpctx, frame);
if (!mpctx->display_sync_active) {
update_av_diff(mpctx, mpctx->time_frame > 0 ?
mpctx->time_frame * mpctx->video_speed : 0);
}
}
// Return the next frame duration as stored in the file.
// frame=0 means the current frame, 1 the frame after that etc.
// Can return -1, though usually will return a fallback if frame unavailable.
@@ -1100,11 +1119,14 @@ void write_video(struct MPContext *mpctx, double endpts)
return;
if (r == VD_EOF) {
int prev_state = mpctx->video_status;
mpctx->video_status =
vo_still_displaying(vo) ? STATUS_DRAINING : STATUS_EOF;
mpctx->delay = 0;
mpctx->last_av_difference = 0;
MP_DBG(mpctx, "video EOF (status=%d)\n", mpctx->video_status);
if (prev_state != mpctx->video_status)
mpctx->sleeptime = 0;
return;
}
@@ -1131,7 +1153,7 @@ void write_video(struct MPContext *mpctx, double endpts)
info->name, p.w, p.h, extra, vo_format_name(p.imgfmt));
MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description);
int vo_r = vo_reconfig(vo, &p, 0);
int vo_r = vo_reconfig(vo, &p);
if (vo_r < 0) {
mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED;
goto error;
@@ -1175,13 +1197,11 @@ void write_video(struct MPContext *mpctx, double endpts)
frame->duration = MPCLAMP(diff, 0, 10) * 1e6;
}
handle_display_sync_frame(mpctx, frame);
mpctx->video_pts = mpctx->next_frames[0]->pts;
mpctx->last_vo_pts = mpctx->video_pts;
mpctx->playback_pts = mpctx->video_pts;
update_avsync_after_frame(mpctx);
schedule_frame(mpctx, frame);
mpctx->osd_force_update = true;
update_osd_msg(mpctx);
+4 -2
View File
@@ -288,6 +288,8 @@ static int open_internal(const stream_info_t *sinfo, const char *url, int flags,
s->is_network = sinfo->is_network;
s->mode = flags & (STREAM_READ | STREAM_WRITE);
MP_VERBOSE(s, "Opening %s\n", url);
if ((s->mode & STREAM_WRITE) && !sinfo->can_write) {
MP_VERBOSE(s, "No write access implemented.\n");
talloc_free(s);
@@ -328,11 +330,11 @@ static int open_internal(const stream_info_t *sinfo, const char *url, int flags,
s->uncached_type = s->type;
MP_VERBOSE(s, "Opened: %s\n", url);
if (s->mime_type)
MP_VERBOSE(s, "Mime-type: '%s'\n", s->mime_type);
MP_VERBOSE(s, "Stream opened successfully.\n");
*ret = s;
return STREAM_OK;
}
+4 -1
View File
@@ -168,6 +168,10 @@ void mp_setup_av_network_options(AVDictionary **dict, struct mpv_global *global,
av_dict_set(dict, "tls_verify", opts->network_tls_verify ? "1" : "0", 0);
if (opts->network_tls_ca_file)
av_dict_set(dict, "ca_file", opts->network_tls_ca_file, 0);
if (opts->network_tls_cert_file)
av_dict_set(dict, "cert_file", opts->network_tls_cert_file, 0);
if (opts->network_tls_key_file)
av_dict_set(dict, "key_file", opts->network_tls_key_file, 0);
char *cust_headers = talloc_strdup(temp, "");
if (opts->network_referrer) {
cust_headers = talloc_asprintf_append(cust_headers, "Referer: %s\r\n",
@@ -242,7 +246,6 @@ static int open_f(stream_t *stream)
talloc_free(temp);
return STREAM_OK;
}
MP_VERBOSE(stream, "Opening %s\n", filename);
// Replace "mms://" with "mmsh://", so that most mms:// URLs just work.
bstr b_filename = bstr0(filename);
-1
View File
@@ -44,7 +44,6 @@ void mp_ass_set_style(ASS_Style *style, double res_y,
if (!style->FontName || strcmp(style->FontName, opts->font) != 0) {
free(style->FontName);
style->FontName = strdup(opts->font);
style->treat_fontname_as_pattern = 1;
}
}
+2 -7
View File
@@ -480,13 +480,8 @@ void osd_rescale_bitmaps(struct sub_bitmaps *imgs, int frame_w, int frame_h,
double yscale = (double)vidh / frame_h;
if (compensate_par < 0)
compensate_par = xscale / yscale / res.display_par;
if (compensate_par > 0) {
if (compensate_par > 1.0) {
xscale /= compensate_par;
} else {
yscale *= compensate_par;
}
}
if (compensate_par > 0)
xscale /= compensate_par;
int cx = vidw / 2 - (int)(frame_w * xscale) / 2;
int cy = vidh / 2 - (int)(frame_h * yscale) / 2;
for (int i = 0; i < imgs->num_parts; i++) {
-3
View File
@@ -471,9 +471,6 @@ static void update_object(struct osd_state *osd, struct osd_object *obj)
void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
struct sub_bitmaps *out_imgs)
{
if (!osd->opts->use_text_osd)
return;
if (obj->force_redraw)
update_object(osd, obj);
+21 -3
View File
@@ -23,6 +23,8 @@
#include <libavutil/common.h>
#include <libavutil/intreadwrite.h>
#include "config.h"
#include "talloc.h"
#include "common/msg.h"
#include "common/av_common.h"
@@ -210,12 +212,19 @@ static void decode(struct sd *sd, struct demux_packet *packet)
continue;
if (r->w <= 0 || r->h <= 0)
continue;
img->bitmap = r->pict.data[0];
#if HAVE_AV_SUBTITLE_NOPICT
uint8_t **data = r->data;
int *linesize = r->linesize;
#else
uint8_t **data = r->pict.data;
int *linesize = r->pict.linesize;
#endif
img->bitmap = data[0];
assert(r->nb_colors > 0);
assert(r->nb_colors * 4 <= sizeof(img->palette));
memcpy(img->palette, r->pict.data[1], r->nb_colors * 4);
memcpy(img->palette, data[1], r->nb_colors * 4);
b->bitmap = img;
b->stride = r->pict.linesize[0];
b->stride = linesize[0];
b->w = r->w;
b->h = r->h;
b->x = r->x;
@@ -276,6 +285,15 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res d, double pts,
d.ml = d.mr = d.mt = d.mb = 0;
int insize[2];
get_resolution(sd, insize);
for (int n = 0; n < res->num_parts; n++) {
struct sub_bitmap *p = &res->parts[n];
if ((p->x + p->w > insize[0] || p->y + p->h > insize[1]) &&
priv->video_params.w > insize[0] && priv->video_params.h > insize[1])
{
insize[0] = priv->video_params.w;
insize[1] = priv->video_params.h;
}
}
osd_rescale_bitmaps(res, insize[0], insize[1], d, video_par);
}
+5 -3
View File
@@ -183,7 +183,7 @@ static int parse_webvtt(AVPacket *in, AVPacket *pkt)
AV_PKT_DATA_WEBVTT_IDENTIFIER,
id_len);
if (buf == NULL) {
av_free_packet(pkt);
av_packet_unref(pkt);
return AVERROR(ENOMEM);
}
memcpy(buf, id, id_len);
@@ -194,7 +194,7 @@ static int parse_webvtt(AVPacket *in, AVPacket *pkt)
AV_PKT_DATA_WEBVTT_SETTINGS,
settings_len);
if (buf == NULL) {
av_free_packet(pkt);
av_packet_unref(pkt);
return AVERROR(ENOMEM);
}
memcpy(buf, settings, settings_len);
@@ -202,7 +202,9 @@ static int parse_webvtt(AVPacket *in, AVPacket *pkt)
pkt->pts = in->pts;
pkt->duration = in->duration;
#if !HAVE_AV_AVPACKET_INT64_DURATION
pkt->convergence_duration = in->convergence_duration;
#endif
return 0;
}
@@ -254,7 +256,7 @@ static void decode(struct sd *sd, struct demux_packet *packet)
done:
avsubtitle_free(&sub);
av_free_packet(&parsed_pkt);
av_packet_unref(&parsed_pkt);
}
static void reset(struct sd *sd)
+2 -1
View File
@@ -90,6 +90,7 @@ const char *const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = {
"hue",
"saturation",
"gamma",
"output-levels",
};
const struct m_opt_choice_alternatives mp_chroma_names[] = {
@@ -709,7 +710,6 @@ void mp_csp_set_image_params(struct mp_csp_params *params,
mp_image_params_guess_csp(&p); // ensure consistency
params->colorspace = p.colorspace;
params->levels_in = p.colorlevels;
params->levels_out = p.outputlevels;
}
// Copy settings from eq into params.
@@ -721,6 +721,7 @@ void mp_csp_copy_equalizer_values(struct mp_csp_params *params,
params->hue = eq->values[MP_CSP_EQ_HUE] / 100.0 * M_PI;
params->saturation = (eq->values[MP_CSP_EQ_SATURATION] + 100) / 100.0;
params->gamma = exp(log(8.0) * eq->values[MP_CSP_EQ_GAMMA] / 100.0);
params->levels_out = eq->values[MP_CSP_EQ_OUTPUT_LEVELS];
}
static int find_eq(int capabilities, const char *name)
+3 -1
View File
@@ -161,6 +161,7 @@ enum mp_csp_equalizer_param {
MP_CSP_EQ_HUE,
MP_CSP_EQ_SATURATION,
MP_CSP_EQ_GAMMA,
MP_CSP_EQ_OUTPUT_LEVELS,
MP_CSP_EQ_COUNT,
};
@@ -168,7 +169,8 @@ enum mp_csp_equalizer_param {
( (1 << MP_CSP_EQ_BRIGHTNESS) \
| (1 << MP_CSP_EQ_CONTRAST) \
| (1 << MP_CSP_EQ_HUE) \
| (1 << MP_CSP_EQ_SATURATION) )
| (1 << MP_CSP_EQ_SATURATION) \
| (1 << MP_CSP_EQ_OUTPUT_LEVELS) )
#define MP_CSP_EQ_CAPS_GAMMA (1 << MP_CSP_EQ_GAMMA)
#define MP_CSP_EQ_CAPS_BRIGHTNESS (1 << MP_CSP_EQ_BRIGHTNESS)
+27 -79
View File
@@ -63,12 +63,10 @@ void video_reset_decoding(struct dec_video *d_video)
mp_image_unrefp(&d_video->waiting_decoded_mpi);
d_video->num_buffered_pts = 0;
d_video->last_pts = MP_NOPTS_VALUE;
d_video->last_packet_pdts = MP_NOPTS_VALUE;
d_video->first_packet_pdts = MP_NOPTS_VALUE;
d_video->decoded_pts = MP_NOPTS_VALUE;
d_video->codec_pts = MP_NOPTS_VALUE;
d_video->codec_dts = MP_NOPTS_VALUE;
d_video->sorted_pts = MP_NOPTS_VALUE;
d_video->unsorted_pts = MP_NOPTS_VALUE;
}
int video_vd_control(struct dec_video *d_video, int cmd, void *arg)
@@ -210,80 +208,28 @@ bool video_init_best_codec(struct dec_video *d_video, char* video_decoders)
return !!d_video->vd_driver;
}
static void add_pts_to_sort(struct dec_video *d_video, double pts)
static void add_avi_pts(struct dec_video *d_video, double pts)
{
if (pts != MP_NOPTS_VALUE) {
int delay = -1;
video_vd_control(d_video, VDCTRL_QUERY_UNSEEN_FRAMES, &delay);
if (delay >= 0 && delay < d_video->num_buffered_pts)
d_video->num_buffered_pts = delay;
if (d_video->num_buffered_pts ==
sizeof(d_video->buffered_pts) / sizeof(double))
if (d_video->num_buffered_pts == MP_ARRAY_SIZE(d_video->buffered_pts)) {
MP_ERR(d_video, "Too many buffered pts\n");
else {
int i, j;
for (i = 0; i < d_video->num_buffered_pts; i++)
if (d_video->buffered_pts[i] < pts)
break;
for (j = d_video->num_buffered_pts; j > i; j--)
d_video->buffered_pts[j] = d_video->buffered_pts[j - 1];
d_video->buffered_pts[i] = pts;
} else {
for (int i = d_video->num_buffered_pts; i > 0; i--)
d_video->buffered_pts[i] = d_video->buffered_pts[i - 1];
d_video->buffered_pts[0] = pts;
d_video->num_buffered_pts++;
}
}
}
// Return true if pts1 comes before pts2. pts1 can be MP_NOPTS_VALUE, but pts2
// always has to be valid. pts1 can't be equal or larger than pts2.
#define PTS_IS_ORDERED(pts1, pts2) \
((pts2) != MP_NOPTS_VALUE && ((pts1) == MP_NOPTS_VALUE || ((pts1) < (pts2))))
static double retrieve_sorted_pts(struct dec_video *d_video, double codec_pts)
static double retrieve_avi_pts(struct dec_video *d_video, double codec_pts)
{
struct MPOpts *opts = d_video->opts;
double sorted_pts;
if (d_video->num_buffered_pts) {
d_video->num_buffered_pts--;
sorted_pts = d_video->buffered_pts[d_video->num_buffered_pts];
} else {
MP_ERR(d_video, "No pts value from demuxer to use for frame!\n");
sorted_pts = MP_NOPTS_VALUE;
return d_video->buffered_pts[d_video->num_buffered_pts];
}
if (!PTS_IS_ORDERED(d_video->sorted_pts, sorted_pts))
d_video->num_sorted_pts_problems++;
d_video->sorted_pts = sorted_pts;
if (!PTS_IS_ORDERED(d_video->unsorted_pts, codec_pts))
d_video->num_unsorted_pts_problems++;
d_video->unsorted_pts = codec_pts;
if (d_video->header->video->avi_dts) {
// Actually, they don't need to be sorted, we just reuse the buffering.
d_video->pts_assoc_mode = 2;
} else if (opts->user_pts_assoc_mode) {
d_video->pts_assoc_mode = opts->user_pts_assoc_mode;
} else if (d_video->pts_assoc_mode == 0) {
if (codec_pts != MP_NOPTS_VALUE)
d_video->pts_assoc_mode = 1;
else
d_video->pts_assoc_mode = 2;
} else {
int probcount1 = d_video->num_unsorted_pts_problems;
int probcount2 = d_video->num_sorted_pts_problems;
if (d_video->pts_assoc_mode == 2) {
int tmp = probcount1;
probcount1 = probcount2;
probcount2 = tmp;
}
if (probcount1 >= probcount2 * 1.5 + 2) {
d_video->pts_assoc_mode = 3 - d_video->pts_assoc_mode;
MP_WARN(d_video, "Switching to pts association mode %d.\n",
d_video->pts_assoc_mode);
}
}
return d_video->pts_assoc_mode == 1 ? codec_pts : sorted_pts;
MP_ERR(d_video, "No pts value from demuxer to use for frame!\n");
return MP_NOPTS_VALUE;
}
struct mp_image *video_decode(struct dec_video *d_video,
@@ -291,9 +237,7 @@ struct mp_image *video_decode(struct dec_video *d_video,
int drop_frame)
{
struct MPOpts *opts = d_video->opts;
bool sort_pts =
(opts->user_pts_assoc_mode != 1 || d_video->header->video->avi_dts)
&& opts->correct_pts;
bool avi_pts = d_video->header->video->avi_dts && opts->correct_pts;
struct demux_packet packet_copy;
if (packet && packet->dts == MP_NOPTS_VALUE) {
@@ -306,15 +250,18 @@ struct mp_image *video_decode(struct dec_video *d_video,
double pkt_dts = packet ? packet->dts : MP_NOPTS_VALUE;
double pkt_pdts = pkt_pts == MP_NOPTS_VALUE ? pkt_dts : pkt_pts;
if (pkt_pdts != MP_NOPTS_VALUE)
d_video->last_packet_pdts = pkt_pdts;
if (pkt_pdts != MP_NOPTS_VALUE && d_video->first_packet_pdts == MP_NOPTS_VALUE)
d_video->first_packet_pdts = pkt_pdts;
if (sort_pts)
add_pts_to_sort(d_video, pkt_pdts);
if (avi_pts)
add_avi_pts(d_video, pkt_pdts);
double prev_codec_pts = d_video->codec_pts;
double prev_codec_dts = d_video->codec_dts;
if (d_video->header->video->avi_dts)
drop_frame = 0;
MP_STATS(d_video, "start decode video");
struct mp_image *mpi = d_video->vd_driver->decode(d_video, packet, drop_frame);
@@ -332,7 +279,7 @@ struct mp_image *video_decode(struct dec_video *d_video,
mpi->fields &= ~MP_IMGFIELD_TOP_FIRST;
mpi->fields |= MP_IMGFIELD_INTERLACED;
}
// Note: the PTS is reordered, but the DTS is not. Both should be monotonic.
double pts = d_video->codec_pts;
double dts = d_video->codec_dts;
@@ -355,20 +302,21 @@ struct mp_image *video_decode(struct dec_video *d_video,
pts = dts;
// Alternative PTS determination methods
if (sort_pts)
pts = retrieve_sorted_pts(d_video, pts);
if (avi_pts)
pts = retrieve_avi_pts(d_video, pts);
if (!opts->correct_pts || pts == MP_NOPTS_VALUE) {
if (opts->correct_pts && !d_video->header->missing_timestamps)
MP_WARN(d_video, "No video PTS! Making something up.\n");
double frame_time = 1.0f / (d_video->fps > 0 ? d_video->fps : 25);
double base = d_video->last_packet_pdts;
double base = d_video->first_packet_pdts;
pts = d_video->decoded_pts;
if (pts == MP_NOPTS_VALUE)
if (pts == MP_NOPTS_VALUE) {
pts = base == MP_NOPTS_VALUE ? 0 : base;
pts += frame_time;
} else {
pts += frame_time;
}
}
if (d_video->has_broken_packet_pts < 0)
+4 -9
View File
@@ -55,17 +55,12 @@ struct dec_video {
double codec_dts;
int num_codec_dts_problems;
// PTS sorting (obscure, non-default)
double buffered_pts[32];
// PTS sorting (needed for AVI-style timestamps)
double buffered_pts[64];
int num_buffered_pts;
double sorted_pts;
int num_sorted_pts_problems;
double unsorted_pts;
int num_unsorted_pts_problems;
int pts_assoc_mode;
// PTS or DTS of packet last read
double last_packet_pdts;
// PTS or DTS of packet first read
double first_packet_pdts;
// There was at least one packet with non-sense timestamps.
int has_broken_packet_pts; // <0: uninitialized, 0: no problems, 1: broken
+5 -57
View File
@@ -37,7 +37,6 @@
#include "video/mp_image_pool.h"
#include "video/hwdec.h"
#include "video/d3d.h"
#include "gpu_memcpy_sse4.h"
// A minor evil.
#ifndef FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO
@@ -98,9 +97,6 @@ typedef struct surface_info {
typedef struct DXVA2Context {
struct mp_log *log;
void (*copy_nv12)(struct mp_image *dest, uint8_t *src_bits,
unsigned src_pitch, unsigned surf_height);
HMODULE d3dlib;
HMODULE dxva2lib;
@@ -243,8 +239,8 @@ static struct mp_image *dxva2_allocate_image(struct lavc_ctx *s,
return mp_image_new_custom_ref(&mpi, w, dxva2_release_img);
}
static void copy_nv12_fallback(struct mp_image *dest, uint8_t *src_bits,
unsigned src_pitch, unsigned surf_height)
static void copy_nv12(struct mp_image *dest, uint8_t *src_bits,
unsigned src_pitch, unsigned surf_height)
{
struct mp_image buf = {0};
mp_image_setfmt(&buf, IMGFMT_NV12);
@@ -254,49 +250,9 @@ static void copy_nv12_fallback(struct mp_image *dest, uint8_t *src_bits,
buf.stride[0] = src_pitch;
buf.planes[1] = src_bits + src_pitch * surf_height;
buf.stride[1] = src_pitch;
mp_image_copy(dest, &buf);
mp_image_copy_gpu(dest, &buf);
}
#pragma GCC push_options
#pragma GCC target("sse4.1")
static void copy_nv12_gpu_sse4(struct mp_image *dest, uint8_t *src_bits,
unsigned src_pitch, unsigned surf_height)
{
const int lines = dest->h;
const int stride_y = dest->stride[0];
const int stride_uv = dest->stride[1];
// If the strides match, the image can be copied in one go
if (stride_y == src_pitch && stride_uv == src_pitch) {
const size_t size = lines * src_pitch;
gpu_memcpy(dest->planes[0], src_bits, size);
gpu_memcpy(dest->planes[1], src_bits + src_pitch * surf_height, size / 2);
} else {
// Copy the Y plane line-by-line
uint8_t *dest_y = dest->planes[0];
const uint8_t *src_y = src_bits;
const int bytes_per_line = dest->w;
for (int i = 0; i < lines; i++) {
gpu_memcpy(dest_y, src_y, bytes_per_line);
dest_y += stride_y;
src_y += src_pitch;
}
// Copy the UV plane line-by-line
uint8_t *dest_uv = dest->planes[1];
const uint8_t *src_uv = src_bits + src_pitch * surf_height;
for (int i = 0; i < lines / 2; i++) {
gpu_memcpy(dest_uv, src_uv, bytes_per_line);
dest_uv += stride_uv;
src_uv += src_pitch;
}
}
}
#pragma GCC pop_options
static struct mp_image *dxva2_retrieve_image(struct lavc_ctx *s,
struct mp_image *img)
{
@@ -324,7 +280,7 @@ static struct mp_image *dxva2_retrieve_image(struct lavc_ctx *s,
return img;
}
ctx->copy_nv12(sw_img, LockedRect.pBits, LockedRect.Pitch, surfaceDesc.Height);
copy_nv12(sw_img, LockedRect.pBits, LockedRect.Pitch, surfaceDesc.Height);
mp_image_set_size(sw_img, img->w, img->h);
mp_image_copy_attributes(sw_img, img);
@@ -408,15 +364,7 @@ static int dxva2_init(struct lavc_ctx *s)
ctx->log = mp_log_new(s, s->log, "dxva2");
ctx->sw_pool = talloc_steal(ctx, mp_image_pool_new(17));
if (av_get_cpu_flags() & AV_CPU_FLAG_SSE4) {
// Use a memcpy implementation optimised for copying from GPU memory
MP_DBG(ctx, "Using SSE4 memcpy\n");
ctx->copy_nv12 = copy_nv12_gpu_sse4;
} else {
// Use the CRT memcpy. This can be slower than software decoding.
MP_WARN(ctx, "Using fallback memcpy (slow)\n");
ctx->copy_nv12 = copy_nv12_fallback;
}
mp_check_gpu_memcpy(ctx->log, NULL);
ctx->deviceHandle = INVALID_HANDLE_VALUE;
+58 -13
View File
@@ -25,7 +25,7 @@
#include <libavcodec/vaapi.h>
#include <libavutil/common.h>
#include <X11/Xlib.h>
#include "config.h"
#include "lavc.h"
#include "common/common.h"
@@ -53,7 +53,9 @@ struct priv {
struct mp_log *log;
struct mp_vaapi_ctx *ctx;
VADisplay display;
Display *x11_display;
const struct va_native_display *native_display_fns;
void *native_display;
// libavcodec shared struct
struct vaapi_context *va_context;
@@ -65,6 +67,47 @@ struct priv {
struct mp_image_pool *sw_pool;
};
struct va_native_display {
void (*create)(struct priv *p);
void (*destroy)(struct priv *p);
};
static const struct va_native_display disp_x11;
static const struct va_native_display *const native_displays[] = {
#if HAVE_VAAPI_X11
&disp_x11,
#endif
NULL
};
#if HAVE_VAAPI_X11
#include <X11/Xlib.h>
#include <va/va_x11.h>
static void x11_destroy(struct priv *p)
{
if (p->native_display)
XCloseDisplay(p->native_display);
p->native_display = NULL;
}
static void x11_create(struct priv *p)
{
p->native_display = XOpenDisplay(NULL);
if (!p->native_display)
return;
p->display = vaGetDisplay(p->native_display);
if (!p->display)
x11_destroy(p);
}
static const struct va_native_display disp_x11 = {
.create = x11_create,
.destroy = x11_destroy,
};
#endif
#define HAS_HEVC VA_CHECK_VERSION(0, 38, 0)
#define PE(av_codec_id, ff_profile, vdp_profile) \
@@ -295,9 +338,8 @@ static void destroy_va_dummy_ctx(struct priv *p)
va_destroy(p->ctx);
p->ctx = NULL;
p->display = NULL;
if (p->x11_display)
XCloseDisplay(p->x11_display);
p->x11_display = NULL;
if (p->native_display_fns)
p->native_display_fns->destroy(p);
}
// Creates a "private" VADisplay, disconnected from the VO. We just create a
@@ -305,15 +347,18 @@ static void destroy_va_dummy_ctx(struct priv *p)
// connection along with struct mp_hwdec_info, if we wanted.)
static bool create_va_dummy_ctx(struct priv *p)
{
p->x11_display = XOpenDisplay(NULL);
if (!p->x11_display)
for (int n = 0; native_displays[n]; n++) {
native_displays[n]->create(p);
if (p->display) {
p->native_display_fns = native_displays[n];
break;
}
}
if (!p->display)
goto destroy_ctx;
VADisplay *display = vaGetDisplay(p->x11_display);
if (!display)
goto destroy_ctx;
p->ctx = va_initialize(display, p->log, true);
p->ctx = va_initialize(p->display, p->log, true);
if (!p->ctx) {
vaTerminate(display);
vaTerminate(p->display);
goto destroy_ctx;
}
return true;
@@ -334,7 +379,7 @@ static void uninit(struct lavc_ctx *ctx)
talloc_free(p->pool);
p->pool = NULL;
if (p->x11_display)
if (p->native_display_fns)
destroy_va_dummy_ctx(p);
talloc_free(p);
-1
View File
@@ -42,7 +42,6 @@ extern const vd_functions_t *const mpcodecs_vd_drivers[];
enum vd_ctrl {
VDCTRL_RESET = 1, // reset decode state after seeking
VDCTRL_QUERY_UNSEEN_FRAMES, // current decoder lag
VDCTRL_FORCE_HWDEC_FALLBACK, // force software decoding fallback
VDCTRL_GET_HWDEC,
};
+33 -43
View File
@@ -74,6 +74,7 @@ struct vd_lavc_params {
int threads;
int bitexact;
int check_hw_profile;
int software_fallback;
char **avopts;
};
@@ -101,6 +102,7 @@ const struct m_sub_options vd_lavc_conf = {
OPT_INT("threads", threads, M_OPT_MIN, .min = 0),
OPT_FLAG("bitexact", bitexact, 0),
OPT_FLAG("check-hw-profile", check_hw_profile, 0),
OPT_FLAG("software-fallback", software_fallback, 0),
OPT_KEYVALUELIST("o", avopts, 0),
{0}
},
@@ -108,6 +110,7 @@ const struct m_sub_options vd_lavc_conf = {
.defaults = &(const struct vd_lavc_params){
.show_all = 0,
.check_hw_profile = 1,
.software_fallback = 1,
.skip_loop_filter = AVDISCARD_DEFAULT,
.skip_idct = AVDISCARD_DEFAULT,
.skip_frame = AVDISCARD_DEFAULT,
@@ -116,7 +119,6 @@ const struct m_sub_options vd_lavc_conf = {
};
const struct vd_lavc_hwdec mp_vd_lavc_vdpau;
const struct vd_lavc_hwdec mp_vd_lavc_vda;
const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox;
const struct vd_lavc_hwdec mp_vd_lavc_vaapi;
const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy;
@@ -133,9 +135,6 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = {
#if HAVE_VIDEOTOOLBOX_HWACCEL
&mp_vd_lavc_videotoolbox,
#endif
#if HAVE_VDA_HWACCEL
&mp_vd_lavc_vda,
#endif
#if HAVE_VAAPI_HWACCEL
&mp_vd_lavc_vaapi,
&mp_vd_lavc_vaapi_copy,
@@ -194,9 +193,7 @@ const struct hwdec_profile_entry *hwdec_find_profile(
}
for (int n = 0; table[n].av_codec; n++) {
if (table[n].av_codec == codec) {
if (table[n].ff_profile == FF_PROFILE_UNKNOWN ||
profile == FF_PROFILE_UNKNOWN ||
table[n].ff_profile == profile ||
if (table[n].ff_profile == profile ||
!lavc_param->check_hw_profile)
return &table[n];
}
@@ -455,7 +452,6 @@ static void uninit_avctx(struct dec_video *vd)
MP_ERR(vd, "Could not close codec.\n");
av_freep(&avctx->extradata);
av_freep(&avctx->slice_offset);
}
if (ctx->hwdec && ctx->hwdec->uninit)
@@ -526,6 +522,9 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx,
assert(ctx->hwdec);
ctx->hwdec_request_reinit |= ctx->hwdec_failed;
ctx->hwdec_failed = false;
if (ctx->hwdec->image_format) {
for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) {
if (ctx->hwdec->image_format == pixfmt2imgfmt(fmt[i])) {
@@ -568,23 +567,16 @@ static int get_buffer2_hwdec(AVCodecContext *avctx, AVFrame *pic, int flags)
struct dec_video *vd = avctx->opaque;
vd_ffmpeg_ctx *ctx = vd->priv;
if (ctx->hwdec_failed)
return avcodec_default_get_buffer2(avctx, pic, flags);
/* Decoders using ffmpeg's hwaccel architecture (everything except vdpau)
* can fall back to software decoding automatically. However, we don't
* want that: multithreading was already disabled. ffmpeg's fallback
* isn't really useful, and causes more trouble than it helps.
*
* Instead of trying to "adjust" the thread_count fields in avctx, let
* decoding fail hard. Then decode_with_fallback() will do our own software
* fallback. Fully reinitializing the decoder is saner, and will probably
* save us from other weird corner cases, like having to "reroute" the
* get_buffer callback.
*/
int imgfmt = pixfmt2imgfmt(pic->format);
if (!IMGFMT_IS_HWACCEL(imgfmt) || !ctx->hwdec)
return -1;
ctx->hwdec_failed = true;
/* Hardware decoding failed, and we will trigger a proper fallback later
* when returning from the decode call. (We are forcing complete
* reinitialization later to reset the thread count properly.)
*/
if (ctx->hwdec_failed)
return avcodec_default_get_buffer2(avctx, pic, flags);
// We expect it to use the exact size used to create the hw decoder in
// get_format_hwdec(). For cropped video, this is expected to be the
@@ -609,8 +601,8 @@ static int get_buffer2_hwdec(AVCodecContext *avctx, AVFrame *pic, int flags)
return 0;
}
static int decode(struct dec_video *vd, struct demux_packet *packet,
int flags, struct mp_image **out_image)
static void decode(struct dec_video *vd, struct demux_packet *packet,
int flags, struct mp_image **out_image)
{
int got_picture = 0;
int ret;
@@ -619,6 +611,9 @@ static int decode(struct dec_video *vd, struct demux_packet *packet,
struct vd_lavc_params *lavc_param = ctx->opts->vd_lavc_params;
AVPacket pkt;
if (ctx->hwdec_request_reinit)
avcodec_flush_buffers(avctx);
if (flags) {
// hr-seek framedrop vs. normal framedrop
avctx->skip_frame = flags == 2 ? AVDISCARD_NONREF : lavc_param->framedrop;
@@ -633,18 +628,21 @@ static int decode(struct dec_video *vd, struct demux_packet *packet,
ret = avcodec_decode_video2(avctx, ctx->pic, &got_picture, &pkt);
hwdec_unlock(ctx);
if (ctx->hwdec_failed || ret < 0) {
if (ret < 0)
MP_WARN(vd, "Error while decoding frame!\n");
return -1;
if (ret < 0) {
MP_WARN(vd, "Error while decoding frame!\n");
if (lavc_param->software_fallback)
ctx->hwdec_failed = true;
return;
}
if (ctx->hwdec_request_reinit)
avcodec_flush_buffers(avctx);
if (ctx->hwdec && ctx->hwdec_failed) {
av_frame_unref(ctx->pic);
return;
}
// Skipped frame, or delayed output due to multithreaded decoding.
if (!got_picture)
return 0;
return;
struct mp_image_params params;
update_image_params(vd, ctx->pic, &params);
@@ -654,7 +652,7 @@ static int decode(struct dec_video *vd, struct demux_packet *packet,
struct mp_image *mpi = mp_image_from_av_frame(ctx->pic);
av_frame_unref(ctx->pic);
if (!mpi)
return 0; // mpi==NULL, or OOM
return;
assert(mpi->planes[0] || mpi->planes[3]);
mp_image_set_params(mpi, &params);
@@ -662,7 +660,6 @@ static int decode(struct dec_video *vd, struct demux_packet *packet,
mpi = ctx->hwdec->process_image(ctx, mpi);
*out_image = mp_img_swap_to_native(mpi);
return 1;
}
static struct mp_image *decode_with_fallback(struct dec_video *vd,
@@ -673,8 +670,8 @@ static struct mp_image *decode_with_fallback(struct dec_video *vd,
return NULL;
struct mp_image *mpi = NULL;
int res = decode(vd, packet, flags, &mpi);
if (res < 0) {
decode(vd, packet, flags, &mpi);
if (ctx->hwdec_failed) {
// Failed hardware decoding? Try again in software.
if (force_fallback(vd) && ctx->avctx)
decode(vd, packet, flags, &mpi);
@@ -701,13 +698,6 @@ static int control(struct dec_video *vd, int cmd, void *arg)
case VDCTRL_RESET:
avcodec_flush_buffers(avctx);
return CONTROL_TRUE;
case VDCTRL_QUERY_UNSEEN_FRAMES:;
int delay = avctx->has_b_frames;
assert(delay >= 0);
if (avctx->active_thread_type & FF_THREAD_FRAME)
delay += avctx->thread_count - 1;
*(int *)arg = delay;
return CONTROL_TRUE;
case VDCTRL_GET_HWDEC: {
int hwdec = ctx->hwdec ? ctx->hwdec->type : 0;
if (!ctx->software_fallback_decoder)
-118
View File
@@ -1,118 +0,0 @@
/*
* This file is part of mpv.
*
* Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
*
* 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 <libavcodec/version.h>
#include <libavcodec/vda.h>
#include "common/av_common.h"
#include "common/msg.h"
#include "video/mp_image.h"
#include "video/decode/lavc.h"
#include "config.h"
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
const char *decoder)
{
hwdec_request_api(info, "videotoolbox");
if (!info || !info->hwctx)
return HWDEC_ERR_NO_CTX;
if (mp_codec_to_av_codec_id(decoder) != AV_CODEC_ID_H264)
return HWDEC_ERR_NO_CODEC;
return 0;
}
static int init(struct lavc_ctx *ctx)
{
return 0;
}
struct vda_error {
int code;
char *reason;
};
static const struct vda_error vda_errors[] = {
{ AVERROR(ENOSYS),
"Hardware doesn't support accelerated decoding for this stream" },
{ AVERROR(EINVAL),
"Invalid configuration provided to VDADecoderCreate" },
{ AVERROR_INVALIDDATA,
"Generic error returned by the decoder layer. The cause can range from"
" VDADecoder finding errors in the bitstream to another application"
" using VDA at the moment. Only one application can use VDA at a"
" givent time." },
{ 0, NULL },
};
static void print_vda_error(struct mp_log *log, int lev, char *message,
int error_code)
{
for (int n = 0; vda_errors[n].code < 0; n++)
if (vda_errors[n].code == error_code) {
mp_msg(log, lev, "%s: %s (%d)\n",
message, vda_errors[n].reason, error_code);
return;
}
mp_msg(log, lev, "%s: %d\n", message, error_code);
}
static int init_decoder(struct lavc_ctx *ctx, int w, int h)
{
av_vda_default_free(ctx->avctx);
#if HAVE_VDA_DEFAULT_INIT2
AVVDAContext *vdactx = av_vda_alloc_context();
vdactx->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
int err = av_vda_default_init2(ctx->avctx, vdactx);
#else
int err = av_vda_default_init(ctx->avctx);
#endif
if (err < 0) {
print_vda_error(ctx->log, MSGL_ERR, "failed to init VDA decoder", err);
return -1;
}
return 0;
}
static void uninit(struct lavc_ctx *ctx)
{
if (ctx->avctx)
av_vda_default_free(ctx->avctx);
}
static struct mp_image *process_image(struct lavc_ctx *ctx, struct mp_image *img)
{
// Same representation. IMGFMT_VDA is only needed to select the libavcodec
// hwaccel driver.
if (img->imgfmt == IMGFMT_VDA)
mp_image_setfmt(img, IMGFMT_VIDEOTOOLBOX);
return img;
}
const struct vd_lavc_hwdec mp_vd_lavc_vda = {
.type = HWDEC_VDA,
.image_format = IMGFMT_VDA,
.probe = probe,
.init = init,
.uninit = uninit,
.init_decoder = init_decoder,
.process_image = process_image,
};
+1 -4
View File
@@ -34,7 +34,6 @@ struct vf_priv_s {
int outfmt;
int colormatrix;
int colorlevels;
int outputlevels;
int primaries;
int gamma;
int chroma_location;
@@ -89,8 +88,6 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in,
out->colorspace = p->colormatrix;
if (p->colorlevels)
out->colorlevels = p->colorlevels;
if (p->outputlevels)
out->outputlevels = p->outputlevels;
if (p->primaries)
out->primaries = p->primaries;
if (p->gamma)
@@ -137,7 +134,6 @@ static const m_option_t vf_opts_fields[] = {
OPT_IMAGEFORMAT("outfmt", outfmt, 0),
OPT_CHOICE_C("colormatrix", colormatrix, 0, mp_csp_names),
OPT_CHOICE_C("colorlevels", colorlevels, 0, mp_csp_levels_names),
OPT_CHOICE_C("outputlevels", outputlevels, 0, mp_csp_levels_names),
OPT_CHOICE_C("primaries", primaries, 0, mp_csp_prim_names),
OPT_CHOICE_C("gamma", gamma, 0, mp_csp_trc_names),
OPT_CHOICE_C("chroma-location", chroma_location, 0, mp_chroma_names),
@@ -147,6 +143,7 @@ static const m_option_t vf_opts_fields[] = {
OPT_INT("dw", dw, 0),
OPT_INT("dh", dh, 0),
OPT_DOUBLE("dar", dar, 0),
OPT_REMOVED("outputlevels", "use the --video-output-levels global option"),
{0}
};
+6 -3
View File
@@ -160,9 +160,12 @@ static struct mp_image *render(struct vf_instance *vf, struct mp_image *in,
if (!p->pipe.filters || in_id == VA_INVALID_ID)
return NULL;
struct mp_image *img = mp_image_pool_get(p->pool, IMGFMT_VAAPI, in->w, in->h);
int r_w, r_h;
va_surface_get_uncropped_size(in, &r_w, &r_h);
struct mp_image *img = mp_image_pool_get(p->pool, IMGFMT_VAAPI, r_w, r_h);
if (!img)
return NULL;
mp_image_set_size(img, in->w, in->h);
bool need_end_picture = false;
bool success = false;
@@ -201,8 +204,8 @@ static struct mp_image *render(struct vf_instance *vf, struct mp_image *in,
goto cleanup;
param->surface = in_id;
param->surface_region = NULL;
param->output_region = NULL;
param->surface_region = &(VARectangle){0, 0, in->w, in->h};
param->output_region = &(VARectangle){0, 0, img->w, img->h};
param->output_background_color = 0;
param->filter_flags = flags;
param->filters = p->pipe.filters;
-3
View File
@@ -118,9 +118,6 @@ static const struct {
#endif
{IMGFMT_VDPAU, AV_PIX_FMT_VDPAU},
#if HAVE_VDA_HWACCEL
{IMGFMT_VDA, AV_PIX_FMT_VDA},
#endif
#if HAVE_VIDEOTOOLBOX_HWACCEL
{IMGFMT_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX},
#endif
@@ -19,18 +19,20 @@
* Taken from the QuickSync decoder by Eric Gur
*/
#ifndef GPU_MEMCPY_SSE4_H_
#define GPU_MEMCPY_SSE4_H_
#pragma GCC push_options
#pragma GCC target("sse4.1")
#include <smmintrin.h>
#include <stdbool.h>
#include <string.h>
#include "gpu_memcpy.h"
// gpu_memcpy is a memcpy style function that copied data very fast from a
// GPU tiled memory (write back)
// Performance tip: page offset (12 lsb) of both addresses should be different
// optimally use a 2K offset between them.
static inline void *gpu_memcpy(void *restrict d, const void *restrict s, size_t size)
void *gpu_memcpy(void *restrict d, const void *restrict s, size_t size)
{
static const size_t regsInLoop = sizeof(size_t) * 2; // 8 or 16
@@ -131,6 +133,3 @@ static inline void *gpu_memcpy(void *restrict d, const void *restrict s, size_t
return d;
}
#pragma GCC pop_options
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef GPU_MEMCPY_SSE4_H_
#define GPU_MEMCPY_SSE4_H_
#include <stddef.h>
void *gpu_memcpy(void *restrict d, const void *restrict s, size_t size);
#endif
-1
View File
@@ -10,7 +10,6 @@ enum hwdec_type {
HWDEC_AUTO = -1,
HWDEC_NONE = 0,
HWDEC_VDPAU = 1,
HWDEC_VDA = 2,
HWDEC_VIDEOTOOLBOX = 3,
HWDEC_VAAPI = 4,
HWDEC_VAAPI_COPY = 5,
+1 -1
View File
@@ -146,7 +146,7 @@ error_exit:
avcodec_close(avctx);
av_free(avctx);
av_frame_free(&pic);
av_free_packet(&pkt);
av_packet_unref(&pkt);
return success;
}
+9 -4
View File
@@ -37,7 +37,6 @@ static const struct mp_imgfmt_entry mp_imgfmt_list[] = {
// not in ffmpeg
{"vdpau_output", IMGFMT_VDPAU_OUTPUT},
// FFmpeg names have an annoying "_vld" suffix
{"vda", IMGFMT_VDA},
{"videotoolbox", IMGFMT_VIDEOTOOLBOX},
{"vaapi", IMGFMT_VAAPI},
// names below this are not preferred over the FFmpeg names
@@ -232,15 +231,21 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
if (pd->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL))
desc.flags |= MP_IMGFLAG_PAL;
if ((desc.flags & MP_IMGFLAG_YUV) && (desc.flags & MP_IMGFLAG_BYTE_ALIGNED))
if ((desc.flags & (MP_IMGFLAG_YUV | MP_IMGFLAG_RGB))
&& (desc.flags & MP_IMGFLAG_BYTE_ALIGNED))
{
bool same_depth = true;
for (int p = 0; p < desc.num_planes; p++) {
same_depth &= planedepth[p] == planedepth[0] &&
desc.bpp[p] == desc.bpp[0];
}
if (same_depth && pd->nb_components == desc.num_planes)
desc.flags |= MP_IMGFLAG_YUV_P;
if (same_depth && pd->nb_components == desc.num_planes) {
if (desc.flags & MP_IMGFLAG_YUV) {
desc.flags |= MP_IMGFLAG_YUV_P;
} else {
desc.flags |= MP_IMGFLAG_RGB_P;
}
}
}
for (int p = 0; p < desc.num_planes; p++) {
+3 -5
View File
@@ -67,6 +67,8 @@
#define MP_IMGFLAG_HWACCEL 0x10000
// Set if the chroma resolution is lower than luma resolution. Unset for non-YUV.
#define MP_IMGFLAG_SUBSAMPLED 0x20000
// Like MP_IMGFLAG_YUV_P, but RGB. The planes are organized as in IMGFMT_GBRP.
#define MP_IMGFLAG_RGB_P 0x40000
// Exactly one of these bits is set in mp_imgfmt_desc.flags
#define MP_IMGFLAG_COLOR_CLASS_MASK \
@@ -205,11 +207,7 @@ enum mp_imgfmt {
IMGFMT_VAAPI,
IMGFMT_DXVA2, // IDirect3DSurface9 (NV12)
IMGFMT_MMAL, // MMAL_BUFFER_HEADER_T
// These use the same underlying format, but FFmpeg requires us to keep
// them separate. The VDA decoder will change the format to
// IMGFMT_VIDEOTOOLBOX, though.
IMGFMT_VIDEOTOOLBOX,
IMGFMT_VDA,
IMGFMT_VIDEOTOOLBOX, // CVPixelBufferRef
// Generic pass-through of AV_PIX_FMT_*. Used for formats which don't have
// a corresponding IMGFMT_ value.
+64 -24
View File
@@ -35,6 +35,7 @@
#include "mp_image.h"
#include "sws_utils.h"
#include "fmt-conversion.h"
#include "gpu_memcpy.h"
#include "video/filter/vf.h"
@@ -300,7 +301,30 @@ void mp_image_unrefp(struct mp_image **p_img)
*p_img = NULL;
}
void mp_image_copy(struct mp_image *dst, struct mp_image *src)
typedef void *(*memcpy_fn)(void *d, const void *s, size_t size);
static void memcpy_pic_cb(void *dst, const void *src, int bytesPerLine, int height,
int dstStride, int srcStride, memcpy_fn cpy)
{
if (bytesPerLine == dstStride && dstStride == srcStride && height) {
if (srcStride < 0) {
src = (uint8_t*)src + (height - 1) * srcStride;
dst = (uint8_t*)dst + (height - 1) * dstStride;
srcStride = -srcStride;
}
cpy(dst, src, srcStride * (height - 1) + bytesPerLine);
} else {
for (int i = 0; i < height; i++) {
cpy(dst, src, bytesPerLine);
src = (uint8_t*)src + srcStride;
dst = (uint8_t*)dst + dstStride;
}
}
}
static void mp_image_copy_cb(struct mp_image *dst, struct mp_image *src,
memcpy_fn cpy)
{
assert(dst->imgfmt == src->imgfmt);
assert(dst->w == src->w && dst->h == src->h);
@@ -308,14 +332,50 @@ void mp_image_copy(struct mp_image *dst, struct mp_image *src)
for (int n = 0; n < dst->num_planes; n++) {
int line_bytes = (mp_image_plane_w(dst, n) * dst->fmt.bpp[n] + 7) / 8;
int plane_h = mp_image_plane_h(dst, n);
memcpy_pic(dst->planes[n], src->planes[n], line_bytes, plane_h,
dst->stride[n], src->stride[n]);
memcpy_pic_cb(dst->planes[n], src->planes[n], line_bytes, plane_h,
dst->stride[n], src->stride[n], cpy);
}
// Watch out for AV_PIX_FMT_FLAG_PSEUDOPAL retardation
if ((dst->fmt.flags & MP_IMGFLAG_PAL) && dst->planes[1] && src->planes[1])
memcpy(dst->planes[1], src->planes[1], MP_PALETTE_SIZE);
}
void mp_image_copy(struct mp_image *dst, struct mp_image *src)
{
mp_image_copy_cb(dst, src, memcpy);
}
void mp_image_copy_gpu(struct mp_image *dst, struct mp_image *src)
{
#if HAVE_SSE4_INTRINSICS
if (av_get_cpu_flags() & AV_CPU_FLAG_SSE4) {
mp_image_copy_cb(dst, src, gpu_memcpy);
return;
}
#endif
mp_image_copy(dst, src);
}
// Helper, only for outputting some log info.
void mp_check_gpu_memcpy(struct mp_log *log, bool *once)
{
if (once) {
if (*once)
return;
*once = true;
}
bool have_sse = false;
#if HAVE_SSE4_INTRINSICS
have_sse = av_get_cpu_flags() & AV_CPU_FLAG_SSE4;
#endif
if (have_sse) {
mp_verbose(log, "Using SSE4 memcpy\n");
} else {
mp_warn(log, "Using fallback memcpy (slow)\n");
}
}
void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
{
dst->pict_type = src->pict_type;
@@ -334,7 +394,6 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
dst->params.colorspace = src->params.colorspace;
dst->params.colorlevels = src->params.colorlevels;
dst->params.chroma_location = src->params.chroma_location;
dst->params.outputlevels = src->params.outputlevels;
}
mp_image_params_guess_csp(&dst->params); // ensure colorspace consistency
if ((dst->fmt.flags & MP_IMGFLAG_PAL) && (src->fmt.flags & MP_IMGFLAG_PAL)) {
@@ -431,10 +490,6 @@ char *mp_image_params_to_str_buf(char *b, size_t bs,
m_opt_choice_str(mp_csp_levels_names, p->colorlevels));
mp_snprintf_cat(b, bs, " CL=%s",
m_opt_choice_str(mp_chroma_names, p->chroma_location));
if (p->outputlevels) {
mp_snprintf_cat(b, bs, " out=%s",
m_opt_choice_str(mp_csp_levels_names, p->outputlevels));
}
if (p->rotate)
mp_snprintf_cat(b, bs, " rot=%d", p->rotate);
if (p->stereo_in > 0 || p->stereo_out > 0) {
@@ -481,7 +536,6 @@ bool mp_image_params_equal(const struct mp_image_params *p1,
p1->d_w == p2->d_w && p1->d_h == p2->d_h &&
p1->colorspace == p2->colorspace &&
p1->colorlevels == p2->colorlevels &&
p1->outputlevels == p2->outputlevels &&
p1->primaries == p2->primaries &&
p1->gamma == p2->gamma &&
p1->chroma_location == p2->chroma_location &&
@@ -675,21 +729,7 @@ struct AVFrame *mp_image_to_av_frame_and_unref(struct mp_image *img)
void memcpy_pic(void *dst, const void *src, int bytesPerLine, int height,
int dstStride, int srcStride)
{
if (bytesPerLine == dstStride && dstStride == srcStride && height) {
if (srcStride < 0) {
src = (uint8_t*)src + (height - 1) * srcStride;
dst = (uint8_t*)dst + (height - 1) * dstStride;
srcStride = -srcStride;
}
memcpy(dst, src, srcStride * (height - 1) + bytesPerLine);
} else {
for (int i = 0; i < height; i++) {
memcpy(dst, src, bytesPerLine);
src = (uint8_t*)src + srcStride;
dst = (uint8_t*)dst + dstStride;
}
}
memcpy_pic_cb(dst, src, bytesPerLine, height, dstStride, srcStride, memcpy);
}
void memset_pic(void *dst, int fill, int bytesPerLine, int height, int stride)
+3 -4
View File
@@ -46,10 +46,6 @@ struct mp_image_params {
enum mp_csp_prim primaries;
enum mp_csp_trc gamma;
enum mp_chroma_location chroma_location;
// The image should be converted to these levels. Unlike colorlevels, it
// does not describe the current state of the image. (Somewhat similar to
// d_w/d_h vs. w/h.)
enum mp_csp_levels outputlevels;
// The image should be rotated clockwise (0-359 degrees).
int rotate;
enum mp_stereo3d_mode stereo_in; // image is encoded with this mode
@@ -106,6 +102,7 @@ int mp_chroma_div_up(int size, int shift);
struct mp_image *mp_image_alloc(int fmt, int w, int h);
void mp_image_copy(struct mp_image *dmpi, struct mp_image *mpi);
void mp_image_copy_gpu(struct mp_image *dst, struct mp_image *src);
void mp_image_copy_attributes(struct mp_image *dmpi, struct mp_image *mpi);
struct mp_image *mp_image_new_copy(struct mp_image *img);
struct mp_image *mp_image_new_ref(struct mp_image *img);
@@ -159,4 +156,6 @@ void memcpy_pic(void *dst, const void *src, int bytesPerLine, int height,
void memset_pic(void *dst, int fill, int bytesPerLine, int height, int stride);
void memset16_pic(void *dst, int fill, int unitsPerLine, int height, int stride);
void mp_check_gpu_memcpy(struct mp_log *log, bool *once);
#endif /* MPLAYER_MP_IMAGE_H */
+2 -2
View File
@@ -27,10 +27,10 @@
struct vo;
struct vo_cocoa_state;
int vo_cocoa_init(struct vo *vo);
void vo_cocoa_init(struct vo *vo);
void vo_cocoa_uninit(struct vo *vo);
int vo_cocoa_config_window(struct vo *vo, uint32_t flags);
int vo_cocoa_config_window(struct vo *vo);
int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg);
+7 -9
View File
@@ -248,7 +248,7 @@ static void cocoa_uninit_light_sensor(struct vo_cocoa_state *s)
}
}
int vo_cocoa_init(struct vo *vo)
void vo_cocoa_init(struct vo *vo)
{
struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state);
*s = (struct vo_cocoa_state){
@@ -265,7 +265,10 @@ int vo_cocoa_init(struct vo *vo)
pthread_cond_init(&s->wakeup, NULL);
vo->cocoa = s;
cocoa_init_light_sensor(vo);
return 1;
if (!s->embedded) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
set_application_icon(NSApp);
}
}
static int vo_cocoa_set_cursor_visibility(struct vo *vo, bool *visible)
@@ -554,7 +557,7 @@ void vo_cocoa_set_opengl_ctx(struct vo *vo, CGLContextObj ctx)
});
}
int vo_cocoa_config_window(struct vo *vo, uint32_t flags)
int vo_cocoa_config_window(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
run_on_main_thread(vo, ^{
@@ -572,7 +575,7 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t flags)
s->old_dwidth = width;
s->old_dheight = height;
if (!(flags & VOFLAG_HIDDEN) && !s->view) {
if (!s->view) {
create_ui(vo, &geo.win, geo.flags);
}
@@ -593,11 +596,6 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t flags)
vo->dheight = s->vo_dheight = frame.size.height;
[s->nsgl_ctx update];
if (!s->embedded) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
set_application_icon(NSApp);
}
});
return 0;
}
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff. Show more