summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cowgill <jcowgill@debian.org>2016-12-27 16:51:30 +0000
committerJames Cowgill <jcowgill@debian.org>2016-12-27 16:51:30 +0000
commitfb3e2206546d2078605d73e9e5b0f4988fdbf6aa (patch)
tree05265a5bf97262b8448a687e7524b132a1ec4370
parentab88beeb05e03b59fc99748dc9f17d27123af034 (diff)
New upstream version 0.23.0
-rw-r--r--DOCS/client-api-changes.rst4
-rw-r--r--DOCS/compile-windows.md13
-rw-r--r--DOCS/interface-changes.rst40
-rw-r--r--DOCS/man/ao.rst5
-rw-r--r--DOCS/man/input.rst7
-rw-r--r--DOCS/man/ipc.rst14
-rw-r--r--DOCS/man/lua.rst28
-rw-r--r--DOCS/man/mpv.rst35
-rw-r--r--DOCS/man/options.rst173
-rw-r--r--DOCS/man/vf.rst9
-rw-r--r--DOCS/man/vo.rst9
-rw-r--r--README.md2
-rw-r--r--RELEASE_NOTES79
-rwxr-xr-xTOOLS/file2string.pl24
-rwxr-xr-xTOOLS/file2string.py27
-rw-r--r--TOOLS/lib/Parse/Matroska.pm30
-rw-r--r--TOOLS/lib/Parse/Matroska/Definitions.pm384
-rw-r--r--TOOLS/lib/Parse/Matroska/Element.pm331
-rw-r--r--TOOLS/lib/Parse/Matroska/Reader.pm426
-rw-r--r--TOOLS/lib/Parse/Matroska/Utils.pm37
-rw-r--r--TOOLS/lua/autoload.lua9
-rwxr-xr-xTOOLS/matroska.pl169
-rwxr-xr-xTOOLS/matroska.py466
-rwxr-xr-xTOOLS/mpv_identify.sh5
-rwxr-xr-xTOOLS/travis-deps4
-rw-r--r--VERSION2
-rw-r--r--audio/decode/ad_lavc.c23
-rw-r--r--audio/decode/ad_spdif.c60
-rw-r--r--audio/decode/dec_audio.c20
-rw-r--r--audio/decode/dec_audio.h3
-rw-r--r--audio/filter/af_lavcac3enc.c16
-rw-r--r--audio/filter/af_lavrresample.c5
-rw-r--r--audio/out/ao.c23
-rw-r--r--audio/out/ao_alsa.c20
-rw-r--r--audio/out/ao_audiounit.m3
-rw-r--r--audio/out/ao_coreaudio.c9
-rw-r--r--audio/out/ao_jack.c8
-rw-r--r--audio/out/ao_lavc.c23
-rw-r--r--audio/out/ao_null.c2
-rw-r--r--audio/out/ao_openal.c2
-rw-r--r--audio/out/ao_opensles.c2
-rw-r--r--audio/out/ao_oss.c2
-rw-r--r--audio/out/ao_pcm.c2
-rw-r--r--audio/out/ao_pulse.c2
-rw-r--r--audio/out/ao_rsound.c2
-rw-r--r--audio/out/ao_sdl.c2
-rw-r--r--audio/out/ao_sndio.c2
-rw-r--r--audio/out/ao_wasapi.c7
-rw-r--r--audio/out/ao_wasapi.h6
-rw-r--r--audio/out/ao_wasapi_utils.c24
-rw-r--r--audio/out/internal.h2
-rw-r--r--audio/out/pull.c6
-rw-r--r--audio/out/push.c46
-rw-r--r--common/av_common.c5
-rw-r--r--common/av_common.h9
-rw-r--r--common/av_log.c2
-rw-r--r--common/codecs.c46
-rw-r--r--common/codecs.h10
-rw-r--r--common/encode_lavc.c18
-rw-r--r--demux/demux.c7
-rw-r--r--demux/demux.h1
-rw-r--r--demux/demux_cue.c3
-rw-r--r--demux/demux_edl.c3
-rw-r--r--demux/demux_lavf.c41
-rw-r--r--demux/demux_libarchive.c3
-rw-r--r--demux/demux_mkv.c24
-rw-r--r--demux/demux_mkv_timeline.c2
-rw-r--r--demux/demux_playlist.c5
-rw-r--r--demux/demux_rar.c3
-rw-r--r--demux/stheader.h2
-rw-r--r--input/ipc.c6
-rw-r--r--libmpv/client.h9
-rw-r--r--misc/bstr.c14
-rw-r--r--misc/bstr.h14
-rw-r--r--misc/charset_conv.c160
-rw-r--r--misc/charset_conv.h1
-rw-r--r--options/m_config.c273
-rw-r--r--options/m_config.h9
-rw-r--r--options/m_option.c75
-rw-r--r--options/m_option.h34
-rw-r--r--options/options.c12
-rw-r--r--options/options.h5
-rw-r--r--osdep/macosx_application.m15
-rw-r--r--osdep/macosx_compat.h1
-rw-r--r--osdep/macosx_events.m19
-rw-r--r--player/client.c52
-rw-r--r--player/client.h2
-rw-r--r--player/command.c66
-rw-r--r--player/core.h4
-rw-r--r--player/loadfile.c2
-rw-r--r--player/lua.c12
-rw-r--r--player/lua/defaults.lua12
-rw-r--r--player/lua/osc.lua44
-rw-r--r--player/main.c2
-rw-r--r--player/playloop.c3
-rw-r--r--player/video.c8
-rw-r--r--stream/stream.c6
-rw-r--r--stream/stream.h1
-rw-r--r--stream/stream_bluray.c3
-rw-r--r--stream/stream_dvd.c3
-rw-r--r--stream/stream_dvdnav.c3
-rw-r--r--stream/tv.c4
-rw-r--r--stream/tv.h2
-rw-r--r--sub/lavc_conv.c3
-rw-r--r--sub/sd_lavc.c5
-rw-r--r--video/csputils.c4
-rw-r--r--video/decode/cuda.c33
-rw-r--r--video/decode/d3d11va.c6
-rw-r--r--video/decode/dec_video.c19
-rw-r--r--video/decode/vd_lavc.c23
-rw-r--r--video/decode/vdpau.c12
-rw-r--r--video/filter/vf.c2
-rw-r--r--video/filter/vf_vdpaurb.c110
-rw-r--r--video/fmt-conversion.c9
-rw-r--r--video/hwdec.h1
-rw-r--r--video/image_writer.c6
-rw-r--r--video/img_format.c17
-rw-r--r--video/img_format.h4
-rw-r--r--video/mp_image.c5
-rw-r--r--video/mp_image.h2
-rw-r--r--video/out/cocoa/events_view.h2
-rw-r--r--video/out/cocoa/events_view.m97
-rw-r--r--video/out/cocoa/mpvadapter.h6
-rw-r--r--video/out/cocoa/video_view.m3
-rw-r--r--video/out/cocoa/window.m179
-rw-r--r--video/out/cocoa_common.m295
-rw-r--r--video/out/opengl/angle_dynamic.c11
-rw-r--r--video/out/opengl/cuda_dynamic.c63
-rw-r--r--video/out/opengl/cuda_dynamic.h146
-rw-r--r--video/out/opengl/hwdec_cuda.c69
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c2
-rw-r--r--video/out/opengl/utils.c11
-rw-r--r--video/out/opengl/utils.h2
-rw-r--r--video/out/opengl/video.c89
-rw-r--r--video/out/opengl/video.h1
-rw-r--r--video/out/vo.c22
-rw-r--r--video/out/vo.h16
-rw-r--r--video/out/vo_direct3d.c2
-rw-r--r--video/out/vo_drm.c1
-rw-r--r--video/out/vo_image.c12
-rw-r--r--video/out/vo_lavc.c19
-rw-r--r--video/out/vo_null.c2
-rw-r--r--video/out/vo_opengl.c113
-rw-r--r--video/out/vo_opengl_cb.c13
-rw-r--r--video/out/vo_rpi.c5
-rw-r--r--video/out/vo_sdl.c2
-rw-r--r--video/out/vo_vaapi.c2
-rw-r--r--video/out/vo_vdpau.c2
-rw-r--r--video/out/vo_wayland.c2
-rw-r--r--video/out/vo_xv.c2
-rw-r--r--video/out/w32_common.c21
-rw-r--r--video/out/wayland_common.c8
-rw-r--r--waftools/fragments/cocoa.m3
-rw-r--r--waftools/fragments/cuda.c12
-rw-r--r--waftools/generators/sources.py4
-rw-r--r--wscript128
-rw-r--r--wscript_build.py8
157 files changed, 2072 insertions, 3278 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst
index 94b39bd..5e6e1d3 100644
--- a/DOCS/client-api-changes.rst
+++ b/DOCS/client-api-changes.rst
@@ -32,13 +32,15 @@ API changes
::
+ --- mpv 0.23.0 ---
+ 1.24 - the deprecated mpv_suspend() and mpv_resume() APIs now do nothing.
--- mpv 0.22.0 ---
1.23 - deprecate setting "no-" options via mpv_set_option*(). For example,
instead of "no-video=" you should set "video=no".
- do not override the SIGPIPE signal handler anymore. This was done as
workaround for the FFmpeg TLS code, which has been fixed long ago.
- deprecate mpv_suspend() and mpv_resume(). They will be stubbed out
- in mpv 0.22.0.
+ in mpv 0.23.0.
- make mpv_set_property() work to some degree before mpv_initialize().
It can now be used instead of mpv_set_option().
- semi-deprecate mpv_set_option()/mpv_set_option_string(). You should
diff --git a/DOCS/compile-windows.md b/DOCS/compile-windows.md
index f0d0dca..6fd5ed7 100644
--- a/DOCS/compile-windows.md
+++ b/DOCS/compile-windows.md
@@ -205,11 +205,10 @@ DLLs in that folder. The simplest solution is to add ``C:\msys64\mingw64\bin``
to the windows system ``%PATH%``. Beware though that this can cause problems or
confusion in Cygwin if that is also installed on the machine.
-Use of the ANGLE OpenGL backend requires a copy of ``d3dcompiler_43.dll`` (yes,
-exactly 43) in the path or in the same folder as mpv. It must be of the same
-architecture (x86_64 / i686) as the mpv you compiled. You can find a copy in the
-official mpv builds:
+Use of the ANGLE OpenGL backend requires a copy of the D3D compiler DLL that
+matches the version of the D3D SDK that ANGLE was built with
+(``d3dcompiler_43.dll`` in case of MinGW-built ANGLE) in the path or in the
+same folder as mpv. It must be of the same architecture (x86_64 / i686) as the
+mpv you compiled. You can find copies here:
-https://mpv.srsfckn.biz/mpv-x86_64-20160118.7z
-
-https://mpv.srsfckn.biz/mpv-i686-20160118.7z
+https://mpv.srsfckn.biz/d3dcompiler.7z
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index 7868f0a..a6133a3 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -19,6 +19,36 @@ Interface changes
::
+ --- mpv 0.23.0 ---
+ - remove deprecated vf_vdpaurb (use "--hwdec=vdpau-copy" instead)
+ - the following properties now have new semantics:
+ - "demuxer" (use "current-demuxer")
+ - "fps" (use "container-fps")
+ - "idle" (use "idle-active")
+ - "cache" (use "cache-percent")
+ - "audio-samplerate" (use "audio-params/samplerate")
+ - "audio-channels" (use "audio-params/channel-count")
+ - "audio-format" (use "audio-codec-name")
+ (the properties equivalent to the old semantics are in parentheses)
+ - remove deprecated --vo and --ao sub-options (like --vo=opengl:...), and
+ replace them with global options. A somewhat complete list can be found
+ here: https://github.com/mpv-player/mpv/wiki/Option-replacement-list#mpv-0210
+ - remove --vo-defaults and --ao-defaults as well
+ - remove deprecated global sub-options (like -demuxer-rawaudio format=...),
+ use flat options (like --demuxer-rawaudio-format=...)
+ - the --sub-codepage option changes in incompatible ways:
+ - detector-selection and fallback syntax is deprecated
+ - enca/libguess are removed and deprecated (behaves as if they hadn't
+ been compiled-in)
+ - --sub-codepage=<codepage> does not force the codepage anymore
+ (this requires different and new syntax)
+ - remove --fs-black-out-screens option for macOS
+ - change how spdif codecs are selected. You can't enable spdif passthrough
+ with --ad anymore. This was deprecated; use --audio-spdif instead.
+ - deprecate the "family" selection with --ad/--vd
+ forcing/excluding codecs with "+", "-", "-" is deprecated as well
+ - explicitly mark --ad-spdif-dtshd as deprecated (it was done so a long time
+ ago, but it didn't complain when using the option)
--- mpv 0.22.0 ---
- the "audio-device-list" property now sets empty device description to the
device name as a fallback
@@ -67,7 +97,7 @@ Interface changes
- "fps" -> "container-fps"
- "idle" -> "idle-active"
- "cache" -> "cache-percent"
- the old names are deprecated and will change behavior in mpv 0.22.0.
+ the old names are deprecated and will change behavior in mpv 0.23.0.
- remove deprecated "hwdec-active" and "hwdec-detected" properties
- deprecate the ao and vo auto-profiles (they never made any sense)
- deprecate "--vo=direct3d_shaders" - use "--vo=direct3d" instead.
@@ -81,17 +111,17 @@ Interface changes
now always sets the device, not the span or speed to be played. No
separating extra "/" is needed. The hidden --cdda-device options is also
deleted (it was redundant with the documented --cdrom-device).
- - deprecate --vo=rpi. It will be removed in mpv 0.22.0. Its functionality
+ - deprecate --vo=rpi. It will be removed in mpv 0.23.0. Its functionality
was folded into --vo=opengl, which now uses RPI hardware decoding by
treating it as a hardware overlay (without applying GL filtering). Also
- to be changed in 0.22.0: the --fs flag will be reset to "no" by default
+ to be changed in 0.23.0: the --fs flag will be reset to "no" by default
(like on the other platforms).
- deprecate --mute=auto (informally has been since 0.18.1)
- deprecate "resume" and "suspend" IPC commands. They will be completely
- removed in 0.22.0.
+ removed in 0.23.0.
- deprecate mp.suspend(), mp.resume(), mp.resume_all() Lua scripting
commands, as well as setting mp.use_suspend. They will be completely
- removed in 0.22.0.
+ removed in 0.23.0.
- the "seek" command's absolute seek mode will now interpret negative
seek times as relative from the end of the file (and clamps seeks that
still go before 0)
diff --git a/DOCS/man/ao.rst b/DOCS/man/ao.rst
index 0e45b1e..5984aba 100644
--- a/DOCS/man/ao.rst
+++ b/DOCS/man/ao.rst
@@ -10,11 +10,6 @@ syntax is:
If the list has a trailing ',', mpv will fall back on drivers not contained
in the list.
-``--ao-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
- Set defaults for each driver.
-
- Deprecated. No replacement.
-
.. note::
See ``--ao=help`` for a list of compiled-in audio output drivers. The
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index 508e7dd..70a05dc 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -2147,10 +2147,9 @@ caveats with some properties (due to historical reasons):
Strictly speaking, option access via API (e.g. ``mpv_set_option_string()``)
has the same problem, and it's only a difference between CLI/API.
-``demuxer``, ``idle``, ``length``, ``audio-samplerate``, ``audio-channels``, ``audio-format``, ``fps``, ``cache``, ``playlist-pos``, ``chapter``
- These behave completely different as property, but are deprecated (newer
- aliases which don't conflict have been added). After the deprecation period
- they will be changed to the proper option behavior.
+``playlist-pos``, ``chapter``
+ These properties behave different from the deprecated options with the same
+ names.
Property Expansion
------------------
diff --git a/DOCS/man/ipc.rst b/DOCS/man/ipc.rst
index 732056e..03be027 100644
--- a/DOCS/man/ipc.rst
+++ b/DOCS/man/ipc.rst
@@ -241,20 +241,6 @@ extra commands can also be used as part of the protocol:
By default, most events are enabled, and there is not much use for this
command.
-``suspend``
- Deprecated, will be removed completely in 0.21.0.
-
- Suspend the mpv main loop. There is a long-winded explanation of this in
- the C API function ``mpv_suspend()``. In short, this prevents the player
- from displaying the next video frame, so that you don't get blocked when
- trying to access the player.
-
-``resume``
- Deprecated, will be removed completely in 0.21.0.
-
- Undo one ``suspend`` call. ``suspend`` increments an internal counter, and
- ``resume`` decrements it. When 0 is reached, the player is actually resumed.
-
``get_version``
Returns the client API version the C API of the remote mpv instance
provides.
diff --git a/DOCS/man/lua.rst b/DOCS/man/lua.rst
index f1d9945..7d91090 100644
--- a/DOCS/man/lua.rst
+++ b/DOCS/man/lua.rst
@@ -43,9 +43,8 @@ timers added with ``mp.add_timeout`` or similar.
When the player quits, all scripts will be asked to terminate. This happens via
a ``shutdown`` event, which by default will make the event loop return. If your
-script got into an endless loop, mpv will probably behave fine during playback
-(unless the player is suspended, see ``mp.suspend``), but it won't terminate
-when quitting, because it's waiting on your script.
+script got into an endless loop, mpv will probably behave fine during playback,
+but it won't terminate when quitting, because it's waiting on your script.
Internally, the C code will call the Lua function ``mp_event_loop`` after
loading a Lua script. This function is normally defined by the default prelude
@@ -412,27 +411,16 @@ These also live in the ``mp`` module, but are documented separately as they
are useful only in special situations.
``mp.suspend()``
- This function has been deprecated in mpv 0.21.0 (no replacement).
-
- Suspend the mpv main loop. There is a long-winded explanation of this in
- the C API function ``mpv_suspend()``. In short, this prevents the player
- from displaying the next video frame, so that you don't get blocked when
- trying to access the player.
-
- Before mpv 0.17.0, this was automatically called by the event handler.
+ This function has been deprecated in mpv 0.21.0 and does nothing starting
+ with mpv 0.23.0 (no replacement).
``mp.resume()``
- This function has been deprecated in mpv 0.21.0 (no replacement).
-
- Undo one ``mp.suspend()`` call. ``mp.suspend()`` increments an internal
- counter, and ``mp.resume()`` decrements it. When 0 is reached, the player
- is actually resumed.
+ This function has been deprecated in mpv 0.21.0 and does nothing starting
+ with mpv 0.23.0 (no replacement).
``mp.resume_all()``
- This function has been deprecated in mpv 0.21.0 (no replacement).
-
- This resets the internal suspend counter and resumes the player. (It's
- like calling ``mp.resume()`` until the player is actually resumed.)
+ This function has been deprecated in mpv 0.21.0 and does nothing starting
+ with mpv 0.23.0 (no replacement).
``mp.get_wakeup_pipe()``
Calls ``mpv_get_wakeup_pipe()`` and returns the read end of the wakeup
diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst
index 4ceae1c..7108306 100644
--- a/DOCS/man/mpv.rst
+++ b/DOCS/man/mpv.rst
@@ -9,6 +9,8 @@ a media player
:Manual section: 1
:Manual group: multimedia
+.. contents:: Table of Contents
+
SYNOPSIS
========
@@ -208,9 +210,6 @@ Alt+2 (and command+2 on OSX)
command + f (OSX only)
Toggle fullscreen (see also ``--fs``).
-command + [ and command + ] (OSX only)
- Set video window alpha.
-
(The following keys are valid if you have a keyboard with multimedia keys.)
PAUSE
@@ -244,6 +243,16 @@ button 5 and button 6
USAGE
=====
+Command line arguments starting with ``-`` are interpreted as options,
+everything else as filenames or URLs. All options except *flag* options (or
+choice options which include ``yes``) require a parameter in the form
+``--option=value``.
+
+One exception is the lone ``-`` (without anything else), which means media data
+will be read from stdin. Also, ``--`` (without anything else) will make the
+player interpret all following arguments as filenames, even if they start with
+``-``. (To play a file named ``-``, you need to use ``./-``.)
+
Every *flag* option has a *no-flag* counterpart, e.g. the opposite of the
``--fs`` option is ``--no-fs``. ``--fs=yes`` is same as ``--fs``, ``--fs=no``
is the same as ``--no-fs``.
@@ -251,6 +260,24 @@ is the same as ``--no-fs``.
If an option is marked as *(XXX only)*, it will only work in combination with
the *XXX* option or if *XXX* is compiled in.
+Legacy option syntax
+--------------------
+
+The ``--option=value`` syntax is not strictly enforced, and the alternative
+legacy syntax ``-option value`` and ``--option value`` will also work. This is
+mostly for compatibility with MPlayer. Using these should be avoided. Their
+semantics can change any time in the future.
+
+For example, the alternative syntax will consider an argument following the
+option a filename. ``mpv -fs no`` will attempt to play a file named ``no``,
+because ``--fs`` is a flag option that requires no parameter. If an option
+changes and its parameter becomes optional, then a command line using the
+alternative syntax will break.
+
+Currently, the parser makes no difference whether an option starts with ``--``
+or a single ``-``. This might also change in the future, and ``--option value``
+might always interpret ``value`` as filename in order to reduce ambiguities.
+
Escaping spaces and other special characters
--------------------------------------------
@@ -431,7 +458,7 @@ tree and play the longest title.
a bitmap video stream which can be superimposed over the main
movie. mpv's subtitle styling and positioning options and keyboard
shortcuts generally do not work with image-based subtitles.
- Exceptions include options like ``--stretch-dvd-subs`` and
+ Exceptions include options like ``--stretch-dvd-subs`` and
``--stretch-image-subs-to-screen``.
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index bf98370..eab9f8f 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -134,11 +134,11 @@ Playback Control
speed higher than normal automatically inserts the ``scaletempo`` audio
filter.
-``--loop=<N|inf|force|no>``
+``--loop=<N|inf|force|no>``, ``--loop``
Loops playback ``N`` times. A value of ``1`` plays it one time (default),
``2`` two times, etc. ``inf`` means forever. ``no`` is the same as ``1`` and
disables looping. If several files are specified on command line, the
- entire playlist is looped.
+ entire playlist is looped. ``--loop`` is the same as ``--loop=inf``.
The ``force`` mode is like ``inf``, but does not skip playlist entries
which have been marked as failing. This means the player might waste CPU
@@ -267,6 +267,26 @@ Playback Control
Note that ``--playlist`` always loads all entries, so you use that instead
if you really have the need for this functionality.
+``--access-references=<yes|no>``
+ Follow any references in the file being opened (default: yes). Disabling
+ this is helpful if the file is automatically scanned (e.g. thumbnail
+ generation). If the thumbnail scanner for example encounters a playlist
+ file, which contains network URLs, and the scanner should not open these,
+ enabling this option will prevent it. This option also disables ordered
+ chapters, mov reference files, opening of archives, and a number of other
+ features.
+
+ On older FFmpeg versions, this will not work in some cases. Some FFmpeg
+ demuxers might not respect this option.
+
+ This option does not prevent opening of paired subtitle files and such. Use
+ ``--autoload-files=no`` to prevent this.
+
+ This option does not always work if you open non-files (for example using
+ ``dvd://directory`` would open a whole bunch of files in the given
+ directory). Prefixing the filename with ``./`` if it doesn't start with
+ a ``/`` will avoid this.
+
``--loop-file=<N|inf|no>``
Loop a single file N times. ``inf`` means forever, ``no`` means normal
playback. For compatibility, ``--loop-file`` and ``--loop-file=yes`` are
@@ -330,9 +350,10 @@ Program Behavior
``--help``, ``--h``
Show short summary of options.
- You can also pass a shell pattern to this option, which will list all
- matching top-level options, e.g. ``--h=*scale*`` for all options that
- contain the word "scale".
+ You can also pass a string to this option, which will list all top-level
+ options which contain the string in the name, e.g. ``--h=scale`` for all
+ options that contain the word ``scale``. The special string ``*`` lists
+ all top-level options.
``-v``
Increment verbosity level, one level for each ``-v`` found on the command
@@ -534,7 +555,7 @@ Video
Specify the video output backend to be used. See `VIDEO OUTPUT DRIVERS`_ for
details and descriptions of available drivers.
-``--vd=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>``
+``--vd=<...>``
Specify a priority list of video decoders to be used, according to their
family and name. See ``--ad`` for further details. Both of these options
use the same syntax and semantics; the only difference is that they
@@ -703,8 +724,8 @@ Video
mechanism in the opengl output path. To use this deinterlacing you
must pass the option: ``vd-lavc-o=deint=[weave|bob|adaptive]``. Pass
``weave`` to not attempt any deinterlacing.
- 10bit HEVC is available if the hardware supports it but it will be
- rounded down to 8 bits.
+ 10 and 12bit HEVC is available if the hardware supports it and a
+ sufficiently new driver (> 375.xx) is used.
``cuda-copy`` has the same behaviour as ``cuda`` - including the ability
to deinterlace inside the decoder. However, traditional deinterlacing
@@ -1100,11 +1121,10 @@ Audio
Possible codecs are ``ac3``, ``dts``, ``dts-hd``. Multiple codecs can be
specified by separating them with ``,``. ``dts`` refers to low bitrate DTS
core, while ``dts-hd`` refers to DTS MA (receiver and OS support varies).
- You should only use either ``dts`` or ``dts-hd`` (if both are specified,
- and ``dts`` comes first, only ``dts`` will be used).
+ If both ``dts`` and ``dts-hd`` are specified, it behaves equivalent to
+ specifying ``dts-hd`` only.
- In general, all codecs in the ``spdif`` family listed with ``--ad=help``
- are supported in theory.
+ In earlier mpv versions
.. admonition:: Warning
@@ -1114,27 +1134,31 @@ Audio
``--ad=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>``
Specify a priority list of audio decoders to be used, according to their
- family and decoder name. Entries like ``family:*`` prioritize all decoders
- of the given family. When determining which decoder to use, the first
- decoder that matches the audio format is selected. If that is unavailable,
- the next decoder is used. Finally, it tries all other decoders that are not
+ decoder name. When determining which decoder to use, the first decoder that
+ matches the audio format is selected. If that is unavailable, the next
+ decoder is used. Finally, it tries all other decoders that are not
explicitly selected or rejected by the option.
+ Specifying family names is deprecated. Entries like ``family:*`` prioritize
+ all decoders of the given family.
+
``-`` at the end of the list suppresses fallback on other available
decoders not on the ``--ad`` list. ``+`` in front of an entry forces the
decoder. Both of these should not normally be used, because they break
- normal decoder auto-selection!
+ normal decoder auto-selection! Both of these methods are deprecated.
- ``-`` in front of an entry disables selection of the decoder.
+ ``-`` in front of an entry disables selection of the decoder. This is
+ deprecated.
.. admonition:: Examples
- ``--ad=lavc:mp3float``
+ ``--ad=mp3float``
Prefer the FFmpeg/Libav ``mp3float`` decoder over all other MP3
decoders.
- ``--ad=spdif:ac3,lavc:*``
- Always prefer spdif AC3 over FFmpeg/Libav over anything else.
+ ``--ad=lavc:mp3float``
+ Prefer the FFmpeg/Libav ``mp3float`` decoder over all other MP3
+ decoders. (Using deprecated family syntax.)
``--ad=help``
List all available decoders.
@@ -1734,66 +1758,31 @@ Subtitles
:all: Load all subs in the current and ``--sub-paths`` directories.
``--sub-codepage=<codepage>``
- If your system supports ``iconv(3)``, you can use this option to specify
- the subtitle codepage. By default, uchardet will be used to guess the
- charset. If mpv is not compiled with uchardet, enca will be used.
- If mpv is compiled with neither uchardet nor enca, ``UTF-8:UTF-8-BROKEN``
- is the default, which means it will try to use UTF-8, otherwise the
- ``UTF-8-BROKEN`` pseudo codepage (see below).
+ You can use this option to specify the subtitle codepage. uchardet will be
+ used to guess the charset. (If mpv was not compiled with uchardet, then
+ ``utf-8`` is the effective default.)
- The default value for this option is ``auto``, whose actual effect depends
- on whether ENCA is compiled.
+ The default value for this option is ``auto``, which enables autodetection.
- .. admonition:: Warning
+ The following steps are taken to determine the final codepage, in order:
- If you force the charset, even subtitles that are known to be
- UTF-8 will be recoded, which is perhaps not what you expect. Prefix
- codepages with ``utf8:`` if you want the codepage to be used only if the
- input is not valid UTF-8.
+ - if the specific codepage has a ``+``, use that codepage
+ - if the data looks like UTF-8, assume it is UTF-8
+ - if ``--sub-codepage`` is set to a specific codepage, use that
+ - run uchardet, and if successful, use that
+ - otherwise, use ``UTF-8-BROKEN``
.. admonition:: Examples
- - ``--sub-codepage=utf8:latin2`` Use Latin 2 if input is not UTF-8.
- - ``--sub-codepage=cp1250`` Always force recoding to cp1250.
-
- The pseudo codepage ``UTF-8-BROKEN`` is used internally. When it
- is the codepage, subtitles are interpreted as UTF-8 with "Latin 1" as
- fallback for bytes which are not valid UTF-8 sequences. iconv is
- never involved in this mode.
+ - ``--sub-codepage=latin2`` Use Latin 2 if input is not UTF-8.
+ - ``--sub-codepage=+cp1250`` Always force recoding to cp1250.
- If the player was compiled with ENCA support, you can control it with the
- following syntax:
+ The pseudo codepage ``UTF-8-BROKEN`` is used internally. If it's set,
+ subtitles are interpreted as UTF-8 with "Latin 1" as fallback for bytes
+ which are not valid UTF-8 sequences. iconv is never involved in this mode.
- ``--sub-codepage=enca:<language>:<fallback codepage>``
-
- Language is specified using a two letter code to help ENCA detect
- the codepage automatically. If an invalid language code is
- entered, mpv will complain and list valid languages. (Note
- however that this list will only be printed when the conversion code is actually
- called, for example when loading an external subtitle). The
- fallback codepage is used if autodetection fails. If no fallback
- is specified, ``UTF-8-BROKEN`` is used.
-
- .. admonition:: Examples
-
- - ``--sub-codepage=enca:pl:cp1250`` guess the encoding, assuming the subtitles
- are Polish, fall back on cp1250
- - ``--sub-codepage=enca:pl`` guess the encoding for Polish, fall back on UTF-8.
- - ``--sub-codepage=enca`` try universal detection, fall back on UTF-8.
-
- If the player was compiled with libguess support, you can use it with:
-
- ``--sub-codepage=guess:<language>:<fallback codepage>``
-
- libguess always needs a language. There is no universal detection
- mode. Use ``--sub-codepage=guess:help`` to get a list of
- languages subject to the same caveat as with ENCA above.
-
- If the player was compiled with uchardet support you can use it with:
-
- ``--sub-codepage=uchardet``
-
- This mode doesn't take language or fallback codepage.
+ This option changed in mpv 0.23.0. The old syntax is still emulated to some
+ degree.
``--sub-fix-timing``, ``--no-sub-fix-timing``
By default, subtitle timing is adjusted to remove minor gaps or overlaps
@@ -2041,10 +2030,6 @@ Window
See also ``--screen``.
-``--fs-black-out-screens``
-
- OS X only. Black out other displays when going fullscreen.
-
``--keep-open=<yes|no|always>``
Do not terminate when playing or seeking beyond the end of the file, and
there is not next file to be played (and ``--loop`` is not used).
@@ -2182,7 +2167,7 @@ Window
``50%x50%``
Forces the window width and height to half the screen width and
height. Will show black borders to compensate for the video aspect
- ration (with most VOs and without ``--no-keepaspect``).
+ ratio (with most VOs and without ``--no-keepaspect``).
``50%+10+10``
Sets the window to half the screen widths, and positions it 10
pixels below/left of the top left corner of the screen.
@@ -2305,7 +2290,7 @@ Window
ensure it does not cause security problems (e.g. make sure to use full
paths if "." is in your path like on Windows). It also only works when
playing video (i.e. not with ``--no-video`` but works with
- ``-vo=null``).
+ ``--vo=null``).
This can be "misused" to disable screensavers that do not support the
proper X API (see also ``--stop-screensaver``). If you think this is too
@@ -3797,21 +3782,7 @@ OpenGL renderer options
-----------------------
The following video options are currently all specific to ``--vo=opengl`` and
-``-vo=opengl-cb`` only, which are the only VOs that implement them.
-
-``--opengl-dumb-mode=<yes|no>``
- This mode is extremely restricted, and will disable most extended OpenGL
- features. This includes high quality scalers and custom shaders!
-
- It is intended for hardware that does not support FBOs (including GLES,
- which supports it insufficiently), or to get some more performance out of
- bad or old hardware.
-
- This mode is forced automatically if needed, and this option is mostly
- useful for debugging. It's also enabled automatically if nothing uses
- features which require FBOs.
-
- This option might be silently removed in the future.
+``--vo=opengl-cb`` only, which are the only VOs that implement them.
``--scale=<filter>``
@@ -4616,6 +4587,20 @@ The following video options are currently all specific to ``--vo=opengl`` and
flipping GL front and backbuffers immediately (i.e. it doesn't call it
in display-sync mode).
+``--opengl-dumb-mode=<yes|no>``
+ This mode is extremely restricted, and will disable most extended OpenGL
+ features. This includes high quality scalers and custom shaders!
+
+ It is intended for hardware that does not support FBOs (including GLES,
+ which supports it insufficiently), or to get some more performance out of
+ bad or old hardware.
+
+ This mode is forced automatically if needed, and this option is mostly
+ useful for debugging. It's also enabled automatically if nothing uses
+ features which require FBOs.
+
+ This option might be silently removed in the future.
+
Miscellaneous
-------------
diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst
index fd155bb..2242351 100644
--- a/DOCS/man/vf.rst
+++ b/DOCS/man/vf.rst
@@ -806,15 +806,6 @@ Available filters are:
1-9
Apply high quality VDPAU scaling (needs capable hardware).
-``vdpaurb``
- This filter is deprecated. Use ``--hwdec=vdpau-copy`` instead.
-
- VDPAU video read back. Works with ``--vo=vdpau`` and ``--vo=opengl`` only.
- This filter will read back frames decoded by VDPAU so that other filters,
- which are not normally compatible with VDPAU, can be used like normal.
- This filter must be specified before ``vdpaupp`` in the filter chain if
- ``vdpaupp`` is used.
-
``d3d11vpp``
Direct3D 11 video post processing. Currently requires D3D11 hardware
decoding for use.
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index 593dc9a..6ff4b42 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -10,11 +10,6 @@ syntax is:
If the list has a trailing ``,``, mpv will fall back on drivers not contained
in the list.
-``--vo-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
- Set defaults for each driver.
-
- Deprecated. No replacement.
-
.. note::
See ``--vo=help`` for a list of compiled-in video output drivers.
@@ -483,9 +478,9 @@ Available video output drivers are:
This is deprecated. Use ``--vo=opengl`` instead, which is the default and
provides the same functionality. The ``rpi`` VO will be removed in
- mpv 0.22.0. Its functionality was folded into --vo=opengl, which now uses
+ mpv 0.23.0. Its functionality was folded into --vo=opengl, which now uses
RPI hardware decoding by treating it as a hardware overlay (without applying
- GL filtering). Also to be changed in 0.22.0: the --fs flag will be reset to
+ GL filtering). Also to be changed in 0.23.0: the --fs flag will be reset to
"no" by default (like on the other platforms).
The following deprecated global options are supported by this video output:
diff --git a/README.md b/README.md
index 41f0213..d2b678c 100644
--- a/README.md
+++ b/README.md
@@ -95,7 +95,7 @@ Essential dependencies (incomplete list):
- Audio output development headers (libasound/ALSA, pulseaudio)
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavfilter
and either libswresample or libavresample)
- At least FFmpeg 2.4.0 or Libav 11 is required.
+ At least FFmpeg 3.2.2 or Libav 12 is required.
- zlib
- iconv (normally provided by the system libc)
- libass (OSD, OSC, text subtitles)
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 0e718d4..a2a859e 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,3 +1,82 @@
+Release 0.23.0
+==============
+
+Now requires at least FFmpeg 3.2.2.
+
+Features
+--------
+
+- vo_rpi: partially undeprecate
+
+Added
+~~~~~
+
+- vo_opengl: hwdec_cuda: Support P016 output surfaces
+
+Removed
+~~~~~~~
+
+- charset_conv: drop enca and libguess support in favor of uchardet
+- vf_vdpaurb: remove this filter in favor of --hwdec=vdpau-copy
+
+
+Options and Commands
+--------------------
+
+Added
+~~~~~
+
+- TOOLS/autoload: allow disabling through script-opts
+- demux, stream: add --access-references to prevent opening referenced files
+
+
+Deprecated
+~~~~~~~~~~
+
+- options: deprecate codec family selection in --vd/--ad
+
+
+Removed
+~~~~~~~
+
+- macOS: remove --fs-black-out-screens
+- options: remove deprecated sub-option handling for --vo and --ao
+
+
+Fixes and Minor Enhancements
+----------------------------
+
+- Windows: window styles improvements (allow minimizing borderless/fullscreen window) (#2229, #2451)
+- ad_spdif: Fix crash when spdif muxer is not available
+- audio: fix --audio-stream-silence with ao_alsa
+- audio: fix --audio-stream-silence with ao_wasapi
+- build: drop build-time dependency on Perl
+- build: support linking ANGLE (previously loaded dynamically)
+- d3d11va: unconditionally load D3D DLLs (#3348)
+- demux_mkv: fix seeking in some broken files (#3920)
+- hwdec_cuda: allow building without CUDA SDK (load CUDA dynamically)
+- macOS: fix dropping of URLs containing query strings on the window
+- macOS: fullscreen refactoring (#2857, #3272, #1352, #2062, #3864)
+- macOS: support append file to paylist on drop (#2166)
+- macOS: update the menu and remove conflicting “Quit & remember position” item (#3865)
+- osc: don't hide playlist buttons, just disable
+- osc: fix possible race condition in right timecode
+- osc: topbar: use same styles as bottombar
+- player: don't print format detection error when aborting loading
+- vdpau: fix vaapi probing if libvdpau-va-gl1 is present
+- video: use demuxer-signaled duration for last video frame (#3924)
+
+
+This listing is not complete. Check DOCS/client-api-changes.rst for a history
+of changes to the client API, and DOCS/interface-changes.rst for a history
+of changes to other user-visible interfaces.
+
+A complete changelog can be seen by running `git log v0.22.0..v0.23.0`
+in the git repository or by visiting either
+https://github.com/mpv-player/mpv/compare/v0.22.0...v0.23.0 or
+https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.22.0..v0.23.0
+
+
Release 0.22.0
==============
diff --git a/TOOLS/file2string.pl b/TOOLS/file2string.pl
deleted file mode 100755
index 341bb06..0000000
--- a/TOOLS/file2string.pl
+++ /dev/null
@@ -1,24 +0,0 @@
-#! /usr/bin/env perl
-
-use strict;
-use warnings;
-
-# Convert the contents of a file into a C string constant.
-# Note that the compiler will implicitly add an extra 0 byte at the end
-# of every string, so code using the string may need to remove that to get
-# the exact contents of the original file.
-# FIXME: why not a char array?
-
-# treat only alphanumeric and punctuations (excluding " and ?) as safe
-my $unsafe_chars = qr{[^][A-Za-z0-9!#%&'()*+,./:;<=>^_{|}~ -]};
-
-for my $file (@ARGV) {
- open my $fh, '<:raw', $file or next;
- print "/* Generated from $file */\n";
- while (<$fh>) {
- # replace unsafe chars with their equivalent octal escapes
- s/($unsafe_chars)/\\@{[sprintf '%03o', ord($1)]}/gos;
- print "\"$_\"\n"
- }
- close $fh;
-}
diff --git a/TOOLS/file2string.py b/TOOLS/file2string.py
new file mode 100755
index 0000000..6cdd1a7
--- /dev/null
+++ b/TOOLS/file2string.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Convert the contents of a file into a C string constant.
+# Note that the compiler will implicitly add an extra 0 byte at the end
+# of every string, so code using the string may need to remove that to get
+# the exact contents of the original file.
+
+import sys
+
+# Indexing a byte string yields int on Python 3.x, and a str on Python 2.x
+def pord(c):
+ return ord(c) if type(c) == str else c
+
+def main(infile):
+ conv = ['\\' + ("%03o" % c) for c in range(256)]
+ safe_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" \
+ "0123456789!#%&'()*+,-./:;<=>?[]^_{|}~ "
+ for c in safe_chars:
+ conv[ord(c)] = c
+ for c, esc in ("\nn", "\tt", r"\\", '""'):
+ conv[ord(c)] = '\\' + esc
+ for line in infile:
+ sys.stdout.write('"' + ''.join(conv[pord(c)] for c in line) + '"\n')
+
+with open(sys.argv[1], 'rb') as infile:
+ sys.stdout.write("// Generated from %s\n\n" % sys.argv[1])
+ main(infile)
diff --git a/TOOLS/lib/Parse/Matroska.pm b/TOOLS/lib/Parse/Matroska.pm
deleted file mode 100644
index e1c08c9..0000000
--- a/TOOLS/lib/Parse/Matroska.pm
+++ /dev/null
@@ -1,30 +0,0 @@
-use 5.008;
-use strict;
-use warnings;
-
-# ABSTRACT: Module collection to parse Matroska files.
-package Parse::Matroska;
-
-=head1 DESCRIPTION
-
-C<use>s L<Parse::Matroska::Reader>. See the documentation
-of the modules mentioned in L</"SEE ALSO"> for more information
-in how to use this module.
-
-It's intended for this module to contain high-level interfaces
-to the other modules in the distribution.
-
-=head1 SOURCE CODE
-
-L<https://github.com/Kovensky/Parse-Matroska>
-
-=head1 SEE ALSO
-
-L<Parse::Matroska::Reader>, L<Parse::Matroska::Element>,
-L<Parse::Matroska::Definitions>.
-
-=cut
-
-use Parse::Matroska::Reader;
-
-1;
diff --git a/TOOLS/lib/Parse/Matroska/Definitions.pm b/TOOLS/lib/Parse/Matroska/Definitions.pm
deleted file mode 100644
index 5a5adcd..0000000
--- a/TOOLS/lib/Parse/Matroska/Definitions.pm
+++ /dev/null
@@ -1,384 +0,0 @@
-use 5.008;
-use strict;
-use warnings;
-
-# ABSTRACT: internal EBML grammar definitions
-package Parse::Matroska::Definitions;
-
-use Parse::Matroska::Utils qw{uniq uncamelize};
-
-use Exporter;
-our @ISA = qw{Exporter};
-our @EXPORT_OK = qw{elem_by_hexid %EBML_DEFINITION %MATROSKA_DEFINITION};
-
-=head1 SYNOPSIS
-
- use Parse::Matroska::Definitions qw{elem_by_hexid};
- my $ebml_id = elem_by_hexid('1a45dfa3');
- print "EBML ID $ebml_id->{elid}'s name: $ebml_id->{name}";
-
-=head1 DESCRIPTION
-
-Contains the definition of the EBML grammar as expected in
-Matroska files. This module is meant mostly for internal use.
-
-As this was extended from a script in mpv-player, some data
-generated is apparently useless for regular module users
-but is still relevant to the mpv-player script. Such data
-is annotated as being for mpv compatibility.
-
-=head1 NOTE
-
-The API of this module is not yet considered stable.
-
-=head1 GLOBALS
-
-These global variables are considered B<immutable>.
-
-=head2 @Parse::Matroska::Definitions::global_elem_list
-
-A global list of known matroska elements. Useful for
-mpv's matroska script, used for generating C headers
-that parse matroska.
-
-=head2 %Parse::Matroska::Definitions::global_elem_dict
-
-A global hash of known matroska elements. Used internally
-by L</elem_by_hexid($id)>.
-
-=cut
-
-@Parse::Matroska::Definitions::global_elem_list = ();
-%Parse::Matroska::Definitions::global_elem_dict = ();
-
-=head2 %EBML_DEFINITION
-
-Optionally-importable hash of known EBML IDs belonging
-to the EBML generic grammar.
-
-=head2 %MATROSKA_DEFINITION
-
-Optionally-importable hash of known EBML IDs belonging
-to the Matroska-specific grammar.
-
-=cut
-
-our %EBML_DEFINITION = define_ebml();
-our %MATROSKA_DEFINITION = define_matroska();
-
-=method elem_by_hexid($id)
-
-Returns an EBML Element Definition corresponding to the provided
-hexadecimal string. Returns C<undef> if the element is unknown.
-
-=cut
-sub elem_by_hexid {
- my ($elid) = @_;
- return $Parse::Matroska::Definitions::global_elem_dict{$elid};
-}
-
-################################################
-### Helper functions for document definition ###
-################################################
-
-# used by elem when setting the 'valname' key
-use constant TYPE_MAP => {
- uint => 'uint64_t',
- str => 'char *',
- binary => 'struct bstr',
- ebml_id => 'uint32_t',
- float => 'double',
- sint => 'int64_t',
-};
-
-# this will be localized to "MATROSKA" or "EBML" on the elem declarations
-our $ELEM_DEFINE_TYPE = undef;
-
-=method elem($name,$elid,$valtype)
-
-NOTE: never call this function yourself; it changes data structures
-that are considered immutable outside of this package.
-
-Internal API function that generates the EBML Element Definitions.
-
-This API function returns an array which first element is C<$elid>
-and the second is a generated hash. The generated hash is stored
-in the @global_elem_list and %global_elem_dict.
-
-The generated hash contains:
-
-=for :list
-= name
-The EBML Element's name, given through C<$name>.
-= elid
-The EBML Element's hex id, given through C<$elid>. Used for lookups by L</elem_by_hexid($id)>.
-= valtype
-The EBML Element's type, given through C<$valtype>, except when C<$valtype> is an arrayref.
-= multiple
-If C<$name> ends with a C<*>, this is set as true and strips the C<*> from L</name>. Used to
-mark elements that may be repeated.
-= subelements
-An arrayref of elements that may be children of this element, given through C<$valtype> if it
-is an arrayref. Sets L</valtype> to C<sub> if there are subelements.
-= subids
-An arrayref listing all the L</elid>s of subelements, C<uniq>ified.
-
-The following elements are for mpv compatibility:
-
-=for :list
-= definename
-Name used for generating C #defines.
-= fieldname
-Name used for generating C struct fields.
-= structname
-Name used for generating C struct names.
-= ebmltype
-A pre-#defined constant to describe the element's type.
-= valname
-Typename used when declaring a struct field referring to this element.
-
-=cut
-sub elem {
- my %e = (name => shift, elid => shift, valtype => shift);
-
- # strip * from name, set 'multiple' if there was one
- $e{multiple} = scalar $e{name} =~ s/\*$//;
-
- # ELEM_DEFINE_TYPE is either MATROSKA or EBML
- $e{definename} = "${ELEM_DEFINE_TYPE}_ID_".uc($e{name});
- $e{fieldname} = uncamelize $e{name};
- $e{structname} = "ebml_$e{fieldname}";
-
- if (ref $e{valtype} eq 'HASH') {
- $e{subelements} = $e{valtype};
- $e{subids} = uniq map { $_->{elid} } values %{$e{subelements}};
- $e{valtype} = 'sub';
- $e{ebmltype} = 'EBML_TYPE_SUBELEMENTS';
- $e{valname} = "struct $e{structname}";
- } else {
- $e{ebmltype} = "EBML_TYPE_\U$e{valtype}";
- die "Unrecognized value type $e{valtype}" unless
- defined ($e{valname} = TYPE_MAP->{$e{valtype}});
- }
- my $e = \%e;
- push @Parse::Matroska::Definitions::global_elem_list, $e;
- $Parse::Matroska::Definitions::global_elem_dict{$e{elid}} = $e;
- return ($e{elid}, $e);
-}
-
-#############################################
-### EBML and Matroska document definitons ###
-#############################################
-
-=method define_ebml
-
-Internal function that defines the EBML generic grammar.
-
-Must not be called from outside the package.
-
-=cut
-sub define_ebml {
- local $ELEM_DEFINE_TYPE = 'EBML';
- return (
- elem('EBML', '1a45dfa3', {
- elem('EBMLVersion', '4286', 'uint'),
- elem('EBMLReadVersion', '42f7', 'uint'),
- elem('EBMLMaxIDLength', '42f2', 'uint'),
- elem('EBMLMaxSizeLength', '42f3', 'uint'),
- elem('DocType', '4282', 'str'),
- elem('DocTypeVersion', '4287', 'uint'),
- elem('DocTypeReadVersion', '4285', 'uint'),
- }),
-
- elem('CRC32', 'bf', 'binary'),
- elem('Void', 'ec', 'binary'),
- );
-}
-
-
-=method define_matroska
-
-Internal function that defines the Matroska-specific EBML grammar.
-
-Must not be called from outside the package.
-
-=cut
-sub define_matroska {
- local $ELEM_DEFINE_TYPE = 'MATROSKA';
- return (
- elem('Segment', '18538067', {
- elem('SeekHead*', '114d9b74', {
- elem('Seek*', '4dbb', {
- elem('SeekID', '53ab', 'ebml_id'),
- elem('SeekPosition', '53ac', 'uint'),
- }),
- }),
-
- elem('Info*', '1549a966', {
- elem('SegmentUID', '73a4', 'binary'),
- elem('PrevUID', '3cb923', 'binary'),
- elem('NextUID', '3eb923', 'binary'),
- elem('TimecodeScale', '2ad7b1', 'uint'),
- elem('DateUTC', '4461', 'sint'),
- elem('Title', '7ba9', 'str'),
- elem('MuxingApp', '4d80', 'str'),
- elem('WritingApp', '5741', 'str'),
- elem('Duration', '4489', 'float'),
- }),
-
- elem('Cluster*', '1f43b675', {
- elem('Timecode', 'e7', 'uint'),
- elem('BlockGroup*', 'a0', {
- elem('Block', 'a1', 'binary'),
- elem('BlockDuration', '9b', 'uint'),
- elem('ReferenceBlock*', 'fb', 'sint'),
- elem('DiscardPadding', '75A2', 'sint'),
- }),
- elem('SimpleBlock*', 'a3', 'binary'),
- }),
-
- elem('Tracks*', '1654ae6b', {
- elem('TrackEntry*', 'ae', {
- elem('TrackNumber', 'd7', 'uint'),
- elem('TrackUID', '73c5', 'uint'),
- elem('TrackType', '83', 'uint'),
- elem('FlagEnabled', 'b9', 'uint'),
- elem('FlagDefault', '88', 'uint'),
- elem('FlagForced', '55aa', 'uint'),
- elem('FlagLacing', '9c', 'uint'),
- elem('MinCache', '6de7', 'uint'),
- elem('MaxCache', '6df8', 'uint'),
- elem('DefaultDuration', '23e383', 'uint'),
- elem('TrackTimecodeScale', '23314f', 'float'),
- elem('MaxBlockAdditionID', '55ee', 'uint'),
- elem('Name', '536e', 'str'),
- elem('Language', '22b59c', 'str'),
- elem('CodecID', '86', 'str'),
- elem('CodecPrivate', '63a2', 'binary'),
- elem('CodecName', '258688', 'str'),
- elem('CodecDecodeAll', 'aa', 'uint'),
- elem('CodecDelay', '56AA', 'uint'),
- elem('SeekPreRoll', '56BB', 'uint'),
- elem('Video', 'e0', {
- elem('FlagInterlaced', '9a', 'uint'),
- elem('PixelWidth', 'b0', 'uint'),
- elem('PixelHeight', 'ba', 'uint'),
- elem('DisplayWidth', '54b0', 'uint'),
- elem('DisplayHeight', '54ba', 'uint'),
- elem('DisplayUnit', '54b2', 'uint'),
- elem('FrameRate', '2383e3', 'float'),
- elem('ColourSpace', '2eb524', 'binary'),
- elem('StereoMode', '53b8', 'uint'),
- elem('Colour', '55B0', {
- elem('MatrixCoefficients', '55B1', 'uint'),
- elem('BitsPerChannel', '55B2', 'uint'),
- elem('ChromaSubsamplingHorz', '55B3', 'uint'),
- elem('ChromaSubsamplingVert', '55B4', 'uint'),
- elem('CbSubsamplingHorz', '55B5', 'uint'),
- elem('CbSubsamplingVert', '55B6', 'uint'),
- elem('ChromaSitingHorz', '55B7', 'uint'),
- elem('ChromaSitingVert', '55B8', 'uint'),
- elem('Range', '55B9', 'uint'),
- elem('TransferCharacteristics', '55BA', 'uint'),
- elem('Primaries', '55BB', 'uint'),
- elem('MaxCLL', '55BC', 'uint'),
- elem('MaxFALL', '55BD', 'uint'),
- elem('MasteringMetadata', '55D0', {
- elem('PrimaryRChromaticityX', '55D1', 'float'),
- elem('PrimaryRChromaticityY', '55D2', 'float'),
- elem('PrimaryGChromaticityX', '55D3', 'float'),
- elem('PrimaryGChromaticityY', '55D4', 'float'),
- elem('PrimaryBChromaticityX', '55D5', 'float'),
- elem('PrimaryBChromaticityY', '55D6', 'float'),
- elem('WhitePointChromaticityX', '55D7', 'float'),
- elem('WhitePointChromaticityY', '55D8', 'float'),
- elem('LuminanceMax', '55D9', 'float'),
- elem('LuminanceMin', '55DA', 'float'),
- }),
- }),
- }),
- elem('Audio', 'e1', {
- elem('SamplingFrequency', 'b5', 'float'),
- elem('OutputSamplingFrequency', '78b5', 'float'),
- elem('Channels', '9f', 'uint'),
- elem('BitDepth', '6264', 'uint'),
- }),
- elem('ContentEncodings', '6d80', {
- elem('ContentEncoding*', '6240', {
- elem('ContentEncodingOrder', '5031', 'uint'),
- elem('ContentEncodingScope', '5032', 'uint'),
- elem('ContentEncodingType', '5033', 'uint'),
- elem('ContentCompression', '5034', {
- elem('ContentCompAlgo', '4254', 'uint'),
- elem('ContentCompSettings', '4255', 'binary'),
- }),
- }),
- }),
- }),
- }),
-
- elem('Cues', '1c53bb6b', {
- elem('CuePoint*', 'bb', {
- elem('CueTime', 'b3', 'uint'),
- elem('CueTrackPositions*', 'b7', {
- elem('CueTrack', 'f7', 'uint'),
- elem('CueClusterPosition', 'f1', 'uint'),
- elem('CueRelativePosition','f0', 'uint'),
- elem('CueDuration', 'b2', 'uint'),
- }),
- }),
- }),
-
- elem('Attachments', '1941a469', {
- elem('AttachedFile*', '61a7', {
- elem('FileDescription', '467e', 'str'),
- elem('FileName', '466e', 'str'),
- elem('FileMimeType', '4660', 'str'),
- elem('FileData', '465c', 'binary'),
- elem('FileUID', '46ae', 'uint'),
- }),
- }),
-
- elem('Chapters', '1043a770', {
- elem('EditionEntry*', '45b9', {
- elem('EditionUID', '45bc', 'uint'),
- elem('EditionFlagHidden', '45bd', 'uint'),
- elem('EditionFlagDefault', '45db', 'uint'),
- elem('EditionFlagOrdered', '45dd', 'uint'),
- elem('ChapterAtom*', 'b6', {
- elem('ChapterUID', '73c4', 'uint'),
- elem('ChapterTimeStart', '91', 'uint'),
- elem('ChapterTimeEnd', '92', 'uint'),
- elem('ChapterFlagHidden', '98', 'uint'),
- elem('ChapterFlagEnabled', '4598', 'uint'),
- elem('ChapterSegmentUID', '6e67', 'binary'),
- elem('ChapterSegmentEditionUID', '6ebc', 'uint'),
- elem('ChapterDisplay*', '80', {
- elem('ChapString', '85', 'str'),
- elem('ChapLanguage*', '437c', 'str'),
- elem('ChapCountry*', '437e', 'str'),
- }),
- }),
- }),
- }),
- elem('Tags*', '1254c367', {
- elem('Tag*', '7373', {
- elem('Targets', '63c0', {
- elem('TargetTypeValue', '68ca', 'uint'),
- elem('TargetTrackUID', '63c5', 'uint'),
- elem('TargetEditionUID', '63c9', 'uint'),
- elem('TargetChapterUID', '63c4', 'uint'),
- elem('TargetAttachmentUID', '63c6', 'uint'),
- }),
- elem('SimpleTag*', '67c8', {
- elem('TagName', '45a3', 'str'),
- elem('TagLanguage', '447a', 'str'),
- elem('TagString', '4487', 'str'),
- }),
- }),
- }),
- }),
- );
-}
-
-1;
diff --git a/TOOLS/lib/Parse/Matroska/Element.pm b/TOOLS/lib/Parse/Matroska/Element.pm
deleted file mode 100644
index fa0830c..0000000
--- a/TOOLS/lib/Parse/Matroska/Element.pm
+++ /dev/null
@@ -1,331 +0,0 @@
-use 5.008;
-use strict;
-use warnings;
-
-# ABSTRACT: a mid-level representation of an EBML element
-package Parse::Matroska::Element;
-
-use Carp;
-use List::Util qw{first};
-
-=head1 SYNOPSIS
-
- use Parse::Matroska::Reader;
- my $reader = Parse::Matroska::Reader->new($path);
- my $elem = $reader->read_element;
-
- print "ID: $elem->{elid}\n";
- print "Name: $elem->{name}\n";
- print "Length: $elem->{content_len}\n";
- print "Type: $elem->{type}\n";
- print "Child count: ", scalar(@{$elem->all_children}), "\n";
- if ($elem->{type} eq 'sub') {
- while (my $chld = $elem->next_child) {
- print "Child Name: $chld->{name}\n";
- }
- } else {
- print "Value: ", $elem->get_value, "\n";
- }
-
-=head1 DESCRIPTION
-
-Represents a single Matroska element as decoded by
-L<Parse::Matroska::Reader>. This is essentially a hash
-augmented with functions for delay-loading of binary
-values and children elements.
-
-=head1 NOTE
-
-The API of this module is not yet considered stable.
-
-=attr elid
-
-The EBML Element ID, suitable for passing to
-L<Parse::Matroska::Definitions/elem_by_hexid>.
-
-=attr name
-
-The EBML Element's name.
-
-=attr type
-
-The EBML Element's type. Can be C<uint>, C<sint>,
-C<float>, C<ebml_id>, C<str> or C<binary>. See L</value>
-for details.
-
-Equivalent to
-C<elem_by_hexid($elem-E<gt>{value})-E<gt>{valtype}>.
-
-=attr value
-
-The EBML Element's value. Should be obtained through
-L</get_value>.
-
-Is an unicode string if the L</type> is C<str>, that is,
-the string has already been decoded by L<Encode/decode>.
-
-Is C<undef> if the L</type> is C<binary> and the contents
-were delay-loaded and not yet read. L</get_value> will
-do the delayed load if needed.
-
-Is an arrayref if the L</type> is C<sub>, containing
-the children nodes that were already loaded.
-
-Is a hashref if the L</type> is C<ebml_id>, containing
-the referred element's information as defined in
-L<Parse::Matroska::Definitions>. Calling
-C<elem_by_hexid($elem-E<gt>{value}-E<gt>{elid})> will
-return the same object as $elem->{value}.
-
-=attr full_len
-
-The entire length of this EBML Element, including
-the header's.
-
-=attr size_len
-
-The length of the size marker. Used when calculating
-L</full_len> from L</content_len>
-
-=attr content_len
-
-The length of the contents of this EBML Element,
-which excludes the header.
-
-=attr reader
-
-A weakened reference to the associated
-L<Parse::Matroska::Reader>.
-
-=method new(%hash)
-
-Creates a new Element initialized with the hash
-given as argument.
-
-=cut
-sub new {
- my $class = shift;
- my $self = {};
- bless $self, $class;
-
- $self->initialize(@_);
- return $self;
-}
-
-=method initialize(%hash)
-
-Called by L</new> on initialization.
-
-=cut
-sub initialize {
- my ($self, %args) = @_;
- for (keys %args) {
- $self->{$_} = $args{$_};
- }
- $self->{depth} = 0 unless $self->{depth};
-}
-
-=method skip
-
-Called by the user to ignore the contents of this EBML node.
-Needed when ignoring the children of a node.
-
-=cut
-sub skip {
- my ($self) = @_;
- my $reader = $self->{reader};
- return unless $reader; # we don't have to skip if there's no reader
- my $pos = $reader->getpos;
- croak "Too late to skip, reads were already done"
- if $pos ne $self->{data_pos};
- $reader->skip($self->{content_len});
-}
-
-=method get_value($keep_bin)
-
-Returns the value contained by this EBML element.
-
-If the element has children, returns an arrayref to
-the children elements that were already encountered.
-
-If the element's type is C<binary> and the value was
-delay-loaded, does the reading now.
-
-If $keep_bin is true, the delay-loaded data is kept
-as the L</value>, otherwise, further calls to
-C<get_value> will reread the data from the L</reader>.
-
-=cut
-sub get_value {
- my ($self, $keep_bin) = @_;
-
- return undef if $self->{type} eq 'skip';
- return $self->{value} if $self->{value};
-
- my $reader = $self->{reader} or
- croak "The associated Reader has been deleted";
-
- # delay-loaded 'binary'
- if ($self->{type} eq 'binary') {
- croak "Cannot seek in the current Reader" unless $self->{data_pos};
- # seek to the data position...
- $reader->setpos($self->{data_pos});
- # read the data, keeping it in value if requested
- if ($keep_bin) {
- $self->{value} = $reader->readlen($self->{content_len});
- return $self->{value};
- } else {
- return $reader->readlen($self->{content_len});
- }
- }
-}
-
-=method next_child($read_bin)
-
-Builtin iterator; reads and returns the next child element.
-Always returns undef if the type isn't C<sub>.
-
-Returns undef at the end of the iterator and resets itself to
-point to the first element; so calling L</next_child($read_bin)>
-after the iterator returned C<undef> will return the first child.
-
-The optional C<$read_bin> parameter has the children elements
-not delay-load their value if their type is C<binary>.
-
-If all children elements have already been read, return
-each element in-order as would be given by
-L</all_children($recurse,$read_bin)>.
-
-=cut
-sub next_child {
- my ($self, $read_bin) = @_;
- return unless $self->{type} eq 'sub';
-
- if ($self->{_all_children_read}) {
- my $idx = $self->{_last_child} ||= 0;
- if ($idx == @{$self->{value}}) {
- # reset the iterator, returning undef once
- $self->{_last_child} = 0;
- return;
- }
- my $ret = $self->{value}->[$idx];
-
- ++$idx;
- $self->{_last_child} = $idx;
- return $ret;
- }
-
- my $len = defined $self->{remaining_len}
- ? $self->{remaining_len}
- : $self->{content_len};
-
- if ($len == 0) {
- # we've read all children; switch into $self->{value} iteration mode
- $self->{_all_children_read} = 1;
- # return undef since the iterator will reset
- return;
- }
-
- $self->{pos_offset} ||= 0;
- my $pos = $self->{data_pos};
- my $reader = $self->{reader} or croak "The associated reader has been deleted";
- $reader->setpos($pos);
- $reader->{fh}->seek($self->{pos_offset}, 1) if $pos;
-
- my $chld = $reader->read_element($read_bin);
- return undef unless defined $chld;
- $self->{pos_offset} += $chld->{full_len};
-
- $self->{remaining_len} = $len - $chld->{full_len};
-
- if ($self->{remaining_len} < 0) {
- croak "Child elements consumed $self->{remaining_len} more bytes than parent $self->{name} contained";
- }
-
- $chld->{depth} = $self->{depth} + 1;
- $self->{value} ||= [];
-
- push @{$self->{value}}, $chld;
-
- return $chld;
-}
-
-=method all_children($recurse,$read_bin)
-
-Calls L</populate_children($recurse,$read_bin)> on self
-and returns an arrayref with the children nodes.
-
-Both C<$recurse> and C<$read_bin> are optional and default
-to false.
-
-=cut
-sub all_children {
- my ($self, $recurse, $read_bin) = @_;
- $self->populate_children($recurse, $read_bin);
- return $self->{value};
-}
-
-=method children_by_name($name)
-
-Searches in the already read children elements for all
-elements with the EBML name C<$name>. Returns an array
-containing all found elements. On scalar context,
-returns only the first element found.
-
-Croaks if the element's C<type> isn't C<sub>.
-
-=cut
-sub children_by_name {
- my ($self, $name) = @_;
- return unless defined wantarray; # don't do work if work isn't wanted
- croak "Element can't have children" unless $self->{type} eq 'sub';
-
- my @found = grep { $_->{name} eq $name } @{$self->{value}};
- return @found if wantarray; # list
- return shift @found if defined wantarray; # scalar
-}
-
-=method populate_children($recurse,$read_bin)
-
-Populates the internal array of children elements, that is,
-requests that the associated L<Matroska::Parser::Reader> reads
-all children elements. Returns itself.
-
-Returns false if the element's C<type> isn't C<sub>.
-
-If C<$recurse> is provided and is true, the method will call
-itself in the children elements with the same parameters it
-received; this will build a full EBML tree.
-
-If C<$read_bin> is provided and is true, disables delay-loading
-of the contents of C<binary>-type nodes, reading the contents
-to memory.
-
-If both C<$recurse> and C<$read_bin> are true, entire EBML trees
-can be loaded without requiring seeks, thus behaving correctly
-on unseekable streams. If C<$read_bin> is false, the entire EBML
-tree is still loaded, but calling L</get_value> on C<binary>-type
-nodes will produce an error on unseekable streams.
-
-=cut
-sub populate_children {
- my ($self, $recurse, $read_bin) = @_;
-
- return unless $self->{type} eq 'sub';
-
- if (@{$self->{value}} && $recurse) {
- # only recurse
- foreach (@{$self->{value}}) {
- $_->populate_children($recurse, $read_bin);
- }
- return $self;
- }
-
- while (my $chld = $self->next_child($read_bin)) {
- $chld->populate_children($recurse, $read_bin) if $recurse;
- }
-
- return $self;
-}
-
-1;
diff --git a/TOOLS/lib/Parse/Matroska/Reader.pm b/TOOLS/lib/Parse/Matroska/Reader.pm
deleted file mode 100644
index 614b7b1..0000000
--- a/TOOLS/lib/Parse/Matroska/Reader.pm
+++ /dev/null
@@ -1,426 +0,0 @@
-use 5.008;
-use strict;
-use warnings;
-
-# ABSTRACT: a low-level reader for EBML files
-package Parse::Matroska::Reader;
-
-use Parse::Matroska::Definitions qw{elem_by_hexid};
-use Parse::Matroska::Element;
-
-use Carp;
-use Scalar::Util qw{openhandle weaken};
-use IO::Handle;
-use IO::File;
-use List::Util qw{first};
-use Encode;
-
-use constant BIGINT_TRY => 'Pari,GMP,FastCalc';
-use Math::BigInt try => BIGINT_TRY;
-use Math::BigRat try => BIGINT_TRY;
-
-=head1 SYNOPSIS
-
- use Parse::Matroska::Reader;
- my $reader = Parse::Matroska::Reader->new($path);
- $reader->close;
- $reader->open(\$string_with_matroska_data);
-
- my $elem = $reader->read_element;
- print "Element ID: $elem->{elid}\n";
- print "Element name: $elem->{name}\n";
- if ($elem->{type} ne 'sub') {
- print "Element value: $elem->get_value\n";
- } else {
- while (my $child = $elem->next_child) {
- print "Child element: $child->{name}\n";
- }
- }
- $reader->close;
-
-=head1 DESCRIPTION
-
-Reads EBML data, which is used in Matroska files.
-This is a low-level reader which is meant to be used as a backend
-for higher level readers. TODO: write the high level readers :)
-
-=head1 NOTE
-
-The API of this module is not yet considered stable.
-
-=method new
-
-Creates a new reader.
-Calls L</open($arg)> with its arguments if provided.
-
-=cut
-sub new {
- my $class = shift;
- my $self = {};
- bless $self, $class;
-
- $self->open(@_) if @_;
- return $self;
-}
-
-=method open($arg)
-
-Creates the internal filehandle. The argument can be:
-
-=for :list
-* An open filehandle or L<IO::Handle> object.
-The filehandle is not C<dup()>ed, so calling L</close> in this
-object will close the given filehandle as well.
-* A scalar containing a path to a file.
-* On perl v5.14 or newer, a scalarref pointing to EBML data.
-For similar functionality in older perls, give an L<IO::String> object
-or the handle to an already C<open>ed scalarref.
-
-=cut
-sub open {
- my ($self, $arg) = @_;
- $self->{fh} = openhandle($arg) || IO::File->new($arg, "<:raw")
- or croak "Can't open $arg: $!";
-}
-
-=method close
-
-Closes the internal filehandle.
-
-=cut
-sub close {
- my ($self) = @_;
- $self->{fh}->close;
- delete $self->{fh};
-}
-
-# equivalent to $self->readlen(1), possibly faster
-sub _getc {
- my ($self) = @_;
- my $c = $self->{fh}->getc;
- croak "Can't do read of length 1: $!" if !defined $c && $!;
- return $c;
-}
-
-=method readlen($length)
-
-Reads C<$length> bytes from the internal filehandle.
-
-=cut
-sub readlen {
- my ($self, $len) = @_;
- my $data;
- my $readlen = $self->{fh}->read($data, $len);
- croak "Can't do read of length $len: $!"
- unless defined $readlen;
- return $data;
-}
-
-# converts a byte string into an integer
-# we do so by converting the integer into a hex string (big-endian)
-# and then reading the hex-string into an integer
-sub _bin2int($) {
- my ($bin) = @_;
- # if the length is larger than 3
- # the resulting integer might be larger than INT_MAX
- if (length($bin) > 3) {
- return Math::BigInt->from_hex(unpack("H*", $bin));
- }
- return hex(unpack("H*", $bin));
-}
-
-# creates a floating-point number with the given mantissa and exponent
-sub _ldexp {
- my ($mantissa, $exponent) = @_;
- my $r = new Math::BigRat($mantissa);
- return $r * Math::BigRat->new(2)**$exponent;
-}
-
-# NOTE: the read_* functions are hard to read because they're ports
-# of even harder to read python functions.
-# TODO: make them readable
-
-=method read_id
-
-Reads an EBML ID atom in hexadecimal string format, suitable
-for passing to L<Parse::Matroska::Definitions/elem_by_hexid($id)>.
-
-=cut
-sub read_id {
- my ($self) = @_;
- my $t = $self->_getc;
- return undef unless defined $t;
- my $i = 0;
- my $mask = 1<<7;
-
- if (ord($t) == 0) {
- croak "Matroska Syntax error: first byte of ID was \\0"
- }
- until (ord($t) & $mask) {
- ++$i;
- $mask >>= 1;
- }
- # return hex string of the bytes we just read
- return unpack "H*", ($t . $self->readlen($i));
-}
-
-=method read_size
-
-Reads an EBML Data Size atom, which immediately follows
-an EBML ID atom.
-
-This returns an array consisting of:
-
-=for :list
-0. The length of the Data Size atom.
-1. The value encoded in the Data Size atom, which is the length of all the data following it.
-
-=cut
-sub read_size {
- my ($self) = @_;
- my $t = $self->_getc;
- my $i = 0;
- my $mask = 1<<7;
-
- if (ord($t) == 0) {
- croak "Matroska Syntax error: first byte of data size was \\0"
- }
- until (ord($t) & $mask) {
- ++$i;
- $mask >>= 1;
- }
- $t = $t & chr($mask-1); # strip length bits (keep only significant bits)
- return ($i+1, _bin2int $t . $self->readlen($i));
-}
-
-=method read_str($length)
-
-Reads a string of length C<$length> bytes from the internal filehandle.
-The string is already L<Encode/decode>d from C<UTF-8>, which is the
-standard Matroska string encoding.
-
-=cut
-{
- my $utf8 = find_encoding("UTF-8");
- sub read_str {
- my ($self, $length) = @_;
- return $utf8->decode($self->readlen($length));
- }
-}
-
-=method read_uint($length)
-
-Reads an unsigned integer of length C<$length> bytes
-from the internal filehandle.
-
-Returns a L<Math::BigInt> object if C<$length> is greater
-than 4.
-
-=cut
-sub read_uint {
- my ($self, $length) = @_;
- return _bin2int $self->readlen($length);
-}
-
-=method read_sint($length)
-
-Reads a signed integer of length C<$length> bytes
-from the internal filehandle.
-
-Returns a L<Math::BigInt> object if C<$length> is greater
-than 4.
-
-=cut
-sub read_sint {
- my ($self, $length) = @_;
- my $i = $self->read_uint($length);
-
- # Apply 2's complement to the unsigned int
- my $mask = int(2 ** ($length * 8 - 1));
- # if the most significant bit is set...
- if ($i & $mask) {
- # subtract the MSB twice
- $i -= 2 * $mask;
- }
- return $i;
-}
-
-=method read_float($length)
-
-Reads an IEEE floating point number of length C<$length>
-bytes from the internal filehandle.
-
-Only lengths C<4> and C<8> are supported (C C<float> and C<double>).
-
-=cut
-{
- my $b1 = new Math::BigInt 1;
-
- sub read_float {
- my ($self, $length) = @_;
- my $i = new Math::BigInt $self->read_uint($length)->bstr;
- my $f;
-
- # These evil expressions reinterpret an unsigned int as IEEE binary floats
- if ($length == 4) {
- $f = _ldexp(($i & ((1<<23) - 1)) + (1<<23), ($i>>23 & ((1<<8) - 1)) - 150);
- $f = -$f if $i & ($b1<<31);
- } elsif ($length == 8) {
- $f = _ldexp(($i & (($b1<<52) - 1)) + ($b1<<52), ($i>>52 & ((1<<12) - 1)) - 1075);
- $f = -$f if $i & ($b1<<63);
- } else {
- croak "Matroska Syntax error: unsupported IEEE float byte size $length";
- }
-
- return $f;
- }
-}
-
-=method read_ebml_id($length)
-
-Reads an EBML ID when it's encoded as the data inside another
-EBML element, that is, when the enclosing element's C<type> is
-C<ebml_id>.
-
-This returns a hashref with the EBML element description as
-defined in L<Parse::Matroska::Definitions>.
-
-=cut
-sub read_ebml_id {
- my ($self, $length) = @_;
- return elem_by_hexid(unpack("H*", $self->readlen($length)));
-}
-
-=method skip($length)
-
-Skips C<$length> bytes in the internal filehandle.
-
-=cut
-sub skip {
- my ($self, $len) = @_;
- return if $self->{fh}->can('seek') && $self->{fh}->seek($len, 1);
- $self->readlen($len);
- return;
-}
-
-=method getpos
-
-Wrapper for L<IO::Seekable/$io-E<gt>getpos> in the internal filehandle.
-
-Returns undef if the internal filehandle can't C<getpos>.
-
-=cut
-sub getpos {
- my ($self) = @_;
- return undef unless $self->{fh}->can('getpos');
- return $self->{fh}->getpos;
-}
-
-=method setpos($pos)
-
-Wrapper for L<IO::Seekable/$io-E<gt>setpos> in the internal filehandle.
-
-Returns C<undef> if the internal filehandle can't C<setpos>.
-
-Croaks if C<setpos> does not seek to the requested position,
-that is, if calling C<getpos> does not yield the same object
-as the C<$pos> argument.
-
-=cut
-sub setpos {
- my ($self, $pos) = @_;
- return undef unless $pos && $self->{fh}->can('setpos');
-
- my $ret = $self->{fh}->setpos($pos);
- croak "Cannot seek to correct position"
- unless $self->getpos eq $pos;
- return $ret;
-}
-
-=method read_element($read_bin)
-
-Reads a full EBML element from the internal filehandle.
-
-Returns a L<Parse::Matroska::Element> object initialized with
-the read data. If C<read_bin> is not present or is false, will
-delay-load the contents of C<binary> type elements, that is,
-they will only be loaded when calling C<get_value> on the
-returned L<Parse::Matroska::Element> object.
-
-Does not read the children of the element if its type is
-C<sub>. Look into the L<Parse::Matroska::Element> interface
-for details in how to read children elements.
-
-Pass a true C<$read_bin> if the stream being read is not
-seekable (C<getpos> is undef) and the contents of C<binary>
-elements is desired, otherwise seeking errors or internal
-filehandle corruption might occur.
-
-=cut
-sub read_element {
- my ($self, $read_bin) = @_;
- return undef if $self->{fh}->eof;
-
- my $elem_pos = $self->getpos;
-
- my $elid = $self->read_id;
- my $elem_def = elem_by_hexid($elid);
- my ($size_len, $content_len) = $self->read_size;
- my $full_len = length($elid)/2 + $size_len + $content_len;
-
- my $elem = Parse::Matroska::Element->new(
- elid => $elid,
- name => $elem_def && $elem_def->{name},
- type => $elem_def && $elem_def->{valtype},
- size_len => $size_len,
- content_len => $content_len,
- full_len => $full_len,
- reader => $self,
- elem_pos => $elem_pos,
- data_pos => $self->getpos,
- );
- weaken($elem->{reader});
-
- if (defined $elem_def) {
- if ($elem->{type} eq 'sub') {
- $elem->{value} = [];
- } elsif ($elem->{type} eq 'str') {
- $elem->{value} = $self->read_str($content_len);
- } elsif ($elem->{type} eq 'ebml_id') {
- $elem->{value} = $self->read_ebml_id($content_len);
- } elsif ($elem->{type} eq 'uint') {
- $elem->{value} = $self->read_uint($content_len);
- } elsif ($elem->{type} eq 'sint') {
- $elem->{value} = $self->read_sint($content_len);
- } elsif ($elem->{type} eq 'float') {
- $elem->{value} = $self->read_float($content_len);
- } elsif ($elem->{type} eq 'skip') {
- $self->skip($content_len);
- } elsif ($elem->{type} eq 'binary') {
- if ($read_bin) {
- $elem->{value} = $self->readlen($content_len);
- } else {
- $self->skip($content_len);
- }
- } else {
- die "Matroska Definition error: type $elem->{valtype} unknown"
- }
- } else {
- $self->skip($content_len);
- }
- return $elem;
-}
-
-1;
-
-=head1 CAVEATS
-
-Children elements have to be processed as soon as an element
-with children is found, or their children ignored with
-L<Parse::Matroska::Element/skip>. Not doing so doesn't cause
-errors but results in an invalid structure, with constant C<0>
-depth.
-
-To work correctly in unseekable streams, either the contents
-of C<binary>-type elements has to be ignored or the C<read_bin>
-flag to C<read_element> has to be true.
diff --git a/TOOLS/lib/Parse/Matroska/Utils.pm b/TOOLS/lib/Parse/Matroska/Utils.pm
deleted file mode 100644
index 127d626..0000000
--- a/TOOLS/lib/Parse/Matroska/Utils.pm
+++ /dev/null
@@ -1,37 +0,0 @@
-use strict;
-use warnings;
-
-# ABSTRACT: internally-used helper functions
-package Parse::Matroska::Utils;
-
-use Exporter;
-our @ISA = qw{Exporter};
-our @EXPORT_OK = qw{uniq uncamelize};
-
-=method uniq(@array)
-
-The same as L<List::MoreUtils/"uniq LIST">.
-Included to avoid depending on it since it's
-not a core module.
-
-=cut
-sub uniq(@) {
- my %seen;
- return grep { !$seen{$_}++ } @_;
-}
-
-=method uncamelize($string)
-
-Converts a "StringLikeTHIS" into a
-"string_like_this".
-
-=cut
-sub uncamelize($) {
- local $_ = shift;
- # lc followed by UC: lc_UC
- s/(?<=[a-z])([A-Z])/_\L$1/g;
- # UC followed by two lc: _UClclc
- s/([A-Z])(?=[a-z]{2})/_\L$1/g;
- # strip leading _ that the second regexp might add; lowercase all
- s/^_//; lc
-}
diff --git a/TOOLS/lua/autoload.lua b/TOOLS/lua/autoload.lua
index fa56a3d..5f8faa3 100644
--- a/TOOLS/lua/autoload.lua
+++ b/TOOLS/lua/autoload.lua
@@ -7,6 +7,13 @@
-- Add at most 5000 * 2 files when starting a file (before + after).
MAXENTRIES = 5000
+local options = require 'mp.options'
+
+o = {
+ disabled = false
+}
+options.read_options(o)
+
function Set (t)
local set = {}
for _, v in pairs(t) do set[v] = true end
@@ -49,7 +56,7 @@ end
function find_and_add_entries()
local path = mp.get_property("path", "")
local dir, filename = mputils.split_path(path)
- if #dir == 0 then
+ if o.disabled or #dir == 0 then
return
end
local pl_count = mp.get_property_number("playlist-count", 1)
diff --git a/TOOLS/matroska.pl b/TOOLS/matroska.pl
deleted file mode 100755
index 41e4f6a..0000000
--- a/TOOLS/matroska.pl
+++ /dev/null
@@ -1,169 +0,0 @@
-#! /usr/bin/env perl
-
-# Generate C definitions for parsing Matroska files.
-
-use strict;
-use warnings;
-
-use FindBin;
-use lib "$FindBin::Bin/lib";
-use Parse::Matroska::Definitions;
-use Parse::Matroska::Reader;
-
-use Getopt::Long;
-use List::Util qw{max};
-
-my @global_elem_list = @Parse::Matroska::Definitions::global_elem_list;
-
-Getopt::Long::Configure(qw{auto_version auto_help});
-my %opt;
-GetOptions(\%opt,
- "generate-header",
- "generate-definitions",
- "full",
- );
-
-if ($opt{"generate-header"}) {
- generate_c_header();
-} elsif ($opt{"generate-definitions"}) {
- generate_c_definitions();
-} else {
- for (@ARGV) {
- my $reader = Parse::Matroska::Reader->new($_ eq '-' ? \*STDIN : $_) or die $!;
- while (my $elem = $reader->read_element($_ eq '-')) {
- process_elem($elem, $_ eq '-');
- }
- }
-}
-
-# Generate declarations for libmpdemux/ebml_types.h
-sub generate_c_header {
- print "/* Generated by TOOLS/matroska.pl, do not edit manually */\n\n";
-
- # Write a #define for the ElementID of each known element
- for my $el (@global_elem_list) {
- printf "#define %-40s 0x%s\n", $el->{definename}, $el->{elid};
- }
- print "\n";
-
- # Define a struct for each ElementID that has child elements
- for my $el (@global_elem_list) {
- next unless $el->{subelements};
- print "\nstruct $el->{structname} {\n";
-
- # Figure out the length of the longest variable name
- # Used for pretty-printing in the next step
- my $l = max(map { length $_->{valname} } values %{$el->{subelements}});
-
- # Output each variable, with pointers for array (multiple) elements
- for my $subel (sort { $a->{definename} cmp $b->{definename} } values %{$el->{subelements}}) {
- printf " %-${l}s %s%s;\n",
- $subel->{valname}, $subel->{multiple}?'*':' ', $subel->{fieldname};
- }
- print "\n";
-
- # Output a counter variable for each element
- # (presence/absence for scalars, item count for arrays)
- for my $subel (sort values %{$el->{subelements}}) {
- print " int n_$subel->{fieldname};\n"
- }
- print "};\n";
- }
- print "\n";
-
- # Output extern references for ebml_elem_desc structs for each of the elements
- # These are defined by generate_c_definitions
- for my $el (@global_elem_list) {
- next unless $el->{subelements};
- print "extern const struct ebml_elem_desc $el->{structname}_desc;\n";
- }
- print "\n";
-
- # Output the max number of sub-elements a known element might have
- printf "#define MAX_EBML_SUBELEMENTS %d\n",
- max(map { scalar keys %{$_->{subelements}} }
- grep { $_->{subelements} } @global_elem_list);
-}
-
-# Generate definitions for libmpdemux/ebml_defs.c
-sub generate_c_definitions {
- print "/* Generated by TOOLS/matroska.pl, do not edit manually */\n\n";
- # ebml_defs.c uses macros declared in ebml.c
- for my $el (@global_elem_list) {
- print "\n";
- if ($el->{subelements}) {
- # set N for the next macros
- print "#define N $el->{fieldname}\n";
-
- # define a struct ebml_$N_desc and gets ready to define fields
- # this secretly opens two scopes; hence the }}; at the end
- print "E_S(\"$el->{name}\", ".scalar(keys %{$el->{subelements}}).")\n";
-
- # define a field for each subelement
- # also does lots of macro magic, but doesn't open a scope
- for my $subel (sort { $a->{definename} cmp $b->{definename} } values %{$el->{subelements}}) {
- print "F($subel->{definename}, $subel->{fieldname}, ".
- ($subel->{multiple}?'1':'0').")\n";
- }
- # close the struct
- print "}};\n";
-
- # unset N since we've used it
- print "#undef N\n";
- } else {
- print "E(\"$el->{name}\", $el->{fieldname}, $el->{ebmltype})\n";
- }
- }
-}
-
-sub repr {
- my @ret;
- foreach (@_) {
- if (/'/) {
- s/"/\\"/g;
- push @ret, "\"$_\"";
- } else {
- push @ret, "'$_'";
- }
- }
- return @ret if wantarray;
- return pop @ret if defined wantarray;
- return;
-}
-
-sub process_elem {
- my ($elem, $read_bin) = @_;
- unless ($opt{full}) {
- if ($elem->{name} eq 'Cluster' || $elem->{name} eq 'Cues') {
- $elem->skip;
- return;
- }
- }
- die unless $elem;
-
- if ($elem->{type} ne 'skip') {
- print "$elem->{depth} $elem->{elid} $elem->{name} size: $elem->{content_len} value: ";
- }
-
- if ($elem->{type} eq 'sub') {
- print "subelements:\n";
- while (my $chld = $elem->next_child($read_bin)) {
- process_elem($chld);
- }
- } elsif ($elem->{type} eq 'binary') {
- my $t = "<skipped $elem->{content_len} bytes>";
- if ($elem->{content_len} < 20) {
- $t = unpack "H*", $elem->get_value;
- }
- print "binary $t\n";
- delete $elem->{value};
- } elsif ($elem->{type} eq 'ebml_id') {
- print "binary $elem->{value}->{elid} (".($elem->{value}->{name}||"UNKNOWN").")\n";
- } elsif ($elem->{type} eq 'skip') {
- # skip
- } elsif ($elem->{type} eq 'str') {
- print "string ". repr($elem->get_value) . "\n";
- } else {
- print "$elem->{type} ". $elem->get_value ."\n";
- }
-}
diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py
new file mode 100755
index 0000000..6e84356
--- /dev/null
+++ b/TOOLS/matroska.py
@@ -0,0 +1,466 @@
+#!/usr/bin/env python
+"""
+Generate C definitions for parsing Matroska files.
+Can also be used to directly parse Matroska files and display their contents.
+"""
+
+#
+# This file is part of MPlayer.
+#
+# MPlayer is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# MPlayer is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with MPlayer; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+# for compatibility with Python 2.x
+from __future__ import print_function
+
+elements_ebml = (
+ 'EBML, 1a45dfa3, sub', (
+ 'EBMLVersion, 4286, uint',
+ 'EBMLReadVersion, 42f7, uint',
+ 'EBMLMaxIDLength, 42f2, uint',
+ 'EBMLMaxSizeLength, 42f3, uint',
+ 'DocType, 4282, str',
+ 'DocTypeVersion, 4287, uint',
+ 'DocTypeReadVersion, 4285, uint',
+ ),
+
+ 'CRC32, bf, binary',
+ 'Void, ec, binary',
+)
+
+elements_matroska = (
+ 'Segment, 18538067, sub', (
+
+ 'SeekHead*, 114d9b74, sub', (
+ 'Seek*, 4dbb, sub', (
+ 'SeekID, 53ab, ebml_id',
+ 'SeekPosition, 53ac, uint',
+ ),
+ ),
+
+ 'Info*, 1549a966, sub', (
+ 'SegmentUID, 73a4, binary',
+ 'PrevUID, 3cb923, binary',
+ 'NextUID, 3eb923, binary',
+ 'TimecodeScale, 2ad7b1, uint',
+ 'DateUTC, 4461, sint',
+ 'Title, 7ba9, str',
+ 'MuxingApp, 4d80, str',
+ 'WritingApp, 5741, str',
+ 'Duration, 4489, float',
+ ),
+
+ 'Cluster*, 1f43b675, sub', (
+ 'Timecode, e7, uint',
+ 'BlockGroup*, a0, sub', (
+ 'Block, a1, binary',
+ 'BlockDuration, 9b, uint',
+ 'ReferenceBlock*, fb, sint',
+ 'DiscardPadding, 75A2, sint',
+ ),
+ 'SimpleBlock*, a3, binary',
+ ),
+
+ 'Tracks*, 1654ae6b, sub', (
+ 'TrackEntry*, ae, sub', (
+ 'TrackNumber, d7, uint',
+ 'TrackUID, 73c5, uint',
+ 'TrackType, 83, uint',
+ 'FlagEnabled, b9, uint',
+ 'FlagDefault, 88, uint',
+ 'FlagForced, 55aa, uint',
+ 'FlagLacing, 9c, uint',
+ 'MinCache, 6de7, uint',
+ 'MaxCache, 6df8, uint',
+ 'DefaultDuration, 23e383, uint',
+ 'TrackTimecodeScale, 23314f, float',
+ 'MaxBlockAdditionID, 55ee, uint',
+ 'Name, 536e, str',
+ 'Language, 22b59c, str',
+ 'CodecID, 86, str',
+ 'CodecPrivate, 63a2, binary',
+ 'CodecName, 258688, str',
+ 'CodecDecodeAll, aa, uint',
+ 'CodecDelay, 56aa, uint',
+ 'SeekPreRoll, 56bb, uint',
+ 'Video, e0, sub', (
+ 'FlagInterlaced, 9a, uint',
+ 'PixelWidth, b0, uint',
+ 'PixelHeight, ba, uint',
+ 'DisplayWidth, 54b0, uint',
+ 'DisplayHeight, 54ba, uint',
+ 'DisplayUnit, 54b2, uint',
+ 'FrameRate, 2383e3, float',
+ 'ColourSpace, 2eb524, binary',
+ 'StereoMode, 53b8, uint',
+ 'Colour, 55b0, sub', (
+ 'MatrixCoefficients, 55B1, uint',
+ 'BitsPerChannel, 55B2, uint',
+ 'ChromaSubsamplingHorz, 55B3, uint',
+ 'ChromaSubsamplingVert, 55B4, uint',
+ 'CbSubsamplingHorz, 55B5, uint',
+ 'CbSubsamplingVert, 55B6, uint',
+ 'ChromaSitingHorz, 55B7, uint',
+ 'ChromaSitingVert, 55B8, uint',
+ 'Range, 55B9, uint',
+ 'TransferCharacteristics, 55BA, uint',
+ 'Primaries, 55BB, uint',
+ 'MaxCLL, 55BC, uint',
+ 'MaxFALL, 55BD, uint',
+ 'MasteringMetadata, 55D0, sub', (
+ 'PrimaryRChromaticityX, 55D1, float',
+ 'PrimaryRChromaticityY, 55D2, float',
+ 'PrimaryGChromaticityX, 55D3, float',
+ 'PrimaryGChromaticityY, 55D4, float',
+ 'PrimaryBChromaticityX, 55D5, float',
+ 'PrimaryBChromaticityY, 55D6, float',
+ 'WhitePointChromaticityX, 55D7, float',
+ 'WhitePointChromaticityY, 55D8, float',
+ 'LuminanceMax, 55D9, float',
+ 'LuminanceMin, 55DA, float',
+ ),
+ ),
+ ),
+ 'Audio, e1, sub', (
+ 'SamplingFrequency, b5, float',
+ 'OutputSamplingFrequency, 78b5, float',
+ 'Channels, 9f, uint',
+ 'BitDepth, 6264, uint',
+ ),
+ 'ContentEncodings, 6d80, sub', (
+ 'ContentEncoding*, 6240, sub', (
+ 'ContentEncodingOrder, 5031, uint',
+ 'ContentEncodingScope, 5032, uint',
+ 'ContentEncodingType, 5033, uint',
+ 'ContentCompression, 5034, sub', (
+ 'ContentCompAlgo, 4254, uint',
+ 'ContentCompSettings, 4255, binary',
+ ),
+ ),
+ ),
+ ),
+ ),
+
+ 'Cues, 1c53bb6b, sub', (
+ 'CuePoint*, bb, sub', (
+ 'CueTime, b3, uint',
+ 'CueTrackPositions*, b7, sub', (
+ 'CueTrack, f7, uint',
+ 'CueClusterPosition, f1, uint',
+ 'CueRelativePosition, f0, uint',
+ 'CueDuration, b2, uint',
+ ),
+ ),
+ ),
+
+ 'Attachments, 1941a469, sub', (
+ 'AttachedFile*, 61a7, sub', (
+ 'FileDescription, 467e, str',
+ 'FileName, 466e, str',
+ 'FileMimeType, 4660, str',
+ 'FileData, 465c, binary',
+ 'FileUID, 46ae, uint',
+ ),
+ ),
+
+ 'Chapters, 1043a770, sub', (
+ 'EditionEntry*, 45b9, sub', (
+ 'EditionUID, 45bc, uint',
+ 'EditionFlagHidden, 45bd, uint',
+ 'EditionFlagDefault, 45db, uint',
+ 'EditionFlagOrdered, 45dd, uint',
+ 'ChapterAtom*, b6, sub', (
+ 'ChapterUID, 73c4, uint',
+ 'ChapterTimeStart, 91, uint',
+ 'ChapterTimeEnd, 92, uint',
+ 'ChapterFlagHidden, 98, uint',
+ 'ChapterFlagEnabled, 4598, uint',
+ 'ChapterSegmentUID, 6e67, binary',
+ 'ChapterSegmentEditionUID, 6ebc, uint',
+ 'ChapterDisplay*, 80, sub', (
+ 'ChapString, 85, str',
+ 'ChapLanguage*, 437c, str',
+ 'ChapCountry*, 437e, str',
+ ),
+ ),
+ ),
+ ),
+ 'Tags*, 1254c367, sub', (
+ 'Tag*, 7373, sub', (
+ 'Targets, 63c0, sub', (
+ 'TargetTypeValue, 68ca, uint',
+ 'TargetTrackUID, 63c5, uint',
+ 'TargetEditionUID, 63c9, uint',
+ 'TargetChapterUID, 63c4, uint',
+ 'TargetAttachmentUID, 63c6, uint',
+ ),
+ 'SimpleTag*, 67c8, sub', (
+ 'TagName, 45a3, str',
+ 'TagLanguage, 447a, str',
+ 'TagString, 4487, str'
+ ),
+ ),
+ ),
+ ),
+)
+
+
+import sys
+from math import ldexp
+from binascii import hexlify
+
+def byte2num(s):
+ return int(hexlify(s), 16)
+
+class EOF(Exception): pass
+
+def camelcase_to_words(name):
+ parts = []
+ start = 0
+ for i in range(1, len(name)):
+ if name[i].isupper() and (name[i-1].islower() or
+ name[i+1:i+2].islower()):
+ parts.append(name[start:i])
+ start = i
+ parts.append(name[start:])
+ return '_'.join(parts).lower()
+
+class MatroskaElement(object):
+
+ def __init__(self, name, elid, valtype, namespace):
+ self.name = name
+ self.definename = '{0}_ID_{1}'.format(namespace, name.upper())
+ self.fieldname = camelcase_to_words(name)
+ self.structname = 'ebml_' + self.fieldname
+ self.elid = elid
+ self.valtype = valtype
+ if valtype == 'sub':
+ self.ebmltype = 'EBML_TYPE_SUBELEMENTS'
+ self.valname = 'struct ' + self.structname
+ else:
+ self.ebmltype = 'EBML_TYPE_' + valtype.upper()
+ try:
+ self.valname = {'uint': 'uint64_t', 'str': 'char *',
+ 'binary': 'bstr', 'ebml_id': 'uint32_t',
+ 'float': 'double', 'sint': 'int64_t',
+ }[valtype]
+ except KeyError:
+ raise SyntaxError('Unrecognized value type ' + valtype)
+ self.subelements = ()
+
+ def add_subelements(self, subelements):
+ self.subelements = subelements
+ self.subids = set(x[0].elid for x in subelements)
+
+elementd = {}
+elementlist = []
+def parse_elems(l, namespace):
+ subelements = []
+ for el in l:
+ if isinstance(el, str):
+ name, hexid, eltype = [x.strip() for x in el.split(',')]
+ multiple = name.endswith('*')
+ name = name.strip('*')
+ new = MatroskaElement(name, hexid, eltype, namespace)
+ elementd[hexid] = new
+ elementlist.append(new)
+ subelements.append((new, multiple))
+ else:
+ new.add_subelements(parse_elems(el, namespace))
+ return subelements
+
+parse_elems(elements_ebml, 'EBML')
+parse_elems(elements_matroska, 'MATROSKA')
+
+def printf(out, *args):
+ out.write(' '.join([str(x) for x in args]))
+ out.write('\n')
+
+def generate_C_header(out):
+ printf(out, '// Generated by TOOLS/matroska.py, do not edit manually')
+ printf(out)
+
+ for el in elementlist:
+ printf(out, '#define {0.definename:40} 0x{0.elid}'.format(el))
+
+ printf(out)
+
+ for el in reversed(elementlist):
+ if not el.subelements:
+ continue
+ printf(out)
+ printf(out, 'struct {0.structname} {{'.format(el))
+ l = max(len(subel.valname) for subel, multiple in el.subelements)+1
+ for subel, multiple in el.subelements:
+ printf(out, ' {e.valname:{l}} {star}{e.fieldname};'.format(
+ e=subel, l=l, star=' *'[multiple]))
+ printf(out)
+ for subel, multiple in el.subelements:
+ printf(out, ' int n_{0.fieldname};'.format(subel))
+ printf(out, '};')
+
+ for el in elementlist:
+ if not el.subelements:
+ continue
+ printf(out, 'extern const struct ebml_elem_desc {0.structname}_desc;'.format(el))
+
+ printf(out)
+ printf(out, '#define MAX_EBML_SUBELEMENTS', max(len(el.subelements)
+ for el in elementlist))
+
+
+def generate_C_definitions(out):
+ printf(out, '// Generated by TOOLS/matroska.py, do not edit manually')
+ printf(out)
+ for el in reversed(elementlist):
+ printf(out)
+ if el.subelements:
+ printf(out, '#define N', el.fieldname)
+ printf(out, 'E_S("{0}", {1})'.format(el.name, len(el.subelements)))
+ for subel, multiple in el.subelements:
+ printf(out, 'F({0.definename}, {0.fieldname}, {1})'.format(
+ subel, int(multiple)))
+ printf(out, '}};')
+ printf(out, '#undef N')
+ else:
+ printf(out, 'E("{0.name}", {0.fieldname}, {0.ebmltype})'.format(el))
+
+def read(s, length):
+ t = s.read(length)
+ if len(t) != length:
+ raise EOF
+ return t
+
+def read_id(s):
+ t = read(s, 1)
+ i = 0
+ mask = 128
+ if ord(t) == 0:
+ raise SyntaxError
+ while not ord(t) & mask:
+ i += 1
+ mask >>= 1
+ t += read(s, i)
+ return t
+
+def read_vint(s):
+ t = read(s, 1)
+ i = 0
+ mask = 128
+ if ord(t) == 0:
+ raise SyntaxError
+ while not ord(t) & mask:
+ i += 1
+ mask >>= 1
+ t = bytes((ord(t) & (mask - 1),))
+ t += read(s, i)
+ return i+1, byte2num(t)
+
+def read_str(s, length):
+ return read(s, length)
+
+def read_uint(s, length):
+ t = read(s, length)
+ return byte2num(t)
+
+def read_sint(s, length):
+ i = read_uint(s, length)
+ mask = 1 << (length * 8 - 1)
+ if i & mask:
+ i -= 2 * mask
+ return i
+
+def read_float(s, length):
+ t = read(s, length)
+ i = byte2num(t)
+ if length == 4:
+ f = ldexp((i & 0x7fffff) + (1 << 23), (i >> 23 & 0xff) - 150)
+ if i & (1 << 31):
+ f = -f
+ elif length == 8:
+ f = ldexp((i & ((1 << 52) - 1)) + (1 << 52), (i >> 52 & 0x7ff) - 1075)
+ if i & (1 << 63):
+ f = -f
+ else:
+ raise SyntaxError
+ return f
+
+def parse_one(s, depth, parent, maxlen):
+ elid = hexlify(read_id(s)).decode('ascii')
+ elem = elementd.get(elid)
+ if parent is not None and elid not in parent.subids and elid not in ('ec', 'bf'):
+ print('Unexpected:', elid)
+ if 1:
+ raise NotImplementedError
+ size, length = read_vint(s)
+ this_length = len(elid) / 2 + size + length
+ if elem is not None:
+ if elem.valtype != 'skip':
+ print(" " * depth, '[' + elid + ']', elem.name, 'size:', length, 'value:', end=' ')
+ if elem.valtype == 'sub':
+ print('subelements:')
+ while length > 0:
+ length -= parse_one(s, depth + 1, elem, length)
+ if length < 0:
+ raise SyntaxError
+ elif elem.valtype == 'str':
+ print('string', repr(read_str(s, length).decode('utf8', 'replace')))
+ elif elem.valtype in ('binary', 'ebml_id'):
+ t = read_str(s, length)
+ dec = ''
+ if elem.valtype == 'ebml_id':
+ idelem = elementd.get(hexlify(t).decode('ascii'))
+ if idelem is None:
+ dec = '(UNKNOWN)'
+ else:
+ dec = '({0.name})'.format(idelem)
+ if len(t) < 20:
+ t = hexlify(t).decode('ascii')
+ else:
+ t = '<{0} bytes>'.format(len(t))
+ print('binary', t, dec)
+ elif elem.valtype == 'uint':
+ print('uint', read_uint(s, length))
+ elif elem.valtype == 'sint':
+ print('sint', read_sint(s, length))
+ elif elem.valtype == 'float':
+ print('float', read_float(s, length))
+ elif elem.valtype == 'skip':
+ read(s, length)
+ else:
+ raise NotImplementedError
+ else:
+ print(depth, 'Unknown element:', elid, 'size:', length)
+ read(s, length)
+ return this_length
+
+if __name__ == "__main__":
+ def parse_toplevel(s):
+ parse_one(s, 0, None, 1 << 63)
+
+ if sys.argv[1] == '--generate-header':
+ generate_C_header(sys.stdout)
+ elif sys.argv[1] == '--generate-definitions':
+ generate_C_definitions(sys.stdout)
+ else:
+ s = open(sys.argv[1], "rb")
+ while 1:
+ start = s.tell()
+ try:
+ parse_toplevel(s)
+ except EOF:
+ if s.tell() != start:
+ raise Exception("Unexpected end of file")
+ break
diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh
index 2bda6e5..980e79a 100755
--- a/TOOLS/mpv_identify.sh
+++ b/TOOLS/mpv_identify.sh
@@ -67,13 +67,12 @@ EOF
chapters
editions
titles
+ duration
audio
audio-bitrate
audio-codec
- audio-format
- channels
- samplerate
+ audio-codec-name
video
angle
diff --git a/TOOLS/travis-deps b/TOOLS/travis-deps
index 2082556..1d97f44 100755
--- a/TOOLS/travis-deps
+++ b/TOOLS/travis-deps
@@ -89,7 +89,7 @@ class Libav < TravisDepsBuilder
{
"libav-stable" => {
:action => :stable,
- :url => 'http://libav.org/releases/libav-11.tar.gz'
+ :url => 'http://libav.org/releases/libav-12.tar.gz'
},
"libav-git" => {
:action => :git,
@@ -97,7 +97,7 @@ class Libav < TravisDepsBuilder
},
"ffmpeg-stable" => {
:action => :stable,
- :url => 'http://www.ffmpeg.org/releases/ffmpeg-2.4.tar.gz'
+ :url => 'http://www.ffmpeg.org/releases/ffmpeg-3.2.2.tar.gz'
},
"ffmpeg-git" => {
:action => :git,
diff --git a/VERSION b/VERSION
index 2157409..ca222b7 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.22.0
+0.23.0
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index e285584..c4d3a2a 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -100,7 +100,6 @@ static int init(struct dec_audio *da, const char *decoder)
lavc_context = avcodec_alloc_context3(lavc_codec);
ctx->avctx = lavc_context;
ctx->avframe = av_frame_alloc();
- lavc_context->refcounted_frames = 1;
lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
lavc_context->codec_id = lavc_codec->id;
@@ -207,7 +206,6 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
if (priv->needs_reset)
control(da, ADCTRL_RESET, NULL);
-#if HAVE_AVCODEC_NEW_CODEC_API
int ret = avcodec_send_packet(avctx, &pkt);
if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
if (ret >= 0 && mpkt)
@@ -220,24 +218,6 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
ret = 0;
}
-#else
- int ret = avcodec_decode_audio4(avctx, priv->avframe, &got_frame, &pkt);
- if (mpkt) {
- // At least "shorten" decodes sub-frames, instead of the whole packet.
- // At least "mpc8" can return 0 and wants the packet again next time.
- if (ret >= 0) {
- ret = FFMIN(ret, mpkt->len); // sanity check against decoder overreads
- mpkt->buffer += ret;
- mpkt->len -= ret;
- mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time
- }
- // LATM may need many packets to find mux info
- if (ret == AVERROR(EAGAIN)) {
- mpkt->len = 0;
- return 0;
- }
- }
-#endif
if (ret < 0) {
MP_ERR(da, "Error decoding audio.\n");
return -1;
@@ -245,8 +225,7 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
if (!got_frame)
return 0;
- double out_pts = mp_pts_from_av(MP_AVFRAME_DEC_PTS(priv->avframe),
- &priv->codec_timebase);
+ double out_pts = mp_pts_from_av(priv->avframe->pts, &priv->codec_timebase);
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
if (!mpframe)
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index 56e4a81..30c7883 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -71,6 +71,7 @@ static void uninit(struct dec_audio *da)
av_freep(&lavf_ctx->pb->buffer);
av_freep(&lavf_ctx->pb);
avformat_free_context(lavf_ctx);
+ spdif_ctx->lavf_ctx = NULL;
}
}
@@ -82,12 +83,10 @@ static int init(struct dec_audio *da, const char *decoder)
spdif_ctx->use_dts_hd = da->opts->dtshd;
spdif_ctx->pool = mp_audio_pool_create(spdif_ctx);
- if (strcmp(decoder, "dts-hd") == 0) {
- decoder = "dts";
+ if (strcmp(decoder, "spdif_dts_hd") == 0)
spdif_ctx->use_dts_hd = true;
- }
- spdif_ctx->codec_id = mp_codec_to_av_codec_id(decoder);
+ spdif_ctx->codec_id = mp_codec_to_av_codec_id(da->codec->codec);
return spdif_ctx->codec_id != AV_CODEC_ID_NONE;
}
@@ -116,16 +115,10 @@ static int determine_codec_profile(struct dec_audio *da, AVPacket *pkt)
goto done;
}
-#if HAVE_AVCODEC_NEW_CODEC_API
if (avcodec_send_packet(ctx, pkt) < 0)
goto done;
if (avcodec_receive_frame(ctx, frame) < 0)
goto done;
-#else
- int got_frame = 0;
- if (avcodec_decode_audio4(ctx, frame, &got_frame, pkt) < 1 || !got_frame)
- goto done;
-#endif
profile = ctx->profile;
@@ -178,11 +171,7 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt)
if (!stream)
goto fail;
-#if HAVE_AVCODEC_HAS_CODECPAR
stream->codecpar->codec_id = spdif_ctx->codec_id;
-#else
- stream->codec->codec_id = spdif_ctx->codec_id;
-#endif
AVDictionary *format_opts = NULL;
@@ -305,22 +294,53 @@ static const int codecs[] = {
AV_CODEC_ID_NONE
};
-static void add_decoders(struct mp_decoder_list *list)
+static bool find_codec(const char *name)
{
for (int n = 0; codecs[n] != AV_CODEC_ID_NONE; n++) {
const char *format = mp_codec_from_av_codec_id(codecs[n]);
- if (format) {
- mp_add_decoder(list, "spdif", format, format,
- "libavformat/spdifenc audio pass-through decoder");
+ if (format && name && strcmp(format, name) == 0)
+ return true;
+ }
+ return false;
+}
+
+// codec is the libavcodec name of the source audio codec.
+// pref is a ","-separated list of names, some of them which do not match with
+// libavcodec names (like dts-hd).
+struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref)
+{
+ struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
+
+ if (!find_codec(codec))
+ return list;
+
+ bool spdif_allowed = false, dts_hd_allowed = false;
+ bstr sel = bstr0(pref);
+ while (sel.len) {
+ bstr decoder;
+ bstr_split_tok(sel, ",", &decoder, &sel);
+ if (decoder.len) {
+ if (bstr_equals0(decoder, codec))
+ spdif_allowed = true;
+ if (bstr_equals0(decoder, "dts-hd") && strcmp(codec, "dts") == 0)
+ spdif_allowed = dts_hd_allowed = true;
}
}
- mp_add_decoder(list, "spdif", "dts", "dts-hd",
+
+ if (!spdif_allowed)
+ return list;
+
+ const char *suffix_name = dts_hd_allowed ? "dts_hd" : codec;
+ char name[80];
+ snprintf(name, sizeof(name), "spdif_%s", suffix_name);
+ mp_add_decoder(list, "spdif", codec, name,
"libavformat/spdifenc audio pass-through decoder");
+ return list;
}
const struct ad_functions ad_spdif = {
.name = "spdif",
- .add_decoders = add_decoders,
+ .add_decoders = NULL,
.init = init,
.uninit = uninit,
.control = control,
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 39e867c..9f28302 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -43,11 +43,12 @@
#include "audio/filter/af.h"
extern const struct ad_functions ad_lavc;
+
+// Not a real codec - specially treated.
extern const struct ad_functions ad_spdif;
static const struct ad_functions * const ad_drivers[] = {
&ad_lavc,
- &ad_spdif,
NULL
};
@@ -90,10 +91,10 @@ static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio)
struct mp_decoder_list *list = audio_decoder_list();
struct mp_decoder_list *new =
- mp_select_decoders(list, codec, opts->audio_decoders);
- if (d_audio->try_spdif) {
+ mp_select_decoders(d_audio->log, list, codec, opts->audio_decoders);
+ if (d_audio->try_spdif && codec) {
struct mp_decoder_list *spdif =
- mp_select_decoder_list(list, codec, "spdif", opts->audio_spdif);
+ select_spdif_codec(codec, opts->audio_spdif);
mp_append_decoders(spdif, new);
talloc_free(new);
new = spdif;
@@ -108,6 +109,8 @@ static const struct ad_functions *find_driver(const char *name)
if (strcmp(ad_drivers[i]->name, name) == 0)
return ad_drivers[i];
}
+ if (strcmp(name, "spdif") == 0)
+ return &ad_spdif;
return NULL;
}
@@ -126,21 +129,18 @@ int audio_init_best_codec(struct dec_audio *d_audio)
const struct ad_functions *driver = find_driver(sel->family);
if (!driver)
continue;
- MP_VERBOSE(d_audio, "Opening audio decoder %s:%s\n",
- sel->family, sel->decoder);
+ MP_VERBOSE(d_audio, "Opening audio decoder %s\n", sel->decoder);
d_audio->ad_driver = driver;
if (init_audio_codec(d_audio, sel->decoder)) {
decoder = sel;
break;
}
- MP_WARN(d_audio, "Audio decoder init failed for "
- "%s:%s\n", sel->family, sel->decoder);
+ MP_WARN(d_audio, "Audio decoder init failed for %s\n", sel->decoder);
}
if (d_audio->ad_driver) {
d_audio->decoder_desc =
- talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
- decoder->decoder);
+ talloc_asprintf(d_audio, "%s (%s)", decoder->decoder, decoder->desc);
MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
} else {
MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index 7bc8b00..ebe7c8a 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -59,4 +59,7 @@ int audio_get_frame(struct dec_audio *d_audio, struct mp_audio **out_frame);
void audio_reset_decoding(struct dec_audio *d_audio);
+// ad_spdif.c
+struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref);
+
#endif /* MPLAYER_DEC_AUDIO_H */
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
index 0a7c5d4..9df5adb 100644
--- a/audio/filter/af_lavcac3enc.c
+++ b/audio/filter/af_lavcac3enc.c
@@ -280,7 +280,6 @@ static int filter_out(struct af_instance *af)
AVPacket pkt = {0};
av_init_packet(&pkt);
-#if HAVE_AVCODEC_NEW_CODEC_API
// Send input as long as it wants.
while (1) {
err = read_input_frame(af, frame);
@@ -310,21 +309,6 @@ static int filter_out(struct af_instance *af)
MP_FATAL(af, "Encode failed.\n");
goto done;
}
-#else
- err = read_input_frame(af, frame);
- if (err < 0)
- goto done;
- if (err == 0)
- goto done;
- err = -1;
- int ok;
- int lavc_ret = avcodec_encode_audio2(s->lavc_actx, &pkt, frame, &ok);
- s->input->samples = 0;
- if (lavc_ret < 0 || !ok) {
- MP_FATAL(af, "Encode failed.\n");
- goto done;
- }
-#endif
MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n",
pkt.size, s->pending->samples + s->input->samples);
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index dc5d1a0..828be66 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -111,12 +111,7 @@ static double get_delay(struct af_resample *s)
}
static int get_out_samples(struct af_resample *s, int in_samples)
{
-#if LIBSWRESAMPLE_VERSION_MAJOR > 1 || LIBSWRESAMPLE_VERSION_MINOR >= 2
return swr_get_out_samples(s->avrctx, in_samples);
-#else
- return av_rescale_rnd(in_samples, s->out_rate, s->in_rate, AV_ROUND_UP)
- + swr_get_delay(s->avrctx, s->out_rate);
-#endif
}
#endif
diff --git a/audio/out/ao.c b/audio/out/ao.c
index b624f41..6cf8de2 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -112,8 +112,8 @@ static bool get_desc(struct m_obj_desc *dst, int index)
.priv_size = ao->priv_size,
.priv_defaults = ao->priv_defaults,
.options = ao->options,
+ .options_prefix = ao->options_prefix,
.global_opts = ao->global_opts,
- .legacy_prefix = ao->legacy_prefix,
.hidden = ao->encode,
.p = ao,
};
@@ -127,11 +127,12 @@ const struct m_obj_list ao_obj_list = {
.allow_unknown_entries = true,
.allow_trailer = true,
.disallow_positional_parameters = true,
+ .use_global_options = true,
};
static struct ao *ao_alloc(bool probing, struct mpv_global *global,
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
- char *name, char **args)
+ char *name)
{
assert(wakeup_cb);
@@ -155,12 +156,9 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global,
.def_buffer = opts->audio_buffer,
.client_name = talloc_strdup(ao, opts->audio_client_name),
};
- struct m_config *config =
- m_config_from_obj_desc_and_args(ao, ao->log, global, &desc,
- name, opts->ao_defs, args);
- if (!config)
+ ao->priv = m_config_group_from_desc(ao, ao->log, global, &desc, name);
+ if (!ao->priv)
goto error;
- ao->priv = config->optstruct;
return ao;
error:
talloc_free(ao);
@@ -171,9 +169,9 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
struct encode_lavc_context *encode_lavc_ctx, int flags,
int samplerate, int format, struct mp_chmap channels,
- char *dev, char *name, char **args)
+ char *dev, char *name)
{
- struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name, args);
+ struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name);
if (!ao)
return NULL;
ao->samplerate = samplerate;
@@ -206,7 +204,7 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
talloc_free(ao);
return ao_init(probing, global, wakeup_cb, wakeup_ctx,
encode_lavc_ctx, flags, samplerate, format, channels,
- rdevice, redirect, NULL);
+ rdevice, redirect);
}
goto fail;
}
@@ -313,8 +311,7 @@ struct ao *ao_init_best(struct mpv_global *global,
mp_verbose(log, "Using preferred device '%s'\n", dev);
}
ao = ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx,
- init_flags, samplerate, format, channels, dev,
- entry->name, entry->attribs);
+ init_flags, samplerate, format, channels, dev, entry->name);
if (ao)
break;
if (!probing)
@@ -571,7 +568,7 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
break; // don't add unsafe/special entries
struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx,
- (char *)d->name, NULL);
+ (char *)d->name);
if (!ao)
continue;
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 2015576..ac29905 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -603,8 +603,8 @@ static int try_open_device(struct ao *ao, const char *device, int mode)
const char *const fallbacks[] = {"hdmi", "iec958", NULL};
for (int n = 0; fallbacks[n]; n++) {
char *ndev = append_params(tmp, fallbacks[n], params);
- MP_VERBOSE(ao, "got error %d; opening iec fallback "
- "device '%s'\n", err, ndev);
+ MP_VERBOSE(ao, "got error '%s'; opening iec fallback "
+ "device '%s'\n", snd_strerror(err), ndev);
err = snd_pcm_open
(&p->alsa, ndev, SND_PCM_STREAM_PLAYBACK, mode);
if (err >= 0)
@@ -845,12 +845,6 @@ static int init_device(struct ao *ao, int mode)
ao->device_buffer = p->buffersize;
- // ao_alsa implements this by relying on underrun behavior (no data means
- // underrun, during which silence is played). Trigger by playing some
- // initial silence.
- if (ao->stream_silence)
- ao_play_silence(ao, p->outburst);
-
return 0;
alsa_error:
@@ -1202,15 +1196,5 @@ const struct ao_driver audio_out_alsa = {
.wakeup = ao_wakeup_poll,
.list_devs = list_devs,
.priv_size = sizeof(struct priv),
- .options = (const struct m_option[]) {
- OPT_SUBOPT_LEGACY("device", "alsa-device"),
- OPT_SUBOPT_LEGACY("resample", "alsa-resample"),
- OPT_SUBOPT_LEGACY("mixer-device", "alsa-mixer-device"),
- OPT_SUBOPT_LEGACY("mixer-name", "alsa-mixer-name"),
- OPT_SUBOPT_LEGACY("mixer-index", "alsa-mixer-index"),
- OPT_SUBOPT_LEGACY("non-interleaved", "alsa-non-interleaved"),
- OPT_SUBOPT_LEGACY("ignore-chmap", "alsa-ignore-chmap"),
- {0}
- },
.global_opts = &ao_alsa_conf,
};
diff --git a/audio/out/ao_audiounit.m b/audio/out/ao_audiounit.m
index 7411a1a..3170352 100644
--- a/audio/out/ao_audiounit.m
+++ b/audio/out/ao_audiounit.m
@@ -195,7 +195,4 @@ const struct ao_driver audio_out_audiounit = {
.pause = stop,
.resume = start,
.priv_size = sizeof(struct priv),
- .options = (const struct m_option[]){
- {0}
- },
};
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 3a7aa2e..ba0dd9b 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -39,7 +39,6 @@ struct priv {
AudioStreamID original_asbd_stream;
int change_physical_format;
- int exclusive;
};
static int64_t ca_get_hardware_latency(struct ao *ao) {
@@ -143,9 +142,7 @@ static int init(struct ao *ao)
{
struct priv *p = ao->priv;
- p->exclusive |= ao->init_flags & AO_INIT_EXCLUSIVE;
-
- if (!af_fmt_is_pcm(ao->format) || p->exclusive) {
+ if (!af_fmt_is_pcm(ao->format) || (ao->init_flags & AO_INIT_EXCLUSIVE)) {
MP_VERBOSE(ao, "redirecting to coreaudio_exclusive\n");
ao->redirect = "coreaudio_exclusive";
return CONTROL_ERROR;
@@ -429,9 +426,7 @@ const struct ao_driver audio_out_coreaudio = {
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]){
OPT_FLAG("change-physical-format", change_physical_format, 0),
- OPT_FLAG("exclusive", exclusive, 0,
- .deprecation_message = "use --audio-exclusive"),
{0}
},
- .legacy_prefix = "coreaudio",
+ .options_prefix = "coreaudio",
};
diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c
index 56c7e28..2ad3cad 100644
--- a/audio/out/ao_jack.c
+++ b/audio/out/ao_jack.c
@@ -246,13 +246,5 @@ const struct ao_driver audio_out_jack = {
.uninit = uninit,
.resume = resume,
.priv_size = sizeof(struct priv),
- .options = (const struct m_option[]) {
- OPT_SUBOPT_LEGACY("port", "jack-port"),
- OPT_SUBOPT_LEGACY("name", "jack-name"),
- OPT_SUBOPT_LEGACY("autostart", "jack-autostart"),
- OPT_SUBOPT_LEGACY("connect", "jack-connect"),
- OPT_SUBOPT_LEGACY("std-channel-layout", "jack-std-channel-layout"),
- {0}
- },
.global_opts = &ao_jack_conf,
};
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index 8ae1317..4dbc55a 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -258,7 +258,6 @@ static void encode_audio_and_write(struct ao *ao, AVFrame *frame)
struct priv *ac = ao->priv;
AVPacket packet = {0};
-#if HAVE_AVCODEC_NEW_CODEC_API
int status = avcodec_send_frame(ac->codec, frame);
if (status < 0) {
MP_ERR(ao, "error encoding at %d %d/%d\n",
@@ -297,28 +296,6 @@ static void encode_audio_and_write(struct ao *ao, AVFrame *frame)
write_packet(ao, &packet);
av_packet_unref(&packet);
}
-#else
- av_init_packet(&packet);
- int got_packet = 0;
- int status = avcodec_encode_audio2(ac->codec, &packet, frame, &got_packet);
- if (status < 0) {
- MP_ERR(ao, "error encoding at %d %d/%d\n",
- frame ? (int) frame->pts : -1,
- ac->codec->time_base.num,
- ac->codec->time_base.den);
- return;
- }
- if (!got_packet) {
- return;
- }
- if (frame) {
- if (ac->savepts == AV_NOPTS_VALUE)
- ac->savepts = frame->pts;
- }
- encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec);
- write_packet(ao, &packet);
- av_packet_unref(&packet);
-#endif
}
// must get exactly ac->aframesize amount of data
diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c
index 7c0c745..7b288a8 100644
--- a/audio/out/ao_null.c
+++ b/audio/out/ao_null.c
@@ -241,5 +241,5 @@ const struct ao_driver audio_out_null = {
OPT_CHANNELS("channel-layouts", channel_layouts, 0),
{0}
},
- .legacy_prefix = "ao-null",
+ .options_prefix = "ao-null",
};
diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c
index aba0494..a1fd95a 100644
--- a/audio/out/ao_openal.c
+++ b/audio/out/ao_openal.c
@@ -374,5 +374,5 @@ const struct ao_driver audio_out_openal = {
DEVICE_OPT_DEPRECATION),
{0}
},
- .legacy_prefix = "ao-openal",
+ .options_prefix = "ao-openal",
};
diff --git a/audio/out/ao_opensles.c b/audio/out/ao_opensles.c
index dd20dbf..5357ab4 100644
--- a/audio/out/ao_opensles.c
+++ b/audio/out/ao_opensles.c
@@ -246,5 +246,5 @@ const struct ao_driver audio_out_opensles = {
OPT_INTRANGE("sample-rate", cfg_sample_rate, 0, 1000, 100000),
{0}
},
- .legacy_prefix = "opensles",
+ .options_prefix = "opensles",
};
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 5bf5fec..c0446eb 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -653,5 +653,5 @@ const struct ao_driver audio_out_oss = {
OPT_STRING("mixer-channel", cfg_oss_mixer_channel, 0),
{0}
},
- .legacy_prefix = "oss",
+ .options_prefix = "oss",
};
diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c
index 169a1b9..4e5ec0a 100644
--- a/audio/out/ao_pcm.c
+++ b/audio/out/ao_pcm.c
@@ -224,5 +224,5 @@ const struct ao_driver audio_out_pcm = {
OPT_FLAG("append", append, 0),
{0}
},
- .legacy_prefix = "ao-pcm",
+ .options_prefix = "ao-pcm",
};
diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c
index 5a68553..6c6a517 100644
--- a/audio/out/ao_pulse.c
+++ b/audio/out/ao_pulse.c
@@ -841,5 +841,5 @@ const struct ao_driver audio_out_pulse = {
OPT_FLAG("latency-hacks", cfg_latency_hacks, 0),
{0}
},
- .legacy_prefix = "pulse",
+ .options_prefix = "pulse",
};
diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c
index 5ecb39b..9689a9e 100644
--- a/audio/out/ao_rsound.c
+++ b/audio/out/ao_rsound.c
@@ -162,6 +162,6 @@ const struct ao_driver audio_out_rsound = {
.deprecation_message = "request --audio-device support on issue tracker"),
{0}
},
- .legacy_prefix = "rsound",
+ .options_prefix = "rsound",
};
diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c
index d9d0062..1564e26 100644
--- a/audio/out/ao_sdl.c
+++ b/audio/out/ao_sdl.c
@@ -212,5 +212,5 @@ const struct ao_driver audio_out_sdl = {
OPT_FLOAT("buflen", buflen, 0),
{0}
},
- .legacy_prefix = "sdl",
+ .options_prefix = "sdl",
};
diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c
index f60fa30..e0fd9f0 100644
--- a/audio/out/ao_sndio.c
+++ b/audio/out/ao_sndio.c
@@ -324,5 +324,5 @@ const struct ao_driver audio_out_sndio = {
DEVICE_OPT_DEPRECATION),
{0}
},
- .legacy_prefix = "ao-sndio",
+ .options_prefix = "ao-sndio",
};
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index 17f3e98..b2e035d 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -496,11 +496,4 @@ const struct ao_driver audio_out_wasapi = {
.hotplug_init = hotplug_init,
.hotplug_uninit = hotplug_uninit,
.priv_size = sizeof(wasapi_state),
- .options = (const struct m_option[]) {
- OPT_FLAG("exclusive", opt_exclusive, 0,
- .deprecation_message = "use --audio-exclusive"),
- OPT_STRING("device", opt_device, 0, DEVICE_OPT_DEPRECATION),
- {NULL},
- },
- .legacy_prefix = "ao-wasapi",
};
diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h
index 6dd130b..65f16d1 100644
--- a/audio/out/ao_wasapi.h
+++ b/audio/out/ao_wasapi.h
@@ -50,6 +50,10 @@ void wasapi_change_uninit(struct ao* ao);
#define SAFE_RELEASE(unk, release) \
do { if ((unk) != NULL) { release; (unk) = NULL; } } while(0)
+#define mp_format_res_str(hres) \
+ (SUCCEEDED(hres) ? "ok" : ((hres) == AUDCLNT_E_UNSUPPORTED_FORMAT) \
+ ? "unsupported" : mp_HRESULT_to_str(hres))
+
enum wasapi_thread_state {
WASAPI_THREAD_FEED = 0,
WASAPI_THREAD_RESUME,
@@ -92,8 +96,6 @@ typedef struct wasapi_state {
// ao options
int opt_exclusive;
- int opt_list;
- char *opt_device;
// format info
WAVEFORMATEXTENSIBLE format;
diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c
index 320bb67..4667b57 100644
--- a/audio/out/ao_wasapi_utils.c
+++ b/audio/out/ao_wasapi_utils.c
@@ -289,18 +289,12 @@ static bool set_ao_format(struct ao *ao, WAVEFORMATEX *wf,
static bool try_format_exclusive(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat)
{
struct wasapi_state *state = ao->priv;
- MP_VERBOSE(ao, "Trying %s (exclusive)\n",
- waveformat_to_str(&wformat->Format));
HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient,
AUDCLNT_SHAREMODE_EXCLUSIVE,
&wformat->Format, NULL);
- if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
- EXIT_ON_ERROR(hr);
-
+ MP_VERBOSE(ao, "Trying %s (exclusive) -> %s\n",
+ waveformat_to_str(&wformat->Format), mp_format_res_str(hr));
return SUCCEEDED(hr);
-exit_label:
- MP_ERR(state, "Error testing exclusive format: %s\n", mp_HRESULT_to_str(hr));
- return false;
}
// This works like try_format_exclusive(), but will try to fallback to the AC3
@@ -393,11 +387,8 @@ static bool search_channels(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat)
for (int j = 0; channel_layouts[j]; j++) {
mp_chmap_from_str(&entry, bstr0(channel_layouts[j]));
if (!wformat->Format.nSamplesPerSec) {
- if (search_samplerates(ao, wformat, &entry)) {
+ if (search_samplerates(ao, wformat, &entry))
mp_chmap_sel_add_map(&chmap_sel, &entry);
- MP_VERBOSE(ao, "%s is supported\n",
- waveformat_to_str(&wformat->Format));
- }
} else {
change_waveformat_channels(wformat, &entry);
if (try_format_exclusive(ao, wformat))
@@ -442,11 +433,12 @@ static bool find_formats_shared(struct ao *ao)
WAVEFORMATEXTENSIBLE wformat;
set_waveformat_with_ao(&wformat, ao);
- MP_VERBOSE(ao, "Trying %s (shared)\n", waveformat_to_str(&wformat.Format));
WAVEFORMATEX *closestMatch;
HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient,
AUDCLNT_SHAREMODE_SHARED,
&wformat.Format, &closestMatch);
+ MP_VERBOSE(ao, "Trying %s (shared) -> %s\n",
+ waveformat_to_str(&wformat.Format), mp_format_res_str(hr));
if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
EXIT_ON_ERROR(hr);
@@ -857,11 +849,7 @@ static LPWSTR select_device(struct mp_log *l, struct device_desc *d)
bstr wasapi_get_specified_device_string(struct ao *ao)
{
- struct wasapi_state *state = ao->priv;
- bstr device = bstr_strip(bstr0(state->opt_device));
- if (!device.len)
- device = bstr_strip(bstr0(ao->device));
- return device;
+ return bstr_strip(bstr0(ao->device));
}
LPWSTR wasapi_find_deviceID(struct ao *ao)
diff --git a/audio/out/internal.h b/audio/out/internal.h
index 3ddc1be..b35f20f 100644
--- a/audio/out/internal.h
+++ b/audio/out/internal.h
@@ -182,8 +182,8 @@ struct ao_driver {
int priv_size;
const void *priv_defaults;
const struct m_option *options;
+ const char *options_prefix;
const struct m_sub_options *global_opts;
- const char *legacy_prefix;
};
// These functions can be called by AOs.
diff --git a/audio/out/pull.c b/audio/out/pull.c
index 44f6ab3..a656de6 100644
--- a/audio/out/pull.c
+++ b/audio/out/pull.c
@@ -101,7 +101,8 @@ static int play(struct ao *ao, void **data, int samples, int flags)
int state = atomic_load(&p->state);
if (!IS_PLAYING(state)) {
set_state(ao, AO_STATE_PLAY);
- ao->driver->resume(ao);
+ if (!ao->stream_silence)
+ ao->driver->resume(ao);
}
return write_samples;
@@ -203,7 +204,8 @@ static void pause(struct ao *ao)
static void resume(struct ao *ao)
{
set_state(ao, AO_STATE_PLAY);
- ao->driver->resume(ao);
+ if (!ao->stream_silence)
+ ao->driver->resume(ao);
}
static bool get_eof(struct ao *ao)
diff --git a/audio/out/push.c b/audio/out/push.c
index 6860638..a4a6808 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -49,6 +49,8 @@ struct ao_push_state {
struct mp_audio_buffer *buffer;
+ struct mp_audio *silence;
+
bool terminate;
bool wait_on_ao;
bool still_playing;
@@ -259,15 +261,38 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return write_samples;
}
+static void ao_get_silence(struct ao *ao, struct mp_audio *data, int size)
+{
+ struct ao_push_state *p = ao->api_priv;
+ if (!p->silence) {
+ p->silence = talloc_zero(p, struct mp_audio);
+ mp_audio_set_format(p->silence, ao->format);
+ mp_audio_set_channels(p->silence, &ao->channels);
+ p->silence->rate = ao->samplerate;
+ }
+ if (p->silence->samples < size) {
+ mp_audio_realloc_min(p->silence, size);
+ p->silence->samples = size;
+ mp_audio_fill_silence(p->silence, 0, size);
+ }
+ *data = *p->silence;
+ data->samples = size;
+}
+
// called locked
static void ao_play_data(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
- struct mp_audio data;
- mp_audio_buffer_peek(p->buffer, &data);
- int max = data.samples;
int space = ao->driver->get_space(ao);
+ bool play_silence = p->paused || (ao->stream_silence && !p->still_playing);
space = MPMAX(space, 0);
+ struct mp_audio data;
+ if (play_silence) {
+ ao_get_silence(ao, &data, space);
+ } else {
+ mp_audio_buffer_peek(p->buffer, &data);
+ }
+ int max = data.samples;
if (data.samples > space)
data.samples = space;
int flags = 0;
@@ -289,7 +314,8 @@ static void ao_play_data(struct ao *ao)
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
r = max;
}
- mp_audio_buffer_skip(p->buffer, r);
+ if (!play_silence)
+ mp_audio_buffer_skip(p->buffer, r);
if (r > 0)
p->expected_end_time = 0;
// Nothing written, but more input data than space - this must mean the
@@ -300,7 +326,7 @@ static void ao_play_data(struct ao *ao)
// Wait until space becomes available. Also wait if we actually wrote data,
// so the AO wakes us up properly if it needs more data.
p->wait_on_ao = space == 0 || r > 0 || stuck;
- p->still_playing |= r > 0;
+ p->still_playing |= r > 0 && !play_silence;
// If we just filled the AO completely (r == space), don't refill for a
// while. Prevents wakeup feedback with byte-granular AOs.
int needed = unlocked_get_space(ao);
@@ -319,12 +345,13 @@ static void *playthread(void *arg)
mpthread_set_name("ao");
pthread_mutex_lock(&p->lock);
while (!p->terminate) {
- if (!p->paused)
+ bool playing = !p->paused || ao->stream_silence;
+ if (playing)
ao_play_data(ao);
if (!p->need_wakeup) {
MP_STATS(ao, "start audio wait");
- if (!p->wait_on_ao || p->paused) {
+ if (!p->wait_on_ao || !playing) {
// Avoid busy waiting, because the audio API will still report
// that it needs new data, even if we're not ready yet, or if
// get_space() decides that the amount of audio buffered in the
@@ -453,8 +480,9 @@ int ao_play_silence(struct ao *ao, int samples)
assert(ao->api == &ao_api_push);
if (samples <= 0 || !af_fmt_is_pcm(ao->format) || !ao->driver->play)
return 0;
- char *p = talloc_size(NULL, samples * ao->sstride);
- af_fill_silence(p, samples * ao->sstride, ao->format);
+ int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num;
+ char *p = talloc_size(NULL, bytes);
+ af_fill_silence(p, bytes, ao->format);
void *tmp[MP_NUM_CHANNELS];
for (int n = 0; n < MP_NUM_CHANNELS; n++)
tmp[n] = p;
diff --git a/common/av_common.c b/common/av_common.c
index 27a3319..f2f4349 100644
--- a/common/av_common.c
+++ b/common/av_common.c
@@ -77,13 +77,8 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st)
// other demuxers must be handled manually.
void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c)
{
-#if HAVE_AVCODEC_HAS_CODECPAR
if (c->lav_codecpar)
avcodec_parameters_to_context(avctx, c->lav_codecpar);
-#else
- if (c->lav_headers)
- mp_copy_lav_codec_headers(avctx, c->lav_headers);
-#endif
}
// Pick a "good" timebase, which will be used to convert double timestamps
diff --git a/common/av_common.h b/common/av_common.h
index b5ca034..4b13dcd 100644
--- a/common/av_common.h
+++ b/common/av_common.h
@@ -46,13 +46,4 @@ void mp_set_avdict(struct AVDictionary **dict, char **kv);
void mp_avdict_print_unset(struct mp_log *log, int msgl, struct AVDictionary *d);
int mp_set_avopts(struct mp_log *log, void *avobj, char **kv);
-#if (LIBAVCODEC_VERSION_MICRO >= 100 && \
- LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 61, 100)) || \
- (LIBAVCODEC_VERSION_MICRO < 100 && \
- LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 0))
-#define MP_AVFRAME_DEC_PTS(frame) ((frame)->pts)
-#else
-#define MP_AVFRAME_DEC_PTS(frame) ((frame)->pkt_pts)
-#endif
-
#endif
diff --git a/common/av_log.c b/common/av_log.c
index 64ce26d..e2a4c33 100644
--- a/common/av_log.c
+++ b/common/av_log.c
@@ -218,9 +218,7 @@ bool print_libav_versions(struct mp_log *log, int v)
mp_msg(log, v, "\n");
}
-#if HAVE_AV_VERSION_INFO
mp_msg(log, v, "%s version: %s\n", LIB_PREFIX, av_version_info());
-#endif
return !mismatch;
}
diff --git a/common/codecs.c b/common/codecs.c
index c0d99eb..5e744da 100644
--- a/common/codecs.c
+++ b/common/codecs.c
@@ -45,9 +45,10 @@ static struct mp_decoder_entry *find_decoder(struct mp_decoder_list *list,
{
for (int n = 0; n < list->num_entries; n++) {
struct mp_decoder_entry *cur = &list->entries[n];
- if (bstr_equals0(decoder, cur->decoder) &&
- bstr_equals0(family, cur->family))
- return cur;
+ if (bstr_equals0(decoder, cur->decoder)) {
+ if (bstr_equals0(family, "*") || bstr_equals0(family, cur->family))
+ return cur;
+ }
}
return NULL;
}
@@ -70,13 +71,14 @@ static void add_new(struct mp_decoder_list *to, struct mp_decoder_entry *entry,
// The selection string corresponds to --vd/--ad directly, and has the
// following syntax:
// selection = [<entry> ("," <entry>)*]
-// entry = <family> ":" <decoder> // prefer decoder
+// entry = [<family> ":"] <decoder> // prefer decoder
// entry = <family> ":*" // prefer all decoders
-// entry = "+" <family> ":" <decoder> // force a decoder
-// entry = "-" <family> ":" <decoder> // exclude a decoder
+// entry = "+" [<family> ":"] <decoder> // force a decoder
+// entry = "-" [<family> ":"] <decoder> // exclude a decoder
// entry = "-" // don't add fallback decoders
// Forcing a decoder means it's added even if the codec mismatches.
-struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all,
+struct mp_decoder_list *mp_select_decoders(struct mp_log *log,
+ struct mp_decoder_list *all,
const char *codec,
const char *selection)
{
@@ -90,16 +92,22 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all,
bstr entry;
bstr_split_tok(sel, ",", &entry, &sel);
if (bstr_equals0(entry, "-")) {
+ mp_warn(log, "Excluding codecs is deprecated.\n");
stop = true;
break;
}
bool force = bstr_eatstart0(&entry, "+");
bool exclude = !force && bstr_eatstart0(&entry, "-");
+ if (exclude || force)
+ mp_warn(log, "Forcing or excluding codecs is deprecated.\n");
struct mp_decoder_list *dest = exclude ? remove : list;
bstr family, decoder;
- if (!bstr_split_tok(entry, ":", &family, &decoder)) {
- family = entry;
- decoder = bstr0("*");
+ if (bstr_split_tok(entry, ":", &family, &decoder)) {
+ mp_warn(log, "Codec family selection is deprecated. "
+ "Pass the codec name directly.\n");
+ } else {
+ family = bstr0("*");
+ decoder = entry;
}
if (bstr_equals0(decoder, "*")) {
for (int n = 0; n < all->num_entries; n++) {
@@ -130,22 +138,6 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all,
return list;
}
-// selection is a ","-separated list of decoders, all in the given family.
-struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all,
- const char *codec,
- const char *family,
- const char *selection)
-{
- struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
- bstr sel = bstr0(selection);
- while (sel.len) {
- bstr decoder;
- bstr_split_tok(sel, ",", &decoder, &sel);
- add_new(list, find_decoder(all, bstr0(family), decoder), codec);
- }
- return list;
-}
-
void mp_append_decoders(struct mp_decoder_list *list, struct mp_decoder_list *a)
{
for (int n = 0; n < a->num_entries; n++)
@@ -158,7 +150,7 @@ void mp_print_decoders(struct mp_log *log, int msgl, const char *header,
mp_msg(log, msgl, "%s\n", header);
for (int n = 0; n < list->num_entries; n++) {
struct mp_decoder_entry *entry = &list->entries[n];
- mp_msg(log, msgl, " %s:%s", entry->family, entry->decoder);
+ mp_msg(log, msgl, " %s", entry->decoder);
if (strcmp(entry->decoder, entry->codec) != 0)
mp_msg(log, msgl, " (%s)", entry->codec);
mp_msg(log, msgl, " - %s\n", entry->desc);
diff --git a/common/codecs.h b/common/codecs.h
index 17316c8..bed5c46 100644
--- a/common/codecs.h
+++ b/common/codecs.h
@@ -18,6 +18,8 @@
#ifndef MP_CODECS_H
#define MP_CODECS_H
+struct mp_log;
+
struct mp_decoder_entry {
const char *family; // decoder module (e.g. ad_lavc => "lavc")
const char *codec; // name of the codec (e.g. "mp3")
@@ -33,15 +35,11 @@ struct mp_decoder_list {
void mp_add_decoder(struct mp_decoder_list *list, const char *family,
const char *codec, const char *decoder, const char *desc);
-struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all,
+struct mp_decoder_list *mp_select_decoders(struct mp_log *log,
+ struct mp_decoder_list *all,
const char *codec,
const char *selection);
-struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all,
- const char *codec,
- const char *family,
- const char *selection);
-
void mp_append_decoders(struct mp_decoder_list *list, struct mp_decoder_list *a);
struct mp_log;
diff --git a/common/encode_lavc.c b/common/encode_lavc.c
index d052385..7e116e3 100644
--- a/common/encode_lavc.c
+++ b/common/encode_lavc.c
@@ -595,12 +595,7 @@ int encode_lavc_alloc_stream(struct encode_lavc_context *ctx,
}
return -1;
}
-#if HAVE_AVCODEC_HAS_CODECPAR
ctx->vcc = avcodec_alloc_context3(ctx->vc);
-#else
- avcodec_get_context_defaults3(ctx->vst->codec, ctx->vc);
- ctx->vcc = ctx->vst->codec;
-#endif
// Using codec->time_base is deprecated, but needed for older lavf.
ctx->vst->time_base = ctx->timebase;
@@ -635,12 +630,7 @@ int encode_lavc_alloc_stream(struct encode_lavc_context *ctx,
}
return -1;
}
-#if HAVE_AVCODEC_HAS_CODECPAR
ctx->acc = avcodec_alloc_context3(ctx->ac);
-#else
- avcodec_get_context_defaults3(ctx->ast->codec, ctx->ac);
- ctx->acc = ctx->ast->codec;
-#endif
// Using codec->time_base is deprecated, but needed for older lavf.
ctx->ast->time_base = ctx->timebase;
@@ -708,10 +698,8 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx,
}
ret = avcodec_open2(codec, ctx->vc, &ctx->voptions);
-#if HAVE_AVCODEC_HAS_CODECPAR
if (ret >= 0)
ret = avcodec_parameters_from_context(ctx->vst->codecpar, codec);
-#endif
// complain about all remaining options, then free the dict
for (de = NULL; (de = av_dict_get(ctx->voptions, "", de,
@@ -747,10 +735,8 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx,
}
ret = avcodec_open2(codec, ctx->ac, &ctx->aoptions);
-#if HAVE_AVCODEC_HAS_CODECPAR
if (ret >= 0)
ret = avcodec_parameters_from_context(ctx->ast->codecpar, codec);
-#endif
// complain about all remaining options, then free the dict
for (de = NULL; (de = av_dict_get(ctx->aoptions, "", de,
@@ -826,11 +812,7 @@ int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVStream *stream,
(int)packet->size);
-#if HAVE_AVCODEC_HAS_CODECPAR
switch (stream->codecpar->codec_type) {
-#else
- switch (stream->codec->codec_type) {
-#endif
case AVMEDIA_TYPE_VIDEO:
ctx->vbytes += packet->size;
++ctx->frames;
diff --git a/demux/demux.c b/demux/demux.c
index 8aa9989..18c9b3b 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -89,6 +89,7 @@ struct demux_opts {
double min_secs;
int force_seekable;
double min_secs_cache;
+ int access_references;
};
#define OPT_BASE_STRUCT struct demux_opts
@@ -100,6 +101,7 @@ const struct m_sub_options demux_conf = {
OPT_INTRANGE("demuxer-max-bytes", max_bytes, 0, 0, INT_MAX),
OPT_FLAG("force-seekable", force_seekable, 0),
OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0),
+ OPT_FLAG("access-references", access_references, 0),
{0}
},
.size = sizeof(struct demux_opts),
@@ -108,6 +110,7 @@ const struct m_sub_options demux_conf = {
.max_bytes = 400 * 1024 * 1024,
.min_secs = 1.0,
.min_secs_cache = 10.0,
+ .access_references = 1,
},
};
@@ -1213,6 +1216,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
return NULL;
struct demuxer *demuxer = talloc_ptrtype(NULL, demuxer);
+ struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf);
*demuxer = (struct demuxer) {
.desc = desc,
.stream = stream,
@@ -1223,6 +1227,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
.glog = log,
.filename = talloc_strdup(demuxer, stream->url),
.is_network = stream->is_network,
+ .access_references = opts->access_references,
.events = DEMUX_EVENT_ALL,
};
demuxer->seekable = stream->seekable;
@@ -1230,8 +1235,6 @@ static struct demuxer *open_given_type(struct mpv_global *global,
!demuxer->stream->uncached_stream->seekable)
demuxer->seekable = false;
- struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf);
-
struct demux_internal *in = demuxer->in = talloc_ptrtype(demuxer, in);
*in = (struct demux_internal){
.log = demuxer->log,
diff --git a/demux/demux.h b/demux/demux.h
index 18f52d4..0e5a5e1 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -186,6 +186,7 @@ typedef struct demuxer {
// Typical examples: text subtitles, playlists
bool fully_read;
bool is_network; // opened directly from a network stream
+ bool access_references; // allow opening other files/URLs
// Bitmask of DEMUX_EVENT_*
int events;
diff --git a/demux/demux_cue.c b/demux/demux_cue.c
index 673e8b9..ba97ca0 100644
--- a/demux/demux_cue.c
+++ b/demux/demux_cue.c
@@ -253,6 +253,9 @@ out:
static int try_open_file(struct demuxer *demuxer, enum demux_check check)
{
+ if (!demuxer->access_references)
+ return -1;
+
struct stream *s = demuxer->stream;
if (check >= DEMUX_CHECK_UNSAFE) {
bstr d = stream_peek(s, PROBE_SIZE);
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 67a4290..623cae3 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -295,6 +295,9 @@ static void build_mpv_edl_timeline(struct timeline *tl)
static int try_open_file(struct demuxer *demuxer, enum demux_check check)
{
+ if (!demuxer->access_references)
+ return -1;
+
struct priv *p = talloc_zero(demuxer, struct priv);
demuxer->priv = p;
demuxer->fully_read = true;
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 7857934..1249563 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -22,6 +22,7 @@
#include <stdbool.h>
#include <string.h>
#include <strings.h>
+#include <errno.h>
#include <assert.h>
#include "config.h"
@@ -167,6 +168,8 @@ static const struct format_hack format_hacks[] = {
BLACKLIST("bin"),
// Useless, does not work with custom streams.
BLACKLIST("image2"),
+ // Probably a security risk.
+ BLACKLIST("ffm"),
// Image demuxers ("<name>_pipe" is detected explicitly)
{"image2pipe", .image_format = true},
{0}
@@ -574,13 +577,8 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
AVFormatContext *avfc = priv->avfc;
AVStream *st = avfc->streams[i];
struct sh_stream *sh = NULL;
-#if HAVE_AVCODEC_HAS_CODECPAR
AVCodecParameters *codec = st->codecpar;
int lavc_delay = codec->initial_padding;
-#else
- AVCodecContext *codec = st->codec;
- int lavc_delay = codec->delay;
-#endif
switch (codec->codec_type) {
case AVMEDIA_TYPE_AUDIO: {
@@ -676,17 +674,9 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
sh->ff_index = st->index;
sh->codec->codec = mp_codec_from_av_codec_id(codec->codec_id);
sh->codec->codec_tag = codec->codec_tag;
-#if HAVE_AVCODEC_HAS_CODECPAR
sh->codec->lav_codecpar = avcodec_parameters_alloc();
if (sh->codec->lav_codecpar)
avcodec_parameters_copy(sh->codec->lav_codecpar, codec);
-#else
- sh->codec->codec = mp_codec_from_av_codec_id(codec->codec_id);
- sh->codec->codec_tag = codec->codec_tag;
- sh->codec->lav_headers = avcodec_alloc_context3(NULL);
- if (sh->codec->lav_headers)
- mp_copy_lav_codec_headers(sh->codec->lav_headers, codec);
-#endif
sh->codec->native_tb_num = st->time_base.num;
sh->codec->native_tb_den = st->time_base.den;
@@ -752,6 +742,14 @@ static int interrupt_cb(void *ctx)
return mp_cancel_test(priv->stream->cancel);
}
+static int block_io_open(struct AVFormatContext *s, AVIOContext **pb,
+ const char *url, int flags, AVDictionary **options)
+{
+ struct demuxer *demuxer = s->opaque;
+ MP_ERR(demuxer, "Not opening '%s' due to --access-references=no.\n", url);
+ return AVERROR(EACCES);
+}
+
static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
{
AVFormatContext *avfc;
@@ -853,6 +851,10 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
.opaque = demuxer,
};
+ avfc->opaque = demuxer;
+ if (!demuxer->access_references)
+ avfc->io_open = block_io_open;
+
mp_set_avdict(&dopts, lavfdopts->avopts);
if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) {
@@ -936,14 +938,9 @@ 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 LIBAVFORMAT_VERSION_MICRO >= 100 && \
- LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 50, 100)
+#if LIBAVFORMAT_VERSION_MICRO >= 100
if (pkt->flags & AV_PKT_FLAG_DISCARD)
MP_ERR(demux, "Edit lists are not correctly supported (FFmpeg issue).\n");
#endif
@@ -1124,12 +1121,8 @@ static void demux_close_lavf(demuxer_t *demuxer)
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]->codec->lav_headers);
-#if HAVE_AVCODEC_HAS_CODECPAR
+ if (priv->streams[n])
avcodec_parameters_free(&priv->streams[n]->codec->lav_codecpar);
-#endif
- }
}
if (priv->own_stream)
free_stream(priv->stream);
diff --git a/demux/demux_libarchive.c b/demux/demux_libarchive.c
index dcdbe65..41b0536 100644
--- a/demux/demux_libarchive.c
+++ b/demux/demux_libarchive.c
@@ -32,6 +32,9 @@ static int cmp_filename(const void *a, const void *b)
static int open_file(struct demuxer *demuxer, enum demux_check check)
{
+ if (!demuxer->access_references)
+ return -1;
+
int flags = 0;
int probe_size = STREAM_BUFFER_SIZE;
if (check <= DEMUX_CHECK_REQUEST) {
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 63b58cd..ddda2ec 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -128,6 +128,8 @@ typedef struct mkv_track {
AVCodecParserContext *av_parser;
AVCodecContext *av_parser_codec;
+ bool require_keyframes;
+
/* stuff for realaudio braincancer */
double ra_pts; /* previous audio timestamp */
uint32_t sub_packet_size; ///< sub packet size, per stream
@@ -200,7 +202,7 @@ typedef struct mkv_demuxer {
bool index_has_durations;
- bool eof_warning;
+ bool eof_warning, keyframe_warning;
struct block_info tmp_block;
} mkv_demuxer_t;
@@ -1511,7 +1513,7 @@ static void parse_flac_chmap(struct mp_chmap *channels, unsigned char *data,
}
static const char *const mkv_audio_tags[][2] = {
- { "A_MPEG/L2", "mp3" },
+ { "A_MPEG/L2", "mp2" },
{ "A_MPEG/L3", "mp3" },
{ "A_AC3", "ac3" },
{ "A_EAC3", "eac3" },
@@ -1701,7 +1703,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
mp_chmap_set_unknown(&sh_a->channels, track->a_channels);
const char *codec = sh_a->codec;
- if (!strcmp(codec, "mp3") || !strcmp(codec, "truehd")) {
+ if (!strcmp(codec, "mp2") || !strcmp(codec, "mp3") ||
+ !strcmp(codec, "truehd"))
+ {
track->parse = true;
} else if (!strcmp(codec, "flac")) {
unsigned char *ptr = extradata;
@@ -1750,6 +1754,11 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
if (sh_a->samplerate == 8000 && strcmp(codec, "ac3") == 0)
track->default_duration = 0;
+ // Deal with some FFmpeg-produced garbage, and assume all audio codecs can
+ // start decoding from anywhere.
+ if (strcmp(codec, "truehd") != 0)
+ track->require_keyframes = true;
+
sh_a->extradata = extradata;
sh_a->extradata_size = extradata_len;
@@ -2472,6 +2481,15 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
current_pts = tc / 1e9 - track->codec_delay;
+ if (track->require_keyframes && !keyframe) {
+ keyframe = true;
+ if (!mkv_d->keyframe_warning) {
+ MP_WARN(demuxer, "This is a broken file! Packets with incorrect "
+ "keyframe flag found. Enabling workaround.\n");
+ mkv_d->keyframe_warning = true;
+ }
+ }
+
if (track->type == MATROSKA_TRACK_AUDIO) {
if (mkv_d->a_skip_to_keyframe)
use_this_block &= keyframe;
diff --git a/demux/demux_mkv_timeline.c b/demux/demux_mkv_timeline.c
index 15f9a5d..476551c 100644
--- a/demux/demux_mkv_timeline.c
+++ b/demux/demux_mkv_timeline.c
@@ -519,7 +519,7 @@ void build_ordered_chapter_timeline(struct timeline *tl)
.opts = mp_get_config_group(ctx, tl->global, NULL),
};
- if (!ctx->opts->ordered_chapters) {
+ if (!ctx->opts->ordered_chapters || !demuxer->access_references) {
MP_INFO(demuxer, "File uses ordered chapters, but "
"you have disabled support for them. Ignoring.\n");
talloc_free(ctx);
diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c
index 7479db1..0f2ebed 100644
--- a/demux/demux_playlist.c
+++ b/demux/demux_playlist.c
@@ -283,6 +283,8 @@ static int parse_dir(struct pl_parser *p)
return 0;
char *path = mp_file_get_path(p, bstr0(p->real_stream->url));
+ if (!path)
+ return -1;
char **files = NULL;
int num_files = 0;
@@ -339,6 +341,9 @@ static const struct pl_format *probe_pl(struct pl_parser *p)
static int open_file(struct demuxer *demuxer, enum demux_check check)
{
+ if (!demuxer->access_references)
+ return -1;
+
bool force = check < DEMUX_CHECK_UNSAFE || check == DEMUX_CHECK_REQUEST;
struct pl_parser *p = talloc_zero(NULL, struct pl_parser);
diff --git a/demux/demux_rar.c b/demux/demux_rar.c
index f35c2cc..7d9adfc 100644
--- a/demux/demux_rar.c
+++ b/demux/demux_rar.c
@@ -23,6 +23,9 @@
static int open_file(struct demuxer *demuxer, enum demux_check check)
{
+ if (!demuxer->access_references)
+ return -1;
+
if (RarProbe(demuxer->stream))
return -1;
diff --git a/demux/stheader.h b/demux/stheader.h
index 240be72..26c1246 100644
--- a/demux/stheader.h
+++ b/demux/stheader.h
@@ -71,8 +71,6 @@ struct mp_codec_params {
int extradata_size;
// Codec specific header data (set by demux_lavf.c only)
- // Which one is in use depends on HAVE_AVCODEC_HAS_CODECPAR.
- struct AVCodecContext *lav_headers;
struct AVCodecParameters *lav_codecpar;
// Timestamp granularity for converting double<->rational timestamps.
diff --git a/input/ipc.c b/input/ipc.c
index c7563e3..f15f24d 100644
--- a/input/ipc.c
+++ b/input/ipc.c
@@ -384,12 +384,6 @@ static char *json_execute_command(struct mpv_handle *client, void *ta_parent,
rc = mpv_request_log_messages(client,
cmd_node->u.list->values[1].u.string);
- } else if (!strcmp("suspend", cmd)) {
- mpv_suspend(client);
- rc = MPV_ERROR_SUCCESS;
- } else if (!strcmp("resume", cmd)) {
- mpv_resume(client);
- rc = MPV_ERROR_SUCCESS;
} else if (!strcmp("enable_event", cmd) ||
!strcmp("disable_event", cmd))
{
diff --git a/libmpv/client.h b/libmpv/client.h
index 788b4f2..51f5c24 100644
--- a/libmpv/client.h
+++ b/libmpv/client.h
@@ -211,7 +211,7 @@ extern "C" {
* relational operators (<, >, <=, >=).
*/
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
-#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 23)
+#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 24)
/**
* Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with.
@@ -506,6 +506,9 @@ mpv_handle *mpv_create_client(mpv_handle *ctx, const char *name);
int mpv_load_config_file(mpv_handle *ctx, const char *filename);
/**
+ * This does nothing since mpv 0.23.0 (API version 1.24). Below is the
+ * description of the old behavior.
+ *
* Stop the playback thread. This means the core will stop doing anything, and
* only run and answer to client API requests. This is sometimes useful; for
* example, no new frame will be queued to the video output, so doing requests
@@ -815,7 +818,7 @@ void mpv_free_node_contents(mpv_node *node);
* - deprecated options shadowed by properties:
* - chapter (option deprecated in 0.21.0)
* - playlist-pos (option deprecated in 0.21.0)
- * The deprecated properties will be removed in mpv 0.22.0.
+ * The deprecated properties will be removed in mpv 0.23.0.
*
* @param name Option name. This is the same as on the mpv command line, but
* without the leading "--".
@@ -929,7 +932,7 @@ int mpv_command_node_async(mpv_handle *ctx, uint64_t reply_userdata,
* In some cases, properties and options still conflict. In these cases,
* mpv_set_property() accesses the options before mpv_initialize(), and
* the properties after mpv_initialize(). These conflicts will be removed
- * in mpv 0.22.0. See mpv_set_option() for further remarks.
+ * in mpv 0.23.0. See mpv_set_option() for further remarks.
*
* @param name The property name. See input.rst for a list of properties.
* @param format see enum mpv_format.
diff --git a/misc/bstr.c b/misc/bstr.c
index 0ef0c35..8c47b44 100644
--- a/misc/bstr.c
+++ b/misc/bstr.c
@@ -1,18 +1,18 @@
/*
* This file is part of mpv.
*
- * mpv is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser 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/>.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
diff --git a/misc/bstr.h b/misc/bstr.h
index 4aba35e..69dbce2 100644
--- a/misc/bstr.h
+++ b/misc/bstr.h
@@ -1,18 +1,18 @@
/*
* This file is part of mpv.
*
- * mpv is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser 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/>.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MPLAYER_BSTR_H
diff --git a/misc/charset_conv.c b/misc/charset_conv.c
index 48e4e9a..1758223 100644
--- a/misc/charset_conv.c
+++ b/misc/charset_conv.c
@@ -28,14 +28,6 @@
#include "common/msg.h"
-#if HAVE_ENCA
-#include <enca.h>
-#endif
-
-#if HAVE_LIBGUESS
-#include <libguess.h>
-#endif
-
#if HAVE_UCHARDET
#include <uchardet.h>
#endif
@@ -81,24 +73,6 @@ static int split_colon(const char *user_cp, int max, bstr *out_arr)
return count;
}
-// Returns true if user_cp implies that calling mp_charset_guess() on the
-// input data is required to determine the real codepage. This is the case
-// if user_cp is not a real iconv codepage, but a magic value that requests
-// for example ENCA charset auto-detection.
-bool mp_charset_requires_guess(const char *user_cp)
-{
- bstr res[2] = {{0}};
- int r = split_colon(user_cp, 2, res);
- // Note that "utf8" is the UTF-8 codepage, while "utf8:..." specifies UTF-8
- // by default, plus a codepage that is used if the input is not UTF-8.
- return bstrcasecmp0(res[0], "enca") == 0 ||
- bstrcasecmp0(res[0], "uchardet") == 0 ||
- bstrcasecmp0(res[0], "auto") == 0 ||
- bstrcasecmp0(res[0], "guess") == 0 ||
- (r > 1 && bstrcasecmp0(res[0], "utf-8") == 0) ||
- (r > 1 && bstrcasecmp0(res[0], "utf8") == 0);
-}
-
static const char *const utf_bom[3] = {"\xEF\xBB\xBF", "\xFF\xFE", "\xFE\xFF"};
static const char *const utf_enc[3] = {"utf-8", "utf-16le", "utf-16be"};
@@ -111,57 +85,6 @@ static const char *ms_bom_guess(bstr buf)
return NULL;
}
-#if HAVE_ENCA
-static const char *enca_guess(struct mp_log *log, bstr buf, const char *language)
-{
- // Do our own UTF-8 detection, because ENCA seems to get it wrong sometimes
- // (suggested by divVerent). Explicitly allow cut-off UTF-8.
- if (bstr_validate_utf8(buf) > -8)
- return "UTF-8";
-
- if (!language || !language[0])
- language = "__"; // neutral language
-
- const char *detected_cp = NULL;
-
- EncaAnalyser analyser = enca_analyser_alloc(language);
- if (analyser) {
- enca_set_termination_strictness(analyser, 0);
- EncaEncoding enc = enca_analyse_const(analyser, buf.start, buf.len);
- const char *tmp = enca_charset_name(enc.charset, ENCA_NAME_STYLE_ICONV);
- if (tmp && enc.charset != ENCA_CS_UNKNOWN)
- detected_cp = tmp;
- enca_analyser_free(analyser);
- } else {
- mp_err(log, "ENCA doesn't know language '%s'\n", language);
- size_t langcnt;
- const char **languages = enca_get_languages(&langcnt);
- mp_err(log, "ENCA supported languages:");
- for (int i = 0; i < langcnt; i++)
- mp_err(log, " %s", languages[i]);
- mp_err(log, "\n");
- free(languages);
- }
-
- return detected_cp;
-}
-#endif
-
-#if HAVE_LIBGUESS
-static const char *libguess_guess(struct mp_log *log, bstr buf,
- const char *language)
-{
- if (!language || !language[0] || strcmp(language, "help") == 0) {
- mp_err(log, "libguess needs a language: "
- "japanese taiwanese chinese korean russian arabic turkish "
- "greek hebrew polish baltic\n");
- return NULL;
- }
-
- return libguess_determine_encoding(buf.start, buf.len, language);
-}
-#endif
-
#if HAVE_UCHARDET
static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf)
{
@@ -177,17 +100,15 @@ static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf)
if (res && !res[0])
res = NULL;
if (res) {
+ mp_verbose(log, "libuchardet detected charset as %s\n", res);
iconv_t icdsc = iconv_open("UTF-8", res);
if (icdsc == (iconv_t)(-1)) {
- mp_warn(log, "Charset detected as %s, but not supported by iconv.\n",
- res);
+ mp_warn(log, "Charset '%s' not supported by iconv.\n", res);
res = NULL;
} else {
iconv_close(icdsc);
}
}
- if (!res && bstr_validate_utf8(buf) >= 0)
- res = "utf-8";
uchardet_delete(det);
return res;
}
@@ -199,22 +120,11 @@ static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf)
// it's a real iconv codepage), user_cp is returned without even looking at
// the buf data.
// The return value may (but doesn't have to) be allocated under talloc_ctx.
-const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf,
- const char *user_cp, int flags)
+static const char *mp_charset_guess_compat(void *talloc_ctx, struct mp_log *log,
+ bstr buf, const char *user_cp,
+ int flags)
{
- if (!mp_charset_requires_guess(user_cp))
- return user_cp;
-
- bool use_auto = strcasecmp(user_cp, "auto") == 0;
- if (use_auto) {
-#if HAVE_UCHARDET
- user_cp = "uchardet";
-#elif HAVE_ENCA
- user_cp = "enca";
-#else
- user_cp = "UTF-8:UTF-8-BROKEN";
-#endif
- }
+ mp_warn(log, "This syntax for the --sub-codepage option is deprecated.\n");
bstr params[3] = {{0}};
split_colon(user_cp, 3, params);
@@ -226,23 +136,12 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf,
const char *res = NULL;
- if (use_auto) {
- res = ms_bom_guess(buf);
- if (res)
- type = bstr0("auto");
- }
-
-#if HAVE_ENCA
- if (bstrcasecmp0(type, "enca") == 0)
- res = enca_guess(log, buf, lang);
-#endif
-#if HAVE_LIBGUESS
- if (bstrcasecmp0(type, "guess") == 0)
- res = libguess_guess(log, buf, lang);
-#endif
#if HAVE_UCHARDET
- if (bstrcasecmp0(type, "uchardet") == 0)
+ if (bstrcasecmp0(type, "uchardet") == 0) {
res = mp_uchardet(talloc_ctx, log, buf);
+ if (!res && bstr_validate_utf8(buf) >= 0)
+ res = "utf-8";
+ }
#endif
if (bstrcasecmp0(type, "utf8") == 0 || bstrcasecmp0(type, "utf-8") == 0) {
@@ -268,6 +167,45 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf,
return res;
}
+const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf,
+ const char *user_cp, int flags)
+{
+ if (strcasecmp(user_cp, "enca") == 0 || strcasecmp(user_cp, "guess") == 0 ||
+ strcasecmp(user_cp, "uchardet") == 0 || strchr(user_cp, ':'))
+ return mp_charset_guess_compat(talloc_ctx, log, buf, user_cp, flags);
+
+ if (user_cp[0] == '+') {
+ mp_verbose(log, "Forcing charset '%s'.\n", user_cp + 1);
+ return user_cp + 1;
+ }
+
+ const char *bom_cp = ms_bom_guess(buf);
+ if (bom_cp) {
+ mp_verbose(log, "Data has a BOM, assuming %s as charset.\n", bom_cp);
+ return bom_cp;
+ }
+
+ int r = bstr_validate_utf8(buf);
+ if (r >= 0 || (r > -8 && (flags & MP_ICONV_ALLOW_CUTOFF))) {
+ mp_verbose(log, "Data looks like UTF-8, ignoring user-provided charset.\n");
+ return "utf-8";
+ }
+
+ const char *res = user_cp;
+ if (strcasecmp(user_cp, "auto") == 0) {
+#if HAVE_UCHARDET
+ res = mp_uchardet(talloc_ctx, log, buf);
+#endif
+ if (!res) {
+ mp_verbose(log, "Charset auto-detection failed.\n");
+ res = "UTF-8-BROKEN";
+ }
+ }
+
+ mp_verbose(log, "Using charset '%s'.\n", res);
+ return res;
+}
+
// Use iconv to convert buf to UTF-8.
// Returns buf.start==NULL on error. Returns buf if cp is NULL, or if there is
// obviously no conversion required (e.g. if cp is "UTF-8").
diff --git a/misc/charset_conv.h b/misc/charset_conv.h
index ddfabbe..9be7a50 100644
--- a/misc/charset_conv.h
+++ b/misc/charset_conv.h
@@ -14,7 +14,6 @@ enum {
bool mp_charset_is_utf8(const char *user_cp);
bool mp_charset_is_utf16(const char *user_cp);
-bool mp_charset_requires_guess(const char *user_cp);
const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf,
const char *user_cp, int flags);
bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags);
diff --git a/options/m_config.c b/options/m_config.c
index 1c5fe01..14aa56d 100644
--- a/options/m_config.c
+++ b/options/m_config.c
@@ -29,16 +29,13 @@
#include <stdbool.h>
#include <pthread.h>
-#if HAVE_FNMATCH
-#include <fnmatch.h>
-#endif
-
#include "libmpv/client.h"
#include "mpv_talloc.h"
#include "m_config.h"
#include "options/m_option.h"
+#include "common/common.h"
#include "common/global.h"
#include "common/msg.h"
#include "common/msg_control.h"
@@ -268,6 +265,39 @@ struct m_config *m_config_from_obj_desc_noalloc(void *talloc_ctx,
return m_config_new(talloc_ctx, log, 0, desc->priv_defaults, desc->options);
}
+static struct m_config_group *find_group(struct mpv_global *global,
+ const struct m_option *cfg)
+{
+ struct m_config_shadow *shadow = global->config;
+ struct m_config *root = shadow->root;
+
+ for (int n = 0; n < root->num_groups; n++) {
+ if (cfg && root->groups[n].group && root->groups[n].group->opts == cfg)
+ return &root->groups[n];
+ }
+
+ return NULL;
+}
+
+// Allocate a priv struct that is backed by global options (like AOs and VOs,
+// anything that uses m_obj_list.use_global_options == true).
+// The result contains a snapshot of the current option values of desc->options.
+// For convenience, desc->options can be NULL; then priv struct is allocated
+// with just zero (or priv_defaults if set).
+void *m_config_group_from_desc(void *ta_parent, struct mp_log *log,
+ struct mpv_global *global, struct m_obj_desc *desc, const char *name)
+{
+ struct m_config_group *group = find_group(global, desc->options);
+ if (group) {
+ return mp_get_config_group(ta_parent, global, group->group);
+ } else {
+ void *d = talloc_zero_size(ta_parent, desc->priv_size);
+ if (desc->priv_defaults)
+ memcpy(d, desc->priv_defaults, desc->priv_size);
+ return d;
+ }
+}
+
static struct m_config_option *m_config_find_negation_opt(struct m_config *config,
struct bstr *name);
@@ -277,40 +307,8 @@ static int m_config_set_obj_params(struct m_config *config, struct mp_log *log,
{
for (int n = 0; args && args[n * 2 + 0]; n++) {
bstr opt = bstr0(args[n * 2 + 0]);
- const char *val = args[n * 2 + 1];
- struct m_config_option *co = m_config_get_co(config, opt);
- if (!co) {
- co = m_config_find_negation_opt(config, &opt);
- if (!co)
- continue;
-
- if (val && val[0])
- return -1; // no parameter allowed
-
- val = "no";
- }
- struct m_config *target = config;
- bool is_legacy = co->opt->type == &m_option_type_subopt_legacy;
- bool force_legacy = !!desc->legacy_prefix;
- if (is_legacy || force_legacy) {
- // Legacy: redirect deprecated sub-options to global ones.
- char tmp[100];
- const char *newopt;
- if (is_legacy) {
- newopt = co->opt->priv;
- } else {
- snprintf(tmp, sizeof(tmp), "%s-%.*s", desc->legacy_prefix,
- BSTR_P(opt));
- newopt = tmp;
- }
- assert(global);
- target = mp_get_root_config(global);
- mp_warn(log, "Using suboptions is deprecated. Use the global '--%s' "
- "option instead of '%.*s' suboption.\n", newopt,
- BSTR_P(opt));
- opt = bstr0(newopt);
- }
- if (m_config_set_option(target, opt, bstr0(val)) < 0)
+ bstr val = bstr0(args[n * 2 + 1]);
+ if (m_config_set_option(config, opt, val) < 0)
return -1;
}
@@ -334,21 +332,6 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent,
if (m_config_set_obj_params(config, log, global, desc, args) < 0)
goto error;
- if (desc->legacy_prefix) {
- assert(global);
- struct m_config *root = mp_get_root_config(global);
- // In this mode, the AO/VO will still access the options via its priv
- // struct (like with real sub-options). We have to copy them over.
- for (int n = 0; n < config->num_opts; n++) {
- struct m_config_option *co = &config->opts[n];
- char opt[100];
- snprintf(opt, sizeof(opt), "%s-%s", desc->legacy_prefix, co->name);
- struct m_config_option *g = m_config_get_co_raw(root, bstr0(opt));
- assert(g);
- m_option_copy(co->opt, co->data, g->data);
- }
- }
-
return config;
error:
talloc_free(config);
@@ -357,8 +340,6 @@ error:
static void ensure_backup(struct m_config *config, struct m_config_option *co)
{
- if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
- return;
if (!co->data)
return;
for (struct m_opt_backup *cur = config->backup_opts; cur; cur = cur->next) {
@@ -457,34 +438,83 @@ static void add_sub_options(struct m_config *config,
};
struct m_config_option next = {
- .name = parent ? parent->name : "",
+ .name = "",
.group = group,
};
+ if (parent && parent->name && parent->name[0])
+ next.name = parent->name;
+ if (subopts->prefix && subopts->prefix[0]) {
+ assert(next.name);
+ next.name = subopts->prefix;
+ }
add_options(config, &next, new_optstruct, new_optstruct_def, subopts->opts);
}
-static void add_global_subopts(struct m_config *config,
- const struct m_obj_list *list)
+#define MAX_VO_AO 16
+
+struct group_entry {
+ const struct m_obj_list *entry;
+ struct m_sub_options subs[MAX_VO_AO];
+ bool initialized;
+};
+
+static struct group_entry g_groups[2]; // limited by max. m_obj_list overall
+static int g_num_groups = 0;
+static pthread_mutex_t g_group_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static const struct m_sub_options *get_cached_group(const struct m_obj_list *list,
+ int n, struct m_sub_options *v)
+{
+ pthread_mutex_lock(&g_group_mutex);
+
+ struct group_entry *group = NULL;
+ for (int i = 0; i < g_num_groups; i++) {
+ if (g_groups[i].entry == list) {
+ group = &g_groups[i];
+ break;
+ }
+ }
+ if (!group) {
+ assert(g_num_groups < MP_ARRAY_SIZE(g_groups));
+ group = &g_groups[g_num_groups++];
+ group->entry = list;
+ }
+
+ if (!group->initialized) {
+ if (!v) {
+ n = -1;
+ group->initialized = true;
+ } else {
+ assert(n < MAX_VO_AO); // simply increase this if it fails
+ group->subs[n] = *v;
+ }
+ }
+
+ pthread_mutex_unlock(&g_group_mutex);
+
+ return n >= 0 ? &group->subs[n] : NULL;
+}
+
+static void init_obj_settings_list(struct m_config *config,
+ const struct m_obj_list *list)
{
struct m_obj_desc desc;
for (int n = 0; ; n++) {
- if (!list->get_desc(&desc, n))
+ if (!list->get_desc(&desc, n)) {
+ if (list->use_global_options)
+ get_cached_group(list, n, NULL);
break;
+ }
if (desc.global_opts)
add_sub_options(config, NULL, desc.global_opts);
- if (desc.legacy_prefix && desc.options) {
- // Legacy: auto-add sub-options as global options (using the prefix).
- struct m_config_option parent = {
- .name = desc.legacy_prefix,
- .group = 0,
- };
- struct m_sub_options *conf = talloc(config, struct m_sub_options);
- *conf = (struct m_sub_options){
+ if (list->use_global_options && desc.options) {
+ struct m_sub_options conf = {
+ .prefix = desc.options_prefix,
.opts = desc.options,
.defaults = desc.priv_defaults,
.size = desc.priv_size,
};
- add_sub_options(config, &parent, conf);
+ add_sub_options(config, NULL, get_cached_group(list, n, &conf));
}
}
}
@@ -517,6 +547,8 @@ static void m_config_add_option(struct m_config *config,
.name = arg->name,
.shadow_offset = -1,
.group = parent ? parent->group : 0,
+ .default_data = &default_value,
+ .is_hidden = !!arg->deprecation_message,
};
if (arg->offset >= 0) {
@@ -524,22 +556,11 @@ static void m_config_add_option(struct m_config *config,
co.data = (char *)optstruct + arg->offset;
if (optstruct_def)
co.default_data = (char *)optstruct_def + arg->offset;
- int size = arg->type->size;
- if (optstruct && size) {
- // The required alignment is unknown, so go with the minimum C
- // could require. Slightly wasteful, but not that much.
- int align = (size - config->shadow_size % size) % size;
- co.shadow_offset = config->shadow_size + align;
- config->shadow_size = co.shadow_offset + size;
- }
}
if (arg->defval)
co.default_data = arg->defval;
- if (!co.default_data)
- co.default_data = &default_value;
-
// Fill in the full name
if (!co.name[0]) {
co.name = parent_name;
@@ -547,25 +568,28 @@ static void m_config_add_option(struct m_config *config,
co.name = talloc_asprintf(config, "%s-%s", parent_name, co.name);
}
- if (co.opt->deprecation_message)
- co.is_hidden = true;
-
- // Option with children -> add them
- if (arg->type->flags & M_OPT_TYPE_HAS_CHILD) {
+ if (arg->type == &m_option_type_subconfig) {
const struct m_sub_options *subopts = arg->priv;
add_sub_options(config, &co, subopts);
} else {
+ int size = arg->type->size;
+ if (optstruct && size) {
+ // The required alignment is unknown, so go with the maximum C
+ // could require. Slightly wasteful, but not that much.
+ int align = (size - config->shadow_size % size) % size;
+ co.shadow_offset = config->shadow_size + align;
+ config->shadow_size = co.shadow_offset + size;
+ }
+
// Initialize options
if (co.data && co.default_data)
init_opt_inplace(arg, co.data, co.default_data);
- }
- // (The deprecation_message check is a hack to exclude --vo-defaults etc.)
- if (arg->type == &m_option_type_obj_settings_list && !arg->deprecation_message)
- add_global_subopts(config, (const struct m_obj_list *)arg->priv);
-
- if (arg->name[0]) // no own name -> hidden
MP_TARRAY_APPEND(config, config->opts, config->num_opts, co);
+
+ if (arg->type == &m_option_type_obj_settings_list)
+ init_obj_settings_list(config, (const struct m_obj_list *)arg->priv);
+ }
}
struct m_config_option *m_config_get_co_raw(const struct m_config *config,
@@ -745,9 +769,6 @@ int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
}
}
-static int parse_subopts(struct m_config *config, char *name, char *prefix,
- struct bstr param, int flags);
-
// Used to turn "--no-foo" into "--foo=no".
static struct m_config_option *m_config_find_negation_opt(struct m_config *config,
struct bstr *name)
@@ -811,22 +832,9 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
if (bstr_equals0(name, "list-options"))
return list_options(config, bstr0("*"), false);
- // Option with children are a bit different to parse
- if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) {
- char prefix[110];
- if (!config->subopt_deprecation_warning) {
- MP_WARN(config, "Suboptions (--%.*s=...) are deprecated. Use "
- "flat options instead.\n", BSTR_P(name));
- config->subopt_deprecation_warning = true;
- }
- assert(strlen(co->name) < 100);
- sprintf(prefix, "%s-", co->name);
- return parse_subopts(config, (char *)co->name, prefix, param, flags);
- }
-
union m_option_value val = {0};
- // Some option tpyes are "impure" and work on the existing data.
+ // Some option types are "impure" and work on the existing data.
// (Prime examples: --vf-add, --sub-file)
if (co->data)
m_option_copy(co->opt, &val, co->data);
@@ -841,48 +849,6 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
return r;
}
-static int parse_subopts(struct m_config *config, char *name, char *prefix,
- struct bstr param, int flags)
-{
- char **lst = NULL;
- // Split the argument into child options
- int r = m_option_type_subconfig.parse(config->log, NULL, bstr0(""), param, &lst);
- if (r < 0)
- return r;
- // Parse the child options
- for (int i = 0; lst && lst[2 * i]; i++) {
- // Build the full name
- char n[110];
- if (snprintf(n, 110, "%s%s", prefix, lst[2 * i]) > 100)
- abort();
- r = m_config_parse_option(config,bstr0(n), bstr0(lst[2 * i + 1]), flags);
- if (r < 0) {
- if (r != M_OPT_EXIT) {
- MP_ERR(config, "Error parsing suboption %s/%s (%s)\n",
- name, lst[2 * i], m_option_strerror(r));
- r = M_OPT_INVALID;
- }
- break;
- }
- }
- talloc_free(lst);
- return r;
-}
-
-int m_config_parse_suboptions(struct m_config *config, char *name,
- char *subopts)
-{
- if (!subopts || !*subopts)
- return 0;
- int r = parse_subopts(config, name, "", bstr0(subopts), 0);
- if (r < 0 && r != M_OPT_EXIT) {
- MP_ERR(config, "Error parsing suboption %s (%s)\n",
- name, m_option_strerror(r));
- r = M_OPT_INVALID;
- }
- return r;
-}
-
int m_config_set_option_ext(struct m_config *config, struct bstr name,
struct bstr param, int flags)
{
@@ -984,14 +950,10 @@ void m_config_print_option_list(const struct m_config *config, const char *name)
for (int i = 0; i < config->num_opts; i++) {
struct m_config_option *co = &sorted[i];
const struct m_option *opt = co->opt;
- if (opt->type->flags & M_OPT_TYPE_HAS_CHILD)
- continue;
if (co->is_hidden)
continue;
-#if HAVE_FNMATCH
- if (fnmatch(name, co->name, 0))
+ if (strcmp(name, "*") != 0 && !strstr(co->name, name))
continue;
-#endif
MP_INFO(config, " %s%-30s", prefix, co->name);
if (opt->type == &m_option_type_choice) {
MP_INFO(config, " Choices:");
@@ -1038,9 +1000,6 @@ char **m_config_list_options(void *ta_parent, const struct m_config *config)
int count = 0;
for (int i = 0; i < config->num_opts; i++) {
struct m_config_option *co = &config->opts[i];
- const struct m_option *opt = co->opt;
- if (opt->type->flags & M_OPT_TYPE_HAS_CHILD)
- continue;
if (co->is_hidden)
continue;
// For use with CONF_TYPE_STRING_LIST, it's important not to set list
diff --git a/options/m_config.h b/options/m_config.h
index 94a6c9e..1e199ca 100644
--- a/options/m_config.h
+++ b/options/m_config.h
@@ -92,8 +92,6 @@ typedef struct m_config {
// For the command line parser
int recursion_depth;
- bool subopt_deprecation_warning;
-
void *optstruct; // struct mpopts or other
int shadow_size;
@@ -136,6 +134,9 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent,
struct mp_log *log, struct mpv_global *global, struct m_obj_desc *desc,
const char *name, struct m_obj_settings *defaults, char **args);
+void *m_config_group_from_desc(void *ta_parent, struct mp_log *log,
+ struct mpv_global *global, struct m_obj_desc *desc, const char *name);
+
// Make sure the option is backed up. If it's already backed up, do nothing.
// All backed up options can be restored with m_config_restore_backups().
void m_config_backup_opt(struct m_config *config, const char *opt);
@@ -197,10 +198,6 @@ struct mpv_node;
int m_config_set_option_node(struct m_config *config, bstr name,
struct mpv_node *data, int flags);
-
-int m_config_parse_suboptions(struct m_config *config, char *name,
- char *subopts);
-
struct m_config_option *m_config_get_co_raw(const struct m_config *config,
struct bstr name);
struct m_config_option *m_config_get_co(const struct m_config *config,
diff --git a/options/m_option.c b/options/m_option.c
index 4ef5481..11bb677 100644
--- a/options/m_option.c
+++ b/options/m_option.c
@@ -1662,10 +1662,7 @@ const m_option_type_t m_option_type_print_fn = {
.parse = parse_print,
};
-
-/////////////////////// Subconfig
#undef VAL
-#define VAL(x) (*(char ***)(x))
// Read s sub-option name, or a positional sub-opt value.
// termset is a string containing the set of chars that terminate an option.
@@ -1750,50 +1747,6 @@ static int split_subconf(struct mp_log *log, bstr optname, bstr *str,
return 0;
}
-static int parse_subconf(struct mp_log *log, const m_option_t *opt,
- struct bstr name, struct bstr param, void *dst)
-{
- int nr = 0;
- char **lst = NULL;
-
- if (param.len == 0)
- return M_OPT_MISSING_PARAM;
-
- struct bstr p = param;
-
- while (p.len) {
- bstr subopt, subparam;
- int r = split_subconf(log, name, &p, &subopt, &subparam);
- if (r < 0)
- return r;
- if (bstr_startswith0(p, ":"))
- p = bstr_cut(p, 1);
- else if (p.len > 0) {
- mp_err(log, "Incorrect termination for '%.*s'\n", BSTR_P(subopt));
- return M_OPT_INVALID;
- }
-
- if (dst) {
- lst = talloc_realloc(NULL, lst, char *, 2 * (nr + 2));
- lst[2 * nr] = bstrto0(lst, subopt);
- lst[2 * nr + 1] = bstrto0(lst, subparam);
- memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *));
- nr++;
- }
- }
-
- if (dst)
- VAL(dst) = lst;
-
- return 1;
-}
-
-const m_option_type_t m_option_type_subconfig = {
- .name = "Subconfig",
- .flags = M_OPT_TYPE_HAS_CHILD,
- .parse = parse_subconf,
-};
-
#undef VAL
// Split the string on the given split character.
@@ -2719,7 +2672,8 @@ static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name,
static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name,
struct bstr name, struct bstr *pstr,
struct m_config *config, int flags, bool nopos,
- struct m_obj_desc *desc, char ***ret)
+ struct m_obj_desc *desc,
+ const struct m_obj_list *list, char ***ret)
{
int nold = 0;
char **args = NULL;
@@ -2737,6 +2691,16 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name,
r = split_subconf(log, opt_name, pstr, &fname, &fval);
if (r < 0)
goto exit;
+
+ if (list->use_global_options) {
+ mp_err(log, "Option %.*s: this option does not accept sub-options.\n",
+ BSTR_P(opt_name));
+ mp_err(log, "Sub-options for --vo and --ao were removed from mpv in "
+ "release 0.23.0.\nSee https://0x0.st/uM for details.\n");
+ r = M_OPT_INVALID;
+ goto exit;
+ }
+
if (bstr_equals0(fname, "help"))
goto print_help;
r = get_obj_param(log, opt_name, name, config, fname, fval, flags,
@@ -2831,7 +2795,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt,
struct m_config *config = m_config_from_obj_desc_noalloc(NULL, log, &desc);
bstr s = bstr0(desc.init_options);
m_obj_parse_sub_config(log, opt, str, &s, config,
- M_SETOPT_CHECK_ONLY, nopos, NULL, &plist);
+ M_SETOPT_CHECK_ONLY, nopos, NULL, list, &plist);
assert(s.len == 0);
talloc_free(config);
}
@@ -2841,7 +2805,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt,
if (!skip)
config = m_config_from_obj_desc_noalloc(NULL, log, &desc);
r = m_obj_parse_sub_config(log, opt, str, pstr, config,
- M_SETOPT_CHECK_ONLY, nopos, &desc,
+ M_SETOPT_CHECK_ONLY, nopos, &desc, list,
_ret ? &plist : NULL);
talloc_free(config);
if (r < 0)
@@ -3359,13 +3323,6 @@ const m_option_type_t m_option_type_alias = {
const m_option_type_t m_option_type_removed = {
.name = "removed",
};
-
-static int parse_dummy(struct mp_log *log, const m_option_t *opt,
- struct bstr name, struct bstr param, void *dst)
-{
- return 1;
-}
-const m_option_type_t m_option_type_subopt_legacy = {
- .name = "legacy suboption",
- .parse = parse_dummy,
+const m_option_type_t m_option_type_subconfig = {
+ .name = "Subconfig",
};
diff --git a/options/m_option.h b/options/m_option.h
index d784d8f..8709d20 100644
--- a/options/m_option.h
+++ b/options/m_option.h
@@ -53,7 +53,6 @@ extern const m_option_type_t m_option_type_choice;
extern const m_option_type_t m_option_type_flags;
extern const m_option_type_t m_option_type_msglevels;
extern const m_option_type_t m_option_type_print_fn;
-extern const m_option_type_t m_option_type_subconfig;
extern const m_option_type_t m_option_type_imgfmt;
extern const m_option_type_t m_option_type_fourcc;
extern const m_option_type_t m_option_type_afmt;
@@ -63,11 +62,11 @@ extern const m_option_type_t m_option_type_size_box;
extern const m_option_type_t m_option_type_channels;
extern const m_option_type_t m_option_type_aspect;
extern const m_option_type_t m_option_type_node;
-extern const m_option_type_t m_option_type_subopt_legacy;
// Used internally by m_config.c
extern const m_option_type_t m_option_type_alias;
extern const m_option_type_t m_option_type_removed;
+extern const m_option_type_t m_option_type_subconfig;
// Callback used by m_option_type_print_fn options.
typedef void (*m_opt_print_fn)(struct mp_log *log);
@@ -117,6 +116,8 @@ struct m_obj_desc {
const void *priv_defaults;
// Options which refer to members in the private struct
const struct m_option *options;
+ // Prefix for each of the above options (none if NULL).
+ const char *options_prefix;
// For free use by the implementer of m_obj_list.get_desc
const void *p;
// If not NULL, options which should be set before applying other options.
@@ -132,10 +133,6 @@ struct m_obj_desc {
const char *replaced_name;
// For convenience: these are added as global command-line options.
const struct m_sub_options *global_opts;
- // Evil hack to essentially force-move .options to global_opts. All options
- // will be added as global options with the given prefix, and using
- // sub-options will be treated as deprecated and redirected.
- const char *legacy_prefix;
};
// Extra definition needed for \ref m_option_type_obj_settings_list options.
@@ -151,6 +148,8 @@ struct m_obj_list {
bool allow_unknown_entries;
// This helps with confusing error messages if unknown flag options are used.
bool disallow_positional_parameters;
+ // Each sub-item is backed by global options (for AOs and VOs).
+ bool use_global_options;
};
// Find entry by name
@@ -188,6 +187,7 @@ typedef int (*m_opt_string_validate_fn)(struct mp_log *log, const m_option_t *op
// m_option.priv points to this if OPT_SUBSTRUCT is used
struct m_sub_options {
+ const char *prefix;
const struct m_option *opts;
size_t size;
const void *defaults;
@@ -406,16 +406,6 @@ struct m_option {
// These flags are used to describe special parser capabilities or behavior.
-// Suboption parser flag.
-/** When this flag is set, m_option::p should point to another m_option
- * array. Only the parse function will be called. If dst is set, it should
- * create/update an array of char* containg opt/val pairs. The options in
- * the child array will then be set automatically by the \ref Config.
- * Also note that suboptions may be directly accessed by using
- * -option:subopt blah.
- */
-#define M_OPT_TYPE_HAS_CHILD (1 << 0)
-
// Wildcard matching flag.
/** If set the option type has a use for option names ending with a *
* (used for -aa*), this only affects the option name matching.
@@ -714,12 +704,6 @@ extern const char m_option_path_separator;
.type = &m_option_type_subconfig, \
.priv = (void*)&subconf)
-// Same as above, but for legacy suboption usage, which have no associated
-// field (no actual data anywhere).
-#define OPT_SUBSTRUCT_LEGACY(optname, subconf) \
- {.name = optname, .offset = -1, .type = &m_option_type_subconfig, \
- .priv = (void*)&subconf}
-
// Provide a another name for the option.
#define OPT_ALIAS(optname, newname) \
{.name = optname, .type = &m_option_type_alias, .priv = newname, \
@@ -736,10 +720,4 @@ extern const char m_option_path_separator;
{.name = optname, .type = &m_option_type_removed, .priv = msg, \
.deprecation_message = "", .offset = -1}
-// Redirect a suboption (e.g. from --vo) to a global option. The redirection
-// is handled as a special case instead of being applied automatically.
-#define OPT_SUBOPT_LEGACY(optname, globalname) \
- {.name = optname, .type = &m_option_type_subopt_legacy, .priv = globalname, \
- .offset = -1}
-
#endif /* MPLAYER_M_OPTION_H */
diff --git a/options/options.c b/options/options.c
index 442c292..f79df7d 100644
--- a/options/options.c
+++ b/options/options.c
@@ -150,8 +150,6 @@ const struct m_sub_options stream_cache_conf = {
static const m_option_t mp_vo_opt_list[] = {
OPT_SETTINGSLIST("vo", video_driver_list, 0, &vo_obj_list, ),
- OPT_SETTINGSLIST("vo-defaults", vo_defs, 0, &vo_obj_list,
- .deprecation_message = "deprecated, use global options"),
OPT_CHOICE_C("hwdec-preload", hwdec_preload_api, 0, mp_hwdec_names),
OPT_SUBSTRUCT("sws", sws_opts, sws_conf, 0),
OPT_FLAG("taskbar-progress", taskbar_progress, 0),
@@ -184,7 +182,6 @@ static const m_option_t mp_vo_opt_list[] = {
({"default", -1})),
OPT_CHOICE_OR_INT("fs-screen", fsscreen_id, 0, 0, 32,
({"all", -2}, {"current", -1})),
- OPT_FLAG("fs-black-out-screens", fs_black_out_screens, 0),
OPT_FLAG("keepaspect", keepaspect, UPDATE_VIDEOPOS),
OPT_FLAG("keepaspect-window", keepaspect_window, 0),
OPT_FLAG("hidpi-window-scale", hidpi_window_scale, 0),
@@ -225,7 +222,6 @@ const struct m_sub_options vo_sub_opts = {
.window_scale = 1.0,
.x11_bypass_compositor = 2,
.mmcss_profile = "Playback",
- .fullscreen = HAVE_RPI ? 1 : 0,
},
};
@@ -430,7 +426,8 @@ const m_option_t mp_opts[] = {
OPT_STRING("audio-spdif", audio_spdif, 0),
- OPT_FLAG("ad-spdif-dtshd", dtshd, 0),
+ OPT_FLAG("ad-spdif-dtshd", dtshd, 0,
+ .deprecation_message = "use --audio-spdif instead"),
OPT_CHOICE_C("hwdec", hwdec_api, 0, mp_hwdec_names),
OPT_STRING("hwdec-codecs", hwdec_codecs, 0),
@@ -510,8 +507,6 @@ const m_option_t mp_opts[] = {
//---------------------- libao/libvo options ------------------------
OPT_SETTINGSLIST("ao", audio_driver_list, 0, &ao_obj_list, ),
- OPT_SETTINGSLIST("ao-defaults", ao_defs, 0, &ao_obj_list,
- .deprecation_message = "deprecated, use global options"),
OPT_STRING("audio-device", audio_device, UPDATE_AUDIO),
OPT_FLAG("audio-exclusive", audio_exclusive, UPDATE_AUDIO),
OPT_STRING("audio-client-name", audio_client_name, UPDATE_AUDIO),
@@ -801,6 +796,7 @@ const m_option_t mp_opts[] = {
OPT_REPLACED("ass-shaper", "sub-ass-shaper"),
OPT_REPLACED("ass-style-override", "sub-ass-style-override"),
OPT_REPLACED("ass-scale-with-window", "sub-ass-scale-with-window"),
+ OPT_REMOVED("fs-black-out-screens", NULL),
{0}
};
@@ -809,7 +805,7 @@ const struct MPOpts mp_default_opts = {
.use_terminal = 1,
.msg_color = 1,
.audio_driver_list = NULL,
- .audio_decoders = "-spdif:*", // never select spdif by default
+ .audio_decoders = NULL,
.video_decoders = NULL,
.deinterlace = -1,
.softvol = SOFTVOL_AUTO,
diff --git a/options/options.h b/options/options.h
index 4ddf9d1..fc37e98 100644
--- a/options/options.h
+++ b/options/options.h
@@ -7,7 +7,7 @@
#include "common/common.h"
typedef struct mp_vo_opts {
- struct m_obj_settings *video_driver_list, *vo_defs;
+ struct m_obj_settings *video_driver_list;
int taskbar_progress;
int ontop;
@@ -18,7 +18,6 @@ typedef struct mp_vo_opts {
int screen_id;
int fsscreen_id;
- int fs_black_out_screens;
char *winname;
int x11_netwm;
int x11_bypass_compositor;
@@ -90,7 +89,7 @@ typedef struct MPOpts {
int auto_load_scripts;
- struct m_obj_settings *audio_driver_list, *ao_defs;
+ struct m_obj_settings *audio_driver_list;
char *audio_device;
int audio_exclusive;
char *audio_client_name;
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m
index bf415d9..d312692 100644
--- a/osdep/macosx_application.m
+++ b/osdep/macosx_application.m
@@ -50,7 +50,7 @@ static pthread_t playback_thread_id;
child:(NSMenu *)child;
- (void)registerMenuItem:(NSMenuItem*)menuItem forKey:(MPMenuKey)key;
- (NSMenu *)appleMenuWithMainMenu:(NSMenu *)mainMenu;
-- (NSMenu *)movieMenu;
+- (NSMenu *)videoMenu;
- (NSMenu *)windowMenu;
@end
@@ -117,17 +117,15 @@ static void terminate_cocoa_application(void)
[self mainMenuItemWithParent:mainMenu child:menu];
[self menuItemWithParent:menu title:@"Hide mpv"
action:@selector(hide:) keyEquivalent: @"h"];
+ [menu addItem:[NSMenuItem separatorItem]];
[self menuItemWithParent:menu title:@"Quit mpv"
action:@selector(stopPlayback) keyEquivalent: @"q"];
- [self menuItemWithParent:menu title:@"Quit mpv & remember position"
- action:@selector(stopPlaybackAndRememberPosition)
- keyEquivalent: @"Q"];
return [menu autorelease];
}
-- (NSMenu *)movieMenu
+- (NSMenu *)videoMenu
{
- NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Movie"];
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Video"];
_R(menu, @"Half Size", @"0", MPM_H_SIZE)
_R(menu, @"Normal Size", @"1", MPM_N_SIZE)
_R(menu, @"Double Size", @"2", MPM_D_SIZE)
@@ -148,7 +146,7 @@ static void terminate_cocoa_application(void)
[NSApp setMainMenu:main_menu];
[NSApp setAppleMenu:[self appleMenuWithMainMenu:main_menu]];
- [NSApp mainMenuItemWithParent:main_menu child:[self movieMenu]];
+ [NSApp mainMenuItemWithParent:main_menu child:[self videoMenu]];
[NSApp mainMenuItemWithParent:main_menu child:[self windowMenu]];
}
@@ -208,7 +206,8 @@ static void terminate_cocoa_application(void)
return [item autorelease];
}
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theApp {
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theApp
+{
return NSTerminateNow;
}
diff --git a/osdep/macosx_compat.h b/osdep/macosx_compat.h
index 76308c6..9ef422b 100644
--- a/osdep/macosx_compat.h
+++ b/osdep/macosx_compat.h
@@ -31,6 +31,7 @@ static const NSWindowStyleMask NSWindowStyleMaskTitled = NSTitledWindowMask;
static const NSWindowStyleMask NSWindowStyleMaskMiniaturizable = NSMiniaturizableWindowMask;
static const NSWindowStyleMask NSWindowStyleMaskResizable = NSResizableWindowMask;
static const NSWindowStyleMask NSWindowStyleMaskBorderless = NSBorderlessWindowMask;
+static const NSWindowStyleMask NSWindowStyleMaskFullScreen = NSFullScreenWindowMask;
static const NSEventType NSEventTypeSystemDefined = NSSystemDefined;
static const NSEventType NSEventTypeKeyDown = NSKeyDown;
diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m
index 6ad2258..494c9aa 100644
--- a/osdep/macosx_events.m
+++ b/osdep/macosx_events.m
@@ -142,7 +142,8 @@ static int mk_flags(NSEvent *event)
return ([event data1] & 0x0000FFFF);
}
-static int mk_down(NSEvent *event) {
+static int mk_down(NSEvent *event)
+{
return (((mk_flags(event) & 0xFF00) >> 8)) == 0xA;
}
@@ -178,11 +179,13 @@ static CGEventRef tap_event_callback(CGEventTapProxy proxy, CGEventType type,
}
}
-void cocoa_init_media_keys(void) {
+void cocoa_init_media_keys(void)
+{
[[EventsResponder sharedInstance] startMediaKeys];
}
-void cocoa_uninit_media_keys(void) {
+void cocoa_uninit_media_keys(void)
+{
[[EventsResponder sharedInstance] stopMediaKeys];
}
@@ -446,10 +449,11 @@ void cocoa_set_input_context(struct input_ctx *input_context)
NSString *chars;
- if ([self useAltGr] && RightAltPressed([event modifierFlags]))
+ if ([self useAltGr] && RightAltPressed([event modifierFlags])) {
chars = [event characters];
- else
+ } else {
chars = [event charactersIgnoringModifiers];
+ }
struct bstr t = bstr0([chars UTF8String]);
int key = convert_key([event keyCode], bstr_decode_utf8(t, &t));
@@ -462,6 +466,9 @@ void cocoa_set_input_context(struct input_ctx *input_context)
- (void)handleFilesArray:(NSArray *)files
{
+ enum mp_dnd_action action = [NSEvent modifierFlags] &
+ NSEventModifierFlagShift ? DND_APPEND : DND_REPLACE;
+
size_t num_files = [files count];
char **files_utf8 = talloc_array(NULL, char*, num_files);
[files enumerateObjectsUsingBlock:^(NSString *p, NSUInteger i, BOOL *_){
@@ -473,7 +480,7 @@ void cocoa_set_input_context(struct input_ctx *input_context)
}];
[_input_lock lock];
if (_inputContext)
- mp_event_drop_files(_inputContext, num_files, files_utf8, DND_REPLACE);
+ mp_event_drop_files(_inputContext, num_files, files_utf8, action);
[_input_lock unlock];
talloc_free(files_utf8);
}
diff --git a/player/client.c b/player/client.c
index 774a4e0..85e3c40 100644
--- a/player/client.c
+++ b/player/client.c
@@ -329,59 +329,11 @@ void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d)
void mpv_suspend(mpv_handle *ctx)
{
- bool do_suspend = false;
-
- MP_WARN(ctx, "warning: mpv_suspend() is deprecated.\n");
-
- pthread_mutex_lock(&ctx->lock);
- if (ctx->suspend_count == INT_MAX) {
- MP_ERR(ctx, "suspend counter overflow");
- } else {
- do_suspend = ctx->suspend_count == 0;
- ctx->suspend_count++;
- }
- pthread_mutex_unlock(&ctx->lock);
-
- if (do_suspend) {
- mp_dispatch_lock(ctx->mpctx->dispatch);
- ctx->mpctx->suspend_count++;
- mp_dispatch_unlock(ctx->mpctx->dispatch);
- }
+ MP_ERR(ctx, "mpv_suspend() is deprecated and does nothing.\n");
}
void mpv_resume(mpv_handle *ctx)
{
- bool do_resume = false;
-
- pthread_mutex_lock(&ctx->lock);
- if (ctx->suspend_count == 0) {
- MP_ERR(ctx, "suspend counter underflow");
- } else {
- do_resume = ctx->suspend_count == 1;
- ctx->suspend_count--;
- }
- pthread_mutex_unlock(&ctx->lock);
-
- if (do_resume) {
- mp_dispatch_lock(ctx->mpctx->dispatch);
- ctx->mpctx->suspend_count--;
- mp_dispatch_unlock(ctx->mpctx->dispatch);
- mp_dispatch_interrupt(ctx->mpctx->dispatch);
- }
-}
-
-void mp_resume_all(mpv_handle *ctx)
-{
- pthread_mutex_lock(&ctx->lock);
- bool do_resume = ctx->suspend_count > 0;
- ctx->suspend_count = 0;
- pthread_mutex_unlock(&ctx->lock);
-
- if (do_resume) {
- mp_dispatch_lock(ctx->mpctx->dispatch);
- ctx->mpctx->suspend_count--;
- mp_dispatch_unlock(ctx->mpctx->dispatch);
- }
}
static void lock_core(mpv_handle *ctx)
@@ -396,8 +348,6 @@ static void unlock_core(mpv_handle *ctx)
void mpv_wait_async_requests(mpv_handle *ctx)
{
- mp_resume_all(ctx);
-
pthread_mutex_lock(&ctx->lock);
while (ctx->reserved_events || ctx->properties_updating)
wait_wakeup(ctx, INT64_MAX);
diff --git a/player/client.h b/player/client.h
index e39d0e6..67b287b 100644
--- a/player/client.h
+++ b/player/client.h
@@ -35,8 +35,6 @@ struct mp_log *mp_client_get_log(struct mpv_handle *ctx);
struct MPContext *mp_client_get_core(struct mpv_handle *ctx);
struct MPContext *mp_client_api_get_core(struct mp_client_api *api);
-void mp_resume_all(struct mpv_handle *ctx);
-
// m_option.c
void *node_get_alloc(struct mpv_node *node);
diff --git a/player/command.c b/player/command.c
index 7c1a6f3..74c7e26 100644
--- a/player/command.c
+++ b/player/command.c
@@ -277,26 +277,6 @@ int mp_on_set_option(void *ctx, struct m_config_option *co, void *data, int flag
{
struct MPContext *mpctx = ctx;
- // These options are too inconsistent as they could be pulled through the
- // property layer. Ideally we'd remove these inconsistencies in the future,
- // though the actual problem is compatibility to user-expected behavior.
- // What matters is whether _write_ access is different - property read
- // access is not used here.
- // We're also fine with cases where the property restricts the writable
- // value range if playback is active, but not otherwise.
- // OK, restrict during playback: vid, aid, sid, deinterlace, video-aspect,
- // vf*, af*, chapter
- // OK, is handled separately: playlist
- // OK, does not conflict on low level: audio-file, sub-file, external-file
- // OK, different value ranges, but happens to work for now: volume, edition
- // Incompatible: tv-freq
- // All the other properties are deprecated in their current form.
- static const char *const no_property[] = {
- "demuxer", "idle", "length", "audio-samplerate", "audio-channels",
- "audio-format", "fps", "cache", "playlist-pos", "chapter", "tv-freq",
- NULL
- };
-
// Normalize "vf*" to "vf"
const char *name = co->name;
bstr bname = bstr0(name);
@@ -306,11 +286,6 @@ int mp_on_set_option(void *ctx, struct m_config_option *co, void *data, int flag
name = tmp;
}
- for (int n = 0; no_property[n]; n++) {
- if (strcmp(co->name, no_property[n]) == 0)
- goto direct_option;
- }
-
struct m_option type = {0};
int r = mp_property_do_silent(name, M_PROPERTY_GET_TYPE, &type, mpctx);
@@ -3594,11 +3569,7 @@ static int mp_property_configuration(void *ctx, struct m_property *prop,
static int mp_property_ffmpeg(void *ctx, struct m_property *prop,
int action, void *arg)
{
-#if HAVE_AV_VERSION_INFO
return m_property_strdup_ro(action, arg, av_version_info());
-#else
- return M_PROPERTY_UNAVAILABLE;
-#endif
}
static int mp_property_alias(void *ctx, struct m_property *prop,
@@ -3614,20 +3585,16 @@ static int mp_property_deprecated_alias(void *ctx, struct m_property *prop,
MPContext *mpctx = ctx;
struct command_ctx *cmd = mpctx->command_ctx;
const char *real_property = prop->priv;
- if (action == M_PROPERTY_SET || action == M_PROPERTY_GET ||
- action == M_PROPERTY_PRINT)
- {
- for (int n = 0; n < cmd->num_warned_deprecated; n++) {
- if (strcmp(cmd->warned_deprecated[n], prop->name) == 0)
- goto done;
- }
- MP_WARN(mpctx, "Warning: property '%s' was replaced with '%s' and "
- "might be removed in the future.\n", prop->name, real_property);
- MP_TARRAY_APPEND(cmd, cmd->warned_deprecated, cmd->num_warned_deprecated,
- (char *)prop->name);
-
- done:;
+ for (int n = 0; n < cmd->num_warned_deprecated; n++) {
+ if (strcmp(cmd->warned_deprecated[n], prop->name) == 0)
+ goto done;
}
+ MP_WARN(mpctx, "Warning: property '%s' was replaced with '%s' and "
+ "might be removed in the future.\n", prop->name, real_property);
+ MP_TARRAY_APPEND(cmd, cmd->warned_deprecated, cmd->num_warned_deprecated,
+ (char *)prop->name);
+
+done:
return mp_property_do(real_property, action, arg, ctx);
}
@@ -3824,13 +3791,10 @@ static const struct m_property mp_properties_base[] = {
{"stream-path", mp_property_stream_path},
{"stream-capture", mp_property_stream_capture},
{"current-demuxer", mp_property_demuxer},
- // conflicts with option
- M_PROPERTY_DEPRECATED_ALIAS("demuxer", "current-demuxer"),
{"file-format", mp_property_file_format},
{"stream-pos", mp_property_stream_pos},
{"stream-end", mp_property_stream_end},
{"duration", mp_property_duration},
- M_PROPERTY_DEPRECATED_ALIAS("length", "duration"), // conflicts with option
{"avsync", mp_property_avsync},
{"total-avsync-change", mp_property_total_avsync_change},
{"drop-frame-count", mp_property_drop_frame_cnt},
@@ -3863,7 +3827,6 @@ static const struct m_property mp_properties_base[] = {
{"seeking", mp_property_seeking},
{"playback-abort", mp_property_playback_abort},
{"cache-percent", mp_property_cache},
- M_PROPERTY_DEPRECATED_ALIAS("cache", "cache-percent"), // conflicts with option
{"cache-free", mp_property_cache_free},
{"cache-used", mp_property_cache_used},
{"cache-size", mp_property_cache_size},
@@ -3878,7 +3841,6 @@ static const struct m_property mp_properties_base[] = {
{"seekable", mp_property_seekable},
{"partially-seekable", mp_property_partially_seekable},
{"idle-active", mp_property_idle},
- M_PROPERTY_DEPRECATED_ALIAS("idle", "idle-active"), // conflicts with option
{"chapter-list", mp_property_list_chapters},
{"track-list", property_list_tracks},
@@ -3901,9 +3863,6 @@ static const struct m_property mp_properties_base[] = {
{"audio-codec", mp_property_audio_codec},
{"audio-params", mp_property_audio_params},
{"audio-out-params", mp_property_audio_out_params},
- // conflicts with option
- M_PROPERTY_DEPRECATED_ALIAS("audio-samplerate", "audio-params/samplerate"),
- M_PROPERTY_DEPRECATED_ALIAS("audio-channels", "audio-params/channel-count"),
{"aid", mp_property_audio},
{"balance", mp_property_balance},
{"audio-device", mp_property_audio_device},
@@ -3940,7 +3899,6 @@ static const struct m_property mp_properties_base[] = {
{"vo-performance", mp_property_vo_performance},
{"current-vo", mp_property_vo},
{"container-fps", mp_property_fps},
- M_PROPERTY_DEPRECATED_ALIAS("fps", "container-fps"), // conflicts with option
{"estimated-vf-fps", mp_property_vf_fps},
{"video-aspect", mp_property_aspect},
{"vid", mp_property_video},
@@ -4036,9 +3994,6 @@ static const struct m_property mp_properties_base[] = {
M_PROPERTY_ALIAS("colormatrix-input-range", "video-params/colorlevels"),
M_PROPERTY_ALIAS("colormatrix-primaries", "video-params/primaries"),
M_PROPERTY_ALIAS("colormatrix-gamma", "video-params/gamma"),
-
- // conflicts with option
- M_PROPERTY_DEPRECATED_ALIAS("audio-format", "audio-codec-name"),
};
// Each entry describes which properties an event (possibly) changes.
@@ -5593,8 +5548,7 @@ void command_init(struct MPContext *mpctx)
for (int n = 0; n < num_opts; n++) {
struct m_config_option *co = m_config_get_co_index(mpctx->mconfig, n);
assert(co->name[0]);
- if ((co->opt->flags & M_OPT_NOPROP) ||
- (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD))
+ if (co->opt->flags & M_OPT_NOPROP)
continue;
struct m_property prop = {0};
diff --git a/player/core.h b/player/core.h
index b33d367..5d05548 100644
--- a/player/core.h
+++ b/player/core.h
@@ -226,7 +226,6 @@ enum playback_status {
typedef struct MPContext {
bool initialized;
bool autodetach;
- int suspend_count;
struct mpv_global *global;
struct MPOpts *opts;
struct mp_log *log;
@@ -354,6 +353,9 @@ typedef struct MPContext {
// As video_pts, but is not reset when seeking away. (For the very short
// period of time until a new frame is decoded and shown.)
double last_vo_pts;
+ // Frame duration field from demuxer. Only used for duration of the last
+ // video frame.
+ double last_frame_duration;
// Video PTS, or audio PTS if video has ended.
double playback_pts;
// audio stats only
diff --git a/player/loadfile.c b/player/loadfile.c
index 6ea4479..b94ce8a 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -1231,7 +1231,7 @@ terminate_playback:
MP_VERBOSE(mpctx, "finished playback, %s (reason %d)\n",
mpv_error_string(end_event.error), end_event.reason);
- if (mpctx->error_playing == MPV_ERROR_UNKNOWN_FORMAT)
+ if (end_event.error == MPV_ERROR_UNKNOWN_FORMAT)
MP_ERR(mpctx, "Failed to recognize file format.\n");
MP_INFO(mpctx, "\n");
diff --git a/player/lua.c b/player/lua.c
index 442a2ba..e76dc46 100644
--- a/player/lua.c
+++ b/player/lua.c
@@ -393,7 +393,6 @@ static int load_lua(struct mpv_handle *client, const char *fname)
r = 0;
error_out:
- mp_resume_all(client);
if (ctx->state)
lua_close(ctx->state);
talloc_free(ctx);
@@ -451,22 +450,17 @@ static int script_find_config_file(lua_State *L)
static int script_suspend(lua_State *L)
{
struct script_ctx *ctx = get_ctx(L);
- MP_WARN(ctx, "mp.suspend() (possibly triggered by mp.use_suspend) is "
- "deprecated.\n");
- mpv_suspend(ctx->client);
+ MP_ERR(ctx, "mp.suspend() is deprecated and does nothing.\n");
return 0;
}
static int script_resume(lua_State *L)
{
- struct script_ctx *ctx = get_ctx(L);
- mpv_resume(ctx->client);
return 0;
}
static int script_resume_all(lua_State *L)
{
- mp_resume_all(get_ctx(L)->client);
return 0;
}
@@ -1134,8 +1128,6 @@ static int script_subprocess(lua_State *L)
luaL_checktype(L, 1, LUA_TTABLE);
void *tmp = mp_lua_PITA(L);
- mp_resume_all(ctx->client);
-
lua_getfield(L, 1, "args"); // args
int num_args = mp_lua_len(L, -1);
char *args[256];
@@ -1193,8 +1185,6 @@ static int script_subprocess_detached(lua_State *L)
luaL_checktype(L, 1, LUA_TTABLE);
void *tmp = mp_lua_PITA(L);
- mp_resume_all(ctx->client);
-
lua_getfield(L, 1, "args"); // args
int num_args = mp_lua_len(L, -1);
char *args[256];
diff --git a/player/lua/defaults.lua b/player/lua/defaults.lua
index c65fda7..08616c5 100644
--- a/player/lua/defaults.lua
+++ b/player/lua/defaults.lua
@@ -452,10 +452,15 @@ end
mp.use_suspend = false
+local suspend_warned = false
+
function mp.dispatch_events(allow_wait)
local more_events = true
if mp.use_suspend then
- mp.suspend()
+ if not suspend_warned then
+ mp.msg.error("mp.use_suspend is now ignored.")
+ suspend_warned = true
+ end
end
while mp.keep_running do
local wait = 0
@@ -475,11 +480,6 @@ function mp.dispatch_events(allow_wait)
end
end
local e = mp.wait_event(wait)
- -- Empty the event queue while suspended; otherwise, each
- -- event will keep us waiting until the core suspends again.
- if mp.use_suspend then
- mp.suspend()
- end
more_events = false
if e.event ~= "none" then
call_event_handlers(e)
diff --git a/player/lua/osc.lua b/player/lua/osc.lua
index 643f32f..4ad6929 100644
--- a/player/lua/osc.lua
+++ b/player/lua/osc.lua
@@ -1356,17 +1356,17 @@ layouts["topbar"] = function()
w = buttonW, h = 36 - padY*2 }
lo = add_layout("playpause")
lo.geometry = geo
- lo.style = osc_styles.smallButtonsL
+ lo.style = osc_styles.smallButtonsBar
geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h }
lo = add_layout("ch_prev")
lo.geometry = geo
- lo.style = osc_styles.smallButtonsL
+ lo.style = osc_styles.smallButtonsBar
geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h }
lo = add_layout("ch_next")
lo.geometry = geo
- lo.style = osc_styles.smallButtonsL
+ lo.style = osc_styles.smallButtonsBar
-- Left timecode
@@ -1374,7 +1374,7 @@ layouts["topbar"] = function()
w = tcW, h = geo.h }
lo = add_layout("tc_left")
lo.geometry = geo
- lo.style = osc_styles.timecodes
+ lo.style = osc_styles.timecodesBar
local sb_l = geo.x + padX
@@ -1384,12 +1384,12 @@ layouts["topbar"] = function()
w = tsW, h = geo.h }
lo = add_layout("cy_sub")
lo.geometry = geo
- lo.style = osc_styles.smallButtonsL
+ lo.style = osc_styles.smallButtonsBar
geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h }
lo = add_layout("cy_audio")
lo.geometry = geo
- lo.style = osc_styles.smallButtonsL
+ lo.style = osc_styles.smallButtonsBar
-- Right timecode
@@ -1397,7 +1397,7 @@ layouts["topbar"] = function()
w = tcW, h = geo.h }
lo = add_layout("tc_right")
lo.geometry = geo
- lo.style = osc_styles.timecodes
+ lo.style = osc_styles.timecodesBar
local sb_r = geo.x - padX
@@ -1409,13 +1409,13 @@ layouts["topbar"] = function()
lo.geometry = geo
lo.layer = 15
- lo.style = osc_styles.timecodes
+ lo.style = osc_styles.timecodesBar
lo.alpha[1] =
math.min(255, user_opts.boxalpha + (255 - user_opts.boxalpha)*0.8)
lo = add_layout("seekbar")
lo.geometry = geo
- lo.style = osc_styles.timecodes
+ lo.style = osc_styles.timecodesBar
lo.slider.border = 0
lo.slider.tooltip_style = osc_styles.timePosBar
lo.slider.stype = user_opts["seekbarstyle"]
@@ -1426,12 +1426,12 @@ layouts["topbar"] = function()
geo = { x = osc_geo.x + padX, y = line2, an = 4, w = 18, h = 18 - padY }
lo = add_layout("pl_prev")
lo.geometry = geo
- lo.style = osc_styles.topButtons
+ lo.style = osc_styles.topButtonsBar
geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h }
lo = add_layout("pl_next")
lo.geometry = geo
- lo.style = osc_styles.topButtons
+ lo.style = osc_styles.topButtonsBar
local t_l = geo.x + geo.w + padX
@@ -1440,7 +1440,7 @@ layouts["topbar"] = function()
an = 6, w = 150, h = geo.h }
lo = add_layout("cache")
lo.geometry = geo
- lo.style = osc_styles.vidtitle
+ lo.style = osc_styles.vidtitleBar
local t_r = geo.x - geo.w - padX*2
@@ -1449,7 +1449,7 @@ layouts["topbar"] = function()
w = t_r - t_l, h = geo.h }
lo = add_layout("title")
lo.geometry = geo
- lo.style = osc_styles.vidtitle
+ lo.style = osc_styles.vidtitleBar
lo.button.maxchars = math.floor(geo.w/7)
end
@@ -1502,8 +1502,9 @@ function osc_init()
elements = {}
-- some often needed stuff
- local pl_count = mp.get_property_number("playlist-count")
+ local pl_count = mp.get_property_number("playlist-count", 0)
local have_pl = (pl_count > 1)
+ local pl_pos = mp.get_property_number("playlist-pos", 0) + 1
local have_ch = (mp.get_property_number("chapters", 0) > 0)
local ne
@@ -1523,8 +1524,8 @@ function osc_init()
ne.eventresponder["mouse_btn0_up"] = function ()
local title = mp.get_property_osd("media-title")
if (have_pl) then
- local pl_pos = countone(mp.get_property_number("playlist-pos"))
- title = "[" .. pl_pos .. "/" .. pl_count .. "] " .. title
+ title = string.format("[%d/%d] %s", countone(pl_pos - 1),
+ pl_count, title)
end
show_message(title)
end
@@ -1538,7 +1539,7 @@ function osc_init()
ne = new_element("pl_prev", "button")
ne.content = "\238\132\144"
- ne.visible = have_pl
+ ne.enabled = (pl_pos > 1)
ne.eventresponder["mouse_btn0_up"] =
function ()
mp.commandv("playlist-prev", "weak")
@@ -1553,7 +1554,7 @@ function osc_init()
ne = new_element("pl_next", "button")
ne.content = "\238\132\129"
- ne.visible = have_pl
+ ne.enabled = (have_pl) and (pl_pos < pl_count)
ne.eventresponder["mouse_btn0_up"] =
function ()
mp.commandv("playlist-next", "weak")
@@ -1755,8 +1756,7 @@ function osc_init()
-- tc_right (total/remaining time)
ne = new_element("tc_right", "button")
- ne.visible = (not (mp.get_property("duration") == nil))
- and (mp.get_property_number("duration") > 0)
+ ne.visible = (mp.get_property_number("duration", 0) > 0)
ne.content = function ()
if (state.rightTC_trem) then
if state.tc_ms then
@@ -1766,7 +1766,7 @@ function osc_init()
end
else
if state.tc_ms then
- return (mp.get_property_osd("length/full"))
+ return (mp.get_property_osd("duration/full"))
else
return (mp.get_property_osd("duration"))
end
@@ -2214,7 +2214,7 @@ mp.observe_property("fullscreen", "bool",
request_init()
end
)
-mp.observe_property("idle", "bool",
+mp.observe_property("idle-active", "bool",
function(name, val)
state.idle = val
tick()
diff --git a/player/main.c b/player/main.c
index 1f32d37..8ebfc35 100644
--- a/player/main.c
+++ b/player/main.c
@@ -96,7 +96,7 @@ const char mp_help_text[] =
" --playlist=<file> specify playlist file\n"
"\n"
" --list-options list all mpv options\n"
-" --h=<pat> print options which match the given shell pattern\n"
+" --h=<string> print options which contain the given string in their name\n"
"\n";
static pthread_mutex_t terminal_owner_lock = PTHREAD_MUTEX_INITIALIZER;
diff --git a/player/playloop.c b/player/playloop.c
index f72994e..9db9396 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -62,9 +62,6 @@ void mp_wait_events(struct MPContext *mpctx)
mp_dispatch_queue_process(mpctx->dispatch, mpctx->sleeptime);
- while (mpctx->suspend_count)
- mp_dispatch_queue_process(mpctx->dispatch, 100);
-
mpctx->in_dispatch = false;
mpctx->sleeptime = INFINITY;
diff --git a/player/video.c b/player/video.c
index 847a5b5..4621d19 100644
--- a/player/video.c
+++ b/player/video.c
@@ -343,6 +343,7 @@ void reset_video_state(struct MPContext *mpctx)
mpctx->delay = 0;
mpctx->time_frame = 0;
mpctx->video_pts = MP_NOPTS_VALUE;
+ mpctx->last_frame_duration = 0;
mpctx->num_past_frames = 0;
mpctx->total_avsync_change = 0;
mpctx->last_av_difference = 0;
@@ -473,7 +474,7 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
mpctx->video_out = init_best_video_out(mpctx->global, &ex);
if (!mpctx->video_out) {
MP_FATAL(mpctx, "Error opening/initializing "
- "the selected video_out (-vo) device.\n");
+ "the selected video_out (--vo) device.\n");
mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED;
goto err_out;
}
@@ -1369,6 +1370,9 @@ void write_video(struct MPContext *mpctx)
{
MP_VERBOSE(mpctx, "assuming this is an image\n");
mpctx->time_frame += opts->image_display_duration;
+ } else if (mpctx->last_frame_duration > 0) {
+ MP_VERBOSE(mpctx, "using demuxer frame duration for last frame\n");
+ mpctx->time_frame += mpctx->last_frame_duration;
} else {
mpctx->time_frame = 0;
}
@@ -1482,6 +1486,8 @@ void write_video(struct MPContext *mpctx)
mpctx->video_pts = mpctx->next_frames[0]->pts;
mpctx->last_vo_pts = mpctx->video_pts;
+ mpctx->last_frame_duration =
+ mpctx->next_frames[0]->pkt_duration / mpctx->video_speed;
shift_frames(mpctx);
diff --git a/stream/stream.c b/stream/stream.c
index c936c5c..4c7aa04 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -230,6 +230,12 @@ 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);
+ if (global->config) {
+ int opt;
+ mp_read_option_raw(global, "access-references", &m_option_type_flag, &opt);
+ s->access_references = opt;
+ }
+
MP_VERBOSE(s, "Opening %s\n", url);
if ((s->mode & STREAM_WRITE) && !sinfo->can_write) {
diff --git a/stream/stream.h b/stream/stream.h
index 4444da8..7d44e30 100644
--- a/stream/stream.h
+++ b/stream/stream.h
@@ -197,6 +197,7 @@ typedef struct stream {
bool fast_skip : 1; // consider stream fast enough to fw-seek by skipping
bool is_network : 1; // original stream_info_t.is_network flag
bool allow_caching : 1; // stream cache makes sense
+ bool access_references : 1; // open other streams
struct mp_log *log;
struct mpv_global *global;
diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c
index 26a78e5..5f08395 100644
--- a/stream/stream_bluray.c
+++ b/stream/stream_bluray.c
@@ -569,6 +569,9 @@ static int bdmv_dir_stream_open(stream_t *stream)
.cfg_title = BLURAY_DEFAULT_TITLE,
};
+ if (!stream->access_references)
+ goto unsupported;
+
char *path = mp_file_get_path(priv, bstr0(stream->url));
if (!path)
goto unsupported;
diff --git a/stream/stream_dvd.c b/stream/stream_dvd.c
index 4b423de..338c236 100644
--- a/stream/stream_dvd.c
+++ b/stream/stream_dvd.c
@@ -951,6 +951,9 @@ static int ifo_stream_open(stream_t *stream)
dvd_priv_t *priv = talloc_zero(stream, dvd_priv_t);
stream->priv = priv;
+ if (!stream->access_references)
+ goto unsupported;
+
char *path = mp_file_get_path(priv, bstr0(stream->url));
if (!path)
goto unsupported;
diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c
index ec15c83..1178f50 100644
--- a/stream/stream_dvdnav.c
+++ b/stream/stream_dvdnav.c
@@ -562,6 +562,9 @@ static int ifo_dvdnav_stream_open(stream_t *stream)
struct priv *priv = talloc_zero(stream, struct priv);
stream->priv = priv;
+ if (!stream->access_references)
+ goto unsupported;
+
priv->track = TITLE_LONGEST;
char *path = mp_file_get_path(priv, bstr0(stream->url));
diff --git a/stream/tv.c b/stream/tv.c
index b2bf150..0b34b56 100644
--- a/stream/tv.c
+++ b/stream/tv.c
@@ -74,7 +74,7 @@ const struct m_sub_options tv_params_conf = {
OPT_INT("audiorate", audiorate, 0),
OPT_STRING("driver", driver, 0),
OPT_STRING("device", device, 0),
- OPT_STRING("freq", freq, 0),
+ OPT_FLOAT("freq", freq, 0),
OPT_STRING("channel", channel, 0),
OPT_STRING("chanlist", chanlist, 0),
OPT_STRING("norm", norm, 0),
@@ -602,7 +602,7 @@ int open_tv(tvi_handle_t *tvh)
/* we need to set frequency */
if (tvh->tv_param->freq)
{
- unsigned long freq = atof(tvh->tv_param->freq)*16;
+ unsigned long freq = tvh->tv_param->freq * 16;
/* set freq in MHz */
funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq);
diff --git a/stream/tv.h b/stream/tv.h
index d22b5b7..434a52d 100644
--- a/stream/tv.h
+++ b/stream/tv.h
@@ -27,7 +27,7 @@
struct mp_log;
typedef struct tv_params {
- char *freq;
+ float freq;
char *channel;
char *chanlist;
char *norm;
diff --git a/sub/lavc_conv.c b/sub/lavc_conv.c
index 3e0165a..3ff350c 100644
--- a/sub/lavc_conv.c
+++ b/sub/lavc_conv.c
@@ -210,9 +210,6 @@ 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;
}
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c
index 2c1b327..4ce8c55 100644
--- a/sub/sd_lavc.c
+++ b/sub/sd_lavc.c
@@ -263,13 +263,8 @@ static void read_sub_bitmaps(struct sd *sd, struct sub *sub)
struct sub_bitmap *b = &sub->inbitmaps[i];
struct pos pos = priv->packer->result[i];
struct AVSubtitleRect *r = b->bitmap;
-#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
b->w = r->w;
b->h = r->h;
b->x = r->x;
diff --git a/video/csputils.c b/video/csputils.c
index 8f6a9e3..6835aee 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -190,10 +190,8 @@ enum mp_csp_trc avcol_trc_to_mp_csp_trc(int avtrc)
case AVCOL_TRC_LINEAR: return MP_CSP_TRC_LINEAR;
case AVCOL_TRC_GAMMA22: return MP_CSP_TRC_GAMMA22;
case AVCOL_TRC_GAMMA28: return MP_CSP_TRC_GAMMA28;
-#if HAVE_AVUTIL_HDR
case AVCOL_TRC_SMPTEST2084: return MP_CSP_TRC_SMPTE_ST2084;
case AVCOL_TRC_ARIB_STD_B67: return MP_CSP_TRC_ARIB_STD_B67;
-#endif
default: return MP_CSP_TRC_AUTO;
}
}
@@ -242,10 +240,8 @@ int mp_csp_trc_to_avcol_trc(enum mp_csp_trc trc)
case MP_CSP_TRC_LINEAR: return AVCOL_TRC_LINEAR;
case MP_CSP_TRC_GAMMA22: return AVCOL_TRC_GAMMA22;
case MP_CSP_TRC_GAMMA28: return AVCOL_TRC_GAMMA28;
-#if HAVE_AVUTIL_HDR
case MP_CSP_TRC_SMPTE_ST2084: return AVCOL_TRC_SMPTEST2084;
case MP_CSP_TRC_ARIB_STD_B67: return AVCOL_TRC_ARIB_STD_B67;
-#endif
default: return AVCOL_TRC_UNSPECIFIED;
}
}
diff --git a/video/decode/cuda.c b/video/decode/cuda.c
index f9dd418..cad02b2 100644
--- a/video/decode/cuda.c
+++ b/video/decode/cuda.c
@@ -17,22 +17,17 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
+// This define and typedef prevent hwcontext_cuda.h trying to include cuda.h
+#define CUDA_VERSION 7050
+typedef void * CUcontext;
+
#include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_cuda.h>
#include "common/av_common.h"
+#include "video/fmt-conversion.h"
#include "video/decode/lavc.h"
-typedef struct CUVIDContext {
- CUcontext cuda_ctx;
-} CUVIDContext;
-
-static void cuvid_ctx_free(AVHWDeviceContext *ctx)
-{
- AVCUDADeviceContext *hwctx = ctx->hwctx;
- cuCtxDestroy(hwctx->cuda_ctx);
-}
-
static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
@@ -43,12 +38,7 @@ static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
static int init(struct lavc_ctx *ctx)
{
- struct CUVIDContext *p = talloc_ptrtype(NULL, p);
-
- *p = (struct CUVIDContext) {
- .cuda_ctx = hwdec_devices_get(ctx->hwdec_devs, HWDEC_CUDA)->ctx,
- };
- ctx->hwdec_priv = p;
+ ctx->hwdec_priv = hwdec_devices_get(ctx->hwdec_devs, HWDEC_CUDA)->ctx;
return 0;
}
@@ -58,7 +48,6 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h)
AVCUDADeviceContext *device_hwctx;
AVHWDeviceContext *device_ctx;
AVHWFramesContext *hwframe_ctx;
- CUVIDContext *priv = ctx->hwdec_priv;
int ret = 0;
if (avctx->hw_frames_ctx) {
@@ -73,10 +62,9 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h)
}
device_ctx = (AVHWDeviceContext*)hw_device_ctx->data;
- device_ctx->free = cuvid_ctx_free;
device_hwctx = device_ctx->hwctx;
- device_hwctx->cuda_ctx = priv->cuda_ctx;
+ device_hwctx->cuda_ctx = ctx->hwdec_priv;
ret = av_hwdevice_ctx_init(hw_device_ctx);
if (ret < 0) {
@@ -103,18 +91,13 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h)
static void uninit(struct lavc_ctx *ctx)
{
- struct CUVIDContext *p = ctx->hwdec_priv;
- if (!p)
- return;
-
- talloc_free(p);
ctx->hwdec_priv = NULL;
}
static struct mp_image *process_image(struct lavc_ctx *ctx, struct mp_image *img)
{
if (img->imgfmt == IMGFMT_CUDA)
- img->params.hw_subfmt = IMGFMT_NV12;
+ img->params.hw_subfmt = pixfmt2imgfmt(ctx->avctx->sw_pix_fmt);
return img;
}
diff --git a/video/decode/d3d11va.c b/video/decode/d3d11va.c
index 8ce0788..e31582d 100644
--- a/video/decode/d3d11va.c
+++ b/video/decode/d3d11va.c
@@ -429,7 +429,6 @@ static bool create_device(struct lavc_ctx *s, BOOL thread_safe)
HRESULT hr;
struct priv *p = s->hwdec_priv;
- d3d_load_dlls();
if (!d3d11_dll) {
MP_ERR(p, "Failed to load D3D11 library\n");
return false;
@@ -492,6 +491,11 @@ static int d3d11va_init(struct lavc_ctx *s)
if (!p)
return -1;
+ // Unconditionally load Direct3D DLLs, even when using a VO-supplied D3D11
+ // device. This prevents a crash that occurs at least with NVIDIA drivers,
+ // where D3D objects are accessed after ANGLE unloads d3d11.dll.
+ d3d_load_dlls();
+
s->hwdec_priv = p;
p->log = mp_log_new(s, s->log, "d3d11va");
if (s->hwdec->type == HWDEC_D3D11VA_COPY) {
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c
index dea5b59..d9dbf0f 100644
--- a/video/decode/dec_video.c
+++ b/video/decode/dec_video.c
@@ -116,11 +116,12 @@ struct mp_decoder_list *video_decoder_list(void)
return list;
}
-static struct mp_decoder_list *mp_select_video_decoders(const char *codec,
+static struct mp_decoder_list *mp_select_video_decoders(struct mp_log *log,
+ const char *codec,
char *selection)
{
struct mp_decoder_list *list = video_decoder_list();
- struct mp_decoder_list *new = mp_select_decoders(list, codec, selection);
+ struct mp_decoder_list *new = mp_select_decoders(log, list, codec, selection);
talloc_free(list);
return new;
}
@@ -143,8 +144,9 @@ bool video_init_best_codec(struct dec_video *d_video)
d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision
struct mp_decoder_entry *decoder = NULL;
- struct mp_decoder_list *list =
- mp_select_video_decoders(d_video->codec->codec, opts->video_decoders);
+ struct mp_decoder_list *list = mp_select_video_decoders(d_video->log,
+ d_video->codec->codec,
+ opts->video_decoders);
mp_print_decoders(d_video->log, MSGL_V, "Codec list:", list);
@@ -153,22 +155,19 @@ bool video_init_best_codec(struct dec_video *d_video)
const struct vd_functions *driver = find_driver(sel->family);
if (!driver)
continue;
- MP_VERBOSE(d_video, "Opening video decoder %s:%s\n",
- sel->family, sel->decoder);
+ MP_VERBOSE(d_video, "Opening video decoder %s\n", sel->decoder);
d_video->vd_driver = driver;
if (init_video_codec(d_video, sel->decoder)) {
decoder = sel;
break;
}
d_video->vd_driver = NULL;
- MP_WARN(d_video, "Video decoder init failed for "
- "%s:%s\n", sel->family, sel->decoder);
+ MP_WARN(d_video, "Video decoder init failed for %s\n", sel->decoder);
}
if (d_video->vd_driver) {
d_video->decoder_desc =
- talloc_asprintf(d_video, "%s [%s:%s]", decoder->desc, decoder->family,
- decoder->decoder);
+ talloc_asprintf(d_video, "%s (%s)", decoder->decoder, decoder->desc);
MP_VERBOSE(d_video, "Selected video codec: %s\n", d_video->decoder_desc);
} else {
MP_ERR(d_video, "Failed to initialize a video decoder for codec '%s'.\n",
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index d25c999..cc3bbc8 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -501,7 +501,6 @@ static void init_avctx(struct dec_video *vd, const char *decoder,
avctx->pkt_timebase = ctx->codec_timebase;
#endif
- avctx->refcounted_frames = 1;
ctx->pic = av_frame_alloc();
if (!ctx->pic)
goto error;
@@ -639,10 +638,10 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame,
.p_w = frame->sample_aspect_ratio.num,
.p_h = frame->sample_aspect_ratio.den,
.color = {
- .space = avcol_spc_to_mp_csp(ctx->avctx->colorspace),
- .levels = avcol_range_to_mp_csp_levels(ctx->avctx->color_range),
- .primaries = avcol_pri_to_mp_csp_prim(ctx->avctx->color_primaries),
- .gamma = avcol_trc_to_mp_csp_trc(ctx->avctx->color_trc),
+ .space = avcol_spc_to_mp_csp(frame->colorspace),
+ .levels = avcol_range_to_mp_csp_levels(frame->color_range),
+ .primaries = avcol_pri_to_mp_csp_prim(frame->color_primaries),
+ .gamma = avcol_trc_to_mp_csp_trc(frame->color_trc),
.sig_peak = ctx->cached_hdr_peak,
},
.chroma_location =
@@ -663,11 +662,9 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx,
MP_VERBOSE(vd, " %s", av_get_pix_fmt_name(fmt[i]));
MP_VERBOSE(vd, "\n");
-#if HAVE_AVCODEC_PROFILE_NAME
const char *profile = avcodec_profile_name(avctx->codec_id, avctx->profile);
MP_VERBOSE(vd, "Codec profile: %s (0x%x)\n", profile ? profile : "unknown",
avctx->profile);
-#endif
assert(ctx->hwdec);
@@ -794,7 +791,6 @@ static void decode(struct dec_video *vd, struct demux_packet *packet,
reset_avctx(vd);
hwdec_lock(ctx);
-#if HAVE_AVCODEC_NEW_CODEC_API
ret = avcodec_send_packet(avctx, packet ? &pkt : NULL);
if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
if (ret >= 0)
@@ -807,10 +803,6 @@ static void decode(struct dec_video *vd, struct demux_packet *packet,
} else {
consumed = true;
}
-#else
- ret = avcodec_decode_video2(avctx, ctx->pic, &got_picture, &pkt);
- consumed = true;
-#endif
hwdec_unlock(ctx);
// Reset decoder if it was fully flushed. Caller might send more flush
@@ -864,9 +856,14 @@ static void decode(struct dec_video *vd, struct demux_packet *packet,
return;
}
assert(mpi->planes[0] || mpi->planes[3]);
- mpi->pts = mp_pts_from_av(MP_AVFRAME_DEC_PTS(ctx->pic), &ctx->codec_timebase);
+ mpi->pts = mp_pts_from_av(ctx->pic->pts, &ctx->codec_timebase);
mpi->dts = mp_pts_from_av(ctx->pic->pkt_dts, &ctx->codec_timebase);
+#if LIBAVCODEC_VERSION_MICRO >= 100
+ mpi->pkt_duration =
+ mp_pts_from_av(av_frame_get_pkt_duration(ctx->pic), &ctx->codec_timebase);
+#endif
+
struct mp_image_params params;
update_image_params(vd, ctx->pic, &params);
mp_image_set_params(mpi, &params);
diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c
index 93a1e6d..a6b6210 100644
--- a/video/decode/vdpau.c
+++ b/video/decode/vdpau.c
@@ -146,12 +146,14 @@ static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
assert(!ctx->hwdec_priv);
- int r = init_copy(ctx);
- if (ctx->hwdec_priv)
- uninit(ctx);
- ctx->hwdec_priv = NULL;
- return r < 0 ? HWDEC_ERR_NO_CTX : 0;
+ int r = HWDEC_ERR_NO_CTX;
+ if (init_copy(ctx) >=0 ) {
+ struct priv *p = ctx->hwdec_priv;
+ r = mp_vdpau_guess_if_emulated(p->mpvdp) ? HWDEC_ERR_EMULATED : 0;
+ uninit(ctx);
+ }
+ return r;
}
static struct mp_image *copy_image(struct lavc_ctx *ctx, struct mp_image *img)
diff --git a/video/filter/vf.c b/video/filter/vf.c
index 93b886e..41fbe9b 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -59,7 +59,6 @@ extern const vf_info_t vf_info_vaapi;
extern const vf_info_t vf_info_vapoursynth;
extern const vf_info_t vf_info_vapoursynth_lazy;
extern const vf_info_t vf_info_vdpaupp;
-extern const vf_info_t vf_info_vdpaurb;
extern const vf_info_t vf_info_buffer;
extern const vf_info_t vf_info_d3d11vpp;
@@ -98,7 +97,6 @@ static const vf_info_t *const filter_list[] = {
#endif
#if HAVE_VDPAU
&vf_info_vdpaupp,
- &vf_info_vdpaurb,
#endif
#if HAVE_D3D_HWACCEL
&vf_info_d3d11vpp,
diff --git a/video/filter/vf_vdpaurb.c b/video/filter/vf_vdpaurb.c
deleted file mode 100644
index 59067b5..0000000
--- a/video/filter/vf_vdpaurb.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * mpv is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-
-#include "video/vdpau.h"
-#include "video/vdpau_mixer.h"
-#include "vf.h"
-
-// This filter will read back decoded frames that have been decoded by vdpau
-// so they can be post-processed by regular filters. As vdpau is still doing
-// the decoding, a vdpau compatible vo must always be used.
-//
-// NB: This filter assumes the video surface will have a 420 chroma type and
-// can always be read back in NV12 format. This is a safe assumption at the
-// time of writing, but may not always remain true.
-
-struct vf_priv_s {
- struct mp_vdpau_ctx *ctx;
-};
-
-static int filter_ext(struct vf_instance *vf, struct mp_image *mpi)
-{
- struct vf_priv_s *p = vf->priv;
-
- if (!mpi) {
- return 0;
- }
-
- // Pass-through anything that's not been decoded by VDPAU
- if (mpi->imgfmt != IMGFMT_VDPAU) {
- vf_add_output_frame(vf, mpi);
- return 0;
- }
-
- if (mp_vdpau_mixed_frame_get(mpi)) {
- MP_ERR(vf, "Can't apply vdpaurb filter after vdpaupp filter.\n");
- mp_image_unrefp(&mpi);
- return -1;
- }
-
- struct mp_hwdec_ctx *hwctx = &p->ctx->hwctx;
-
- struct mp_image *out = hwctx->download_image(hwctx, mpi, vf->out_pool);
- if (!out || out->imgfmt != IMGFMT_NV12) {
- mp_image_unrefp(&mpi);
- mp_image_unrefp(&out);
- return -1;
- }
-
- vf_add_output_frame(vf, out);
- mp_image_unrefp(&mpi);
- return 0;
-}
-
-static int reconfig(struct vf_instance *vf, struct mp_image_params *in,
- struct mp_image_params *out)
-{
- *out = *in;
- if (in->imgfmt == IMGFMT_VDPAU) {
- out->imgfmt = IMGFMT_NV12;
- out->hw_subfmt = 0;
- }
- return 0;
-}
-
-static int query_format(struct vf_instance *vf, unsigned int fmt)
-{
- return vf_next_query_format(vf, fmt == IMGFMT_VDPAU ? IMGFMT_NV12 : fmt);
-}
-
-static int vf_open(vf_instance_t *vf)
-{
- struct vf_priv_s *p = vf->priv;
-
- MP_WARN(vf, "This filter is deprecated and will be removed.\n");
- MP_WARN(vf, "Use --hwdec=vdpau-copy instead.\n");
-
- vf->filter_ext = filter_ext;
- vf->filter = NULL;
- vf->reconfig = reconfig;
- vf->query_format = query_format;
-
- p->ctx = hwdec_devices_load(vf->hwdec_devs, HWDEC_VDPAU);
- if (!p->ctx)
- return 0;
-
- return 1;
-}
-
-const vf_info_t vf_info_vdpaurb = {
- .description = "vdpau readback",
- .name = "vdpaurb",
- .open = vf_open,
- .priv_size = sizeof(struct vf_priv_s),
-};
diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c
index 32330dd..7a9e208 100644
--- a/video/fmt-conversion.c
+++ b/video/fmt-conversion.c
@@ -73,10 +73,8 @@ static const struct {
{IMGFMT_XYZ12, AV_PIX_FMT_XYZ12},
-#ifdef AV_PIX_FMT_RGBA64
{IMGFMT_RGBA64, AV_PIX_FMT_RGBA64},
{IMGFMT_BGRA64, AV_PIX_FMT_BGRA64},
-#endif
#if LIBAVUTIL_VERSION_MICRO >= 100
{IMGFMT_BGR0, AV_PIX_FMT_BGR0},
@@ -90,9 +88,7 @@ static const struct {
{IMGFMT_0BGR, AV_PIX_FMT_ABGR},
#endif
-#ifdef AV_PIX_FMT_YA16
{IMGFMT_YA16, AV_PIX_FMT_YA16},
-#endif
{IMGFMT_VDPAU, AV_PIX_FMT_VDPAU},
#if HAVE_VIDEOTOOLBOX_HWACCEL
@@ -103,14 +99,13 @@ static const struct {
#if HAVE_D3D_HWACCEL
{IMGFMT_D3D11VA, AV_PIX_FMT_D3D11VA_VLD},
#endif
-#if HAVE_AV_PIX_FMT_MMAL
{IMGFMT_MMAL, AV_PIX_FMT_MMAL},
-#endif
#if HAVE_CUDA_HWACCEL
{IMGFMT_CUDA, AV_PIX_FMT_CUDA},
#endif
-#ifdef AV_PIX_FMT_P010
{IMGFMT_P010, AV_PIX_FMT_P010},
+#ifdef AV_PIX_FMT_P016
+ {IMGFMT_P016, AV_PIX_FMT_P016},
#endif
{0, AV_PIX_FMT_NONE}
diff --git a/video/hwdec.h b/video/hwdec.h
index 857d07c..f2fa794 100644
--- a/video/hwdec.h
+++ b/video/hwdec.h
@@ -44,6 +44,7 @@ struct mp_hwdec_ctx {
// HWDEC_D3D11VA: ID3D11Device*
// HWDEC_DXVA2: IDirect3DDevice9*
// HWDEC_DXVA2_COPY: IDirect3DDevice9*
+ // HWDEC_CUDA: CUcontext*
void *ctx;
// Optional.
diff --git a/video/image_writer.c b/video/image_writer.c
index 8a5980c..59d986f 100644
--- a/video/image_writer.c
+++ b/video/image_writer.c
@@ -133,7 +133,6 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
pic->color_trc = mp_csp_trc_to_avcol_trc(image->params.color.gamma);
}
-#if HAVE_AVCODEC_NEW_CODEC_API
int ret = avcodec_send_frame(avctx, pic);
if (ret < 0)
goto error_exit;
@@ -142,11 +141,6 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp
if (ret < 0)
goto error_exit;
got_output = 1;
-#else
- int ret = avcodec_encode_video2(avctx, &pkt, pic, &got_output);
- if (ret < 0)
- goto error_exit;
-#endif
fwrite(pkt.data, pkt.size, 1, fp);
diff --git a/video/img_format.c b/video/img_format.c
index 24545a8..0232f53 100644
--- a/video/img_format.c
+++ b/video/img_format.c
@@ -161,21 +161,14 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
int shift = -1; // shift for all components, or -1 if not uniform
for (int c = 0; c < pd->nb_components; c++) {
AVComponentDescriptor d = pd->comp[c];
-#if HAVE_AV_NEW_PIXDESC
- int depth = d.depth;
- int step = d.step;
-#else
- int depth = d.depth_minus1 + 1;
- int step = d.step_minus1 + 1;
-#endif
// multiple components per plane -> Y is definitive, ignore chroma
if (!desc.bpp[d.plane])
- desc.bpp[d.plane] = step * el_size;
- planedepth[d.plane] += depth;
- need_endian |= (depth + d.shift) > 8;
+ desc.bpp[d.plane] = d.step * el_size;
+ planedepth[d.plane] += d.depth;
+ need_endian |= (d.depth + d.shift) > 8;
if (c == 0)
- desc.component_bits = depth;
- if (depth != desc.component_bits)
+ desc.component_bits = d.depth;
+ if (d.depth != desc.component_bits)
desc.component_bits = 0;
if (c == 0)
shift = d.shift;
diff --git a/video/img_format.h b/video/img_format.h
index a91dcf8..ee731aa 100644
--- a/video/img_format.h
+++ b/video/img_format.h
@@ -151,8 +151,10 @@ enum mp_imgfmt {
IMGFMT_NV12,
IMGFMT_NV21,
- // Like IMGFMT_NV12, but with 16 bits per component
+ // Like IMGFMT_NV12, but with 10 bits per component (and 6 bits of padding)
IMGFMT_P010,
+ // Like IMGFMT_NV12, but with 16 bits per component
+ IMGFMT_P016,
// RGB/BGR Formats
diff --git a/video/mp_image.c b/video/mp_image.c
index b56c9e6..2c4627c 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -386,6 +386,7 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
dst->fields = src->fields;
dst->pts = src->pts;
dst->dts = src->dts;
+ dst->pkt_duration = src->pkt_duration;
dst->params.rotate = src->params.rotate;
dst->params.stereo_in = src->params.stereo_in;
dst->params.stereo_out = src->params.stereo_out;
@@ -744,9 +745,7 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *av_frame)
mp_image_copy_fields_from_av_frame(&t, av_frame);
for (int p = 0; p < MP_MAX_PLANES; p++)
t.bufs[p] = av_frame->buf[p];
-#if HAVE_AVUTIL_HAS_HWCONTEXT
t.hwctx = av_frame->hw_frames_ctx;
-#endif
return mp_image_new_ref(&t);
}
@@ -763,9 +762,7 @@ struct AVFrame *mp_image_to_av_frame(struct mp_image *img)
mp_image_copy_fields_to_av_frame(frame, new_ref);
for (int p = 0; p < MP_MAX_PLANES; p++)
frame->buf[p] = new_ref->bufs[p];
-#if HAVE_AVUTIL_HAS_HWCONTEXT
frame->hw_frames_ctx = new_ref->hwctx;
-#endif
*new_ref = (struct mp_image){0};
talloc_free(new_ref);
return frame;
diff --git a/video/mp_image.h b/video/mp_image.h
index 7c0f7ba..6606f19 100644
--- a/video/mp_image.h
+++ b/video/mp_image.h
@@ -85,7 +85,7 @@ typedef struct mp_image {
/* only inside filter chain */
double pts;
/* only after decoder */
- double dts;
+ double dts, pkt_duration;
/* for private use */
void* priv;
diff --git a/video/out/cocoa/events_view.h b/video/out/cocoa/events_view.h
index 3429563..6ad51cc 100644
--- a/video/out/cocoa/events_view.h
+++ b/video/out/cocoa/events_view.h
@@ -20,8 +20,6 @@
@interface MpvEventsView : NSView <NSDraggingDestination>
@property(nonatomic, retain) MpvCocoaAdapter *adapter;
-- (void)setFullScreen:(BOOL)willBeFullscreen;
-- (void)clear;
- (BOOL)canHideCursor;
- (void)signalMousePosition;
@end
diff --git a/video/out/cocoa/events_view.m b/video/out/cocoa/events_view.m
index 4a0c4bf..d377597 100644
--- a/video/out/cocoa/events_view.m
+++ b/video/out/cocoa/events_view.m
@@ -28,8 +28,6 @@
@property(nonatomic, assign) BOOL clearing;
@property(nonatomic, assign) BOOL hasMouseDown;
@property(nonatomic, retain) NSTrackingArea *tracker;
-- (BOOL)hasDock:(NSScreen*)screen;
-- (BOOL)hasMenubar:(NSScreen*)screen;
- (int)mpvButtonNumber:(NSEvent*)event;
- (void)mouseDownEvent:(NSEvent *)event;
- (void)mouseUpEvent:(NSEvent *)event;
@@ -41,7 +39,8 @@
@synthesize tracker = _tracker;
@synthesize hasMouseDown = _mouse_down;
-- (id)initWithFrame:(NSRect)frame {
+- (id)initWithFrame:(NSRect)frame
+{
self = [super initWithFrame:frame];
if (self) {
[self registerForDraggedTypes:@[NSFilenamesPboardType,
@@ -51,54 +50,6 @@
return self;
}
-- (void)setFullScreen:(BOOL)willBeFullscreen
-{
- if (willBeFullscreen && ![self isInFullScreenMode]) {
- NSApplicationPresentationOptions popts =
- NSApplicationPresentationDefault;
-
- if ([self hasMenubar:[self.adapter fsScreen]])
- // Cocoa raises an exception when autohiding the menubar but
- // not the dock. They probably got bored while programming the
- // multi screen support and took some shortcuts (tested on 10.8).
- popts |= NSApplicationPresentationAutoHideMenuBar |
- NSApplicationPresentationAutoHideDock;
-
- if ([self hasDock:[self.adapter fsScreen]])
- popts |= NSApplicationPresentationAutoHideDock;
-
- NSDictionary *fsopts = @{
- NSFullScreenModeAllScreens : @([self.adapter fsModeAllScreens]),
- NSFullScreenModeApplicationPresentationOptions : @(popts)
- };
-
- // The original "windowed" window will stay around since sending a
- // view fullscreen wraps it in another window. This is noticeable when
- // sending the View fullscreen to another screen. Make it go away
- // manually.
- [self.window orderOut:self];
-
- [self enterFullScreenMode:[self.adapter fsScreen]
- withOptions:fsopts];
- }
-
- if (!willBeFullscreen && [self isInFullScreenMode]) {
- [self exitFullScreenModeWithOptions:nil];
-
- // Show the "windowed" window again.
- [self.window makeKeyAndOrderFront:self];
- [self.window makeFirstResponder:self];
- }
-}
-
-- (void)clear
-{
- if ([self isInFullScreenMode]) {
- self.clearing = YES;
- [self exitFullScreenModeWithOptions:nil];
- }
-}
-
// mpv uses flipped coordinates, because X11 uses those. So let's just use them
// as well without having to do any coordinate conversion of mouse positions.
- (BOOL)isFlipped { return YES; }
@@ -146,21 +97,25 @@
{
return [self.adapter mouseEnabled];
}
-- (BOOL)acceptsFirstResponder {
+- (BOOL)acceptsFirstResponder
+{
return [self.adapter keyboardEnabled] || [self.adapter mouseEnabled];
}
-- (BOOL)becomeFirstResponder {
+- (BOOL)becomeFirstResponder
+{
return [self.adapter keyboardEnabled] || [self.adapter mouseEnabled];
}
- (BOOL)resignFirstResponder { return YES; }
-- (void)keyDown:(NSEvent *)event {
+- (void)keyDown:(NSEvent *)event
+{
[self.adapter putKeyEvent:event];
}
-- (void)keyUp:(NSEvent *)event {
+- (void)keyUp:(NSEvent *)event
+{
[self.adapter putKeyEvent:event];
}
@@ -348,10 +303,11 @@
NSPasteboard *pboard = [sender draggingPasteboard];
NSArray *types = [pboard types];
if ([types containsObject:NSFilenamesPboardType] ||
- [types containsObject:NSURLPboardType])
+ [types containsObject:NSURLPboardType]) {
return NSDragOperationCopy;
- else
+ } else {
return NSDragOperationNone;
+ }
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
@@ -362,7 +318,11 @@
options:@{}];
NSMutableArray* ar = [[[NSMutableArray alloc] init] autorelease];
for (NSURL* url in pbitems) {
- [ar addObject:[url path]];
+ if (url.fileURL) {
+ [ar addObject:[url path]];
+ } else {
+ [ar addObject:[url absoluteString]];
+ }
}
[self.adapter handleFilesArray:ar];
return YES;
@@ -374,27 +334,6 @@
return NO;
}
-- (BOOL)hasDock:(NSScreen*)screen
-{
- NSRect vF = [screen visibleFrame];
- NSRect f = [screen frame];
- return
- // The visible frame's width is smaller: dock is on left or right end
- // of this method's receiver.
- vF.size.width < f.size.width ||
- // The visible frame's veritical origin is bigger: dock is
- // on the bottom of this method's receiver.
- vF.origin.y > f.origin.y;
-
-}
-
-- (BOOL)hasMenubar:(NSScreen*)screen
-{
- NSRect vF = [screen visibleFrame];
- NSRect f = [screen frame];
- return f.size.height + f.origin.y > vF.size.height + vF.origin.y;
-}
-
- (int)mpvButtonNumber:(NSEvent*)event
{
int buttonNumber = [event buttonNumber];
diff --git a/video/out/cocoa/mpvadapter.h b/video/out/cocoa/mpvadapter.h
index 5b87e89..e547708 100644
--- a/video/out/cocoa/mpvadapter.h
+++ b/video/out/cocoa/mpvadapter.h
@@ -26,14 +26,14 @@
- (void)putAxis:(int)mpkey delta:(float)delta;
- (void)putCommand:(char*)cmd;
- (void)handleFilesArray:(NSArray *)files;
-- (void)didChangeWindowedScreenProfile:(NSScreen *)screen;
+- (void)didChangeWindowedScreenProfile:(NSNotification *)notification;
- (void)performAsyncResize:(NSSize)size;
- (void)didChangeMousePosition;
- (BOOL)isInFullScreenMode;
- (BOOL)keyboardEnabled;
- (BOOL)mouseEnabled;
-- (NSScreen *)fsScreen;
-- (BOOL)fsModeAllScreens;
+
+- (NSScreen *)getTargetScreen;
@property(nonatomic, assign) struct vo *vout;
@end
diff --git a/video/out/cocoa/video_view.m b/video/out/cocoa/video_view.m
index 786c6ef..cb09dc8 100644
--- a/video/out/cocoa/video_view.m
+++ b/video/out/cocoa/video_view.m
@@ -22,7 +22,8 @@
@implementation MpvVideoView
@synthesize adapter = _adapter;
-- (id)initWithFrame:(NSRect)frame {
+- (id)initWithFrame:(NSRect)frame
+{
self = [super initWithFrame:frame];
if (self) {
[self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
diff --git a/video/out/cocoa/window.m b/video/out/cocoa/window.m
index d89e296..68e5222 100644
--- a/video/out/cocoa/window.m
+++ b/video/out/cocoa/window.m
@@ -26,15 +26,25 @@
#include "window.h"
@interface MpvVideoWindow()
+@property(nonatomic, retain) NSScreen *targetScreen;
+@property(nonatomic, retain) NSScreen *previousScreen;
+@property(nonatomic, retain) NSScreen *currentScreen;
+
- (NSRect)frameRect:(NSRect)frameRect forCenteredContentSize:(NSSize)newSize;
- (void)setCenteredContentSize:(NSSize)newSize;
@end
@implementation MpvVideoWindow {
NSSize _queued_video_size;
+ NSRect _unfs_content_frame;
+ NSRect _unfs_screen_frame;
+ int _is_animating;
}
@synthesize adapter = _adapter;
+@synthesize targetScreen = _target_screen;
+@synthesize previousScreen = _previous_screen;
+@synthesize currentScreen = _current_screen;
- (id)initWithContentRect:(NSRect)content_rect
styleMask:(NSUInteger)style_mask
backing:(NSBackingStoreType)buffering_type
@@ -46,10 +56,96 @@
defer:flag]) {
[self setBackgroundColor:[NSColor blackColor]];
[self setMinSize:NSMakeSize(50,50)];
+ [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
+
+ self.targetScreen = [self screen];
+ self.currentScreen = [self screen];
+ _is_animating = 0;
+ _unfs_content_frame = [self convertRectToScreen:[[self contentView] frame]];
+ _unfs_screen_frame = [[self screen] frame];
}
return self;
}
+- (void)toggleFullScreen:(id)sender
+{
+ if (_is_animating)
+ return;
+
+ _is_animating = 1;
+
+ self.targetScreen = [self.adapter getTargetScreen];
+ if(![self targetScreen] && ![self previousScreen]) {
+ self.targetScreen = [self screen];
+ } else if (![self targetScreen]) {
+ self.targetScreen = self.previousScreen;
+ self.previousScreen = nil;
+ } else {
+ self.previousScreen = [self screen];
+ }
+
+ if (![self.adapter isInFullScreenMode]) {
+ _unfs_content_frame = [self convertRectToScreen:[[self contentView] frame]];
+ _unfs_screen_frame = [[self screen] frame];
+ }
+
+ //move window to target screen when going to fullscreen
+ if (![self.adapter isInFullScreenMode] && ![[self targetScreen] isEqual:[self screen]]) {
+ [self setFrame:[self calculateWindowPositionForScreen:[self targetScreen]] display:YES];
+ }
+
+ [super toggleFullScreen:sender];
+
+ if (![self.adapter isInFullScreenMode]) {
+ [self setStyleMask:([self styleMask] | NSWindowStyleMaskFullScreen)];
+ NSRect frame = [[self targetScreen] frame];
+ [self setFrame:frame display:YES];
+ } else {
+ [self setStyleMask:([self styleMask] & ~NSWindowStyleMaskFullScreen)];
+ NSRect frame = [self calculateWindowPositionForScreen:[self targetScreen]];
+ [self setFrame:frame display:YES];
+ [self setContentAspectRatio:_unfs_content_frame.size];
+ [self setCenteredContentSize:_unfs_content_frame.size];
+ }
+}
+
+- (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window
+{
+ return [NSArray arrayWithObject:window];
+}
+
+- (NSArray*)customWindowsToExitFullScreenForWindow:(NSWindow*)window
+{
+ return [NSArray arrayWithObject:window];
+}
+
+// we still need to keep those around or it will use the standard animation
+- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration {}
+
+- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration {}
+
+- (void)windowDidEnterFullScreen:(NSNotification *)notification
+{
+ _is_animating = 0;
+ [self.adapter windowDidEnterFullScreen:notification];
+}
+
+- (void)windowDidExitFullScreen:(NSNotification *)notification
+{
+ _is_animating = 0;
+ [self.adapter windowDidExitFullScreen:notification];
+}
+
+- (void)windowDidFailToEnterFullScreen:(NSWindow *)window
+{
+ _is_animating = 0;
+}
+
+- (void)windowDidFailToExitFullScreen:(NSWindow *)window
+{
+ _is_animating = 0;
+}
+
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
{
// XXX: we maybe only need expose for this
@@ -58,12 +154,18 @@
- (void)windowDidChangeScreen:(NSNotification *)notification
{
+ //this event doesn't exclusively trigger on screen change
+ //examples: screen reconfigure, toggling fullscreen
+ if (!_is_animating && ![[self currentScreen] isEqual:[self screen]]) {
+ self.previousScreen = [self screen];
+ }
+ self.currentScreen = [self screen];
[self.adapter windowDidChangeScreen:notification];
}
- (void)windowDidChangeScreenProfile:(NSNotification *)notification
{
- [self.adapter didChangeWindowedScreenProfile:[self screen]];
+ [self.adapter didChangeWindowedScreenProfile:notification];
}
- (void)windowDidResignKey:(NSNotification *)notification
@@ -125,8 +227,41 @@
animate:NO];
}
+- (NSRect)calculateWindowPositionForScreen:(NSScreen *)screen
+{
+ NSRect frame = [self frameRectForContentRect:_unfs_content_frame];
+ NSRect targetFrame = [screen frame];
+
+ CGFloat x_per = (_unfs_screen_frame.size.width - frame.size.width);
+ CGFloat y_per = (_unfs_screen_frame.size.height - frame.size.height);
+ if (x_per > 0) x_per = (frame.origin.x - _unfs_screen_frame.origin.x)/x_per;
+ if (y_per > 0) y_per = (frame.origin.y - _unfs_screen_frame.origin.y)/y_per;
+
+ frame.origin.x = targetFrame.origin.x +
+ (targetFrame.size.width - frame.size.width)*x_per;
+ frame.origin.y = targetFrame.origin.y +
+ (targetFrame.size.height - frame.size.height)*y_per;
+
+ //screen bounds right and left
+ if (frame.origin.x + frame.size.width > targetFrame.origin.x + targetFrame.size.width)
+ frame.origin.x = targetFrame.origin.x + targetFrame.size.width - frame.size.width;
+ if (frame.origin.x < targetFrame.origin.x)
+ frame.origin.x = targetFrame.origin.x;
+
+ //screen bounds top and bottom
+ if (frame.origin.y + frame.size.height > targetFrame.origin.y + targetFrame.size.height)
+ frame.origin.y = targetFrame.origin.y + targetFrame.size.height - frame.size.height;
+ if (frame.origin.y < targetFrame.origin.y)
+ frame.origin.y = targetFrame.origin.y;
+
+ return frame;
+}
+
- (NSRect)constrainFrameRect:(NSRect)nf toScreen:(NSScreen *)screen
{
+ if (_is_animating)
+ screen = [self targetScreen];
+
NSRect of = [self frame];
NSRect vf = [screen ?: self.screen ?: [NSScreen mainScreen] visibleFrame];
NSRect ncf = [self contentRectForFrameRect:nf];
@@ -136,7 +271,7 @@
if (NSMaxY(nf) > NSMaxY(vf))
nf.origin.y = NSMaxY(vf) - NSHeight(nf);
- // Prevent the window's titlebar from exiting the screen on the top edge.
+ // Prevent the window's titlebar from exiting the screen on the bottom edge.
if (NSMaxY(ncf) < NSMinY(vf))
nf.origin.y = NSMinY(vf) + NSMinY(ncf) - NSMaxY(ncf);
@@ -157,33 +292,47 @@
return nf;
}
+- (void)windowWillStartLiveResize:(NSNotification *)notification
+{
+ [self.adapter windowWillStartLiveResize:notification];
+}
+
- (void)windowDidEndLiveResize:(NSNotification *)notification
{
+ [self.adapter windowDidEndLiveResize:notification];
[self setFrame:[self constrainFrameRect:self.frame toScreen:self.screen]
display:NO];
}
-- (void)tryDequeueSize {
+- (void)updateWindowFrame:(NSSize)newSize
+{
+ _unfs_content_frame = [self frameRect:_unfs_content_frame forCenteredContentSize:newSize];
+}
+
+- (void)tryDequeueSize
+{
if (_queued_video_size.width <= 0.0 || _queued_video_size.height <= 0.0)
return;
- // XXX find a way to kill this state
- if (![self.adapter isInFullScreenMode]) {
- [self setContentAspectRatio:_queued_video_size];
- [self setCenteredContentSize:_queued_video_size];
- _queued_video_size = NSZeroSize;
- }
+ [self setContentAspectRatio:_queued_video_size];
+ [self setCenteredContentSize:_queued_video_size];
+ _queued_video_size = NSZeroSize;
}
-- (void)queueNewVideoSize:(NSSize)new_size
+- (void)queueNewVideoSize:(NSSize)newSize
{
- if (NSEqualSizes(_queued_video_size, new_size))
- return;
- _queued_video_size = new_size;
- [self tryDequeueSize];
+ if ([self.adapter isInFullScreenMode]) {
+ [self updateWindowFrame:newSize];
+ } else {
+ if (NSEqualSizes(_queued_video_size, newSize))
+ return;
+ _queued_video_size = newSize;
+ [self tryDequeueSize];
+ }
}
-- (void)windowDidBecomeMain:(NSNotification *)notification {
+- (void)windowDidBecomeMain:(NSNotification *)notification
+{
[self tryDequeueSize];
}
@end
diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m
index 719169d..164663c 100644
--- a/video/out/cocoa_common.m
+++ b/video/out/cocoa_common.m
@@ -49,11 +49,10 @@
#include "common/msg.h"
-static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
- const CVTimeStamp* outputTime, CVOptionFlags flagsIn,
+static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
+ const CVTimeStamp* outputTime, CVOptionFlags flagsIn,
CVOptionFlags* flagsOut, void* displayLinkContext);
static int vo_cocoa_fullscreen(struct vo *vo);
-static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s);
static void cocoa_add_screen_reconfiguration_observer(struct vo *vo);
static void cocoa_rm_screen_reconfiguration_observer(struct vo *vo);
@@ -70,15 +69,13 @@ struct vo_cocoa_state {
NSOpenGLContext *nsgl_ctx;
NSScreen *current_screen;
- NSScreen *fs_screen;
double screen_fps;
NSInteger window_level;
+ int fullscreen;
bool embedded; // wether we are embedding in another GUI
- atomic_bool waiting_frame;
-
IOPMAssertionID power_mgmt_assertion;
io_connect_t light_sensor;
uint64_t last_lmuvalue;
@@ -90,8 +87,6 @@ struct vo_cocoa_state {
uint32_t old_dwidth;
uint32_t old_dheight;
- id fs_icc_changed_ns_observer;
-
pthread_mutex_t lock;
pthread_cond_t wakeup;
@@ -122,14 +117,11 @@ static void queue_new_video_size(struct vo *vo, int w, int h)
{
struct vo_cocoa_state *s = vo->cocoa;
struct mp_vo_opts *opts = vo->opts;
- if ([s->window conformsToProtocol: @protocol(MpvSizing)]) {
- id<MpvSizing> win = (id<MpvSizing>) s->window;
- NSRect r = NSMakeRect(0, 0, w, h);
- if(!opts->hidpi_window_scale) {
- r = [s->current_screen convertRectFromBacking:r];
- }
- [win queueNewVideoSize:NSMakeSize(r.size.width, r.size.height)];
- }
+ id<MpvSizing> win = (id<MpvSizing>) s->window;
+ NSRect r = NSMakeRect(0, 0, w, h);
+ if(!opts->hidpi_window_scale)
+ r = [s->current_screen convertRectFromBacking:r];
+ [win queueNewVideoSize:NSMakeSize(r.size.width, r.size.height)];
}
static void flag_events(struct vo *vo, int events)
@@ -258,6 +250,39 @@ static void cocoa_uninit_light_sensor(struct vo_cocoa_state *s)
}
}
+static NSScreen *get_screen_by_id(struct vo *vo, int screen_id)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+
+ NSArray *screens = [NSScreen screens];
+ int n_of_displays = [screens count];
+ if (screen_id >= n_of_displays) {
+ MP_INFO(s, "Screen ID %d does not exist, falling back to main "
+ "device\n", screen_id);
+ return nil;
+ } else if (screen_id < 0) {
+ return nil;
+ }
+ return [screens objectAtIndex:(screen_id)];
+}
+
+static void vo_cocoa_update_screen_info(struct vo *vo)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ struct mp_vo_opts *opts = vo->opts;
+
+ if (s->embedded)
+ return;
+
+ if (s->current_screen && s->window) {
+ s->current_screen = [s->window screen];
+ } else if (!s->current_screen) {
+ s->current_screen = get_screen_by_id(vo, opts->screen_id);
+ if (!s->current_screen)
+ s->current_screen = [NSScreen mainScreen];
+ }
+}
+
void vo_cocoa_init(struct vo *vo)
{
struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state);
@@ -265,6 +290,7 @@ void vo_cocoa_init(struct vo *vo)
.power_mgmt_assertion = kIOPMNullAssertionID,
.log = mp_log_new(s, vo->log, "cocoa"),
.embedded = vo->opts->WinID >= 0,
+ .fullscreen = 0,
};
if (!s->embedded) {
NSImage* blankImage = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
@@ -274,6 +300,7 @@ void vo_cocoa_init(struct vo *vo)
pthread_mutex_init(&s->lock, NULL);
pthread_cond_init(&s->wakeup, NULL);
vo->cocoa = s;
+ vo_cocoa_update_screen_info(vo);
cocoa_init_light_sensor(vo);
cocoa_add_screen_reconfiguration_observer(vo);
if (!s->embedded) {
@@ -314,7 +341,6 @@ void vo_cocoa_uninit(struct vo *vo)
run_on_main_thread(vo, ^{
enable_power_management(s);
cocoa_uninit_light_sensor(s);
- cocoa_rm_fs_screen_profile_observer(s);
cocoa_rm_screen_reconfiguration_observer(vo);
[s->nsgl_ctx release];
@@ -325,12 +351,13 @@ void vo_cocoa_uninit(struct vo *vo)
[s->video removeFromSuperview];
[s->view removeFromSuperview];
- [(MpvEventsView *)s->view clear];
[s->view release];
// if using --wid + libmpv there's no window to release
- if (s->window)
- [s->window release];
+ if (s->window) {
+ [s->window setDelegate:nil];
+ [s->window close];
+ }
if (!s->embedded)
[s->blankCursor release];
@@ -341,44 +368,11 @@ void vo_cocoa_uninit(struct vo *vo)
});
}
-static int get_screen_handle(struct vo *vo, int identifier, NSWindow *window,
- NSScreen **screen) {
- struct vo_cocoa_state *s = vo->cocoa;
- NSArray *screens = [NSScreen screens];
- int n_of_displays = [screens count];
-
- if (identifier >= n_of_displays) { // check if the identifier is out of bounds
- MP_INFO(s, "Screen ID %d does not exist, falling back to main "
- "device\n", identifier);
- identifier = -1;
- }
-
- if (identifier < 0) {
- // default behaviour gets either the window screen or the main screen
- // if window is not available
- if (! (*screen = [window screen]) )
- *screen = [screens objectAtIndex:0];
- return 0;
- } else {
- *screen = [screens objectAtIndex:(identifier)];
- return 1;
- }
-}
-
-static void vo_cocoa_update_screens_pointers(struct vo *vo)
-{
- struct vo_cocoa_state *s = vo->cocoa;
- struct mp_vo_opts *opts = vo->opts;
- get_screen_handle(vo, opts->screen_id, s->window, &s->current_screen);
- get_screen_handle(vo, opts->fsscreen_id, s->window, &s->fs_screen);
-}
-
static void vo_cocoa_update_screen_fps(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
- NSScreen *screen = vo->opts->fullscreen ? s->fs_screen : s->current_screen;
- NSDictionary* sinfo = [screen deviceDescription];
+ NSDictionary* sinfo = [s->current_screen deviceDescription];
NSNumber* sid = [sinfo objectForKey:@"NSScreenNumber"];
CGDirectDisplayID did = [sid longValue];
@@ -416,21 +410,6 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
return kCVReturnSuccess;
}
-static void vo_cocoa_update_screen_info(struct vo *vo, struct mp_rect *out_rc)
-{
- struct vo_cocoa_state *s = vo->cocoa;
-
- if (s->embedded)
- return;
-
- vo_cocoa_update_screens_pointers(vo);
-
- if (out_rc) {
- NSRect r = [s->current_screen frame];
- *out_rc = (struct mp_rect){0, 0, r.size.width, r.size.height};
- }
-}
-
static void vo_set_level(struct vo *vo, int ontop)
{
struct vo_cocoa_state *s = vo->cocoa;
@@ -553,40 +532,12 @@ static int cocoa_set_window_title(struct vo *vo)
return VO_TRUE;
}
-static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s)
-{
- [[NSNotificationCenter defaultCenter]
- removeObserver:s->fs_icc_changed_ns_observer];
-}
-
-static void cocoa_add_fs_screen_profile_observer(struct vo *vo)
-{
- struct vo_cocoa_state *s = vo->cocoa;
-
- if (s->fs_icc_changed_ns_observer)
- cocoa_rm_fs_screen_profile_observer(s);
-
- if (vo->opts->fsscreen_id < 0)
- return;
-
- void (^nblock)(NSNotification *n) = ^(NSNotification *n) {
- flag_events(vo, VO_EVENT_ICC_PROFILE_CHANGED);
- };
-
- s->fs_icc_changed_ns_observer = [[NSNotificationCenter defaultCenter]
- addObserverForName:NSScreenColorSpaceDidChangeNotification
- object:s->fs_screen
- queue:nil
- usingBlock:nblock];
-}
-
static void cocoa_screen_reconfiguration_observer(
CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *ctx)
{
if (flags & kCGDisplaySetModeFlag) {
struct vo *vo = ctx;
MP_WARN(vo, "detected display mode change, updating screen info\n");
- vo_cocoa_update_screen_info(vo, NULL);
vo_cocoa_update_screen_fps(vo);
}
}
@@ -615,11 +566,13 @@ void vo_cocoa_set_opengl_ctx(struct vo *vo, CGLContextObj ctx)
int vo_cocoa_config_window(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
+ struct mp_vo_opts *opts = vo->opts;
+
run_on_main_thread(vo, ^{
- struct mp_rect screenrc;
- vo_cocoa_update_screen_info(vo, &screenrc);
vo_cocoa_update_screen_fps(vo);
+ NSRect r = [s->current_screen frame];
+ struct mp_rect screenrc = {0, 0, r.size.width, r.size.height};
struct vo_win_geometry geo;
vo_calc_window_geometry(vo, &screenrc, &geo);
vo_apply_window_geometry(vo, &geo);
@@ -638,10 +591,10 @@ int vo_cocoa_config_window(struct vo *vo)
if (!s->embedded && s->window) {
if (reset_size)
queue_new_video_size(vo, width, height);
- vo_cocoa_fullscreen(vo);
- cocoa_add_fs_screen_profile_observer(vo);
+ if (opts->fullscreen && !s->fullscreen)
+ vo_cocoa_fullscreen(vo);
cocoa_set_window_title(vo);
- vo_set_level(vo, vo->opts->ontop);
+ vo_set_level(vo, opts->ontop);
GLint o;
if (!CGLGetParameter(s->cgl_ctx, kCGLCPSurfaceOpacity, &o) && !o) {
@@ -691,9 +644,6 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height)
pthread_mutex_lock(&s->lock);
- // Make vo.c not do video timing, which would slow down resizing.
- vo_event(vo, VO_EVENT_LIVE_RESIZING);
-
// Wait until a new frame with the new size was rendered. For some reason,
// Cocoa requires this to be done before drawRect() returns.
struct timespec e = mp_time_us_to_timespec(mp_add_timeout(mp_time_us(), 0.1));
@@ -702,18 +652,9 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height)
break;
}
- vo_query_and_reset_events(vo, VO_EVENT_LIVE_RESIZING);
-
pthread_mutex_unlock(&s->lock);
}
-static void draw_changes_after_next_frame(struct vo *vo)
-{
- struct vo_cocoa_state *s = vo->cocoa;
- if (atomic_compare_exchange_strong(&s->waiting_frame, &(bool){false}, true))
- NSDisableScreenUpdates();
-}
-
void vo_cocoa_swap_buffers(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
@@ -730,9 +671,6 @@ void vo_cocoa_swap_buffers(struct vo *vo)
s->frame_h = vo->dheight;
pthread_cond_signal(&s->wakeup);
pthread_mutex_unlock(&s->lock);
-
- if (atomic_compare_exchange_strong(&s->waiting_frame, &(bool){true}, false))
- NSEnableScreenUpdates();
}
static int vo_cocoa_check_events(struct vo *vo)
@@ -754,25 +692,14 @@ static int vo_cocoa_check_events(struct vo *vo)
static int vo_cocoa_fullscreen(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
- struct mp_vo_opts *opts = vo->opts;
if (s->embedded)
return VO_NOTIMPL;
- vo_cocoa_update_screen_info(vo, NULL);
-
- draw_changes_after_next_frame(vo);
- [(MpvEventsView *)s->view setFullScreen:opts->fullscreen];
-
- if ([s->view window] != s->window) {
- // cocoa implements fullscreen views by moving the view to a fullscreen
- // window. Set that window delegate to the cocoa adapter to trigger
- // calls to -windowDidResignKey: and -windowDidBecomeKey:
- [[s->view window] setDelegate:s->adapter];
- }
-
- flag_events(vo, VO_EVENT_ICC_PROFILE_CHANGED);
- resize_event(vo);
+ [s->window toggleFullScreen:nil];
+ // for whatever reason sometimes cocoa doesn't create an up event on
+ // the fullscreen input key
+ cocoa_put_key(MP_INPUT_RELEASE_ALL);
return VO_TRUE;
}
@@ -782,10 +709,7 @@ static void vo_cocoa_control_get_icc_profile(struct vo *vo, void *arg)
struct vo_cocoa_state *s = vo->cocoa;
bstr *p = arg;
- vo_cocoa_update_screen_info(vo, NULL);
-
- NSScreen *screen = vo->opts->fullscreen ? s->fs_screen : s->current_screen;
- NSData *profile = [[screen colorSpace] ICCProfileData];
+ NSData *profile = [[s->current_screen colorSpace] ICCProfileData];
p->start = talloc_memdup(NULL, (void *)[profile bytes], [profile length]);
p->len = [profile length];
@@ -793,59 +717,61 @@ static void vo_cocoa_control_get_icc_profile(struct vo *vo, void *arg)
static int vo_cocoa_control_on_main_thread(struct vo *vo, int request, void *arg)
{
- struct mp_vo_opts *opts = vo->opts;
+ struct vo_cocoa_state *s = vo->cocoa;
switch (request) {
case VOCTRL_FULLSCREEN:
return vo_cocoa_fullscreen(vo);
+ case VOCTRL_GET_FULLSCREEN:
+ *(int *)arg = s->fullscreen;
+ return VO_TRUE;
case VOCTRL_ONTOP:
return vo_cocoa_ontop(vo);
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
- int *s = arg;
- NSSize size = [vo->cocoa->view frame].size;
- s[0] = size.width;
- s[1] = size.height;
+ int *sz = arg;
+ NSSize size = [s->view frame].size;
+ sz[0] = size.width;
+ sz[1] = size.height;
return VO_TRUE;
}
case VOCTRL_SET_UNFS_WINDOW_SIZE: {
- int *s = arg;
+ int *sz = arg;
int w, h;
- w = s[0];
- h = s[1];
+ w = sz[0];
+ h = sz[1];
queue_new_video_size(vo, w, h);
return VO_TRUE;
}
case VOCTRL_GET_WIN_STATE: {
- const bool minimized = [[vo->cocoa->view window] isMiniaturized];
+ const bool minimized = [[s->view window] isMiniaturized];
*(int *)arg = minimized ? VO_WIN_STATE_MINIMIZED : 0;
return VO_TRUE;
}
case VOCTRL_SET_CURSOR_VISIBILITY:
return vo_cocoa_set_cursor_visibility(vo, arg);
case VOCTRL_UPDATE_WINDOW_TITLE: {
- struct vo_cocoa_state *s = vo->cocoa;
talloc_free(s->window_title);
s->window_title = talloc_strdup(s, (char *) arg);
return cocoa_set_window_title(vo);
}
case VOCTRL_RESTORE_SCREENSAVER:
- enable_power_management(vo->cocoa);
+ enable_power_management(s);
return VO_TRUE;
case VOCTRL_KILL_SCREENSAVER:
- disable_power_management(vo->cocoa);
+ disable_power_management(s);
return VO_TRUE;
case VOCTRL_GET_ICC_PROFILE:
vo_cocoa_control_get_icc_profile(vo, arg);
return VO_TRUE;
case VOCTRL_GET_DISPLAY_FPS:
- if (vo->cocoa->screen_fps > 0.0) {
- *(double *)arg = vo->cocoa->screen_fps;
+ if (s->screen_fps > 0.0) {
+ *(double *)arg = s->screen_fps;
return VO_TRUE;
}
break;
case VOCTRL_GET_AMBIENT_LUX:
- if (vo->cocoa->light_sensor != IO_OBJECT_NULL) {
- *(int *)arg = vo->cocoa->last_lux;
+ if (s->light_sensor != IO_OBJECT_NULL) {
+ *(int *)arg = s->last_lux;
return VO_TRUE;
}
break;
@@ -877,35 +803,39 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
@implementation MpvCocoaAdapter
@synthesize vout = _video_output;
-- (void)performAsyncResize:(NSSize)size {
+- (void)performAsyncResize:(NSSize)size
+{
struct vo_cocoa_state *s = self.vout->cocoa;
- if (!atomic_load(&s->waiting_frame))
- vo_cocoa_resize_redraw(self.vout, size.width, size.height);
+ vo_cocoa_resize_redraw(self.vout, size.width, size.height);
}
-- (BOOL)keyboardEnabled {
+- (BOOL)keyboardEnabled
+{
return !!mp_input_vo_keyboard_enabled(self.vout->input_ctx);
}
-- (BOOL)mouseEnabled {
+- (BOOL)mouseEnabled
+{
return !!mp_input_mouse_enabled(self.vout->input_ctx);
}
-- (void)setNeedsResize {
+- (void)setNeedsResize
+{
resize_event(self.vout);
}
- (void)recalcMovableByWindowBackground:(NSPoint)p
{
BOOL movable = NO;
- if (![self isInFullScreenMode]) {
+ if (!self.vout->cocoa->fullscreen) {
movable = !mp_input_test_dragging(self.vout->input_ctx, p.x, p.y);
}
[self.vout->cocoa->window setMovableByWindowBackground:movable];
}
-- (void)signalMouseMovement:(NSPoint)point {
+- (void)signalMouseMovement:(NSPoint)point
+{
mp_input_set_mouse_pos(self.vout->input_ctx, point.x, point.y);
[self recalcMovableByWindowBackground:point];
}
@@ -933,18 +863,18 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
ta_free(cmd_);
}
-- (BOOL)isInFullScreenMode {
- return self.vout->opts->fullscreen;
+- (BOOL)isInFullScreenMode
+{
+ return self.vout->cocoa->fullscreen;
}
-- (NSScreen *)fsScreen {
+- (NSScreen *)getTargetScreen
+{
struct vo_cocoa_state *s = self.vout->cocoa;
- return s->fs_screen;
-}
+ struct mp_vo_opts *opts = self.vout->opts;
-- (BOOL)fsModeAllScreens
-{
- return self.vout->opts->fs_black_out_screens;
+ int screen_id = s->fullscreen ? opts->screen_id : opts->fsscreen_id;
+ return get_screen_by_id(self.vout, screen_id);
}
- (void)handleFilesArray:(NSArray *)files
@@ -954,11 +884,36 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
- (void)windowDidChangeScreen:(NSNotification *)notification
{
- vo_cocoa_update_screen_info(self.vout, NULL);
+ vo_cocoa_update_screen_info(self.vout);
vo_cocoa_update_screen_fps(self.vout);
}
-- (void)didChangeWindowedScreenProfile:(NSScreen *)screen
+- (void)windowDidEnterFullScreen:(NSNotification *)notification
+{
+ struct vo_cocoa_state *s = self.vout->cocoa;
+ s->fullscreen = 1;
+ s->pending_events |= VO_EVENT_FULLSCREEN_STATE;
+}
+
+- (void)windowDidExitFullScreen:(NSNotification *)notification
+{
+ struct vo_cocoa_state *s = self.vout->cocoa;
+ s->fullscreen = 0;
+ s->pending_events |= VO_EVENT_FULLSCREEN_STATE;
+}
+
+- (void)windowWillStartLiveResize:(NSNotification *)notification
+{
+ // Make vo.c not do video timing, which would slow down resizing.
+ vo_event(self.vout, VO_EVENT_LIVE_RESIZING);
+}
+
+- (void)windowDidEndLiveResize:(NSNotification *)notification
+{
+ vo_query_and_reset_events(self.vout, VO_EVENT_LIVE_RESIZING);
+}
+
+- (void)didChangeWindowedScreenProfile:(NSNotification *)notification
{
flag_events(self.vout, VO_EVENT_ICC_PROFILE_CHANGED);
}
diff --git a/video/out/opengl/angle_dynamic.c b/video/out/opengl/angle_dynamic.c
index f4540c4..1ff3cc8 100644
--- a/video/out/opengl/angle_dynamic.c
+++ b/video/out/opengl/angle_dynamic.c
@@ -1,11 +1,21 @@
#include <pthread.h>
#include <windows.h>
+#ifndef ANGLE_NO_ALIASES
#define ANGLE_NO_ALIASES
+#endif
+
#include "angle_dynamic.h"
+#include "config.h"
#include "common/common.h"
+#if HAVE_EGL_ANGLE_LIB
+bool angle_load(void)
+{
+ return true;
+}
+#else
#define ANGLE_DECL(NAME, VAR) \
VAR;
ANGLE_FNS(ANGLE_DECL)
@@ -31,3 +41,4 @@ bool angle_load(void)
pthread_once(&angle_load_once, angle_do_load);
return angle_loaded;
}
+#endif
diff --git a/video/out/opengl/cuda_dynamic.c b/video/out/opengl/cuda_dynamic.c
new file mode 100644
index 0000000..1135a1f
--- /dev/null
+++ b/video/out/opengl/cuda_dynamic.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cuda_dynamic.h"
+
+#include <pthread.h>
+
+#if defined(_WIN32)
+# include <windows.h>
+# define dlopen(filename, flags) LoadLibrary(TEXT(filename))
+# define dlsym(handle, symbol) (void *)GetProcAddress(handle, symbol)
+# define dlclose(handle) FreeLibrary(handle)
+#else
+# include <dlfcn.h>
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define CUDA_LIBNAME "nvcuda.dll"
+#else
+# define CUDA_LIBNAME "libcuda.so.1"
+#endif
+
+#define CUDA_DECL(NAME, TYPE) \
+ TYPE *mpv_ ## NAME;
+CUDA_FNS(CUDA_DECL)
+
+static bool cuda_loaded = false;
+static pthread_once_t cuda_load_once = PTHREAD_ONCE_INIT;
+
+static void cuda_do_load(void)
+{
+ void *lib = dlopen(CUDA_LIBNAME, RTLD_LAZY);
+ if (!lib) {
+ return;
+ }
+
+#define CUDA_LOAD_SYMBOL(NAME, TYPE) \
+ mpv_ ## NAME = dlsym(lib, #NAME); if (!mpv_ ## NAME) return;
+
+ CUDA_FNS(CUDA_LOAD_SYMBOL)
+
+ cuda_loaded = true;
+}
+
+bool cuda_load(void)
+{
+ pthread_once(&cuda_load_once, cuda_do_load);
+ return cuda_loaded;
+}
diff --git a/video/out/opengl/cuda_dynamic.h b/video/out/opengl/cuda_dynamic.h
new file mode 100644
index 0000000..ecf212a
--- /dev/null
+++ b/video/out/opengl/cuda_dynamic.h
@@ -0,0 +1,146 @@
+/*
+ * This file is part of mpv.
+ *
+ * It is based on an equivalent file in ffmpeg that was
+ * constructed from documentation, rather than from any
+ * original cuda headers.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MPV_CUDA_DYNAMIC_H
+#define MPV_CUDA_DYNAMIC_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#define CUDA_VERSION 7050
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define CUDAAPI __stdcall
+#else
+#define CUDAAPI
+#endif
+
+#define CU_CTX_SCHED_BLOCKING_SYNC 4
+
+typedef int CUdevice;
+
+typedef struct CUarray_st *CUarray;
+typedef struct CUgraphicsResource_st *CUgraphicsResource;
+typedef struct CUstream_st *CUstream;
+
+typedef void* CUcontext;
+#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64)
+typedef unsigned long long CUdeviceptr;
+#else
+typedef unsigned int CUdeviceptr;
+#endif
+
+typedef enum cudaError_enum {
+ CUDA_SUCCESS = 0
+} CUresult;
+
+typedef enum CUmemorytype_enum {
+ CU_MEMORYTYPE_HOST = 1,
+ CU_MEMORYTYPE_DEVICE = 2,
+ CU_MEMORYTYPE_ARRAY = 3
+} CUmemorytype;
+
+typedef struct CUDA_MEMCPY2D_st {
+ size_t srcXInBytes;
+ size_t srcY;
+ CUmemorytype srcMemoryType;
+ const void *srcHost;
+ CUdeviceptr srcDevice;
+ CUarray srcArray;
+ size_t srcPitch;
+
+ size_t dstXInBytes;
+ size_t dstY;
+ CUmemorytype dstMemoryType;
+ void *dstHost;
+ CUdeviceptr dstDevice;
+ CUarray dstArray;
+ size_t dstPitch;
+
+ size_t WidthInBytes;
+ size_t Height;
+} CUDA_MEMCPY2D;
+
+typedef enum CUGLDeviceList_enum {
+ CU_GL_DEVICE_LIST_ALL = 1,
+ CU_GL_DEVICE_LIST_CURRENT_FRAME = 2,
+ CU_GL_DEVICE_LIST_NEXT_FRAME = 3,
+} CUGLDeviceList;
+
+typedef unsigned int GLenum;
+typedef unsigned int GLuint;
+
+#define CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD 2
+
+typedef CUresult CUDAAPI tcuInit(unsigned int Flags);
+typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext *pctx, unsigned int flags, CUdevice dev);
+typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext *pctx);
+typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext *pctx);
+typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx);
+typedef CUresult CUDAAPI tcuMemcpy2D_v2(const CUDA_MEMCPY2D *pcopy);
+typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char** pstr);
+typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char** pstr);
+typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned int* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned int cudaDeviceCount, CUGLDeviceList deviceList);
+typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned int Flags);
+typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource);
+typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream);
+typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream);
+typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);
+
+#define CUDA_FNS(FN) \
+ FN(cuInit, tcuInit) \
+ FN(cuCtxCreate_v2, tcuCtxCreate_v2) \
+ FN(cuCtxPushCurrent_v2, tcuCtxPushCurrent_v2) \
+ FN(cuCtxPopCurrent_v2, tcuCtxPopCurrent_v2) \
+ FN(cuCtxDestroy_v2, tcuCtxDestroy_v2) \
+ FN(cuMemcpy2D_v2, tcuMemcpy2D_v2) \
+ FN(cuGetErrorName, tcuGetErrorName) \
+ FN(cuGetErrorString, tcuGetErrorString) \
+ FN(cuGLGetDevices_v2, tcuGLGetDevices_v2) \
+ FN(cuGraphicsGLRegisterImage, tcuGraphicsGLRegisterImage) \
+ FN(cuGraphicsUnregisterResource, tcuGraphicsUnregisterResource) \
+ FN(cuGraphicsMapResources, tcuGraphicsMapResources) \
+ FN(cuGraphicsUnmapResources, tcuGraphicsUnmapResources) \
+ FN(cuGraphicsSubResourceGetMappedArray, tcuGraphicsSubResourceGetMappedArray) \
+
+#define CUDA_EXT_DECL(NAME, TYPE) \
+ extern TYPE *mpv_ ## NAME;
+
+CUDA_FNS(CUDA_EXT_DECL)
+
+#define cuInit mpv_cuInit
+#define cuCtxCreate mpv_cuCtxCreate_v2
+#define cuCtxPushCurrent mpv_cuCtxPushCurrent_v2
+#define cuCtxPopCurrent mpv_cuCtxPopCurrent_v2
+#define cuCtxDestroy mpv_cuCtxDestroy_v2
+#define cuMemcpy2D mpv_cuMemcpy2D_v2
+#define cuGetErrorName mpv_cuGetErrorName
+#define cuGetErrorString mpv_cuGetErrorString
+#define cuGLGetDevices mpv_cuGLGetDevices_v2
+#define cuGraphicsGLRegisterImage mpv_cuGraphicsGLRegisterImage
+#define cuGraphicsUnregisterResource mpv_cuGraphicsUnregisterResource
+#define cuGraphicsMapResources mpv_cuGraphicsMapResources
+#define cuGraphicsUnmapResources mpv_cuGraphicsUnmapResources
+#define cuGraphicsSubResourceGetMappedArray mpv_cuGraphicsSubResourceGetMappedArray
+
+bool cuda_load(void);
+
+#endif // MPV_CUDA_DYNAMIC_H
diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c
index 539acbd..4edad96 100644
--- a/video/out/opengl/hwdec_cuda.c
+++ b/video/out/opengl/hwdec_cuda.c
@@ -27,22 +27,18 @@
* when decoding 10bit streams (there is some hardware dithering going on).
*/
-#include <libavutil/hwcontext.h>
-#include <libavutil/hwcontext_cuda.h>
-
+#include "cuda_dynamic.h"
#include "video/mp_image_pool.h"
#include "hwdec.h"
#include "video.h"
-#include <cudaGL.h>
-
struct priv {
struct mp_hwdec_ctx hwctx;
struct mp_image layout;
GLuint gl_textures[2];
CUgraphicsResource cu_res[2];
CUarray cu_array[2];
- bool mapped;
+ int sample_width;
CUcontext cuda_ctx;
};
@@ -81,7 +77,21 @@ static struct mp_image *cuda_download_image(struct mp_hwdec_ctx *ctx,
if (hw_image->imgfmt != IMGFMT_CUDA)
return NULL;
- struct mp_image *out = mp_image_pool_get(swpool, IMGFMT_NV12,
+ int sample_width;
+ switch (hw_image->params.hw_subfmt) {
+ case IMGFMT_NV12:
+ sample_width = 1;
+ break;
+ case IMGFMT_P010:
+ case IMGFMT_P016:
+ sample_width = 2;
+ break;
+ default:
+ return NULL;
+ }
+
+ struct mp_image *out = mp_image_pool_get(swpool,
+ hw_image->params.hw_subfmt,
hw_image->w, hw_image->h);
if (!out)
return NULL;
@@ -101,7 +111,8 @@ static struct mp_image *cuda_download_image(struct mp_hwdec_ctx *ctx,
.dstHost = out->planes[n],
.srcPitch = hw_image->stride[n],
.dstPitch = out->stride[n],
- .WidthInBytes = mp_image_plane_w(out, n) * (n + 1),
+ .WidthInBytes = mp_image_plane_w(out, n) *
+ (n + 1) * sample_width,
.Height = mp_image_plane_h(out, n),
};
@@ -130,13 +141,19 @@ static int cuda_create(struct gl_hwdec *hw)
int ret = 0, eret = 0;
if (hw->gl->version < 210 && hw->gl->es < 300) {
- MP_ERR(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n");
+ MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n");
return -1;
}
struct priv *p = talloc_zero(hw, struct priv);
hw->priv = p;
+ bool loaded = cuda_load();
+ if (!loaded) {
+ MP_VERBOSE(hw, "Failed to load CUDA symbols\n");
+ return -1;
+ }
+
ret = CHECK_CU(cuInit(0));
if (ret < 0)
goto error;
@@ -176,11 +193,32 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
int ret = 0, eret = 0;
assert(params->imgfmt == hw->driver->imgfmt);
- params->imgfmt = IMGFMT_NV12;
+ params->imgfmt = params->hw_subfmt;
params->hw_subfmt = 0;
mp_image_set_params(&p->layout, params);
+ GLint luma_format, chroma_format;
+ GLenum type;
+ switch (params->imgfmt) {
+ case IMGFMT_NV12:
+ luma_format = GL_R8;
+ chroma_format = GL_RG8;
+ type = GL_UNSIGNED_BYTE;
+ p->sample_width = 1;
+ break;
+ case IMGFMT_P010:
+ case IMGFMT_P016:
+ luma_format = GL_R16;
+ chroma_format = GL_RG16;
+ type = GL_UNSIGNED_SHORT;
+ p->sample_width = 2;
+ break;
+ default:
+ MP_ERR(hw, "Unsupported format: %s\n", mp_imgfmt_to_name(params->imgfmt));
+ return -1;
+ }
+
ret = CHECK_CU(cuCtxPushCurrent(p->cuda_ctx));
if (ret < 0)
return ret;
@@ -193,10 +231,10 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl->TexImage2D(GL_TEXTURE_2D, 0, n == 0 ? GL_R8 : GL_RG8,
+ gl->TexImage2D(GL_TEXTURE_2D, 0, n == 0 ? luma_format : chroma_format,
mp_image_plane_w(&p->layout, n),
mp_image_plane_h(&p->layout, n),
- 0, n == 0 ? GL_RED : GL_RG, GL_UNSIGNED_BYTE, NULL);
+ 0, n == 0 ? GL_RED : GL_RG, type, NULL);
gl->BindTexture(GL_TEXTURE_2D, 0);
ret = CHECK_CU(cuGraphicsGLRegisterImage(&p->cu_res[n], p->gl_textures[n],
@@ -241,6 +279,8 @@ static void destroy(struct gl_hwdec *hw)
}
CHECK_CU(cuCtxPopCurrent(&dummy));
+ CHECK_CU(cuCtxDestroy(p->cuda_ctx));
+
gl->DeleteTextures(2, p->gl_textures);
hwdec_devices_remove(hw->devs, &p->hwctx);
@@ -261,7 +301,7 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image,
for (int n = 0; n < 2; n++) {
// widthInBytes must account for the chroma plane
- // elements being two bytes wide.
+ // elements being two samples wide.
CUDA_MEMCPY2D cpy = {
.srcMemoryType = CU_MEMORYTYPE_DEVICE,
.dstMemoryType = CU_MEMORYTYPE_ARRAY,
@@ -269,7 +309,8 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image,
.srcPitch = hw_image->stride[n],
.srcY = 0,
.dstArray = p->cu_array[n],
- .WidthInBytes = mp_image_plane_w(&p->layout, n) * (n + 1),
+ .WidthInBytes = mp_image_plane_w(&p->layout, n) *
+ (n + 1) * p->sample_width,
.Height = mp_image_plane_h(&p->layout, n),
};
ret = CHECK_CU(cuMemcpy2D(&cpy));
diff --git a/video/out/opengl/hwdec_d3d11egl.c b/video/out/opengl/hwdec_d3d11egl.c
index 690609b..0ca954b 100644
--- a/video/out/opengl/hwdec_d3d11egl.c
+++ b/video/out/opengl/hwdec_d3d11egl.c
@@ -32,7 +32,7 @@
#include "video/decode/d3d.h"
#ifndef EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE
-#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x3AAB
+#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB
#endif
struct priv {
diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c
index 6c879fd..aa43728 100644
--- a/video/out/opengl/utils.c
+++ b/video/out/opengl/utils.c
@@ -100,13 +100,11 @@ void gl_upload_tex(GL *gl, GLenum target, GLenum format, GLenum type,
gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
-mp_image_t *gl_read_window_contents(GL *gl)
+mp_image_t *gl_read_window_contents(GL *gl, int w, int h)
{
if (gl->es)
return NULL; // ES can't read from front buffer
- GLint vp[4]; //x, y, w, h
- gl->GetIntegerv(GL_VIEWPORT, vp);
- mp_image_t *image = mp_image_alloc(IMGFMT_RGB24, vp[2], vp[3]);
+ mp_image_t *image = mp_image_alloc(IMGFMT_RGB24, w, h);
if (!image)
return NULL;
gl->BindFramebuffer(GL_FRAMEBUFFER, gl->main_fb);
@@ -114,9 +112,8 @@ mp_image_t *gl_read_window_contents(GL *gl)
gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
gl->ReadBuffer(obj);
//flip image while reading (and also avoid stride-related trouble)
- for (int y = 0; y < vp[3]; y++) {
- gl->ReadPixels(vp[0], vp[1] + vp[3] - y - 1, vp[2], 1,
- GL_RGB, GL_UNSIGNED_BYTE,
+ for (int y = 0; y < h; y++) {
+ gl->ReadPixels(0, h - y - 1, w, 1, GL_RGB, GL_UNSIGNED_BYTE,
image->planes[0] + y * image->stride[0]);
}
gl->PixelStorei(GL_PACK_ALIGNMENT, 4);
diff --git a/video/out/opengl/utils.h b/video/out/opengl/utils.h
index 33c2daa..f4e522c 100644
--- a/video/out/opengl/utils.h
+++ b/video/out/opengl/utils.h
@@ -30,7 +30,7 @@ void gl_upload_tex(GL *gl, GLenum target, GLenum format, GLenum type,
const void *dataptr, int stride,
int x, int y, int w, int h);
-mp_image_t *gl_read_window_contents(GL *gl);
+mp_image_t *gl_read_window_contents(GL *gl, int w, int h);
const char* mp_sampler_type(GLenum texture_target);
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 498d892..3bd67c2 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -428,95 +428,6 @@ const struct m_sub_options gl_video_conf = {
.change_flags = UPDATE_RENDERER,
};
-#define LEGACY_SCALER_OPTS(n) \
- OPT_SUBOPT_LEGACY(n, n), \
- OPT_SUBOPT_LEGACY(n"-param1", n"-param1"), \
- OPT_SUBOPT_LEGACY(n"-param2", n"-param2"), \
- OPT_SUBOPT_LEGACY(n"-blur", n"-blur"), \
- OPT_SUBOPT_LEGACY(n"-wparam", n"-wparam"), \
- OPT_SUBOPT_LEGACY(n"-clamp", n"-clamp"), \
- OPT_SUBOPT_LEGACY(n"-radius", n"-radius"), \
- OPT_SUBOPT_LEGACY(n"-antiring", n"-antiring"), \
- OPT_SUBOPT_LEGACY(n"-window", n"-window")
-
-const struct m_sub_options gl_video_conf_legacy = {
- .opts = (const m_option_t[]) {
- OPT_SUBOPT_LEGACY("dumb-mode", "opengl-dumb-mode"),
- OPT_SUBOPT_LEGACY("gamma", "opengl-gamma"),
- OPT_SUBOPT_LEGACY("gamma-auto", "gamma-auto"),
- OPT_SUBOPT_LEGACY("target-prim", "target-prim"),
- OPT_SUBOPT_LEGACY("target-trc", "target-trc"),
- OPT_SUBOPT_LEGACY("target-brightness", "target-brightness"),
- OPT_SUBOPT_LEGACY("hdr-tone-mapping", "hdr-tone-mapping"),
- OPT_SUBOPT_LEGACY("tone-mapping-param", "tone-mapping-param"),
- OPT_SUBOPT_LEGACY("pbo", "opengl-pbo"),
- LEGACY_SCALER_OPTS("scale"),
- LEGACY_SCALER_OPTS("dscale"),
- LEGACY_SCALER_OPTS("cscale"),
- LEGACY_SCALER_OPTS("tscale"),
- OPT_SUBOPT_LEGACY("scaler-lut-size", "scaler-lut-size"),
- OPT_SUBOPT_LEGACY("scaler-resizes-only", "scaler-resizes-only"),
- OPT_SUBOPT_LEGACY("linear-scaling", "linear-scaling"),
- OPT_SUBOPT_LEGACY("correct-downscaling", "correct-downscaling"),
- OPT_SUBOPT_LEGACY("sigmoid-upscaling", "sigmoid-upscaling"),
- OPT_SUBOPT_LEGACY("sigmoid-center", "sigmoid-center"),
- OPT_SUBOPT_LEGACY("sigmoid-slope", "sigmoid-slope"),
- OPT_SUBOPT_LEGACY("fbo-format", "opengl-fbo-format"),
- OPT_SUBOPT_LEGACY("dither-depth", "dither-depth"),
- OPT_SUBOPT_LEGACY("dither", "dither"),
- OPT_SUBOPT_LEGACY("dither-size-fruit", "dither-size-fruit"),
- OPT_SUBOPT_LEGACY("temporal-dither", "temporal-dither"),
- OPT_SUBOPT_LEGACY("temporal-dither-period", "temporal-dither-period"),
- OPT_SUBOPT_LEGACY("alpha", "alpha"),
- OPT_SUBOPT_LEGACY("rectangle-textures", "opengl-rectangle-textures"),
- OPT_SUBOPT_LEGACY("background", "background"),
- OPT_SUBOPT_LEGACY("interpolation", "interpolation"),
- OPT_SUBOPT_LEGACY("interpolation-threshold", "interpolation-threshold"),
- OPT_SUBOPT_LEGACY("blend-subtitles", "blend-subtitles"),
- OPT_SUBOPT_LEGACY("user-shaders", "opengl-shaders"),
- OPT_SUBOPT_LEGACY("deband", "deband"),
- OPT_SUBOPT_LEGACY("deband-iterations", "deband-iterations"),
- OPT_SUBOPT_LEGACY("deband-threshold", "deband-threshold"),
- OPT_SUBOPT_LEGACY("deband-range", "deband-range"),
- OPT_SUBOPT_LEGACY("deband-grain", "deband-grain"),
- OPT_SUBOPT_LEGACY("sharpen", "sharpen"),
- OPT_SUBOPT_LEGACY("icc-profile", "icc-profile"),
- OPT_SUBOPT_LEGACY("icc-profile-auto", "icc-profile-auto"),
- OPT_SUBOPT_LEGACY("icc-cache-dir", "icc-cache-dir"),
- OPT_SUBOPT_LEGACY("icc-intent", "icc-intent"),
- OPT_SUBOPT_LEGACY("icc-contrast", "icc-contrast"),
- OPT_SUBOPT_LEGACY("3dlut-size", "icc-3dlut-size"),
-
- OPT_REMOVED("approx-gamma", "this is always enabled now"),
- OPT_REMOVED("cscale-down", "chroma is never downscaled"),
- OPT_REMOVED("scale-sep", "this is set automatically whenever sane"),
- OPT_REMOVED("indirect", "this is set automatically whenever sane"),
- OPT_REMOVED("srgb", "use target-prim=bt709:target-trc=srgb instead"),
- OPT_REMOVED("source-shader", "use :deband to enable debanding"),
- OPT_REMOVED("prescale-luma", "use opengl-shaders for prescaling"),
- OPT_REMOVED("scale-shader", "use opengl-shaders instead"),
- OPT_REMOVED("pre-shaders", "use opengl-shaders instead"),
- OPT_REMOVED("post-shaders", "use opengl-shaders instead"),
-
- OPT_SUBOPT_LEGACY("lscale", "scale"),
- OPT_SUBOPT_LEGACY("lscale-down", "scale-down"),
- OPT_SUBOPT_LEGACY("lparam1", "scale-param1"),
- OPT_SUBOPT_LEGACY("lparam2", "scale-param2"),
- OPT_SUBOPT_LEGACY("lradius", "scale-radius"),
- OPT_SUBOPT_LEGACY("lantiring", "scale-antiring"),
- OPT_SUBOPT_LEGACY("cparam1", "cscale-param1"),
- OPT_SUBOPT_LEGACY("cparam2", "cscale-param2"),
- OPT_SUBOPT_LEGACY("cradius", "cscale-radius"),
- OPT_SUBOPT_LEGACY("cantiring", "cscale-antiring"),
- OPT_SUBOPT_LEGACY("smoothmotion", "interpolation"),
- OPT_SUBOPT_LEGACY("smoothmotion-threshold", "tscale-param1"),
- OPT_SUBOPT_LEGACY("scale-down", "dscale"),
- OPT_SUBOPT_LEGACY("fancy-downscaling", "correct-downscaling"),
-
- {0}
- },
-};
-
static void uninit_rendering(struct gl_video *p);
static void uninit_scaler(struct gl_video *p, struct scaler *scaler);
static void check_gl_features(struct gl_video *p);
diff --git a/video/out/opengl/video.h b/video/out/opengl/video.h
index 54b7022..3b5f452 100644
--- a/video/out/opengl/video.h
+++ b/video/out/opengl/video.h
@@ -137,7 +137,6 @@ struct gl_video_opts {
};
extern const struct m_sub_options gl_video_conf;
-extern const struct m_sub_options gl_video_conf_legacy;
struct gl_video;
struct vo_frame;
diff --git a/video/out/vo.c b/video/out/vo.c
index cbd2ca8..64bf7ab 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -63,6 +63,9 @@ extern const struct vo_driver video_out_tct;
const struct vo_driver *const video_out_drivers[] =
{
+#if HAVE_RPI
+ &video_out_rpi,
+#endif
#if HAVE_GL
&video_out_opengl,
#endif
@@ -103,9 +106,6 @@ const struct vo_driver *const video_out_drivers[] =
#if HAVE_GL
&video_out_opengl_cb,
#endif
-#if HAVE_RPI
- &video_out_rpi,
-#endif
NULL
};
@@ -176,8 +176,8 @@ static bool get_desc(struct m_obj_desc *dst, int index)
.priv_size = vo->priv_size,
.priv_defaults = vo->priv_defaults,
.options = vo->options,
+ .options_prefix = vo->options_prefix,
.global_opts = vo->global_opts,
- .legacy_prefix = vo->legacy_prefix,
.hidden = vo->encode || !strcmp(vo->name, "opengl-cb"),
.p = vo,
};
@@ -196,6 +196,7 @@ const struct m_obj_list vo_obj_list = {
.allow_unknown_entries = true,
.allow_trailer = true,
.disallow_positional_parameters = true,
+ .use_global_options = true,
};
static void dispatch_wakeup_cb(void *ptr)
@@ -214,7 +215,7 @@ static void dealloc_vo(struct vo *vo)
}
static struct vo *vo_create(bool probing, struct mpv_global *global,
- struct vo_extra *ex, char *name, char **args)
+ struct vo_extra *ex, char *name)
{
assert(ex->wakeup_cb);
@@ -254,11 +255,9 @@ static struct vo *vo_create(bool probing, struct mpv_global *global,
mp_input_set_mouse_transform(vo->input_ctx, NULL, NULL);
if (vo->driver->encode != !!vo->encode_lavc_ctx)
goto error;
- vo->config = m_config_from_obj_desc_and_args(vo, vo->log, global, &desc,
- name, vo->opts->vo_defs, args);
- if (!vo->config)
+ vo->priv = m_config_group_from_desc(vo, vo->log, global, &desc, name);
+ if (!vo->priv)
goto error;
- vo->priv = vo->config->optstruct;
if (pthread_create(&vo->in->thread, NULL, vo_thread, vo))
goto error;
@@ -283,8 +282,7 @@ struct vo *init_best_video_out(struct mpv_global *global, struct vo_extra *ex)
if (strlen(vo_list[n].name) == 0)
goto autoprobe;
bool p = !!vo_list[n + 1].name;
- struct vo *vo = vo_create(p, global, ex, vo_list[n].name,
- vo_list[n].attribs);
+ struct vo *vo = vo_create(p, global, ex, vo_list[n].name);
if (vo)
return vo;
}
@@ -296,7 +294,7 @@ autoprobe:
const struct vo_driver *driver = video_out_drivers[i];
if (driver == &video_out_null)
break;
- struct vo *vo = vo_create(true, global, ex, (char *)driver->name, NULL);
+ struct vo *vo = vo_create(true, global, ex, (char *)driver->name);
if (vo)
return vo;
}
diff --git a/video/out/vo.h b/video/out/vo.h
index 99e6cca..724e03c 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -312,17 +312,16 @@ struct vo_driver {
const void *priv_defaults;
// List of options to parse into priv struct (requires priv_size to be set)
- // Deprecated. Use global options or global_opts instead.
+ // This will register them as global options (with options_prefix), and
+ // copy the current value at VO creation time to the priv struct.
const struct m_option *options;
- // Global options to register if the VO is compiled in.
- // mp_get_config_group() or other function can be used to access them.
- const struct m_sub_options *global_opts;
+ // All options in the above array are prefixed with this string. (It's just
+ // for convenience and makes no difference in semantics.)
+ const char *options_prefix;
- // Evil hack: add .options as global options, using the provided prefix.
- // For further evilness, the options will be copied to the priv struct
- // like with normal .options behavior.
- const char *legacy_prefix;
+ // Registers global options that go to a separate options struct.
+ const struct m_sub_options *global_opts;
};
struct vo {
@@ -356,7 +355,6 @@ struct vo {
struct m_config_cache *opts_cache; // cache for ->opts
struct mp_vo_opts *opts;
- struct m_config *config; // config for ->priv
bool want_redraw; // redraw as soon as possible
diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c
index c99ea37..63de6fe 100644
--- a/video/out/vo_direct3d.c
+++ b/video/out/vo_direct3d.c
@@ -1747,5 +1747,5 @@ const struct vo_driver video_out_direct3d = {
.priv_size = sizeof(d3d_priv),
.priv_defaults = &defaults,
.options = opts,
- .legacy_prefix = "vo-direct3d",
+ .options_prefix = "vo-direct3d",
};
diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c
index 7e642e3..9235758 100644
--- a/video/out/vo_drm.c
+++ b/video/out/vo_drm.c
@@ -490,5 +490,4 @@ const struct vo_driver video_out_drm = {
.wait_events = wait_events,
.wakeup = wakeup,
.priv_size = sizeof(struct priv),
- .legacy_prefix = "drm",
};
diff --git a/video/out/vo_image.c b/video/out/vo_image.c
index f799a97..e1bc1aa 100644
--- a/video/out/vo_image.c
+++ b/video/out/vo_image.c
@@ -160,18 +160,6 @@ const struct vo_driver video_out_image =
.name = "image",
.untimed = true,
.priv_size = sizeof(struct priv),
- .options = (const struct m_option[]) {
- OPT_SUBOPT_LEGACY("jpeg-quality", "vo-image-jpeg-quality"),
- OPT_SUBOPT_LEGACY("jpeg-smooth", "vo-image-jpeg-smooth"),
- OPT_SUBOPT_LEGACY("jpeg-source-chroma", "vo-image-jpeg-source-chroma"),
- OPT_SUBOPT_LEGACY("png-compression", "vo-image-png-compression"),
- OPT_SUBOPT_LEGACY("png-filter", "vo-image-png-filter"),
- OPT_SUBOPT_LEGACY("format", "vo-image-format"),
- OPT_SUBOPT_LEGACY("high-bit-depth", "vo-image-high-bit-depth"),
- OPT_SUBOPT_LEGACY("tag-colorspace", "vo-image-tag-colorspace"),
- OPT_SUBOPT_LEGACY("outdir", "vo-image-outdir"),
- {0},
- },
.preinit = preinit,
.query_format = query_format,
.reconfig = reconfig,
diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c
index 1721136..5c7406d 100644
--- a/video/out/vo_lavc.c
+++ b/video/out/vo_lavc.c
@@ -241,7 +241,6 @@ static void encode_video_and_write(struct vo *vo, AVFrame *frame)
struct priv *vc = vo->priv;
AVPacket packet = {0};
-#if HAVE_AVCODEC_NEW_CODEC_API
int status = avcodec_send_frame(vc->codec, frame);
if (status < 0) {
MP_ERR(vo, "error encoding at %d %d/%d\n",
@@ -276,24 +275,6 @@ static void encode_video_and_write(struct vo *vo, AVFrame *frame)
write_packet(vo, &packet);
av_packet_unref(&packet);
}
-#else
- av_init_packet(&packet);
- int got_packet = 0;
- int status = avcodec_encode_video2(vc->codec, &packet, frame, &got_packet);
- if (status < 0) {
- MP_ERR(vo, "error encoding at %d %d/%d\n",
- frame ? (int) frame->pts : -1,
- vc->codec->time_base.num,
- vc->codec->time_base.den);
- return;
- }
- if (!got_packet) {
- return;
- }
- encode_lavc_write_stats(vo->encode_lavc_ctx, vc->codec);
- write_packet(vo, &packet);
- av_packet_unref(&packet);
-#endif
}
static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi)
diff --git a/video/out/vo_null.c b/video/out/vo_null.c
index 39c1bf6..fcf8dc9 100644
--- a/video/out/vo_null.c
+++ b/video/out/vo_null.c
@@ -101,5 +101,5 @@ const struct vo_driver video_out_null = {
OPT_DOUBLE("fps", cfg_fps, M_OPT_RANGE, .min = 0, .max = 10000),
{0},
},
- .legacy_prefix = "vo-null",
+ .options_prefix = "vo-null",
};
diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c
index 2517ba7..7f65a1e 100644
--- a/video/out/vo_opengl.c
+++ b/video/out/vo_opengl.c
@@ -62,40 +62,13 @@ struct vo_opengl_opts {
int pattern[2];
};
-#define OPT_BASE_STRUCT struct vo_opengl_opts
-static const struct m_sub_options vo_opengl_conf = {
- .opts = (const m_option_t[]) {
- OPT_FLAG("opengl-glfinish", use_glFinish, 0),
- OPT_FLAG("opengl-waitvsync", waitvsync, 0),
- OPT_INT("opengl-swapinterval", swap_interval, 0),
- OPT_CHOICE("opengl-dwmflush", dwm_flush, 0,
- ({"no", -1}, {"auto", 0}, {"windowed", 1}, {"yes", 2})),
- OPT_FLAG("opengl-dcomposition", allow_direct_composition, 0),
- OPT_FLAG("opengl-debug", use_gl_debug, 0),
- OPT_STRING_VALIDATE("opengl-backend", backend, 0,
- mpgl_validate_backend_opt),
- OPT_FLAG("opengl-sw", allow_sw, 0),
- OPT_CHOICE("opengl-es", es, 0, ({"no", -1}, {"auto", 0}, {"yes", 1})),
- OPT_INTPAIR("opengl-check-pattern", pattern, 0),
- OPT_INTRANGE("opengl-vsync-fences", vsync_fences, 0,
- 0, NUM_VSYNC_FENCES),
-
- {0}
- },
- .defaults = &(const struct vo_opengl_opts){
- .swap_interval = 1,
- .allow_direct_composition = 1,
- },
- .size = sizeof(struct vo_opengl_opts),
-};
-
struct gl_priv {
struct vo *vo;
struct mp_log *log;
MPGLContext *glctx;
GL *gl;
- struct vo_opengl_opts *opts;
+ struct vo_opengl_opts opts;
struct gl_video *renderer;
@@ -133,7 +106,7 @@ static void resize(struct gl_priv *p)
static void check_pattern(struct vo *vo, int item)
{
struct gl_priv *p = vo->priv;
- int expected = p->opts->pattern[p->last_pattern];
+ int expected = p->opts.pattern[p->last_pattern];
if (item == expected) {
p->last_pattern++;
if (p->last_pattern >= 2)
@@ -151,7 +124,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
struct gl_priv *p = vo->priv;
GL *gl = p->gl;
- if (gl->FenceSync && p->num_vsync_fences < p->opts->vsync_fences) {
+ if (gl->FenceSync && p->num_vsync_fences < p->opts.vsync_fences) {
GLsync fence = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);;
if (fence)
p->vsync_fences[p->num_vsync_fences++] = fence;
@@ -159,7 +132,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
gl_video_render_frame(p->renderer, frame, gl->main_fb);
- if (p->opts->use_glFinish)
+ if (p->opts.use_glFinish)
gl->Finish();
}
@@ -171,30 +144,30 @@ static void flip_page(struct vo *vo)
mpgl_swap_buffers(p->glctx);
p->frames_rendered++;
- if (p->frames_rendered > 5 && !p->opts->use_gl_debug)
+ if (p->frames_rendered > 5 && !p->opts.use_gl_debug)
gl_video_set_debug(p->renderer, false);
- if (p->opts->use_glFinish)
+ if (p->opts.use_glFinish)
gl->Finish();
- if (p->opts->waitvsync || p->opts->pattern[0]) {
+ if (p->opts.waitvsync || p->opts.pattern[0]) {
if (gl->GetVideoSync) {
unsigned int n1 = 0, n2 = 0;
gl->GetVideoSync(&n1);
- if (p->opts->waitvsync)
+ if (p->opts.waitvsync)
gl->WaitVideoSync(2, (n1 + 1) % 2, &n2);
int step = n1 - p->prev_sgi_sync_count;
p->prev_sgi_sync_count = n1;
MP_DBG(vo, "Flip counts: %u->%u, step=%d\n", n1, n2, step);
- if (p->opts->pattern[0])
+ if (p->opts.pattern[0])
check_pattern(vo, step);
} else {
MP_WARN(vo, "GLX_SGI_video_sync not available, disabling.\n");
- p->opts->waitvsync = 0;
- p->opts->pattern[0] = 0;
+ p->opts.waitvsync = 0;
+ p->opts.pattern[0] = 0;
}
}
- while (p->opts->vsync_fences > 0 && p->num_vsync_fences >= p->opts->vsync_fences) {
+ while (p->opts.vsync_fences > 0 && p->num_vsync_fences >= p->opts.vsync_fences) {
gl->ClientWaitSync(p->vsync_fences[0], GL_SYNC_FLUSH_COMMANDS_BIT, 1e9);
gl->DeleteSync(p->vsync_fences[0]);
MP_TARRAY_REMOVE_AT(p->vsync_fences, p->num_vsync_fences, 0);
@@ -299,7 +272,8 @@ static int control(struct vo *vo, uint32_t request, void *data)
return VO_NOTIMPL;
}
case VOCTRL_SCREENSHOT_WIN: {
- struct mp_image *screen = gl_read_window_contents(p->gl);
+ struct mp_image *screen =
+ gl_read_window_contents(p->gl, vo->dwidth, vo->dheight);
if (!screen)
break; // redirect to backend
// set image parameters according to the display, if possible
@@ -389,7 +363,6 @@ static int preinit(struct vo *vo)
struct gl_priv *p = vo->priv;
p->vo = vo;
p->log = vo->log;
- p->opts = mp_get_config_group(vo, vo->global, &vo_opengl_conf);
int vo_flags = 0;
@@ -399,29 +372,29 @@ static int preinit(struct vo *vo)
if (alpha_mode == 1)
vo_flags |= VOFLAG_ALPHA;
- if (p->opts->use_gl_debug)
+ if (p->opts.use_gl_debug)
vo_flags |= VOFLAG_GL_DEBUG;
- if (p->opts->es == 1)
+ if (p->opts.es == 1)
vo_flags |= VOFLAG_GLES;
- if (p->opts->es == -1)
+ if (p->opts.es == -1)
vo_flags |= VOFLAG_NO_GLES;
- if (p->opts->allow_sw)
+ if (p->opts.allow_sw)
vo_flags |= VOFLAG_SW;
- if (p->opts->allow_direct_composition)
+ if (p->opts.allow_direct_composition)
vo_flags |= VOFLAG_ANGLE_DCOMP;
- p->glctx = mpgl_init(vo, p->opts->backend, vo_flags);
+ p->glctx = mpgl_init(vo, p->opts.backend, vo_flags);
if (!p->glctx)
goto err_out;
p->gl = p->glctx->gl;
- p->glctx->dwm_flush_opt = p->opts->dwm_flush;
+ p->glctx->dwm_flush_opt = p->opts.dwm_flush;
if (p->gl->SwapInterval) {
- p->gl->SwapInterval(p->opts->swap_interval);
+ p->gl->SwapInterval(p->opts.swap_interval);
} else {
MP_VERBOSE(vo, "swap_control extension missing.\n");
}
@@ -454,21 +427,7 @@ err_out:
return -1;
}
-static const struct m_option legacy_options[] = {
- OPT_SUBOPT_LEGACY("glfinish", "opengl-glfinish"),
- OPT_SUBOPT_LEGACY("waitvsync", "opengl-waitvsync"),
- OPT_SUBOPT_LEGACY("swapinterval", "opengl-swapinterval"),
- OPT_SUBOPT_LEGACY("dwmflush", "opengl-dwmflush"),
- OPT_SUBOPT_LEGACY("dcomposition", "opengl-dcomposition"),
- OPT_SUBOPT_LEGACY("debug", "opengl-debug"),
- OPT_SUBOPT_LEGACY("backend", "opengl-backend"),
- OPT_SUBOPT_LEGACY("sw", "opengl-sw"),
- OPT_SUBOPT_LEGACY("es", "opengl-es"),
- OPT_SUBOPT_LEGACY("check-pattern", "opengl-check-pattern"),
- OPT_SUBOPT_LEGACY("vsync-fences", "opengl-vsync-fences"),
- OPT_SUBSTRUCT_LEGACY("", gl_video_conf_legacy),
- {0},
-};
+#define OPT_BASE_STRUCT struct gl_priv
const struct vo_driver video_out_opengl = {
.description = "Extended OpenGL Renderer",
@@ -484,6 +443,28 @@ const struct vo_driver video_out_opengl = {
.wakeup = wakeup,
.uninit = uninit,
.priv_size = sizeof(struct gl_priv),
- .options = legacy_options,
- .global_opts = &vo_opengl_conf,
+ .options = (const m_option_t[]) {
+ OPT_FLAG("opengl-glfinish", opts.use_glFinish, 0),
+ OPT_FLAG("opengl-waitvsync", opts.waitvsync, 0),
+ OPT_INT("opengl-swapinterval", opts.swap_interval, 0),
+ OPT_CHOICE("opengl-dwmflush", opts.dwm_flush, 0,
+ ({"no", -1}, {"auto", 0}, {"windowed", 1}, {"yes", 2})),
+ OPT_FLAG("opengl-dcomposition", opts.allow_direct_composition, 0),
+ OPT_FLAG("opengl-debug", opts.use_gl_debug, 0),
+ OPT_STRING_VALIDATE("opengl-backend", opts.backend, 0,
+ mpgl_validate_backend_opt),
+ OPT_FLAG("opengl-sw", opts.allow_sw, 0),
+ OPT_CHOICE("opengl-es", opts.es, 0, ({"no", -1}, {"auto", 0}, {"yes", 1})),
+ OPT_INTPAIR("opengl-check-pattern", opts.pattern, 0),
+ OPT_INTRANGE("opengl-vsync-fences", opts.vsync_fences, 0,
+ 0, NUM_VSYNC_FENCES),
+
+ {0}
+ },
+ .priv_defaults = &(const struct gl_priv){
+ .opts = {
+ .swap_interval = 1,
+ .allow_direct_composition = 1,
+ },
+ },
};
diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c
index c66f6d4..852b790 100644
--- a/video/out/vo_opengl_cb.c
+++ b/video/out/vo_opengl_cb.c
@@ -144,7 +144,7 @@ static void copy_vo_opts(struct vo *vo)
// copy the struct with an assignment.
// Just remove all the dynamic data to avoid confusion.
struct mp_vo_opts opts = *vo->opts;
- opts.video_driver_list = opts.vo_defs = NULL;
+ opts.video_driver_list = NULL;
opts.winname = NULL;
opts.sws_opts = NULL;
p->ctx->vo_opts = opts;
@@ -204,6 +204,9 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts,
int mpv_opengl_cb_uninit_gl(struct mpv_opengl_cb_context *ctx)
{
+ if (!ctx)
+ return 0;
+
// Bring down the decoder etc., which still might be using the hwdec
// context. Setting initialized=false guarantees it can't come back.
@@ -529,13 +532,6 @@ static int preinit(struct vo *vo)
return 0;
}
-#define OPT_BASE_STRUCT struct vo_priv
-static const struct m_option options[] = {
- OPT_SUBOPT_LEGACY("debug", "opengl-debug"),
- OPT_SUBSTRUCT_LEGACY("", gl_video_conf_legacy),
- {0},
-};
-
const struct vo_driver video_out_opengl_cb = {
.description = "OpenGL Callbacks for libmpv",
.name = "opengl-cb",
@@ -548,5 +544,4 @@ const struct vo_driver video_out_opengl_cb = {
.flip_page = flip_page,
.uninit = uninit,
.priv_size = sizeof(struct vo_priv),
- .options = options,
};
diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c
index acec865..139da95 100644
--- a/video/out/vo_rpi.c
+++ b/video/out/vo_rpi.c
@@ -869,9 +869,6 @@ static void uninit(struct vo *vo)
static int preinit(struct vo *vo)
{
- MP_WARN(vo, "This VO is deprecated! Use --vo=opengl instead (which has "
- "the same features and which is the default).\n");
-
struct priv *p = vo->priv;
p->background_layer = p->layer;
@@ -933,5 +930,5 @@ const struct vo_driver video_out_rpi = {
.uninit = uninit,
.priv_size = sizeof(struct priv),
.options = options,
- .legacy_prefix = "rpi",
+ .options_prefix = "rpi",
};
diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c
index 76f336f..e32e89a 100644
--- a/video/out/vo_sdl.c
+++ b/video/out/vo_sdl.c
@@ -1032,5 +1032,5 @@ const struct vo_driver video_out_sdl = {
.flip_page = flip_page,
.wait_events = wait_events,
.wakeup = wakeup,
- .legacy_prefix = "sdl",
+ .options_prefix = "sdl",
};
diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c
index 0b74185..4aa1ef3 100644
--- a/video/out/vo_vaapi.c
+++ b/video/out/vo_vaapi.c
@@ -696,5 +696,5 @@ const struct vo_driver video_out_vaapi = {
OPT_FLAG("scaled-osd", force_scaled_osd, 0),
{0}
},
- .legacy_prefix = "vo-vaapi",
+ .options_prefix = "vo-vaapi",
};
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index 757c31e..eb89301 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -1164,5 +1164,5 @@ const struct vo_driver video_out_vdpau = {
OPT_REPLACED("output_surfaces", "output-surfaces"),
{NULL},
},
- .legacy_prefix = "vo-vdpau",
+ .options_prefix = "vo-vdpau",
};
diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c
index 6a7b18a..37ab4c7 100644
--- a/video/out/vo_wayland.c
+++ b/video/out/vo_wayland.c
@@ -677,6 +677,6 @@ const struct vo_driver video_out_wayland = {
OPT_FLAG("rgb565", use_rgb565, 0),
{0}
},
- .legacy_prefix = "vo-wayland",
+ .options_prefix = "vo-wayland",
};
diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c
index 1cc5b01..cbc6443 100644
--- a/video/out/vo_xv.c
+++ b/video/out/vo_xv.c
@@ -933,5 +933,5 @@ const struct vo_driver video_out_xv = {
OPT_REMOVED("no-colorkey", "use ck-method=none instead"),
{0}
},
- .legacy_prefix = "xv",
+ .options_prefix = "xv",
};
diff --git a/video/out/w32_common.c b/video/out/w32_common.c
index f4fbb20..0de9148 100644
--- a/video/out/w32_common.c
+++ b/video/out/w32_common.c
@@ -320,7 +320,7 @@ static void DropTarget_Init(DropTarget* This, struct vo_w32_state *w32)
static void add_window_borders(HWND hwnd, RECT *rc)
{
- AdjustWindowRect(rc, GetWindowLong(hwnd, GWL_STYLE), 0);
+ AdjustWindowRect(rc, GetWindowLongPtrW(hwnd, GWL_STYLE), 0);
}
// basically a reverse AdjustWindowRect (win32 doesn't appear to have this)
@@ -727,7 +727,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
signal_events(w32, VO_EVENT_WIN_STATE);
update_display_info(w32); // if we moved between monitors
- MP_VERBOSE(w32, "move window: %d:%d\n", w32->window_x, w32->window_y);
+ MP_DBG(w32, "move window: %d:%d\n", w32->window_x, w32->window_y);
break;
}
case WM_SIZE: {
@@ -1112,10 +1112,15 @@ static void update_screen_rect(struct vo_w32_state *w32)
static DWORD update_style(struct vo_w32_state *w32, DWORD style)
{
- const DWORD NO_FRAME = WS_OVERLAPPED;
- const DWORD FRAME = WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
- style &= ~(NO_FRAME | FRAME);
- style |= (w32->opts->border && !w32->current_fs) ? FRAME : NO_FRAME;
+ const DWORD NO_FRAME = WS_OVERLAPPED | WS_MINIMIZEBOX;
+ const DWORD FRAME = WS_OVERLAPPEDWINDOW;
+ const DWORD FULLSCREEN = NO_FRAME | WS_SYSMENU;
+ style &= ~(NO_FRAME | FRAME | FULLSCREEN);
+ if (w32->current_fs) {
+ style |= FULLSCREEN;
+ } else {
+ style |= w32->opts->border ? FRAME : NO_FRAME;
+ }
return style;
}
@@ -1137,7 +1142,7 @@ static void reinit_window_state(struct vo_w32_state *w32)
w32->window, w32->current_fs);
}
- DWORD style = update_style(w32, GetWindowLong(w32->window, GWL_STYLE));
+ DWORD style = update_style(w32, GetWindowLongPtrW(w32->window, GWL_STYLE));
if (w32->opts->ontop)
layer = HWND_TOPMOST;
@@ -1180,7 +1185,7 @@ static void reinit_window_state(struct vo_w32_state *w32)
r.top = w32->window_y;
r.bottom = r.top + w32->dh;
- SetWindowLong(w32->window, GWL_STYLE, style);
+ SetWindowLongPtrW(w32->window, GWL_STYLE, style);
RECT cr = r;
add_window_borders(w32->window, &r);
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index 480f296..35d0dfe 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -675,9 +675,9 @@ static void schedule_resize(struct vo_wayland_state *wl,
height = MPMIN(height, wl->display.current_output->height/scale);
}
- // don't keep the aspect ration in fullscreen mode, because the compositor
- // shows the desktop in the border regions if the video has not the same
- // aspect ration as the screen
+ // don't keep the aspect ratio in fullscreen mode because the compositor
+ // shows the desktop in the border regions if the video does not have the same
+ // aspect ratio as the screen
/* if only the height is changed we have to calculate the width
* in any other case we calculate the height */
switch (edges) {
@@ -946,8 +946,8 @@ void vo_wayland_uninit(struct vo *vo)
struct vo_wayland_state *wl = vo->wayland;
destroy_cursor(wl);
destroy_window(wl);
- destroy_display(wl);
destroy_input(wl);
+ destroy_display(wl);
for (int n = 0; n < 2; n++)
close(wl->wakeup_pipe[n]);
talloc_free(wl);
diff --git a/waftools/fragments/cocoa.m b/waftools/fragments/cocoa.m
index 3c62304..91b3aaa 100644
--- a/waftools/fragments/cocoa.m
+++ b/waftools/fragments/cocoa.m
@@ -4,7 +4,8 @@
#include "osdep/macosx_compat.h"
-int main(int argc, char **argv) {
+int main(int argc, char **argv)
+{
@autoreleasepool {
NSArray *ary = @[@1, @2, @3];
NSLog(@"test subscripting: %@", ary[0]);
diff --git a/waftools/fragments/cuda.c b/waftools/fragments/cuda.c
new file mode 100644
index 0000000..c63ec29
--- /dev/null
+++ b/waftools/fragments/cuda.c
@@ -0,0 +1,12 @@
+#define CUDA_VERSION 7050
+
+typedef void * CUcontext;
+
+#include <libavutil/hwcontext.h>
+#include <libavutil/hwcontext_cuda.h>
+
+int main(int argc, char *argv[]) {
+ enum AVHWDeviceType type = AV_HWDEVICE_TYPE_CUDA;
+ AVCUDADeviceContextInternal *foo;
+ return 0;
+}
diff --git a/waftools/generators/sources.py b/waftools/generators/sources.py
index 6f15210..b6af693 100644
--- a/waftools/generators/sources.py
+++ b/waftools/generators/sources.py
@@ -2,11 +2,11 @@ from waflib.Build import BuildContext
import os
def __file2string_cmd__(ctx):
- return '"${{BIN_PERL}}" "{0}/TOOLS/file2string.pl" "${{SRC}}" > "${{TGT}}"' \
+ return '"${{BIN_PYTHON}}" "{0}/TOOLS/file2string.py" "${{SRC}}" > "${{TGT}}"' \
.format(ctx.srcnode.abspath())
def __matroska_cmd__(ctx, argument):
- return '"${{BIN_PERL}}" "{0}/TOOLS/matroska.pl" "{1}" "${{SRC}}" > "${{TGT}}"' \
+ return '"${{BIN_PYTHON}}" "{0}/TOOLS/matroska.py" "{1}" "${{SRC}}" > "${{TGT}}"' \
.format(ctx.srcnode.abspath(), argument)
def __zshcomp_cmd__(ctx, argument):
diff --git a/wscript b/wscript
index 2b0de8b..94db7e2 100644
--- a/wscript
+++ b/wscript
@@ -81,6 +81,7 @@ build_options = [
}, {
'name': '--zsh-comp',
'desc': 'zsh completion',
+ 'func': check_ctx_vars('BIN_PERL'),
'func': check_true,
'default': 'disable',
}, {
@@ -128,10 +129,6 @@ main_dependencies = [
'func': check_statement(['poll.h', 'unistd.h', 'sys/mman.h'],
'struct pollfd pfd; poll(&pfd, 1, 0); fork(); int f[2]; pipe(f); munmap(f,0)'),
}, {
- 'name': 'fnmatch',
- 'desc': 'fnmatch()',
- 'func': check_statement('fnmatch.h', 'fnmatch("", "", 0)')
- }, {
'name': 'posix-or-mingw',
'desc': 'development environment',
'deps_any': [ 'posix', 'mingw' ],
@@ -356,16 +353,6 @@ iconv support use --disable-iconv.",
'desc': 'cdda support (libcdio)',
'func': check_pkg_config('libcdio_paranoia'),
}, {
- 'name': '--enca',
- 'desc': 'ENCA support',
- 'deps': [ 'iconv' ],
- 'func': check_statement('enca.h', 'enca_get_languages(NULL)', lib='enca'),
- }, {
- 'name': '--libguess',
- 'desc': 'libguess support',
- 'deps': [ 'iconv' ],
- 'func': check_pkg_config('libguess', '>= 1.0'),
- }, {
'name': '--uchardet',
'desc': 'uchardet support',
'deps': [ 'iconv' ],
@@ -401,13 +388,28 @@ iconv support use --disable-iconv.",
}
]
+# Libav 12:
+# libavutil 55.20.0
+# libavcodec 57.25.0
+# libavformat 57.7.2
+# libswscale 4.0.0
+# libavfilter 6.7.0
+# libavresample 3.0.0
+# FFmpeg 3.2.2:
+# libavutil 55.34.100
+# libavcodec 57.64.101
+# libavformat 57.56.100
+# libswscale 4.2.100
+# libavfilter 6.65.100
+# libswresample 2.3.100
+
libav_pkg_config_checks = [
- 'libavutil', '>= 54.02.0',
- 'libavcodec', '>= 56.1.0',
- 'libavformat', '>= 56.01.0',
- 'libswscale', '>= 2.1.3'
+ 'libavutil', '>= 55.20.0',
+ 'libavcodec', '>= 57.25.0',
+ 'libavformat', '>= 57.07.0',
+ 'libswscale', '>= 4.0.0'
]
-libav_versions_string = "FFmpeg 2.4 or Libav 11"
+libav_versions_string = "FFmpeg 3.2.2 or Libav 12"
libav_dependencies = [
{
@@ -420,11 +422,11 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_
}, {
'name': '--libswresample',
'desc': 'libswresample',
- 'func': check_pkg_config('libswresample', '>= 1.1.100'),
+ 'func': check_pkg_config('libswresample', '>= 2.3.100'),
}, {
'name': '--libavresample',
'desc': 'libavresample',
- 'func': check_pkg_config('libavresample', '>= 2.1.0'),
+ 'func': check_pkg_config('libavresample', '>= 3.0.0'),
'deps_neg': ['libswresample'],
}, {
'name': 'resampler',
@@ -436,13 +438,13 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_
}, {
'name': 'libavfilter',
'desc': 'libavfilter',
- 'func': check_pkg_config('libavfilter', '>= 5.0.0'),
+ 'func': check_pkg_config('libavfilter', '>= 6.7.0'),
'req': True,
'fmsg': 'libavfilter is a required dependency.',
}, {
'name': '--libavdevice',
'desc': 'libavdevice',
- 'func': check_pkg_config('libavdevice', '>= 55.0.0'),
+ 'func': check_pkg_config('libavdevice', '>= 57.0.0'),
}, {
'name': 'avcodec-chroma-pos-api',
'desc': 'libavcodec avcodec_enum_to_chroma_pos API',
@@ -462,73 +464,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_
'enum AVFrameSideDataType type = AV_FRAME_DATA_SKIP_SAMPLES',
use='libav')
}, {
- 'name': 'av-pix-fmt-mmal',
- 'desc': 'libavutil AV_PIX_FMT_MMAL',
- 'func': check_statement('libavutil/pixfmt.h',
- 'int x = AV_PIX_FMT_MMAL',
- use='libav'),
- }, {
- 'name': 'av-version-info',
- 'desc': 'libavtuil av_version_info()',
- 'func': check_statement('libavutil/avutil.h',
- 'const char *x = av_version_info()',
- use='libav'),
- }, {
- 'name': 'av-new-pixdesc',
- 'desc': 'libavutil new pixdesc fields',
- 'func': check_statement('libavutil/pixdesc.h',
- 'AVComponentDescriptor d; int x = d.depth',
- use='libav'),
- }, {
- 'name': 'av-avpacket-int64-duration',
- 'desc': 'libavcodec 64 bit AVPacket.duration',
- 'func': check_statement('libavcodec/avcodec.h',
- 'int x[(int)sizeof(((AVPacket){0}).duration) - 7]',
- use='libav'),
- }, {
- 'name': 'av-subtitle-nopict',
- 'desc': 'libavcodec AVSubtitleRect AVPicture removal',
- 'func': check_statement('libavcodec/avcodec.h',
- 'AVSubtitleRect r = {.linesize={0}}',
- use='libav'),
- }, {
- 'name': 'avcodec-profile-name',
- 'desc': 'libavcodec avcodec_profile_name()',
- 'func': check_statement('libavcodec/avcodec.h',
- 'avcodec_profile_name(0,0)',
- use='libav'),
- }, {
- 'name': 'avcodec-new-codec-api',
- 'desc': 'libavcodec decode/encode API',
- 'func': check_statement('libavcodec/avcodec.h',
- 'avcodec_send_packet(0,0)',
- use='libav'),
- }, {
- 'name': 'avcodec-has-codecpar',
- 'desc': 'libavcodec AVCodecParameters API',
- 'func': check_statement('libavformat/avformat.h',
- '(void)offsetof(AVStream, codecpar)',
- use='libav'),
- }, {
- 'name': 'avutil-has-hwcontext',
- 'desc': 'libavutil AVHWFramesContext API',
- 'func': check_statement('libavutil/frame.h',
- '(void)offsetof(AVFrame, hw_frames_ctx)',
- use='libav'),
- }, {
- 'name': 'avutil-hdr',
- 'desc': 'libavutil HDR TRCs',
- 'func': check_statement('libavutil/pixfmt.h',
- 'AVCOL_TRC_SMPTEST2084,'
- 'AVCOL_TRC_ARIB_STD_B67',
- use='libav'),
- }, {
'name': 'avutil-mastering-metadata',
'desc': 'libavutil mastering display metadata struct',
'func': check_statement('libavutil/frame.h',
'AV_FRAME_DATA_MASTERING_DISPLAY_METADATA',
use='libav'),
- }
+ },
]
audio_output_features = [
@@ -736,6 +677,15 @@ video_output_features = [
'func': check_statement(['EGL/egl.h', 'EGL/eglext.h'],
'int x = EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE')
} , {
+ 'name': '--egl-angle-lib',
+ 'desc': 'OpenGL Win32 ANGLE Library',
+ 'deps': [ 'egl-angle' ],
+ 'groups': [ 'gl' ],
+ 'func': check_statement(['EGL/egl.h'],
+ 'eglCreateWindowSurface(0, 0, 0, 0)',
+ cflags="-DGL_APICALL= -DEGLAPI= -DANGLE_NO_ALIASES -DANGLE_EXPORT=",
+ lib=['EGL', 'GLESv2', 'dxguid', 'd3d9', 'gdi32', 'stdc++'])
+ } , {
'name': '--vdpau',
'desc': 'VDPAU acceleration',
'deps': [ 'x11' ],
@@ -913,9 +863,8 @@ hwaccel_features = [
}, {
'name': '--cuda-hwaccel',
'desc': 'CUDA hwaccel',
- 'func': compose_checks(
- check_cc(lib="cuda"),
- check_headers('libavutil/hwcontext_cuda.h', use='libav')),
+ 'func': check_cc(fragment=load_fragment('cuda.c'),
+ use='libav'),
}, {
'name': 'sse4-intrinsics',
'desc': 'GCC SSE4 intrinsics for GPU memcpy',
@@ -1047,11 +996,12 @@ def configure(ctx):
ctx.find_program(cc, var='CC')
ctx.find_program(pkg_config, var='PKG_CONFIG')
ctx.find_program(ar, var='AR')
- ctx.find_program('perl', var='BIN_PERL')
+ ctx.find_program('python', var='BIN_PYTHON')
ctx.find_program('rst2html', var='RST2HTML', mandatory=False)
ctx.find_program('rst2man', var='RST2MAN', mandatory=False)
ctx.find_program('rst2pdf', var='RST2PDF', mandatory=False)
ctx.find_program(windres, var='WINDRES', mandatory=False)
+ ctx.find_program('perl', var='BIN_PERL', mandatory=False)
ctx.load('compiler_c')
ctx.load('waf_customizations')
diff --git a/wscript_build.py b/wscript_build.py
index ac7e0b1..b7c7b39 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -28,7 +28,7 @@ def _build_man(ctx):
name = 'rst2man',
target = 'DOCS/man/mpv.1',
source = 'DOCS/man/mpv.rst',
- rule = '${RST2MAN} ${SRC} ${TGT}',
+ rule = '${RST2MAN} --strip-elements-with-class=contents ${SRC} ${TGT}',
install_path = ctx.env.MANDIR + '/man1')
_add_rst_manual_dependencies(ctx)
@@ -38,7 +38,7 @@ def _build_pdf(ctx):
name = 'rst2pdf',
target = 'DOCS/man/mpv.pdf',
source = 'DOCS/man/mpv.rst',
- rule = '${RST2PDF} -c --repeat-table-rows ${SRC} -o ${TGT}',
+ rule = '${RST2PDF} -c -b 1 --repeat-table-rows ${SRC} -o ${TGT}',
install_path = ctx.env.DOCDIR)
_add_rst_manual_dependencies(ctx)
@@ -322,9 +322,8 @@ def build(ctx):
( "video/filter/vf_stereo3d.c" ),
( "video/filter/vf_sub.c" ),
( "video/filter/vf_vapoursynth.c", "vapoursynth-core" ),
- ( "video/filter/vf_vavpp.c", "vaapi"),
+ ( "video/filter/vf_vavpp.c", "vaapi" ),
( "video/filter/vf_vdpaupp.c", "vdpau" ),
- ( "video/filter/vf_vdpaurb.c", "vdpau" ),
( "video/filter/vf_yadif.c" ),
( "video/out/aspect.c" ),
( "video/out/bitmap_packer.c" ),
@@ -347,6 +346,7 @@ def build(ctx):
( "video/out/opengl/context_w32.c", "gl-win32" ),
( "video/out/opengl/context_x11.c", "gl-x11" ),
( "video/out/opengl/context_x11egl.c", "egl-x11" ),
+ ( "video/out/opengl/cuda_dynamic.c", "cuda-hwaccel" ),
( "video/out/opengl/egl_helpers.c", "egl-helpers" ),
( "video/out/opengl/formats.c", "gl" ),
( "video/out/opengl/hwdec.c", "gl" ),