Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
349e437466 | ||
|
|
f47a055440 | ||
|
|
80c03b49bf | ||
|
|
e7fbc86d58 | ||
|
|
85a4557369 | ||
|
|
7c0a9b8ff7 | ||
|
|
f2bc9e4dd1 | ||
|
|
f8b85dd65d | ||
|
|
bde10d2771 | ||
|
|
22c1468b5a | ||
|
|
01843cf9e7 |
No files matched your search
+34
-86
@@ -11,58 +11,36 @@ on:
|
||||
|
||||
jobs:
|
||||
mingw:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
target: [i686-w64-mingw32, x86_64-w64-mingw32]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Increase -N suffix here to force full rebuild after changes
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: mingw_prefix/
|
||||
key: "${{ matrix.target }}-6"
|
||||
key: "${{ matrix.target }}-1"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y autoconf automake pkg-config g++-mingw-w64 gcc-multilib meson nasm
|
||||
sudo apt-get install -y autoconf automake pkg-config g++-mingw-w64 gcc-multilib nasm yasm
|
||||
./bootstrap.py
|
||||
|
||||
- name: Build libraries
|
||||
- name: Build
|
||||
run: |
|
||||
./ci/build-mingw64.sh
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
- name: Build with meson
|
||||
run: |
|
||||
./ci/build-mingw64.sh meson
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
- name: Print meson log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/meson-logs/meson-log.txt
|
||||
|
||||
- name: Build with waf
|
||||
run: |
|
||||
./ci/build-mingw64.sh waf pack
|
||||
env:
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
- name: Print waf log
|
||||
- name: Print configure log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/config.log
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mpv-${{ matrix.target }}
|
||||
path: mpv-git-*.zip
|
||||
|
||||
macos:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -70,49 +48,46 @@ jobs:
|
||||
cc:
|
||||
- "clang"
|
||||
os:
|
||||
- "macos-10.15"
|
||||
- "macos-11"
|
||||
- "macos-12"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Remove stray upstream python binary symlinks under /usr/local
|
||||
- name: Override Xcode 13.0 if it's the default toolchain
|
||||
run: |
|
||||
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete -print
|
||||
brew unlink python && brew link --overwrite python
|
||||
XCODE_PATH="$(xcode-select -p)"
|
||||
case "${XCODE_PATH}" in
|
||||
*Xcode_13.0*)
|
||||
sudo xcode-select -s "/Applications/Xcode_13.1.app"
|
||||
echo "Updated Xcode path ${XCODE_PATH} -> $(xcode-select -p)"
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew update
|
||||
brew install autoconf automake pkg-config libtool python freetype fribidi little-cms2 lua@5.1 libass ffmpeg meson
|
||||
brew install autoconf automake pkg-config libtool python freetype fribidi little-cms2 luajit libass ffmpeg
|
||||
|
||||
- name: Build with meson
|
||||
- name: Build
|
||||
run: |
|
||||
./ci/build-macos.sh meson
|
||||
./ci/build-macos.sh
|
||||
env:
|
||||
CC: "${{ matrix.cc }}"
|
||||
TRAVIS_OS_NAME: "${{ matrix.os }}"
|
||||
|
||||
- name: Print meson log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/meson-logs/meson-log.txt
|
||||
|
||||
- name: Build with waf
|
||||
run: |
|
||||
./ci/build-macos.sh waf
|
||||
env:
|
||||
CC: "${{ matrix.cc }}"
|
||||
TRAVIS_OS_NAME: "${{ matrix.os }}"
|
||||
|
||||
- name: Print waf log
|
||||
- name: Print configure log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/config.log
|
||||
|
||||
linux:
|
||||
runs-on: "ubuntu-22.04"
|
||||
runs-on: "ubuntu-20.04"
|
||||
container:
|
||||
image: "registry.opensuse.org/home/mia/images/images/mpv-ci:stable-deps"
|
||||
image: "registry.cirno.systems/kiwi/containers/mpv-ci:stable-deps"
|
||||
# Disable seccomp until a container manager in GitHub recognizes
|
||||
# clone3() syscall,
|
||||
# <https://github.com/actions/virtual-environments/issues/3812>.
|
||||
options: --security-opt seccomp=unconfined
|
||||
env:
|
||||
CC: "${{ matrix.cc }}"
|
||||
strategy:
|
||||
@@ -121,57 +96,41 @@ jobs:
|
||||
- "gcc"
|
||||
- "clang"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
./bootstrap.py
|
||||
# workaround to avoid "fatal: unsafe repository" error
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
- name: Build with meson
|
||||
- name: Build
|
||||
run: |
|
||||
./ci/build-tumbleweed.sh meson
|
||||
./ci/build-tumbleweed.sh
|
||||
|
||||
- name: Print meson log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/meson-logs/meson-log.txt
|
||||
|
||||
- name: Build with waf
|
||||
run: |
|
||||
./ci/build-tumbleweed.sh waf
|
||||
|
||||
- name: Print waf log
|
||||
- name: Print configure log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/config.log
|
||||
|
||||
freebsd:
|
||||
runs-on: macos-12 # until https://github.com/actions/runner/issues/385
|
||||
runs-on: macos-10.15 # until https://github.com/actions/runner/issues/385
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test in FreeBSD VM
|
||||
uses: vmactions/freebsd-vm@v0
|
||||
uses: vmactions/freebsd-vm@v0.1.5 # aka FreeBSD 13.0
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
# Requested in ci/build-freebsd.sh
|
||||
pkg install -y \
|
||||
cmake \
|
||||
evdev-proto \
|
||||
ffmpeg \
|
||||
libplacebo \
|
||||
libxkbcommon \
|
||||
libXinerama \
|
||||
libxpresent \
|
||||
luajit \
|
||||
meson \
|
||||
openal-soft \
|
||||
pkgconf \
|
||||
python3 \
|
||||
sdl2 \
|
||||
sndio \
|
||||
vulkan-headers \
|
||||
wayland-protocols \
|
||||
#
|
||||
@@ -186,7 +145,6 @@ jobs:
|
||||
libcdio-paranoia \
|
||||
libdvdnav \
|
||||
mujs \
|
||||
pipewire \
|
||||
pulseaudio \
|
||||
rubberband \
|
||||
sekrit-twc-zimg \
|
||||
@@ -195,13 +153,3 @@ jobs:
|
||||
#
|
||||
run: |
|
||||
./ci/build-freebsd.sh
|
||||
|
||||
- name: Print meson log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/meson-logs/meson-log.txt
|
||||
|
||||
- name: Print waf log
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
cat ./build/config.log
|
||||
@@ -36,5 +36,3 @@
|
||||
|
||||
/old_build
|
||||
/Makefile
|
||||
|
||||
/subprojects
|
||||
@@ -1,70 +0,0 @@
|
||||
# Differences Between Meson and Waf
|
||||
|
||||
mpv currently supports two different build systems: waf and meson. In general,
|
||||
option names between both build systems are mostly the same. In most cases,
|
||||
``--enable-foo`` in waf becomes ``-Dfoo=enabled`` in meson. Likewise,
|
||||
``--disable-foo`` becomes ``-Dfoo=disabled``. For the rest of this document,
|
||||
Waf options will be noted as ``--foo`` while meson options are noted as
|
||||
``foo``.
|
||||
|
||||
## Universal Options
|
||||
|
||||
Meson has several [universal options](https://mesonbuild.com/Builtin-options.html#universal-options)
|
||||
that you get for free. In some cases, these overlapped with custom waf options.
|
||||
|
||||
* ``--libmpv-static`` and ``--libmpv-shared`` were combined into one option:
|
||||
``libmpv``. Use ``default_library`` to control if you want to build static or
|
||||
shared libraries.
|
||||
* Waf had a boolean ``--optimize`` option. In meson, this is a universal option,
|
||||
``optimization``, which can take several different values. In mpv's meson
|
||||
build, the default is ``2``.
|
||||
* Instead of ``--debug-build``, meson simply calls it ``debug``. It is enabled
|
||||
by default.
|
||||
|
||||
## Changed Options
|
||||
|
||||
* The legacy lua names (``52``, ``52deb``, etc.) for ``--lua`` are not
|
||||
supported in the meson build. Instead, pass the generic pkg-config values
|
||||
such as ``lua52``, ``lua5.2``, etc.
|
||||
* ``--lgpl`` was changed to ``gpl``. If ``gpl`` is false, the build is LGPL2.1+.
|
||||
|
||||
### Boolean Options
|
||||
|
||||
The following options are all booleans that accept ``true`` or ``false``
|
||||
instead of ``enabled`` or ``disabled``.
|
||||
|
||||
* ``build-date``
|
||||
* ``cplayer``
|
||||
* ``gpl``
|
||||
* ``libmpv``
|
||||
* ``ta-leak-report``
|
||||
* ``tests``
|
||||
|
||||
## Removed Options
|
||||
|
||||
There are options removed with no equivalent in the meson build.
|
||||
|
||||
* ``--asm`` was removed since it doesn't do anything.
|
||||
* ``--android`` was removed since meson knows if the machine is android.
|
||||
* ``--clang-compilation-database`` was removed. Meson can do this on its own
|
||||
by invoking ninja (``ninja -t compdb``).
|
||||
* ``--tvos`` was removed since it doesn't do anything.
|
||||
* ``--static-build`` was removed. Use ``default_library``.
|
||||
* ``--swift-static`` was removed. The swift library always dynamically links.
|
||||
|
||||
## Renamed Options
|
||||
|
||||
These are some other options that were renamed.
|
||||
|
||||
* ``--gl-wayland`` was renamed to ``egl-wayland``.
|
||||
* ``--swift`` was renamed to ``swift-build``.
|
||||
|
||||
## Other
|
||||
|
||||
* The meson build supports passing the ``SOURCE_DATE_EPOCH`` environment variable
|
||||
during the compilation step for those who want reproducibility without having to
|
||||
disable the build date.
|
||||
* The ``Configuration`` line shown by ``mpv -v`` does not show everything passed on
|
||||
cli since meson does not have any easy way to access a user's argv. Instead, it
|
||||
simply shows whatever the value of ``prefix`` is regardless if it was specified
|
||||
or not.
|
||||
@@ -32,13 +32,6 @@ API changes
|
||||
|
||||
::
|
||||
|
||||
--- mpv 0.35.0 ---
|
||||
2.0 - remove headers/functions of the obsolete opengl_cb API
|
||||
- remove mpv_opengl_init_params.extra_exts field
|
||||
- remove deprecated mpv_detach_destroy. Use mpv_destroy instead.
|
||||
- remove obsolete mpv_suspend and mpv_resume
|
||||
- remove deprecated SCRIPT_INPUT_DISPATCH, PAUSE and UNPAUSE, TRACKS_CHANGED
|
||||
TRACK_SWITCHED, METADATA_UPDATE, CHAPTER_CHANGE events
|
||||
--- mpv 0.33.0 ---
|
||||
1.109 - add MPV_RENDER_API_TYPE_SW and related (software rendering API)
|
||||
- inactivate the opengl_cb API (always fails to initialize now)
|
||||
@@ -61,6 +54,7 @@ API changes
|
||||
It is a good idea to write better wrappers for your use, though.
|
||||
--- mpv 0.31.0 ---
|
||||
1.107 - Deprecate MPV_EVENT_TICK
|
||||
|
||||
--- mpv 0.30.0 ---
|
||||
1.106 - Add cancel_fn to mpv_stream_cb_info
|
||||
1.105 - Fix deadlock problems with MPV_RENDER_PARAM_ADVANCED_CONTROL and if
|
||||
@@ -78,6 +72,7 @@ API changes
|
||||
- add mpv_abort_async_command()
|
||||
1.102 - rename struct mpv_opengl_drm_osd_size to mpv_opengl_drm_draw_surface_size
|
||||
- rename MPV_RENDER_PARAM_DRM_OSD_SIZE to MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE
|
||||
|
||||
--- mpv 0.29.0 ---
|
||||
1.101 - add MPV_RENDER_PARAM_ADVANCED_CONTROL and related API
|
||||
- add MPV_RENDER_PARAM_NEXT_FRAME_INFO and related symbols
|
||||
|
||||
+37
-37
@@ -3,26 +3,26 @@ General usage
|
||||
|
||||
::
|
||||
|
||||
mpv infile --o=outfile [--of=outfileformat] [--ofopts=formatoptions] [--orawts] \
|
||||
mpv infile -o outfile [-of outfileformat] [-ofopts formatoptions] [-orawts] \
|
||||
[(any other mpv options)] \
|
||||
--ovc=outvideocodec [--ovcopts=outvideocodecoptions] \
|
||||
--oac=outaudiocodec [--oacopts=outaudiocodecoptions]
|
||||
-ovc outvideocodec [-ovcopts outvideocodecoptions] \
|
||||
-oac outaudiocodec [-oacopts outaudiocodecoptions]
|
||||
|
||||
Help for these options is provided if giving help as parameter, as in::
|
||||
|
||||
mpv --ovc=help
|
||||
mpv -ovc help
|
||||
|
||||
The suboptions of these generally are identical to ffmpeg's (as option parsing
|
||||
is simply delegated to ffmpeg). The option --ocopyts enables copying timestamps
|
||||
is simply delegated to ffmpeg). The option -ocopyts enables copying timestamps
|
||||
from the source as-is, instead of fixing them to match audio playback time
|
||||
(note: this doesn't work with all output container formats); --orawts even turns
|
||||
(note: this doesn't work with all output container formats); -orawts even turns
|
||||
off discontinuity fixing.
|
||||
|
||||
Note that if neither --ofps nor --oautofps is specified, VFR encoding is assumed
|
||||
and the time base is 24000fps. --oautofps sets --ofps to a guessed fps number
|
||||
Note that if neither -ofps nor -oautofps is specified, VFR encoding is assumed
|
||||
and the time base is 24000fps. -oautofps sets -ofps to a guessed fps number
|
||||
from the input video. Note that not all codecs and not all formats support VFR
|
||||
encoding, and some which do have bugs when a target bitrate is specified - use
|
||||
--ofps or --oautofps to force CFR encoding in these cases.
|
||||
-ofps or -oautofps to force CFR encoding in these cases.
|
||||
|
||||
Of course, the options can be stored in a profile, like this .config/mpv/mpv.conf
|
||||
section::
|
||||
@@ -48,7 +48,7 @@ to encoding. This is not the case anymore.)
|
||||
|
||||
One can then encode using this profile using the command::
|
||||
|
||||
mpv infile --o=outfile.mp4 --profile=myencprofile
|
||||
mpv infile -o outfile.mp4 -profile myencprofile
|
||||
|
||||
Some example profiles are provided in a file
|
||||
etc/encoding-profiles.conf; as for this, see below.
|
||||
@@ -62,10 +62,10 @@ for.
|
||||
|
||||
Typical MPEG-4 Part 2 ("ASP", "DivX") encoding, AVI container::
|
||||
|
||||
mpv infile --o=outfile.avi \
|
||||
mpv infile -o outfile.avi \
|
||||
--vf=fps=25 \
|
||||
--ovc=mpeg4 --ovcopts=qscale=4 \
|
||||
--oac=libmp3lame --oacopts=b=128k
|
||||
-ovc mpeg4 -ovcopts qscale=4 \
|
||||
-oac libmp3lame -oacopts ab=128k
|
||||
|
||||
Note: AVI does not support variable frame rate, so the fps filter must be used.
|
||||
The frame rate should ideally match the input (25 for PAL, 24000/1001 or
|
||||
@@ -73,22 +73,22 @@ The frame rate should ideally match the input (25 for PAL, 24000/1001 or
|
||||
|
||||
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container::
|
||||
|
||||
mpv infile --o=outfile.mkv \
|
||||
--ovc=libx264 --ovcopts=preset=medium,crf=23,profile=baseline \
|
||||
--oac=libopus --oacopts=qscale=3
|
||||
mpv infile -o outfile.mkv \
|
||||
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
|
||||
-oac libvorbis -oacopts qscale=3
|
||||
|
||||
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, MPEG-4 (MP4) container::
|
||||
|
||||
mpv infile --o=outfile.mp4 \
|
||||
--ovc=libx264 --ovcopts=preset=medium,crf=23,profile=baseline \
|
||||
--oac=aac --oacopts=b=128k
|
||||
mpv infile -o outfile.mp4 \
|
||||
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
|
||||
-oac aac -oacopts ab=128k
|
||||
|
||||
Typical VP8 encoding, WebM (restricted Matroska) container::
|
||||
|
||||
mpv infile -o outfile.mkv \
|
||||
--of=webm \
|
||||
--ovc=libvpx --ovcopts=qmin=6,b=1000000k \
|
||||
--oac=libopus --oacopts=qscale=3
|
||||
-of webm \
|
||||
-ovc libvpx -ovcopts qmin=6,b=1000000k \
|
||||
-oac libvorbis -oacopts qscale=3
|
||||
|
||||
|
||||
Device targets
|
||||
@@ -111,18 +111,18 @@ section.
|
||||
Refer to the top of that file for more comments - in a nutshell, the following
|
||||
options are added by it::
|
||||
|
||||
--profile=enc-to-dvdpal # DVD-Video PAL, use dvdauthor -v pal+4:3 -a ac3+en
|
||||
--profile=enc-to-dvdntsc # DVD-Video NTSC, use dvdauthor -v ntsc+4:3 -a ac3+en
|
||||
--profile=enc-to-bb-9000 # MP4 for Blackberry Bold 9000
|
||||
--profile=enc-to-nok-6300 # 3GP for Nokia 6300
|
||||
--profile=enc-to-psp # MP4 for PlayStation Portable
|
||||
--profile=enc-to-iphone # MP4 for iPhone
|
||||
--profile=enc-to-iphone-4 # MP4 for iPhone 4 (double res)
|
||||
--profile=enc-to-iphone-5 # MP4 for iPhone 5 (even larger res)
|
||||
-profile enc-to-dvdpal DVD-Video PAL, use dvdauthor -v pal+4:3 -a ac3+en
|
||||
-profile enc-to-dvdntsc DVD-Video NTSC, use dvdauthor -v ntsc+4:3 -a ac3+en
|
||||
-profile enc-to-bb-9000 MP4 for Blackberry Bold 9000
|
||||
-profile enc-to-nok-6300 3GP for Nokia 6300
|
||||
-profile enc-to-psp MP4 for PlayStation Portable
|
||||
-profile enc-to-iphone MP4 for iPhone
|
||||
-profile enc-to-iphone-4 MP4 for iPhone 4 (double res)
|
||||
-profile enc-to-iphone-5 MP4 for iPhone 5 (even larger res)
|
||||
|
||||
You can encode using these with a command line like::
|
||||
|
||||
mpv infile --o=outfile.mp4 --profile=enc-to-bb-9000
|
||||
mpv infile -o outfile.mp4 -profile enc-to-bb-9000
|
||||
|
||||
Of course, you are free to override options set by these profiles by specifying
|
||||
them after the -profile option.
|
||||
@@ -133,19 +133,19 @@ What works
|
||||
|
||||
* Encoding at variable frame rate (default)
|
||||
* Encoding at constant frame rate using --vf=fps=RATE
|
||||
* 2-pass encoding (specify flags=+pass1 in the first pass's --ovcopts, specify
|
||||
* 2-pass encoding (specify flags=+pass1 in the first pass's -ovcopts, specify
|
||||
flags=+pass2 in the second pass)
|
||||
* Hardcoding subtitles using vobsub, ass or srt subtitle rendering (just
|
||||
configure mpv for the subtitles as usual)
|
||||
* Hardcoding any other mpv OSD (e.g. time codes, using --osdlevel=3 and
|
||||
--vf=expand=::::1)
|
||||
* Hardcoding any other mpv OSD (e.g. time codes, using -osdlevel 3 and -vf
|
||||
expand=::::1)
|
||||
* Encoding directly from a DVD, network stream, webcam, or any other source
|
||||
mpv supports
|
||||
* Using x264 presets/tunings/profiles (by using profile=, tune=, preset= in the
|
||||
--ovcopts)
|
||||
-ovcopts)
|
||||
* Deinterlacing/Inverse Telecine with any of mpv's filters for that
|
||||
* Audio file converting: mpv --o=outfile.m4a infile.flac --no-video
|
||||
--oac=aac --oacopts=b=320k
|
||||
* Audio file converting: mpv -o outfile.mp3 infile.flac -no-video -oac
|
||||
libmp3lame -oacopts ab=320k
|
||||
|
||||
What does not work yet
|
||||
======================
|
||||
|
||||
@@ -26,33 +26,6 @@ Interface changes
|
||||
|
||||
::
|
||||
|
||||
=======
|
||||
--- mpv 0.35.1 --- (feature backport due to special circumstances)
|
||||
- add `--vd-lavc-dr=auto` and make it the default
|
||||
--- mpv 0.35.0 ---
|
||||
- add the `--vo=gpu-next` video output driver, as well as the options
|
||||
`--allow-delayed-peak-detect`, `--builtin-scalers`,
|
||||
`--interpolation-preserve` `--lut`, `--lut-type`, `--image-lut`,
|
||||
`--image-lut-type` and `--target-lut` along with it.
|
||||
- add `--target-colorspace-hint`
|
||||
- add `--tone-mapping-crosstalk`
|
||||
- add `--tone-mapping` options `auto`, `spline` and `bt.2446a`
|
||||
- add `--inverse-tone-mapping`
|
||||
- add `--gamut-mapping-mode`, replacing `--gamut-clipping` and `--gamut-warning`
|
||||
- add `--tone-mapping-mode`, replacing `--tone-mapping-desaturate` and
|
||||
`--tone-mapping-desaturate-exponent`.
|
||||
- add `dolbyvision` sub-parameter to `format` video filter
|
||||
- `--sub-visibility` no longer has any effect on secondary subtitles
|
||||
- add `film-grain` sub-parameter to `format` video filter
|
||||
- add experimental `--vo=dmabuf-wayland` video output driver
|
||||
- add `--x11-present` for controlling whether to use xorg's present extension
|
||||
- add `engine` option to the `rubberband` audio filter to support the new
|
||||
engine introduced in rubberband 3.0.0. Defaults to `finer` (new engine).
|
||||
- add `--wayland-configure-bounds` option
|
||||
- deprecate `--gamma-factor`
|
||||
- deprecate `--gamma-auto`
|
||||
- remove `--vulkan-disable-events`
|
||||
- add `--glsl-shader-opts`
|
||||
--- mpv 0.34.0 ---
|
||||
- deprecate selecting by card number with `--drm-connector`, add
|
||||
`--drm-device` which can be used instead
|
||||
|
||||
+4
-4
@@ -161,14 +161,14 @@ Available filters are:
|
||||
Would play media at 1.2x normal speed, with audio at normal pitch.
|
||||
Changing playback speed would change pitch, leaving audio tempo at
|
||||
1.2x.
|
||||
|
||||
|
||||
``scaletempo2[=option1:option2:...]``
|
||||
Scales audio tempo without altering pitch.
|
||||
The algorithm is ported from chromium and uses the
|
||||
The algorithm is ported from chromium and uses the
|
||||
Waveform Similarity Overlap-and-add (WSOLA) method.
|
||||
It seems to achieve a higher audio quality than scaletempo and rubberband.
|
||||
|
||||
By default, the ``search-interval`` and ``window-size`` parameters
|
||||
By default, the ``search-interval`` and ``window-size`` parameters
|
||||
have the same values as in chromium.
|
||||
|
||||
``min-speed=<speed>``
|
||||
@@ -180,7 +180,7 @@ Available filters are:
|
||||
|
||||
``search-interval=<amount>``
|
||||
Length in milliseconds to search for best overlap position. (default: 30)
|
||||
|
||||
|
||||
``window-size=<amount>``
|
||||
Length in milliseconds of the overlap-and-add window. (default: 20)
|
||||
|
||||
|
||||
+5
-26
@@ -30,8 +30,7 @@ Available audio output drivers are:
|
||||
explicitly reject multichannel output, as there is no way to detect
|
||||
whether a certain channel layout is actually supported.
|
||||
|
||||
You can also try `using the upmix plugin
|
||||
<https://github.com/mpv-player/mpv/wiki/ALSA-Surround-Sound-and-Upmixing>`_.
|
||||
You can also try `using the upmix plugin <http://git.io/vfuAy>`_.
|
||||
This setup enables multichannel audio on the ``default`` device
|
||||
with automatic upmixing with shared access, so playing stereo
|
||||
and multichannel audio at the same time will work as expected.
|
||||
@@ -101,7 +100,7 @@ Available audio output drivers are:
|
||||
exclusive mode (bypasses the sound server).
|
||||
|
||||
``openal``
|
||||
OpenAL audio output driver.
|
||||
OpenAL audio output driver. This is broken and does not work.
|
||||
|
||||
``--openal-num-buffers=<2-128>``
|
||||
Specify the number of audio buffers to use. Lower values are better for
|
||||
@@ -113,7 +112,9 @@ Available audio output drivers are:
|
||||
|
||||
``--openal-direct-channels=<yes|no>``
|
||||
Enable OpenAL Soft's direct channel extension when available to avoid
|
||||
tinting the sound with ambisonics or HRTF. Default: yes.
|
||||
tinting the sound with ambisonics or HRTF.
|
||||
Channels are dropped when when they are not available as downmixing
|
||||
will be disabled. Default: no.
|
||||
|
||||
``pulse``
|
||||
PulseAudio audio output driver
|
||||
@@ -145,22 +146,6 @@ Available audio output drivers are:
|
||||
Allow mpv to use PulseAudio even if the sink is suspended (default: no).
|
||||
Can be useful if PulseAudio is running as a bridge to jack and mpv has its sink-input set to the one jack is using.
|
||||
|
||||
``pipewire``
|
||||
PipeWire audio output driver
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--pipewire-buffer=<1-2000|native>``
|
||||
Set the audio buffer size in milliseconds. A higher value buffers
|
||||
more data, and has a lower probability of buffer underruns. A smaller
|
||||
value makes the audio stream react faster, e.g. to playback speed
|
||||
changes.
|
||||
|
||||
``--pipewire-remote=<remote>``
|
||||
Specify the PipeWire remote daemon name to connect to via local UNIX
|
||||
sockets.
|
||||
An empty <remote> string uses the default remote named ``pipewire-0``.
|
||||
|
||||
``sdl``
|
||||
SDL 1.2+ audio output driver. Should work on any platform supported by SDL
|
||||
1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
|
||||
@@ -234,11 +219,5 @@ Available audio output drivers are:
|
||||
``no-waveheader`` option - with ``waveheader`` it's broken, because
|
||||
it will write a WAVE header every time the file is opened.
|
||||
|
||||
``sndio``
|
||||
Audio output to the OpenBSD sndio sound system
|
||||
|
||||
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
|
||||
layouts.)
|
||||
|
||||
``wasapi``
|
||||
Audio output to the Windows Audio Session API.
|
||||
@@ -142,9 +142,4 @@ Configurable Options
|
||||
Default: 16
|
||||
|
||||
Set the font size used for the REPL and the console. This will be
|
||||
multiplied by "scale".
|
||||
|
||||
``history_dedup``
|
||||
Default: true
|
||||
|
||||
Remove duplicate entries in history as to only keep the latest one.
|
||||
multiplied by "scale."
|
||||
+28
-35
@@ -431,7 +431,7 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
Playback is stopped. If idle mode (``--idle``) is enabled, the player
|
||||
will enter idle mode, otherwise it will exit.
|
||||
|
||||
This command is similar to ``loadfile`` in that it only manipulates the
|
||||
This comm and is similar to ``loadfile`` in that it only manipulates the
|
||||
state of what to play next, without waiting until the current file is
|
||||
unloaded, and the next one is loaded.
|
||||
|
||||
@@ -551,9 +551,9 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
|
||||
``playback_only`` (``MPV_FORMAT_FLAG``)
|
||||
Boolean indicating whether the process should be killed when playback
|
||||
of the current playlist entry terminates (optional, default: true). If
|
||||
enabled, stopping playback will automatically kill the process, and you
|
||||
can't start it outside of playback.
|
||||
terminates (optional, default: true). If enabled, stopping playback
|
||||
will automatically kill the process, and you can't start it outside of
|
||||
playback.
|
||||
|
||||
``capture_size`` (``MPV_FORMAT_INT64``)
|
||||
Integer setting the maximum number of stdout plus stderr bytes that can
|
||||
@@ -581,7 +581,7 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
instead. (Unlike the underlying OS mechanisms, the mpv command cannot
|
||||
start a process with empty environment. Fortunately, that is completely
|
||||
useless.) The format of the list is as in the ``execle()`` syscall. Each
|
||||
string item defines an environment variable as in ``NAME=VALUE``.
|
||||
string item defines an environment variable as in ``NANME=VALUE``.
|
||||
|
||||
On Lua, you may use ``utils.get_env_list()`` to retrieve the current
|
||||
environment if you e.g. simply want to add a new variable.
|
||||
@@ -600,14 +600,12 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
The command returns the following result (as ``MPV_FORMAT_NODE_MAP``):
|
||||
|
||||
``status`` (``MPV_FORMAT_INT64``)
|
||||
Typically this is the process exit code (0 or positive) if the process
|
||||
terminates normally, or negative for other errors (failed to start,
|
||||
terminated by mpv, and others). The meaning of negative values is
|
||||
undefined, other than meaning error (and does not correspond to OS low
|
||||
level exit status values).
|
||||
The raw exit status of the process. It will be negative on error. The
|
||||
meaning of negative values is undefined, other than meaning error (and
|
||||
does not correspond to OS low level exit status values).
|
||||
|
||||
On Windows, it can happen that a negative return value is returned even
|
||||
if the process terminates normally, because the win32 ``UINT`` exit
|
||||
On Windows, it can happen that a negative return value is returned
|
||||
even if the process exits gracefully, because the win32 ``UINT`` exit
|
||||
code is assigned to an ``int`` variable before being set as ``int64_t``
|
||||
field in the result map. This might be fixed later.
|
||||
|
||||
@@ -618,9 +616,9 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
Same as ``stdout``, but for stderr.
|
||||
|
||||
``error_string`` (``MPV_FORMAT_STRING``)
|
||||
Empty string if the process terminated normally. The string ``killed``
|
||||
if the process was terminated in an unusual way. The string ``init`` if
|
||||
the process could not be started.
|
||||
Empty string if the process exited gracefully. The string ``killed`` if
|
||||
the process was terminated in an unusual way. The string ``init`` if the
|
||||
process could not be started.
|
||||
|
||||
On Windows, ``killed`` is only returned when the process has been
|
||||
killed by mpv as a result of ``playback_only`` being set to true.
|
||||
@@ -635,19 +633,17 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
it was somehow killed or returned an error status has to be queried from
|
||||
the result value.
|
||||
|
||||
This command can be asynchronously aborted via API. Also see `Asynchronous
|
||||
command details`_. Only the ``run`` command can start processes in a truly
|
||||
detached way.
|
||||
This command can be asynchronously aborted via API.
|
||||
|
||||
.. note:: The subprocess will always be terminated on player exit if it
|
||||
wasn't started in detached mode, even if ``playback_only`` is
|
||||
false.
|
||||
In all cases, the subprocess will be terminated on player exit. Also see
|
||||
`Asynchronous command details`_. Only the ``run`` command can start
|
||||
processes in a truly detached way.
|
||||
|
||||
.. admonition:: Warning
|
||||
|
||||
Don't forget to set the ``playback_only`` field to false if you want
|
||||
the command to run while the player is in idle mode, or if you don't
|
||||
want the end of playback to kill the command.
|
||||
Don't forget to set the ``playback_only`` field if you want the command
|
||||
run while the player is in idle mode, or if you don't want that end of
|
||||
playback kills the command.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
@@ -672,7 +668,7 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
|
||||
``quit-watch-later [<code>]``
|
||||
Exit player, and store current playback position. Playing that file later
|
||||
will seek to the previous position on start. The (optional) argument is
|
||||
exactly as in the ``quit`` command. See `RESUMING PLAYBACK`_.
|
||||
exactly as in the ``quit`` command.
|
||||
|
||||
``sub-add <url> [<flags> [<title> [<lang>]]]``
|
||||
Load the given subtitle file or stream. By default, it is selected as
|
||||
@@ -1604,8 +1600,10 @@ This list uses the event name field value, and the C API symbol in brackets:
|
||||
``data``
|
||||
The new value of the property.
|
||||
|
||||
The following events also happen, but are deprecated: ``idle``, ``tick``
|
||||
Use ``mpv_observe_property()`` (Lua: ``mp.observe_property()``) instead.
|
||||
The following events also happen, but are deprecated: ``tracks-changed``,
|
||||
``track-switched``, ``pause``, ``unpause``, ``metadata-update``, ``idle``,
|
||||
``tick``, ``chapter-change``. Use ``mpv_observe_property()``
|
||||
(Lua: ``mp.observe_property()``) instead.
|
||||
|
||||
Hooks
|
||||
~~~~~
|
||||
@@ -1819,7 +1817,7 @@ Property list
|
||||
|
||||
.. note::
|
||||
|
||||
Most options can be set at runtime via properties as well. Just remove the
|
||||
Most options can be set as runtime via properties as well. Just remove the
|
||||
leading ``--`` from the option name. These are not documented below, see
|
||||
`OPTIONS`_ instead. Only properties which do not exist as option with the
|
||||
same name, or which have very different behavior from the options are
|
||||
@@ -2981,7 +2979,7 @@ Property list
|
||||
If tracks of the requested type are selected via ``--lavfi-complex``, the
|
||||
first one is returned.
|
||||
|
||||
``chapter-list`` (RW)
|
||||
``chapter-list``
|
||||
List of chapters, current entry marked. Currently, the raw property value
|
||||
is useless.
|
||||
|
||||
@@ -3072,8 +3070,7 @@ Property list
|
||||
processed for C escape sequences before passing it to the OSD code. See
|
||||
`Flat command syntax`_ for details.
|
||||
|
||||
A list of tags can be found here:
|
||||
https://aeg-dev.github.io/AegiSite/docs/3.2/ass_tags/
|
||||
A list of tags can be found here: http://docs.aegisub.org/latest/ASS_Tags/
|
||||
|
||||
``vo-configured``
|
||||
Whether the VO is configured right now. Usually this corresponds to whether
|
||||
@@ -3390,10 +3387,6 @@ Property list
|
||||
not a map, as order matters and duplicate entries are possible. Recursive
|
||||
profiles are not expanded, and show up as special ``profile`` options.
|
||||
|
||||
The ``profile-restore`` field is currently missing if it holds the default
|
||||
value (either because it was not set, or set explicitly to ``default``),
|
||||
but in the future it might hold the value ``default``.
|
||||
|
||||
``command-list``
|
||||
The list of input commands. This returns an array of maps, where each map
|
||||
node represents a command. This map currently only has a single entry:
|
||||
|
||||
+10
-4
@@ -73,6 +73,12 @@ Unsupported Lua APIs and their JS alternatives
|
||||
|
||||
``utils.to_string(v)`` see ``dump`` below.
|
||||
|
||||
``mp.suspend()`` JS: none (deprecated).
|
||||
|
||||
``mp.resume()`` JS: none (deprecated).
|
||||
|
||||
``mp.resume_all()`` JS: none (deprecated).
|
||||
|
||||
``mp.get_next_timeout()`` see event loop below.
|
||||
|
||||
``mp.dispatch_events([allow_wait])`` see event loop below.
|
||||
@@ -91,7 +97,7 @@ Where the Lua APIs use ``nil`` to indicate error, JS APIs use ``undefined``.
|
||||
``mp.command_native(table [,def])`` (LE)
|
||||
|
||||
``id = mp.command_native_async(table [,fn])`` (LE) Notes: ``id`` is true-thy on
|
||||
success, ``error`` is empty string on success.
|
||||
success, ``fn`` is called always a-sync, ``error`` is empty string on success.
|
||||
|
||||
``mp.abort_async_command(id)``
|
||||
|
||||
@@ -215,9 +221,9 @@ Additional utilities
|
||||
``undefined`` if the variable is not defined.
|
||||
|
||||
``mp.utils.get_user_path(path)``
|
||||
Trivial wrapper of the ``expand-path`` mpv command, returns a string.
|
||||
``read_file``, ``write_file``, ``append_file`` and ``require`` already
|
||||
expand the path internally and accept mpv meta-paths like ``~~desktop/foo``.
|
||||
Expands (mpv) meta paths like ``~/x``, ``~~/y``, ``~~desktop/z`` etc.
|
||||
``read_file``, ``write_file``, ``append_file`` and ``require`` already use
|
||||
this internally.
|
||||
|
||||
``mp.utils.read_file(fname [,max])``
|
||||
Returns the content of file ``fname`` as string. If ``max`` is provided and
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ Linkage to libmpv
|
||||
-----------------
|
||||
|
||||
The current implementation requires that your plugins are **not** linked against
|
||||
libmpv. What your plugins use are not symbols from a libmpv binary, but
|
||||
libmpv. What your plugins uses are not symbols from a libmpv binary, but
|
||||
symbols from the mpv host binary.
|
||||
|
||||
Examples
|
||||
|
||||
+12
-2
@@ -191,8 +191,6 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
If starting the command failed for some reason, ``nil, error`` is returned,
|
||||
and ``fn`` is called indicating failure, using the same error value.
|
||||
|
||||
``fn`` is always called asynchronously, even if the command failed to start.
|
||||
|
||||
``mp.abort_async_command(t)``
|
||||
Abort a ``mp.command_native_async`` call. The argument is the return value
|
||||
of that command (which starts asynchronous execution of the command).
|
||||
@@ -529,6 +527,18 @@ Advanced mp functions
|
||||
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 and does nothing starting
|
||||
with mpv 0.23.0 (no replacement).
|
||||
|
||||
``mp.resume()``
|
||||
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 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
|
||||
pipe. This is deprecated, but still works. (See ``client.h`` for details.)
|
||||
|
||||
+36
-50
@@ -39,12 +39,9 @@ LIRC support - configure remotes as input devices instead).
|
||||
|
||||
See the ``--input-`` options for ways to customize it.
|
||||
|
||||
The following listings are not necessarily complete. See ``etc/input.conf``
|
||||
in the mpv source files for a list of default bindings. User ``input.conf``
|
||||
files and Lua scripts can define additional key bindings.
|
||||
|
||||
See `COMMAND INTERFACE`_ and `Key names`_ sections for more details on
|
||||
configuring keybindings.
|
||||
The following listings are not necessarily complete. See ``etc/input.conf`` for
|
||||
a list of default bindings. User ``input.conf`` files and Lua scripts can
|
||||
define additional key bindings.
|
||||
|
||||
See also ``--input-test`` for interactive binding details by key, and the
|
||||
`stats`_ built-in script for key bindings list (including print to terminal).
|
||||
@@ -110,8 +107,7 @@ q
|
||||
|
||||
Q
|
||||
Like ``q``, but store the current playback position. Playing the same file
|
||||
later will resume at the old playback position if possible. See
|
||||
`RESUMING PLAYBACK`_.
|
||||
later will resume at the old playback position if possible.
|
||||
|
||||
/ and *
|
||||
Decrease/increase volume.
|
||||
@@ -128,9 +124,6 @@ m
|
||||
\#
|
||||
Cycle through the available audio tracks.
|
||||
|
||||
E
|
||||
Cycle through the available Editions.
|
||||
|
||||
f
|
||||
Toggle fullscreen (see also ``--fs``).
|
||||
|
||||
@@ -774,7 +767,7 @@ the following options:
|
||||
|
||||
[something]
|
||||
profile-restore=copy-equal
|
||||
vf-add=rotate=PI/2 # rotate by 90 degrees
|
||||
vf-add=rotate=90
|
||||
|
||||
Then running these commands will result in behavior as commented:
|
||||
|
||||
@@ -782,9 +775,9 @@ the following options:
|
||||
|
||||
set vf vflip
|
||||
apply-profile something
|
||||
vf add hflip
|
||||
vf-add=hflip
|
||||
apply-profile something
|
||||
# vf == vflip,rotate=PI/2,hflip,rotate=PI/2
|
||||
# vf == vflip,rotate=90,hflip,rotate=90
|
||||
apply-profile something restore
|
||||
# vf == vflip
|
||||
|
||||
@@ -848,7 +841,7 @@ and unintuitive behavior.
|
||||
profile-desc=Mess up video when entering fullscreen
|
||||
profile-cond=fullscreen
|
||||
profile-restore=copy
|
||||
vf-add=rotate=PI/2 # rotate by 90 degrees
|
||||
vf-add=rotate=90
|
||||
|
||||
This appends the ``rotate`` filter to the video filter chain when entering
|
||||
fullscreen. When leaving fullscreen, the ``vf`` option is set to the value
|
||||
@@ -861,7 +854,7 @@ and unintuitive behavior.
|
||||
|
||||
[something]
|
||||
profile-cond=fullscreen
|
||||
vf-add=@rot:rotate=PI/2
|
||||
vf-add=@rot:rotate=90
|
||||
|
||||
[something-inv]
|
||||
profile-cond=not fullscreen
|
||||
@@ -1095,33 +1088,6 @@ Additional options that can be tried:
|
||||
- without audio ``--framedrop=no --speed=1.01`` may help for live sources
|
||||
(results can be mixed)
|
||||
|
||||
RESUMING PLAYBACK
|
||||
=================
|
||||
|
||||
mpv is capable of storing the playback position of the currently playing file
|
||||
and resume from there the next time that file is played. This is done with the
|
||||
commands ``quit-watch-later`` (bound to Shift+Q by default) and
|
||||
``write-watch-later-config``, and with the ``--save-position-on-quit`` option.
|
||||
|
||||
The difference between always quitting with a key bound to ``quit-watch-later``
|
||||
and using ``--save-position-on-quit`` is that the latter will save the playback
|
||||
position even when mpv is closed with a method other than a keybinding, for
|
||||
example if you shutdown your system without closing mpv beforehand, unless of
|
||||
course mpv is terminated abruptly and doesn't have the time to save (e.g. with
|
||||
the KILL Unix signal).
|
||||
|
||||
mpv also stores options other than the playback position when they have been
|
||||
modified after playback began, for example the volume and the fullscreen state,
|
||||
and restores their values the next time the file is played. Which options are
|
||||
saved can be configured with the ``--watch-later-options`` option.
|
||||
|
||||
When playing multiple playlist entries, mpv checks if one them has a resume
|
||||
config file associated, and if it finds one it restarts playback from it. For
|
||||
example, if you use ``quit-watch-later`` on the 5th episode of a show, and
|
||||
later play all the episodes, mpv will automatically resume playback from
|
||||
episode 5.
|
||||
|
||||
More options to configure this functionality are listed in `Watch Later`_.
|
||||
|
||||
PROTOCOLS
|
||||
=========
|
||||
@@ -1355,16 +1321,36 @@ a VO using the OS GUI API is active). ``--stop-screensaver=no`` disables this.
|
||||
|
||||
A common problem is that Linux desktop environments ignore the standard
|
||||
screensaver APIs on which mpv relies. In particular, mpv uses the Screen Saver
|
||||
extension (XSS) on X11, and the idle-inhibit protocol on Wayland.
|
||||
extension (XSS) on X11, and the idle-inhibit on Wayland.
|
||||
|
||||
GNOME in particular still ignores the idle-inhibit protocol, and has its own
|
||||
D-Bus interfaces for display power management, which mpv does not support.
|
||||
GNOME is one of the worst offenders, and ignores even the now widely supported
|
||||
idle-inhibit protocol. (This is either due to a combination of malice and
|
||||
incompetence, but since implementing this protocol would only take a few lines
|
||||
of code, it is most likely the former. You will also notice how GNOME advocates
|
||||
react offended whenever their sabotage is pointed out, which indicates either
|
||||
hypocrisy, or even worse ignorance.)
|
||||
|
||||
Such incompatible desktop environments (i.e. which ignore standards) typically
|
||||
require using a DBus API. This is ridiculous in several ways. The immediate
|
||||
practical problem is that it would require adding a quite unwieldy dependency
|
||||
for a DBus library, somehow integrating its mainloop into mpv, and other
|
||||
generally unacceptable things.
|
||||
|
||||
However, since mpv does not officially support GNOME, this is not much of a
|
||||
problem. If you are one of those miserable users who want to use mpv on GNOME,
|
||||
report a bug on the GNOME issue tracker:
|
||||
https://gitlab.gnome.org/groups/GNOME/-/issues
|
||||
|
||||
Alternatively, you may be able to write a Lua script that calls the
|
||||
``xdg-screensaver`` command line program. (By the way, this a command line
|
||||
program is an utterly horrible kludge that tries to identify your DE, and then
|
||||
tries to send the correct DBus command via a DBus CLI tool.) If you find the
|
||||
idea of having to write a script just so your screensaver doesn't kick in
|
||||
ridiculous, do not use GNOME, or use GNOME video software instead of mpv (good
|
||||
luck).
|
||||
|
||||
Before mpv 0.33.0, the X11 backend ran ``xdg-screensaver reset`` in 10 second
|
||||
intervals when not paused in order to support screensaver inhibition in these
|
||||
environments. This functionality was removed in 0.33.0, but it is possible to
|
||||
call the ``xdg-screensaver`` command line program from a user script instead.
|
||||
|
||||
intervals when not paused. This hack was removed in 0.33.0.
|
||||
|
||||
.. include:: options.rst
|
||||
|
||||
|
||||
+222
-387
@@ -298,10 +298,10 @@ Playback Control
|
||||
:no: Never use precise seeks.
|
||||
:absolute: Use precise seeks if the seek is to an absolute position in the
|
||||
file, such as a chapter seek, but not for relative seeks like
|
||||
the default behavior of arrow keys.
|
||||
the default behavior of arrow keys (default).
|
||||
:default: Like ``absolute``, but enable hr-seeks in audio-only cases. The
|
||||
exact behavior is implementation specific and may change with
|
||||
new releases (default).
|
||||
new releases.
|
||||
:yes: Use precise seeks whenever possible.
|
||||
:always: Same as ``yes`` (for compatibility).
|
||||
|
||||
@@ -746,6 +746,23 @@ Program Behavior
|
||||
|
||||
Note that the ``--no-config`` option takes precedence over this option.
|
||||
|
||||
``--save-position-on-quit``
|
||||
Always save the current playback position on quit. When this file is
|
||||
played again later, the player will seek to the old playback position on
|
||||
start. This does not happen if playback of a file is stopped in any other
|
||||
way than quitting. For example, going to the next file in the playlist
|
||||
will not save the position, and start playback at beginning the next time
|
||||
the file is played.
|
||||
|
||||
This behavior is disabled by default, but is always available when quitting
|
||||
the player with Shift+Q.
|
||||
|
||||
``--watch-later-directory=<path>``
|
||||
The directory in which to store the "watch later" temporary files.
|
||||
|
||||
The default is a subdirectory named "watch_later" underneath the
|
||||
config directory (usually ``~/.config/mpv/``).
|
||||
|
||||
``--dump-stats=<filename>``
|
||||
Write certain statistics to the given file. The file is truncated on
|
||||
opening. The file will contain raw samples, each with a timestamp. To
|
||||
@@ -787,6 +804,18 @@ Program Behavior
|
||||
Pretend that all files passed to mpv are concatenated into a single, big
|
||||
file. This uses timeline/EDL support internally.
|
||||
|
||||
``--no-resume-playback``
|
||||
Do not restore playback position from the ``watch_later`` configuration
|
||||
subdirectory (usually ``~/.config/mpv/watch_later/``).
|
||||
See ``quit-watch-later`` input command.
|
||||
|
||||
``--resume-playback-check-mtime``
|
||||
Only restore the playback position from the ``watch_later`` configuration
|
||||
subdirectory (usually ``~/.config/mpv/watch_later/``) if the file's
|
||||
modification time is the same as at the time of saving. This may prevent
|
||||
skipping forward in files with the same name which have different content.
|
||||
(Default: ``no``)
|
||||
|
||||
``--profile=<profile1,profile2,...>``
|
||||
Use the given profile(s), ``--profile=help`` displays a list of the
|
||||
defined profiles.
|
||||
@@ -822,6 +851,42 @@ Program Behavior
|
||||
- ``--reset-on-next-file=all``
|
||||
Try to reset all settings that were changed during playback.
|
||||
|
||||
``--watch-later-options=option1,option2,...``
|
||||
The options that are saved in "watch later" files if they have been changed
|
||||
since when mpv started. These values will be restored the next time the
|
||||
files are played. The playback position is always saved as ``start``, so
|
||||
adding ``start`` to this list has no effect.
|
||||
|
||||
When removing options, existing watch later data won't be modified and will
|
||||
still be applied fully, but new watch later data won't contain these
|
||||
options.
|
||||
|
||||
This is a string list option. See `List Options`_ for details.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
- ``--watch-later-options-remove=fullscreen``
|
||||
The fullscreen state won't be saved to watch later files.
|
||||
- ``--watch-later-options-remove=volume``
|
||||
``--watch-later-options-remove=mute``
|
||||
The volume and mute state won't be saved to watch later files.
|
||||
- ``--watch-later-options-clr``
|
||||
No option will be saved to watch later files except the starting
|
||||
position.
|
||||
|
||||
``--write-filename-in-watch-later-config``
|
||||
Prepend the watch later config files with the name of the file they refer
|
||||
to. This is simply written as comment on the top of the file.
|
||||
|
||||
.. warning::
|
||||
|
||||
This option may expose privacy-sensitive information and is thus
|
||||
disabled by default.
|
||||
|
||||
``--ignore-path-in-watch-later-config``
|
||||
Ignore path (i.e. use filename only) when using watch later feature.
|
||||
(Default: disabled)
|
||||
|
||||
``--show-profile=<profile>``
|
||||
Show the description and content of a profile. Lists all profiles if no
|
||||
parameter is provided.
|
||||
@@ -981,9 +1046,10 @@ Program Behavior
|
||||
the overlay permanent).
|
||||
|
||||
``--load-osd-console=<yes|no>``
|
||||
Enable the built-in script that shows a console on a key binding and lets
|
||||
you enter commands (default: yes). The ````` key is used to show the
|
||||
console by default, and ``ESC`` to hide it again.
|
||||
Enable the builtin script that shows a console on a key binding and lets
|
||||
you enter commands (default: yes). By default,. The ``´`` key is used to
|
||||
show the console, and ``ESC`` to hide it again. (This is based on a user
|
||||
script called ``repl.lua``.)
|
||||
|
||||
``--load-auto-profiles=<yes|no|auto>``
|
||||
Enable the builtin script that does auto profiles (default: auto). See
|
||||
@@ -996,75 +1062,6 @@ Program Behavior
|
||||
only by mpv internally, or mpv-provided scripts, config files, or .desktop
|
||||
files. See `PSEUDO GUI MODE`_ for details.
|
||||
|
||||
Watch Later
|
||||
-----------
|
||||
|
||||
``--save-position-on-quit``
|
||||
Always save the current playback position on quit. When this file is
|
||||
played again later, the player will seek to the old playback position on
|
||||
start. This does not happen if playback of a file is stopped in any other
|
||||
way than quitting. For example, going to the next file in the playlist
|
||||
will not save the position, and start playback at beginning the next time
|
||||
the file is played.
|
||||
|
||||
This behavior is disabled by default, but is always available when quitting
|
||||
the player with Shift+Q.
|
||||
|
||||
See `RESUMING PLAYBACK`_.
|
||||
|
||||
``--watch-later-directory=<path>``
|
||||
The directory in which to store the "watch later" temporary files.
|
||||
|
||||
The default is a subdirectory named "watch_later" underneath the
|
||||
config directory (usually ``~/.config/mpv/``).
|
||||
|
||||
``--no-resume-playback``
|
||||
Do not restore playback position from the ``watch_later`` configuration
|
||||
subdirectory (usually ``~/.config/mpv/watch_later/``).
|
||||
|
||||
``--resume-playback-check-mtime``
|
||||
Only restore the playback position from the ``watch_later`` configuration
|
||||
subdirectory (usually ``~/.config/mpv/watch_later/``) if the file's
|
||||
modification time is the same as at the time of saving. This may prevent
|
||||
skipping forward in files with the same name which have different content.
|
||||
(Default: ``no``)
|
||||
|
||||
``--watch-later-options=option1,option2,...``
|
||||
The options that are saved in "watch later" files if they have been changed
|
||||
since when mpv started. These values will be restored the next time the
|
||||
files are played. The playback position is always saved as ``start``, so
|
||||
adding ``start`` to this list has no effect.
|
||||
|
||||
When removing options, existing watch later data won't be modified and will
|
||||
still be applied fully, but new watch later data won't contain these
|
||||
options.
|
||||
|
||||
This is a string list option. See `List Options`_ for details.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
- ``--watch-later-options-remove=fullscreen``
|
||||
The fullscreen state won't be saved to watch later files.
|
||||
- ``--watch-later-options-remove=volume``
|
||||
``--watch-later-options-remove=mute``
|
||||
The volume and mute state won't be saved to watch later files.
|
||||
- ``--watch-later-options-clr``
|
||||
No option will be saved to watch later files except the starting
|
||||
position.
|
||||
|
||||
``--write-filename-in-watch-later-config``
|
||||
Prepend the watch later config files with the name of the file they refer
|
||||
to. This is simply written as comment on the top of the file.
|
||||
|
||||
.. warning::
|
||||
|
||||
This option may expose privacy-sensitive information and is thus
|
||||
disabled by default.
|
||||
|
||||
``--ignore-path-in-watch-later-config``
|
||||
Ignore path (i.e. use filename only) when using watch later feature.
|
||||
(Default: disabled)
|
||||
|
||||
Video
|
||||
-----
|
||||
|
||||
@@ -1179,40 +1176,26 @@ Video
|
||||
Whether hardware decoding is actually done depends on the video codec. If
|
||||
hardware decoding is not possible, mpv will fall back on software decoding.
|
||||
|
||||
Hardware decoding is not enabled by default, to keep the out-of-the-box
|
||||
configuration as reliable as possible. However, when using modern hardware,
|
||||
hardware video decoding should work correctly, offering reduced CPU usage,
|
||||
and possibly lower power consumption. On older systems, it may be necessary
|
||||
to use hardware decoding due to insufficient CPU resources; and even on
|
||||
modern systems, sufficiently complex content (eg: 4K60 AV1) may require it.
|
||||
Hardware decoding is not enabled by default, because it is typically an
|
||||
additional source of errors. It is worth using only if your CPU is too
|
||||
slow to decode a specific video.
|
||||
|
||||
.. note::
|
||||
|
||||
Use the ``Ctrl+h`` shortcut to toggle hardware decoding at runtime. It
|
||||
toggles this option between ``auto`` and ``no``.
|
||||
|
||||
If you decide you want to use hardware decoding by default, the general
|
||||
recommendation is to try out decoding with the command line option, and
|
||||
prove to yourself that it works as desired for the content you care
|
||||
about. After that, you can add it to your config file.
|
||||
Always enabling HW decoding by putting it into the config file is
|
||||
discouraged. If you use the Ubuntu package, delete ``/etc/mpv/mpv.conf``,
|
||||
as the package tries to enable HW decoding by default by setting
|
||||
``hwdec=vaapi`` (which is less than ideal, and may even cause
|
||||
sub-optimal wrappers to be used). Or at least change it to
|
||||
``hwdec=auto-safe``.
|
||||
|
||||
When testing, you should start by using ``hwdec=auto-safe`` as it will
|
||||
limit itself to choosing from hwdecs that are actively supported by the
|
||||
development team. If that doesn't result in working hardware decoding,
|
||||
you can try ``hwdec=auto`` to have it attempt to load every possible
|
||||
hwdec, but if ``auto-safe`` didn't work, you will probably need to know
|
||||
exactly which hwdec matches your hardware and read up on that entry
|
||||
below.
|
||||
|
||||
If ``auto-safe`` or ``auto`` produced the desired results, we recommend
|
||||
just sticking with that and only setting a specific hwdec in your config
|
||||
file if it is really necessary.
|
||||
|
||||
If you use the Ubuntu package, keep in mind that their
|
||||
``/etc/mpv/mpv.conf`` contains ``hwdec=vaapi``, which is less than
|
||||
ideal as it may not be the right choice for your system, and it may end
|
||||
up using an inefficient wrapper library under the covers. We recommend
|
||||
removing this line or deleting the file altogether.
|
||||
Use one of the auto modes if you want to enable hardware decoding.
|
||||
Explicitly selecting the mode is mostly meant for testing and debugging.
|
||||
It's a bad idea to put explicit selection into the config file if you
|
||||
want thing to just keep working after updates and so on.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -1227,7 +1210,8 @@ Video
|
||||
``Ctrl+h`` default binding to enable it at runtime.
|
||||
- If you're not sure, but want hardware decoding always enabled by
|
||||
default, put ``hwdec=auto-safe`` into your ``mpv.conf``, and
|
||||
acknowledge that this may cause problems.
|
||||
acknowledge that this use case is not "really" supported and may cause
|
||||
problems.
|
||||
- If you want to test available hardware decoding methods, pass
|
||||
``--hwdec=auto --hwdec-codecs=all`` and look at the terminal output.
|
||||
- If you're a developer, or want to perform elaborate tests, you may
|
||||
@@ -1240,35 +1224,26 @@ Video
|
||||
:yes: exactly the same as ``auto``
|
||||
:auto-safe: enable any whitelisted hw decoder (see below)
|
||||
:auto-copy: enable best hw decoder with copy-back (see below)
|
||||
|
||||
Actively supported hwdecs:
|
||||
|
||||
:d3d11va: requires ``--vo=gpu`` with ``--gpu-context=d3d11`` or
|
||||
``--gpu-context=angle`` (Windows 8+ only)
|
||||
:d3d11va-copy: copies video back to system RAM (Windows 8+ only)
|
||||
:vdpau: requires ``--vo=gpu`` with X11, or ``--vo=vdpau`` (Linux only)
|
||||
:vdpau-copy: copies video back into system RAM (Linux with some GPUs only)
|
||||
:vaapi: requires ``--vo=gpu`` or ``--vo=vaapi`` (Linux only)
|
||||
:vaapi-copy: copies video back into system RAM (Linux with some GPUs only)
|
||||
:videotoolbox: requires ``--vo=gpu`` (macOS 10.8 and up),
|
||||
or ``--vo=libmpv`` (iOS 9.0 and up)
|
||||
:videotoolbox-copy: copies video back into system RAM (macOS 10.8 or iOS 9.0 and up)
|
||||
:vaapi: requires ``--vo=gpu``, ``--vo=vaapi`` or ``--vo=dmabuf-wayland`` (Linux only)
|
||||
:vaapi-copy: copies video back into system RAM (Linux with some GPUs only)
|
||||
:nvdec: requires ``--vo=gpu`` (Any platform CUDA is available)
|
||||
:nvdec-copy: copies video back to system RAM (Any platform CUDA is available)
|
||||
:drm: requires ``--vo=gpu`` (Linux only)
|
||||
:drm-copy: copies video back to system RAM (Linux ony)
|
||||
|
||||
Other hwdecs (only use if you know you have to):
|
||||
|
||||
:dxva2: requires ``--vo=gpu`` with ``--gpu-context=d3d11``,
|
||||
``--gpu-context=angle`` or ``--gpu-context=dxinterop``
|
||||
(Windows only)
|
||||
:dxva2-copy: copies video back to system RAM (Windows only)
|
||||
:vdpau: requires ``--vo=gpu`` with X11, or ``--vo=vdpau`` (Linux only)
|
||||
:vdpau-copy: copies video back into system RAM (Linux with some GPUs only)
|
||||
:mediacodec: requires ``--vo=gpu --gpu-context=android``
|
||||
or ``--vo=mediacodec_embed`` (Android only)
|
||||
:d3d11va: requires ``--vo=gpu`` with ``--gpu-context=d3d11`` or
|
||||
``--gpu-context=angle`` (Windows 8+ only)
|
||||
:d3d11va-copy: copies video back to system RAM (Windows 8+ only)
|
||||
:mediacodec: requires ``--vo=mediacodec_embed`` (Android only)
|
||||
:mediacodec-copy: copies video back to system RAM (Android only)
|
||||
:mmal: requires ``--vo=gpu`` (Raspberry Pi only - default if available)
|
||||
:mmal-copy: copies video back to system RAM (Raspberry Pi only)
|
||||
:nvdec: requires ``--vo=gpu`` (Any platform CUDA is available)
|
||||
:nvdec-copy: copies video back to system RAM (Any platform CUDA is available)
|
||||
:cuda: requires ``--vo=gpu`` (Any platform CUDA is available)
|
||||
:cuda-copy: copies video back to system RAM (Any platform CUDA is available)
|
||||
:crystalhd: copies video back to system RAM (Any platform supported by hardware)
|
||||
@@ -1305,7 +1280,7 @@ Video
|
||||
|
||||
Because these copy the decoded video back to system RAM, they're often less
|
||||
efficient than the direct modes, and may not help too much over software
|
||||
decoding if you are short on CPU resources.
|
||||
decoding.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -1334,12 +1309,7 @@ Video
|
||||
In theory, hardware decoding does not reduce video quality (at least
|
||||
for the codecs h264 and HEVC). However, due to restrictions in video
|
||||
output APIs, as well as bugs in the actual hardware decoders, there can
|
||||
be some loss, or even blatantly incorrect results. This has largely
|
||||
ceased to be a problem with modern hardware, but there is a lot of
|
||||
hardware out there, so caveat emptor. Known problems are discussed
|
||||
below, but the list cannot be considered exhaustive, as even hwdecs that
|
||||
work well on certain hardware generations may be problematic on other
|
||||
ones.
|
||||
be some loss, or even blatantly incorrect results.
|
||||
|
||||
In some cases, RGB conversion is forced, which means the RGB conversion
|
||||
is performed by the hardware decoding API, instead of the shaders
|
||||
@@ -1355,6 +1325,10 @@ Video
|
||||
doesn't support 10 bit or HDR encodings, so these limitations are
|
||||
unlikely to be relevant.
|
||||
|
||||
``vaapi`` and ``d3d11va`` are safe. Enabling deinterlacing (or simply
|
||||
their respective post-processing filters) will possibly at least reduce
|
||||
color quality by converting the output to a 8 bit format.
|
||||
|
||||
``dxva2`` is not safe. It appears to always use BT.601 for forced RGB
|
||||
conversion, but actual behavior depends on the GPU drivers. Some drivers
|
||||
appear to convert to limited range RGB, which gives a faded appearance.
|
||||
@@ -1365,11 +1339,6 @@ Video
|
||||
``rpi`` always uses the hardware overlay renderer, even with
|
||||
``--vo=gpu``.
|
||||
|
||||
``mediacodec`` is not safe. It forces RGB conversion (not with ``-copy``)
|
||||
and how well it handles non-standard colorspaces is not known.
|
||||
In the rare cases where 10-bit is supported the bit depth of the output
|
||||
will be reduced to 8.
|
||||
|
||||
``cuda`` should usually be safe, but depending on how a file/stream
|
||||
has been mixed, it has been reported to corrupt the timestamps causing
|
||||
glitched, flashing frames. It can also sometimes cause massive
|
||||
@@ -1381,9 +1350,20 @@ Video
|
||||
conversion. It also discards the top left pixel of each frame for
|
||||
some reason.
|
||||
|
||||
If you run into any weird decoding issues, frame glitches or
|
||||
discoloration, and you have ``--hwdec`` turned on, the first thing you
|
||||
should try is disabling it.
|
||||
All other methods, in particular the copy-back methods (like
|
||||
``dxva2-copy`` etc.) should hopefully be safe, although they can still
|
||||
cause random decoding issues. At the very least, they shouldn't affect
|
||||
the colors of the image.
|
||||
|
||||
In particular, ``auto-copy`` will only select "safe" modes
|
||||
(although potentially slower than other methods), but there's still no
|
||||
guarantee the chosen hardware decoder will actually work correctly.
|
||||
|
||||
In general, it's very strongly advised to avoid hardware decoding
|
||||
unless **absolutely** necessary, i.e. if your CPU is insufficient to
|
||||
decode the file in questions. If you run into any weird decoding issues,
|
||||
frame glitches or discoloration, and you have ``--hwdec`` turned on,
|
||||
the first thing you should try is disabling it.
|
||||
|
||||
``--gpu-hwdec-interop=<auto|all|no|name>``
|
||||
This option is for troubleshooting hwdec interop issues. Since it's a
|
||||
@@ -1552,7 +1532,7 @@ Video
|
||||
video will be either cut off, or black bars are added.
|
||||
|
||||
This value is multiplied with the value derived from ``--video-zoom`` and
|
||||
the normal video aspect ratio. This option is disabled if the
|
||||
the normal video aspect aspect ratio. This option is disabled if the
|
||||
``--no-keepaspect`` option is used.
|
||||
|
||||
``--video-align-x=<-1-1>``, ``--video-align-y=<-1-1>``
|
||||
@@ -1690,29 +1670,16 @@ Video
|
||||
the number of packets that could not be decoded. Values below an unspecified
|
||||
count will not have this problem, because mpv retains the packets.
|
||||
|
||||
``--vd-lavc-film-grain=<auto|cpu|gpu>``
|
||||
Enables film grain application on the GPU. If video decoding is done on
|
||||
the CPU, doing film grain application on the GPU can speed up decoding.
|
||||
This option can also help hardware decoding, as it can reduce the number
|
||||
of frame copies done.
|
||||
|
||||
By default, it's set to ``auto``, so if the VO supports film grain
|
||||
application, then it will be treated as ``gpu``. If the VO does not
|
||||
support this, then it will be treated as ``cpu``, regardless of the setting.
|
||||
Currently, only ``gpu-next`` supports film grain application.
|
||||
|
||||
``--vd-lavc-dr=<auto|yes|no>``
|
||||
Enable direct rendering (default: auto). If this is set to ``yes``, the
|
||||
``--vd-lavc-dr=<yes|no>``
|
||||
Enable direct rendering (default: yes). If this is set to ``yes``, the
|
||||
video will be decoded directly to GPU video memory (or staging buffers).
|
||||
This can speed up video upload, and may help with large resolutions or
|
||||
slow hardware. This works only with the following VOs:
|
||||
|
||||
- ``gpu``: requires at least OpenGL 4.4 or Vulkan.
|
||||
- ``libmpv``: The libmpv render API has optional support.
|
||||
|
||||
The ``auto`` option will try to guess whether DR can improve performance
|
||||
on your particular hardware. Currently this enables it on AMD or NVIDIA
|
||||
if using OpenGL or unconditionally if using Vulkan.
|
||||
(In particular, this can't be made work with ``opengl-cb``, but the libmpv
|
||||
render API has optional support.)
|
||||
|
||||
Using video filters of any kind that write to the image data (or output
|
||||
newly allocated frames) will silently disable the DR code path.
|
||||
@@ -1720,7 +1687,7 @@ Video
|
||||
``--vd-lavc-bitexact``
|
||||
Only use bit-exact algorithms in all decoding steps (for codec testing).
|
||||
|
||||
``--vd-lavc-fast`` (MPEG-1/2 and H.264 only)
|
||||
``--vd-lavc-fast`` (MPEG-2, MPEG-4, and H.264 only)
|
||||
Enable optimizations which do not comply with the format specification and
|
||||
potentially cause problems, like simpler dequantization, simpler motion
|
||||
compensation, assuming use of the default quantization matrix, assuming YUV
|
||||
@@ -1746,14 +1713,12 @@ Video
|
||||
no, libavcodec won't output frames that were either decoded before an
|
||||
initial keyframe was decoded, or frames that are recognized as corrupted.
|
||||
|
||||
``--vd-lavc-skiploopfilter=<skipvalue>`` (H.264, HEVC only)
|
||||
Skips the loop filter (AKA deblocking) during decoding. Since
|
||||
``--vd-lavc-skiploopfilter=<skipvalue> (H.264 only)``
|
||||
Skips the loop filter (AKA deblocking) during H.264 decoding. Since
|
||||
the filtered frame is supposed to be used as reference for decoding
|
||||
dependent frames, this has a worse effect on quality than not doing
|
||||
deblocking on e.g. MPEG-2 video. But at least for high bitrate HDTV,
|
||||
this provides a big speedup with little visible quality loss.
|
||||
Codecs other than H.264 or HEVC may have partial support for this option
|
||||
(often only ``all`` and ``none``).
|
||||
|
||||
``<skipvalue>`` can be one of the following:
|
||||
|
||||
@@ -1765,7 +1730,7 @@ Video
|
||||
:nonkey: Skip all frames except keyframes.
|
||||
:all: Skip all frames.
|
||||
|
||||
``--vd-lavc-skipidct=<skipvalue>`` (MPEG-1/2/4 only)
|
||||
``--vd-lavc-skipidct=<skipvalue> (MPEG-1/2 only)``
|
||||
Skips the IDCT step. This degrades quality a lot in almost all cases
|
||||
(see skiploopfilter for available skip values).
|
||||
|
||||
@@ -1788,7 +1753,7 @@ Video
|
||||
Normally, this is autodetected by libavcodec. But if the bitstream contains
|
||||
no x264 version info (or it was somehow skipped), and the stream was in fact
|
||||
encoded by an old x264 version (build 150 or earlier), and if the stream
|
||||
uses 4:4:4 chroma, then libavcodec will by default show corrupted video.
|
||||
uses ``4:4:4`` chroma, then libavcodec will by default show corrupted video.
|
||||
This option sets the libavcodec ``x264_build`` option to ``150``, which
|
||||
means that if the stream contains no version info, or was not encoded by
|
||||
x264 at all, it assumes it was encoded by the old version. Enabling this
|
||||
@@ -2032,9 +1997,9 @@ Audio
|
||||
|
||||
Using this mode is recommended for direct hardware output, especially
|
||||
over HDMI (see HDMI warning below).
|
||||
- ``--audio-channels=<stereo|mono>``
|
||||
Force a downmix to stereo or mono. These are special-cases of the
|
||||
previous item. (See paragraphs below for implications.)
|
||||
- ``--audio-channels=stereo``
|
||||
Force a plain stereo downmix. This is a special-case of the previous
|
||||
item. (See paragraphs below for implications.)
|
||||
|
||||
If a list of layouts is given, each item can be either an explicit channel
|
||||
layout name (like ``5.1``), or a channel number. Channel numbers refer to
|
||||
@@ -2652,6 +2617,11 @@ Subtitles
|
||||
Can be used to disable display of secondary subtitles, but still select and
|
||||
decode them.
|
||||
|
||||
.. note::
|
||||
|
||||
If ``--sub-visibility=no``, secondary subtitles are hidden regardless of
|
||||
``--secondary-sub-visibility``.
|
||||
|
||||
``--sub-clear-on-seek``
|
||||
(Obscure, rarely useful.) Can be used to play broken mkv files with
|
||||
duplicate ReadOrder fields. ReadOrder is the first field in a
|
||||
@@ -2713,6 +2683,12 @@ Subtitles
|
||||
``--sub-border-color=<color>``
|
||||
See ``--sub-color``. Color used for the sub font border.
|
||||
|
||||
.. note::
|
||||
|
||||
ignored when ``--sub-back-color`` is
|
||||
specified (or more exactly: when that option is not set to completely
|
||||
transparent).
|
||||
|
||||
``--sub-border-size=<size>``
|
||||
Size of the sub font border in scaled pixels (see ``--sub-font-size``
|
||||
for details). A value of 0 disables borders.
|
||||
@@ -2779,7 +2755,7 @@ Subtitles
|
||||
``--sub-justify=<auto|left|center|right>``
|
||||
Control how multi line subs are justified irrespective of where they
|
||||
are aligned (default: ``auto`` which justifies as defined by
|
||||
``--sub-align-x``).
|
||||
``--sub-align-y``).
|
||||
Left justification is recommended to make the subs easier to read
|
||||
as it is easier for the eyes.
|
||||
|
||||
@@ -2791,12 +2767,6 @@ Subtitles
|
||||
``--sub-shadow-color=<color>``
|
||||
See ``--sub-color``. Color used for sub text shadow.
|
||||
|
||||
.. note::
|
||||
|
||||
ignored when ``--sub-back-color`` is
|
||||
specified (or more exactly: when that option is not set to completely
|
||||
transparent).
|
||||
|
||||
``--sub-shadow-offset=<size>``
|
||||
Displacement of the sub text shadow in scaled pixels (see
|
||||
``--sub-font-size`` for details). A value of 0 disables shadows.
|
||||
@@ -2968,7 +2938,7 @@ Window
|
||||
|
||||
``--keep-open=<yes|no|always>``
|
||||
Do not terminate when playing or seeking beyond the end of the file, and
|
||||
there is no next file to be played (and ``--loop`` is not used).
|
||||
there is not next file to be played (and ``--loop`` is not used).
|
||||
Instead, pause the player. When trying to seek beyond end of the file, the
|
||||
player will attempt to seek to the last frame.
|
||||
|
||||
@@ -3292,12 +3262,10 @@ Window
|
||||
1). A value of 1 means square pixels (correct for (almost?) all LCDs). See
|
||||
also ``--monitoraspect`` and ``--video-aspect-override``.
|
||||
|
||||
``--stop-screensaver=<yes|no|always>``
|
||||
``--stop-screensaver``, ``--no-stop-screensaver``
|
||||
Turns off the screensaver (or screen blanker and similar mechanisms) at
|
||||
startup and turns it on again on exit (default: yes). When using ``yes``,
|
||||
the screensaver will re-enable when playback is not active. ``always`` will
|
||||
always disable the screensaver. Note that stopping the screensaver is only
|
||||
possible if a video output is available (i.e. there is an open mpv window).
|
||||
startup and turns it on again on exit (default: yes). The screensaver is
|
||||
always re-enabled when the player is paused.
|
||||
|
||||
This is not supported on all video outputs or platforms. Sometimes it is
|
||||
implemented, but does not work (especially with Linux "desktops"). Read the
|
||||
@@ -3327,7 +3295,7 @@ Window
|
||||
On Android, the ID is interpreted as ``android.view.Surface``. Pass it as a
|
||||
value cast to ``intptr_t``. Use with ``--vo=mediacodec_embed`` and
|
||||
``--hwdec=mediacodec`` for direct rendering using MediaCodec, or with
|
||||
``--vo=gpu --gpu-context=android`` (with or without ``--hwdec=mediacodec``).
|
||||
``--vo=gpu --gpu-context=android`` (with or without ``--hwdec=mediacodec-copy``).
|
||||
|
||||
``--no-window-dragging``
|
||||
Don't move the window when clicking on it and moving the mouse pointer.
|
||||
@@ -3368,23 +3336,6 @@ Window
|
||||
|
||||
``never`` asks the window manager to never disable the compositor.
|
||||
|
||||
``--x11-present=<no|auto|yes>``
|
||||
Whether or not to use presentation statistics from X11's presentation
|
||||
extension (default: ``auto``).
|
||||
|
||||
mpv asks X11 for present events which it then may use for more accurate
|
||||
frame presentation. This only has an effect if ``--video-sync=display-...``
|
||||
is being used.
|
||||
|
||||
The auto option enumerates XRandr providers for autodetection. If amd, radeon,
|
||||
intel, or nouveau (the standard x86 Mesa drivers) is found and nvidia is NOT
|
||||
found, presentation feedback is enabled. Other drivers are not assumed to
|
||||
work, so they are not enabled automatically.
|
||||
|
||||
``yes`` or ``no`` can still be passed regardless to enable/disable this
|
||||
mechanism in case there is good/bad behavior with whatever your combination
|
||||
of hardware/drivers/etc. happens to be.
|
||||
|
||||
|
||||
Disc Devices
|
||||
------------
|
||||
@@ -4096,10 +4047,6 @@ OSD
|
||||
|
||||
See `Property Expansion`_.
|
||||
|
||||
``--osd-playing-msg-duration=<time>``
|
||||
Set the duration of ``osd-playing-msg`` in ms. If this is unset,
|
||||
``osd-playing-msg`` stays on screen for the duration of ``osd-duration``.
|
||||
|
||||
``--osd-bar-align-x=<-1-1>``
|
||||
Position of the OSD bar. -1 is far left, 0 is centered, 1 is far right.
|
||||
Fractional values (like 0.5) are allowed.
|
||||
@@ -4235,7 +4182,6 @@ Screenshot
|
||||
:jpg: JPEG (default)
|
||||
:jpeg: JPEG (alias for jpg)
|
||||
:webp: WebP
|
||||
:jxl: JPEG XL
|
||||
|
||||
``--screenshot-tag-colorspace=<yes|no>``
|
||||
Tag screenshots with the appropriate colorspace.
|
||||
@@ -4381,16 +4327,6 @@ Screenshot
|
||||
more CPU time. Note that this also affects the screenshot quality when used
|
||||
with lossy WebP files. The default is 4.
|
||||
|
||||
``--screenshot-jxl-distance=<0-15>``
|
||||
Set the JPEG XL Butteraugli distance. Lower means better quality. Lossless
|
||||
is 0.0, and 1.0 is approximately equivalent to JPEG quality 90 for
|
||||
photographic content. Use 0.1 for "visually lossless" screenshots. The
|
||||
default is 1.0.
|
||||
|
||||
``--screenshot-jxl-effort=<1-9>``
|
||||
Set the JPEG XL compression effort. Higher effort (usually) means better
|
||||
compression, but takes more CPU time. The default is 3.
|
||||
|
||||
``--screenshot-sw=<yes|no>``
|
||||
Whether to use software rendering for screenshots (default: no).
|
||||
|
||||
@@ -5077,9 +5013,8 @@ ALSA audio output options
|
||||
GPU renderer options
|
||||
-----------------------
|
||||
|
||||
The following video options are currently all specific to ``--vo=gpu``,
|
||||
``--vo=libmpv`` and ``--vo=gpu-next``, which are the only VOs that implement
|
||||
them.
|
||||
The following video options are currently all specific to ``--vo=gpu`` and
|
||||
``--vo=libmpv`` only, which are the only VOs that implement them.
|
||||
|
||||
``--scale=<filter>``
|
||||
The filter function to use when upscaling video.
|
||||
@@ -5332,15 +5267,6 @@ them.
|
||||
|
||||
Set this to ``-1`` to disable this logic.
|
||||
|
||||
``--interpolation-preserve``
|
||||
Preserve the previous frames' interpolated results even when renderer
|
||||
parameters are changed - with the exception of options related to
|
||||
cropping and video placement, which always invalidate the cache. Enabling
|
||||
this option makes dynamic updates of renderer settings slightly smoother at
|
||||
the cost of slightly higher latency in response to such changes. Defaults
|
||||
to on. (Only affects ``--vo=gpu-next``, note that ``--vo=gpu`` always
|
||||
invalidates interpolated frames)
|
||||
|
||||
``--opengl-pbo``
|
||||
Enable use of PBOs. On some drivers this can be faster, especially if the
|
||||
source video size is huge (e.g. so called "4K" video). On other drivers it
|
||||
@@ -5475,6 +5401,11 @@ them.
|
||||
use of compute shaders over fragment shaders wherever possible. Enabled by
|
||||
default, although Nvidia users may want to disable it.
|
||||
|
||||
``--vulkan-disable-events``
|
||||
Disable the use of VkEvents, for debugging purposes or for compatibility
|
||||
with some older drivers / vulkan portability layers that don't provide
|
||||
working VkEvent support.
|
||||
|
||||
``--vulkan-display-display=<n>``
|
||||
The index of the display, on the selected Vulkan device, to present on when
|
||||
using the ``displayvk`` GPU context. Use ``--vulkan-display-display=help``
|
||||
@@ -5577,18 +5508,11 @@ them.
|
||||
``--wayland-app-id=<string>``
|
||||
Set the client app id for Wayland-based video output methods (default: ``mpv``).
|
||||
|
||||
``--wayland-configure-bounds=<yes|no>``
|
||||
Controls whether or not mpv opts into the configure bounds event if sent by the
|
||||
compositor (default: yes). This restricts the initial size of the mpv window to
|
||||
a certain maximum size intended by the compositor. In most cases, this simply
|
||||
just prevents the mpv window from being larger than the size of the monitor when
|
||||
it first renders. This option will take precedence over any ``autofit`` or
|
||||
``geometry`` type settings if the configure bounds are used.
|
||||
|
||||
``--wayland-disable-vsync=<yes|no>``
|
||||
Disable mpv's internal vsync for Wayland-based video output (default: no).
|
||||
This is mainly useful for benchmarking wayland VOs when combined with
|
||||
``video-sync=display-desync``, ``--no-audio``, and ``--untimed=yes``.
|
||||
Disable vsync for the wayland contexts (default: no). Useful for benchmarking
|
||||
the wayland context when combined with ``video-sync=display-desync``,
|
||||
``--no-audio``, and ``--untimed=yes``. Only works with ``--gpu-context=wayland``
|
||||
and ``--gpu-context=waylandvk``.
|
||||
|
||||
``--wayland-edge-pixels-pointer=<value>``
|
||||
Defines the size of an edge border (default: 10) to initiate client side
|
||||
@@ -5861,13 +5785,6 @@ them.
|
||||
``--glsl-shader=<file>``
|
||||
CLI/config file only alias for ``--glsl-shaders-append``.
|
||||
|
||||
``--glsl-shader-opts=param1=value1,param2=value2,...``
|
||||
Specifies the options to use for tunable shader parameters. You can target
|
||||
specific named shaders by prefixing the shader name with a ``/``, e.g.
|
||||
``shader/param=value``. Without a prefix, parameters affect all shaders.
|
||||
The shader name is the base part of the shader filename, without the
|
||||
extension. (``--vo=gpu-next`` only)
|
||||
|
||||
``--deband``
|
||||
Enable the debanding algorithm. This greatly reduces the amount of visible
|
||||
banding, blocking and other quantization artifacts, at the expense of
|
||||
@@ -5904,7 +5821,7 @@ them.
|
||||
values will sharpen the image (but add more ringing and aliasing). Negative
|
||||
values will blur the image. If your GPU is powerful enough, consider
|
||||
alternatives like the ``ewa_lanczossharp`` scale filter, or the
|
||||
``--scale-blur`` option. (Only for ``--vo=gpu``)
|
||||
``--scale-blur`` option.
|
||||
|
||||
``--opengl-glfinish``
|
||||
Call ``glFinish()`` before swapping buffers (default: disabled). Slower,
|
||||
@@ -6200,44 +6117,28 @@ them.
|
||||
other ways (like with the ``--gamma`` option or key bindings and the
|
||||
``gamma`` property), the value is multiplied with the other gamma value.
|
||||
|
||||
This option is deprecated and may be removed in the future.
|
||||
Recommended values based on the environmental brightness:
|
||||
|
||||
1.0
|
||||
Pitch black or dimly lit room (default)
|
||||
1.1
|
||||
Moderately lit room, home
|
||||
1.2
|
||||
Brightly illuminated room, office
|
||||
|
||||
NOTE: This is based around the assumptions of typical movie content, which
|
||||
contains an implicit end-to-end of about 0.8 from scene to display. For
|
||||
bright environments it can be useful to cancel that out.
|
||||
|
||||
``--gamma-auto``
|
||||
Automatically corrects the gamma value depending on ambient lighting
|
||||
conditions (adding a gamma boost for bright rooms).
|
||||
|
||||
This option is deprecated and may be removed in the future.
|
||||
With ambient illuminance of 16 lux, mpv will pick the 1.0 gamma value (no
|
||||
boost), and slightly increase the boost up until 1.2 for 256 lux.
|
||||
|
||||
NOTE: Only implemented on macOS.
|
||||
|
||||
``--image-lut=<file>``
|
||||
Specifies a custom LUT file (in Adobe .cube format) to apply to the colors
|
||||
during image decoding. The exact interpretation of the LUT depends on
|
||||
the value of ``--image-lut-type``. (Only for ``--vo=gpu-next``)
|
||||
|
||||
``--image-lut-type=<value>``
|
||||
Controls the interpretation of color values fed to and from the LUT
|
||||
specified as ``--image-lut``. Valid values are:
|
||||
|
||||
auto
|
||||
Chooses the interpretation of the LUT automatically from tagged
|
||||
metadata, and otherwise falls back to ``native``. (Default)
|
||||
native
|
||||
Applied to the raw image contents in its native colorspace, before
|
||||
decoding to RGB. For example, for a HDR10 image, this would be fed
|
||||
PQ-encoded YCbCr values in the range 0.0 - 1.0.
|
||||
normalized
|
||||
Applied to the normalized RGB image contents, after decoding from
|
||||
its native color encoding, but before linearization.
|
||||
conversion
|
||||
Fully replaces the color decoding. A LUT of this type should ingest the
|
||||
image's native colorspace and output normalized non-linear RGB.
|
||||
|
||||
``--target-colorspace-hint``
|
||||
Automatically configure the output colorspace of the display to pass
|
||||
through the input values of the stream (e.g. for HDR passthrough), if
|
||||
possible. Requires a supporting driver and ``--vo=gpu-next``.
|
||||
|
||||
``--target-prim=<value>``
|
||||
Specifies the primaries of the display. Video colors will be adapted to
|
||||
this colorspace when ICC color management is not being used. Valid values
|
||||
@@ -6353,20 +6254,12 @@ them.
|
||||
In such a configuration, we highly recommend setting ``--tone-mapping``
|
||||
to ``mobius`` or even ``clip``.
|
||||
|
||||
``--target-lut=<file>``
|
||||
Specifies a custom LUT file (in Adobe .cube format) to apply to the colors
|
||||
before display on-screen. This LUT is fed values in normalized RGB, after
|
||||
encoding into the target colorspace, so after the application of
|
||||
``--target-trc``. (Only for ``--vo=gpu-next``)
|
||||
|
||||
``--tone-mapping=<value>``
|
||||
Specifies the algorithm used for tone-mapping images onto the target
|
||||
display. This is relevant for both HDR->SDR conversion as well as gamut
|
||||
reduction (e.g. playing back BT.2020 content on a standard gamut display).
|
||||
Valid values are:
|
||||
|
||||
auto
|
||||
Choose the best curve according to internal heuristics. (Default)
|
||||
clip
|
||||
Hard-clip any out-of-range values. Use this when you care about
|
||||
perfect color accuracy for in-range values at the cost of completely
|
||||
@@ -6392,17 +6285,13 @@ them.
|
||||
you should also enable ``--hdr-compute-peak`` for the best results.
|
||||
bt.2390
|
||||
Perceptual tone mapping curve (EETF) specified in ITU-R Report BT.2390.
|
||||
This is the recommended curve to use for typical HDR-mastered content.
|
||||
(Default)
|
||||
gamma
|
||||
Fits a logarithmic transfer between the tone curves.
|
||||
linear
|
||||
Linearly stretches the entire reference gamut to (a linear multiple of)
|
||||
the display.
|
||||
spline
|
||||
Perceptually linear single-pivot polynomial. (``--vo=gpu-next`` only)
|
||||
bt.2446a
|
||||
HDR<->SDR mapping specified in ITU-R Report BT.2446, method A. This is
|
||||
the recommended curve for well-mastered content. (``--vo=gpu-next``
|
||||
only)
|
||||
|
||||
``--tone-mapping-param=<value>``
|
||||
Set tone mapping parameters. By default, this is set to the special string
|
||||
@@ -6423,25 +6312,10 @@ them.
|
||||
Specifies the local contrast coefficient at the display peak. Defaults
|
||||
to 0.5, which means that in-gamut values will be about half as bright
|
||||
as when clipping.
|
||||
bt.2390
|
||||
Specifies the offset for the knee point. Defaults to 1.0, which is
|
||||
higher than the value from the original ITU-R specification (0.5).
|
||||
(``--vo=gpu-next`` only)
|
||||
gamma
|
||||
Specifies the exponent of the function. Defaults to 1.8.
|
||||
linear
|
||||
Specifies the scale factor to use while stretching. Defaults to 1.0.
|
||||
spline
|
||||
Specifies the knee point (in PQ space). Defaults to 0.30.
|
||||
|
||||
``--inverse-tone-mapping``
|
||||
If set, allows inverse tone mapping (expanding SDR to HDR). Not supported
|
||||
by all tone mapping curves. Use with caution. (``--vo=gpu-next`` only)
|
||||
|
||||
``--tone-mapping-crosstalk=<0.0..0.30>``
|
||||
If nonzero, apply an extra crosstalk matrix before tone mapping. Can help
|
||||
improve the appearance of strongly saturated monochromatic highlights.
|
||||
(Default: 0.04, only affects ``--vo=gpu-next``)
|
||||
|
||||
``--tone-mapping-max-boost=<1.0..10.0>``
|
||||
Upper limit for how much the tone mapping algorithm is allowed to boost
|
||||
@@ -6449,48 +6323,7 @@ them.
|
||||
allows no additional brightness boost. A value of 2.0 would allow
|
||||
over-exposing by a factor of 2, and so on. Raising this setting can help
|
||||
reveal details that would otherwise be hidden in dark scenes, but raising
|
||||
it too high will make dark scenes appear unnaturally bright. (``--vo=gpu``
|
||||
only)
|
||||
|
||||
``--tone-mapping-mode``
|
||||
Controls how the tone mapping function is applied to colors.
|
||||
|
||||
auto
|
||||
Choose the best mode automatically. (Default)
|
||||
rgb
|
||||
Tone-map per-channel (RGB). Has a tendency to severely distort colors,
|
||||
desaturate highlights, and is generally not very recommended. However,
|
||||
this is the mode used in many displays and TVs (especially early ones),
|
||||
and so sometimes it's needed to reproduce the artistic intent a film
|
||||
was mastered with.
|
||||
max
|
||||
Tone-map on the brightest component in the video. Has a tendency to
|
||||
lead to weirdly oversaturated colors, and loss of dark details.
|
||||
hybrid
|
||||
A hybrid approach that uses linear tone-mapping for midtones and
|
||||
per-channel tone mapping for highlights.
|
||||
luma
|
||||
Luminance-based method from ITU-R BT.2446a, including fixed gamut
|
||||
reductions to account for brightness-related perceptual nonuniformity.
|
||||
(``--vo=gpu-next`` only)
|
||||
|
||||
``--gamut-mapping-mode``
|
||||
Specifies the algorithm used for reducing the gamut of images for the
|
||||
target display, after any tone mapping is done.
|
||||
|
||||
auto
|
||||
Choose the best mode automatically. (Default)
|
||||
clip
|
||||
Hard-clip to the gamut (per-channel).
|
||||
warn
|
||||
Simply highlight out-of-gamut pixels.
|
||||
desaturate
|
||||
Chromatically desaturate out-of-gamut colors towards white.
|
||||
darken
|
||||
Linearly darken the entire image, then clip to the color volume. Unlike
|
||||
``clip``, this does not destroy detail in saturated regions, but comes
|
||||
at the cost of sometimes significantly lowering output brightness.
|
||||
(``--vo=gpu-next`` only)
|
||||
it too high will make dark scenes appear unnaturally bright.
|
||||
|
||||
``--hdr-compute-peak=<auto|yes|no>``
|
||||
Compute the HDR peak and frame average brightness per-frame instead of
|
||||
@@ -6502,14 +6335,6 @@ them.
|
||||
The special value ``auto`` (default) will enable HDR peak computation
|
||||
automatically if compute shaders and SSBOs are supported.
|
||||
|
||||
``--allow-delayed-peak-detect``
|
||||
When using ``--hdr-compute-peak``, allow delaying the detected peak by a
|
||||
frame when beneficial for performance. In particular, this is required to
|
||||
avoid an unnecessary FBO indirection when no advanced rendering is required
|
||||
otherwise. Has no effect if there already is an indirect pass, such as when
|
||||
advanced scaling is enabled. Defaults to on. (Only affects
|
||||
``--vo=gpu-next``, note that ``--vo=gpu`` always delays the peak.)
|
||||
|
||||
``--hdr-peak-decay-rate=<1.0..1000.0>``
|
||||
The decay rate used for the HDR peak detection algorithm (default: 100.0).
|
||||
This is only relevant when ``--hdr-compute-peak`` is enabled. Higher values
|
||||
@@ -6534,6 +6359,46 @@ them.
|
||||
aggressive, up to the limit of the high threshold (at which point the
|
||||
filter becomes instant).
|
||||
|
||||
``--tone-mapping-desaturate=<0.0..1.0>``
|
||||
Apply desaturation for highlights (default: 0.75). The parameter controls
|
||||
the strength of the desaturation curve. A value of 0.0 completely disables
|
||||
it, while a value of 1.0 means that overly bright colors will tend towards
|
||||
white. (This is not always the case, especially not for highlights that are
|
||||
near primary colors)
|
||||
|
||||
Values in between apply progressively more/less aggressive desaturation.
|
||||
This setting helps prevent unnaturally oversaturated colors for
|
||||
super-highlights, by (smoothly) turning them into less saturated (per
|
||||
channel tone mapped) colors instead. This makes images feel more natural,
|
||||
at the cost of chromatic distortions for out-of-range colors. The default
|
||||
value of 0.75 provides a good balance. Setting this to 0.0 preserves the
|
||||
chromatic accuracy of the tone mapping process.
|
||||
|
||||
``--tone-mapping-desaturate-exponent=<0.0..20.0>``
|
||||
This setting controls the exponent of the desaturation curve, which
|
||||
controls how bright a color needs to be in order to start being
|
||||
desaturated. The default of 1.5 provides a reasonable balance. Decreasing
|
||||
this exponent makes the curve more aggressive.
|
||||
|
||||
``--gamut-warning``
|
||||
If enabled, mpv will mark all clipped/out-of-gamut pixels that exceed a
|
||||
given threshold (currently hard-coded to 101%). The affected pixels will be
|
||||
inverted to make them stand out. Note: This option applies after the
|
||||
effects of all of mpv's color space transformation / tone mapping options,
|
||||
so it's a good idea to combine this with ``--tone-mapping=clip`` and use
|
||||
``--target-prim`` to set the gamut to simulate. For example,
|
||||
``--target-prim=bt.709`` would make mpv highlight all pixels that exceed the
|
||||
gamut of a standard gamut (sRGB) display. This option also does not work
|
||||
well with ICC profiles, since the 3DLUTs are always generated against the
|
||||
source color space and have chromatically-accurate clipping built in.
|
||||
|
||||
``--gamut-clipping``
|
||||
If enabled (default: yes), mpv will colorimetrically clip out-of-gamut
|
||||
colors by desaturating them (preserving luma), rather than hard-clipping
|
||||
each component individually. This should make playback of wide gamut
|
||||
content on typical (standard gamut) monitors look much more aesthetically
|
||||
pleasing and less blown-out.
|
||||
|
||||
``--use-embedded-icc-profile``
|
||||
Load the embedded ICC profile contained in media files such as PNG images.
|
||||
(Default: yes). Note that this option only works when also using a display
|
||||
@@ -6591,30 +6456,6 @@ them.
|
||||
value ``inf`` causes the BT.1886 curve to be treated as a pure power gamma
|
||||
2.4 function.
|
||||
|
||||
``--lut=<file>``
|
||||
Specifies a custom LUT (in Adobe .cube format) to apply to the colors
|
||||
as part of color conversion. The exact interpretation depends on the value
|
||||
of ``--lut-type``. (Only for ``--vo=gpu-next``)
|
||||
|
||||
``--lut-type=<value>``
|
||||
Controls the interpretation of color values fed to and from the LUT
|
||||
specified as ``--lut``. Valid values are:
|
||||
|
||||
auto
|
||||
Chooses the interpretation of the LUT automatically from tagged
|
||||
metadata, and otherwise falls back to ``native``. (Default)
|
||||
native
|
||||
Applied to raw image contents in its native RGB colorspace (non-linear
|
||||
light), before conversion to the output color space.
|
||||
normalized
|
||||
Applied to the normalized RGB image contents, in linear light, before
|
||||
conversion to the output color space.
|
||||
conversion
|
||||
Fully replaces the conversion from the image color space to the output
|
||||
color space. If such a LUT is present, it has the highest priority, and
|
||||
overrides any ICC profiles, as well as options related to tone mapping
|
||||
and output colorimetry (``--target-prim``, ``--target-trc`` etc.).
|
||||
|
||||
``--blend-subtitles=<yes|video|no>``
|
||||
Blend subtitles directly onto upscaled video frames, before interpolation
|
||||
and/or color management (default: no). Enabling this causes subtitles to be
|
||||
@@ -6749,9 +6590,9 @@ Miscellaneous
|
||||
other hand, setting a too high value can reduce responsiveness with low
|
||||
FPS value.
|
||||
|
||||
This option is interesting for client API users using the render API
|
||||
because you can stop it from limiting your FPS
|
||||
(see ``mpv_render_context_render()`` documentation).
|
||||
For client API users using the render API (or the deprecated ``opengl-cb``
|
||||
API), this option is interesting, because you can stop the render API
|
||||
from limiting your FPS (see ``mpv_render_context_render()`` documentation).
|
||||
|
||||
This applies only to audio timing modes (e.g. ``--video-sync=audio``). In
|
||||
other modes (``--video-sync=display-...``), video timing relies on vsync
|
||||
@@ -6946,8 +6787,9 @@ Miscellaneous
|
||||
(which are not marked as cover art), external cover art will not be loaded.
|
||||
|
||||
:no: Don't automatically load cover art.
|
||||
:exact: Load the media filename with an image file extension (default).
|
||||
:fuzzy: Load all cover art containing the media filename.
|
||||
:exact: Load the media filename with an image file extension.
|
||||
:fuzzy: Load all cover art containing the media filename and filenames
|
||||
in an internal whitelist, such as ``cover.jpg`` (default).
|
||||
:all: Load all images in the current directory.
|
||||
|
||||
See ``--cover-art-files`` for details about what constitutes cover art.
|
||||
@@ -6955,13 +6797,6 @@ Miscellaneous
|
||||
See ``--audio-display`` how to control display of cover art (this can be
|
||||
used to disable cover art that is part of the file).
|
||||
|
||||
``--cover-art-whitelist=<no|yes>``
|
||||
Whether to load filenames in an internal whitelist, such as ``cover.jpg``,
|
||||
as cover art. If ``cover-art-auto`` is set to ``no``, the whitelisted
|
||||
filenames are never loaded even if this option is set to ``yes``.
|
||||
|
||||
Default: ``yes``.
|
||||
|
||||
``--autoload-files=<yes|no>``
|
||||
Automatically load/select external files (default: yes).
|
||||
|
||||
@@ -7014,7 +6849,7 @@ Miscellaneous
|
||||
that are unavailable to outside users.
|
||||
|
||||
This replaces ``--record-file``. It is similar to the ancient/removed
|
||||
``--stream-capture``/``--capture`` options, and provides better behavior in
|
||||
``--stream-capture``/``-capture`` options, and provides better behavior in
|
||||
most cases (i.e. actually works).
|
||||
|
||||
``--lavfi-complex=<string>``
|
||||
|
||||
@@ -236,11 +236,6 @@ Configurable Options
|
||||
|
||||
Enable the OSC when fullscreen
|
||||
|
||||
``idlescreen``
|
||||
Default: yes
|
||||
|
||||
Show the mpv logo and message when idle
|
||||
|
||||
``scalewindowed``
|
||||
Default: 1.0
|
||||
|
||||
@@ -315,14 +310,6 @@ Configurable Options
|
||||
|
||||
Display timecodes with milliseconds
|
||||
|
||||
``tcspace``
|
||||
Default: 100 (allowed: 50-200)
|
||||
|
||||
Adjust space reserved for timecodes (current time and time remaining) in
|
||||
the ``bottombar`` and ``topbar`` layouts. The timecode width depends on the
|
||||
font, and with some fonts the spacing near the timecodes becomes too small.
|
||||
Use values above 100 to increase that spacing, or below 100 to decrease it.
|
||||
|
||||
``visibility``
|
||||
Default: auto (auto hide/show on mouse move)
|
||||
|
||||
@@ -395,26 +382,6 @@ Configurable Options
|
||||
Update chapter markers positions on duration changes, e.g. live streams.
|
||||
The updates are unoptimized - consider disabling it on very low-end systems.
|
||||
|
||||
``chapters_osd``, ``playlist_osd``
|
||||
Default: yes
|
||||
|
||||
Whether to display the chapters/playlist at the OSD when left-clicking the
|
||||
next/previous OSC buttons, respectively.
|
||||
|
||||
``chapter_fmt``
|
||||
Default: ``Chapter: %s``
|
||||
|
||||
Template for the chapter-name display when hovering the seekbar.
|
||||
Use ``no`` to disable chapter display on hover. Otherwise it's a lua
|
||||
``string.format`` template and ``%s`` is replaced with the actual name.
|
||||
|
||||
``unicodeminus``
|
||||
Default: no
|
||||
|
||||
Use a Unicode minus sign instead of an ASCII hyphen when displaying
|
||||
the remaining playback time.
|
||||
|
||||
|
||||
Script Commands
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -437,10 +404,6 @@ to set auto mode (the default) with ``b``::
|
||||
a script-message osc-visibility never
|
||||
b script-message osc-visibility auto
|
||||
|
||||
``osc-idlescreen``
|
||||
Controls the visibility of the mpv logo on idle. Valid arguments are ``yes``,
|
||||
``no``, and ``cycle`` to toggle between yes and no.
|
||||
|
||||
``osc-playlist``, ``osc-chapterlist``, ``osc-tracklist``
|
||||
Shows a limited view of the respective type of list using the OSC. First
|
||||
argument is duration in seconds.
|
||||
|
||||
+1
-9
@@ -308,14 +308,6 @@ Available mpv-only filters are:
|
||||
:709-1886: Scene-referred using the BT709+BT1886 interaction
|
||||
:gamma1.2: Scene-referred using a pure power OOTF (gamma=1.2)
|
||||
|
||||
``<dolbyvision=yes|no>``
|
||||
Whether or not to include Dolby Vision metadata (default: yes). If
|
||||
disabled, any Dolby Vision metadata will be stripped from frames.
|
||||
|
||||
``<film-grain=yes|no>``
|
||||
Whether or not to include film grain metadata (default: yes). If
|
||||
disabled, any film grain metadata will be stripped from frames.
|
||||
|
||||
``<stereo-in>``
|
||||
Set the stereo mode the video is assumed to be encoded in. Use
|
||||
``--vf=format:stereo-in=help`` to list all available modes. Check with
|
||||
@@ -465,7 +457,7 @@ Available mpv-only filters are:
|
||||
::
|
||||
|
||||
import vapoursynth as vs
|
||||
from vapoursynth import core
|
||||
core = vs.get_core()
|
||||
core.std.AddBorders(video_in, 10, 10, 20, 20).set_output()
|
||||
|
||||
.. warning::
|
||||
|
||||
+44
-76
@@ -21,46 +21,6 @@ in the list.
|
||||
|
||||
Available video output drivers are:
|
||||
|
||||
``gpu``
|
||||
General purpose, customizable, GPU-accelerated video output driver. It
|
||||
supports extended scaling methods, dithering, color management, custom
|
||||
shaders, HDR, and more.
|
||||
|
||||
See `GPU renderer options`_ for options specific to this VO.
|
||||
|
||||
By default, it tries to use fast and fail-safe settings. Use the
|
||||
``gpu-hq`` profile to use this driver with defaults set to high quality
|
||||
rendering. The profile can be applied with ``--profile=gpu-hq`` and its
|
||||
contents can be viewed with ``--show-profile=gpu-hq``.
|
||||
|
||||
This VO abstracts over several possible graphics APIs and windowing
|
||||
contexts, which can be influenced using the ``--gpu-api`` and
|
||||
``--gpu-context`` options.
|
||||
|
||||
Hardware decoding over OpenGL-interop is supported to some degree. Note
|
||||
that in this mode, some corner case might not be gracefully handled, and
|
||||
color space conversion and chroma upsampling is generally in the hand of
|
||||
the hardware decoder APIs.
|
||||
|
||||
``gpu`` makes use of FBOs by default. Sometimes you can achieve better
|
||||
quality or performance by changing the ``--fbo-format`` option to
|
||||
``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include Mesa/Intel not
|
||||
accepting ``rgb16``, Mesa sometimes not being compiled with float texture
|
||||
support, and some macOS setups being very slow with ``rgb16`` but fast
|
||||
with ``rgb32f``. If you have problems, you can also try enabling the
|
||||
``--gpu-dumb-mode=yes`` option.
|
||||
|
||||
``gpu-next``
|
||||
Experimental video renderer based on ``libplacebo``. This supports almost
|
||||
the same set of features as ``--vo=gpu``. See `GPU renderer options`_ for a
|
||||
list.
|
||||
|
||||
Should generally be faster and higher quality, but some features may still
|
||||
be missing or misbehave. Expect (and report!) bugs. See here for a list of
|
||||
known differences and bugs:
|
||||
|
||||
https://github.com/mpv-player/mpv/wiki/GPU-Next-vs-GPU
|
||||
|
||||
``xv`` (X11 only)
|
||||
Uses the XVideo extension to enable hardware-accelerated display. This is
|
||||
the most compatible VO on X, but may be low-quality, and has issues with
|
||||
@@ -118,9 +78,7 @@ Available video output drivers are:
|
||||
|
||||
``vdpau`` (X11 only)
|
||||
Uses the VDPAU interface to display and optionally also decode video.
|
||||
Hardware decoding is used with ``--hwdec=vdpau``. Note that there is
|
||||
absolutely no reason to use this, other than compatibility. We strongly
|
||||
recommend that you use ``--vo=gpu`` with ``--hwdec=nvdec`` instead.
|
||||
Hardware decoding is used with ``--hwdec=vdpau``.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -270,6 +228,35 @@ Available video output drivers are:
|
||||
``--vo-direct3d-exact-backbuffer``
|
||||
Always resize the backbuffer to window size.
|
||||
|
||||
``gpu``
|
||||
General purpose, customizable, GPU-accelerated video output driver. It
|
||||
supports extended scaling methods, dithering, color management, custom
|
||||
shaders, HDR, and more.
|
||||
|
||||
See `GPU renderer options`_ for options specific to this VO.
|
||||
|
||||
By default, it tries to use fast and fail-safe settings. Use the
|
||||
``gpu-hq`` profile to use this driver with defaults set to high quality
|
||||
rendering. The profile can be applied with ``--profile=gpu-hq`` and its
|
||||
contents can be viewed with ``--show-profile=gpu-hq``.
|
||||
|
||||
This VO abstracts over several possible graphics APIs and windowing
|
||||
contexts, which can be influenced using the ``--gpu-api`` and
|
||||
``--gpu-context`` options.
|
||||
|
||||
Hardware decoding over OpenGL-interop is supported to some degree. Note
|
||||
that in this mode, some corner case might not be gracefully handled, and
|
||||
color space conversion and chroma upsampling is generally in the hand of
|
||||
the hardware decoder APIs.
|
||||
|
||||
``gpu`` makes use of FBOs by default. Sometimes you can achieve better
|
||||
quality or performance by changing the ``--fbo-format`` option to
|
||||
``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include Mesa/Intel not
|
||||
accepting ``rgb16``, Mesa sometimes not being compiled with float texture
|
||||
support, and some macOS setups being very slow with ``rgb16`` but fast
|
||||
with ``rgb32f``. If you have problems, you can also try enabling the
|
||||
``--gpu-dumb-mode=yes`` option.
|
||||
|
||||
``sdl``
|
||||
SDL 2.0+ Render video output driver, depending on system with or without
|
||||
hardware acceleration. Should work on all platforms supported by SDL 2.0.
|
||||
@@ -286,20 +273,13 @@ Available video output drivers are:
|
||||
``--sdl-switch-mode``
|
||||
Instruct SDL to switch the monitor video mode when going fullscreen.
|
||||
|
||||
``dmabuf-wayland``
|
||||
Experimental Wayland output driver designed for use with either drm stateless
|
||||
or VA API hardware decoding. The driver is designed to avoid any GPU to CPU copies,
|
||||
and to perform scaling and color space conversion using fixed-function hardware,
|
||||
if available, rather than GPU shaders. This frees up GPU resources for other tasks.
|
||||
Currently this driver is experimental and only works with the ``--hwdec=vaapi``
|
||||
or ``hwdec=drm`` drivers;
|
||||
OSD is also not supported. Supported compositors : Weston and Sway.
|
||||
|
||||
``vaapi``
|
||||
Intel VA API video output driver with support for hardware decoding. Note
|
||||
that there is absolutely no reason to use this, other than compatibility.
|
||||
This is low quality, and has issues with OSD. We strongly recommend that
|
||||
you use ``--vo=gpu`` with ``--hwdec=vaapi`` instead.
|
||||
This is low quality, and has issues with OSD.
|
||||
|
||||
.. note:: This driver is for compatibility with crappy systems. You can
|
||||
use vaapi hardware decoding with ``--vo=gpu`` too.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
@@ -615,11 +595,11 @@ Available video output drivers are:
|
||||
based, and related to the CRTC.
|
||||
(default: primary)
|
||||
|
||||
When using this option with the drmprime-overlay hwdec interop, only the
|
||||
OSD is rendered to this plane.
|
||||
When using this option with the drmprime-drm hwdec interop, only the OSD
|
||||
is rendered to this plane.
|
||||
|
||||
``--drm-drmprime-video-plane=<primary|overlay|N>``
|
||||
Select the DRM plane to use for video with the drmprime-overlay hwdec
|
||||
Select the DRM plane to use for video with the drmprime-drm hwdec
|
||||
interop (used by e.g. the rkmpp hwdec on RockChip SoCs, and v4l2 hwdec:s
|
||||
on various other SoC:s). The plane is unused otherwise. This option
|
||||
accepts the same values as ``--drm-draw-plane``. (default: overlay)
|
||||
@@ -645,29 +625,17 @@ Available video output drivers are:
|
||||
``--drm-draw-surface-size=<[WxH]>``
|
||||
Sets the size of the surface used on the draw plane. The surface will
|
||||
then be upscaled to the current screen resolution. This option can be
|
||||
useful when used together with the drmprime-overlay hwdec interop at
|
||||
high resolutions, as it allows scaling the draw plane (which in this
|
||||
case only handles the OSD) down to a size the GPU can handle.
|
||||
useful when used together with the drmprime-drm hwdec interop at high
|
||||
resolutions, as it allows scaling the draw plane (which in this case
|
||||
only handles the OSD) down to a size the GPU can handle.
|
||||
|
||||
When used without the drmprime-overlay hwdec interop this option will
|
||||
just cause the video to get rendered at a different resolution and then
|
||||
When used without the drmprime-drm hwdec interop this option will just
|
||||
cause the video to get rendered at a different resolution and then
|
||||
scaled to screen size.
|
||||
|
||||
Note: this option is only available with DRM atomic support.
|
||||
(default: display resolution)
|
||||
|
||||
``--drm-vrr-enabled=<no|yes|auto>``
|
||||
Toggle use of Variable Refresh Rate (VRR), aka Freesync or Adaptive Sync
|
||||
on compatible systems. VRR allows for the display to be refreshed at any
|
||||
rate within a range (usually ~40Hz-60Hz for 60Hz displays). This can help
|
||||
with playback of 24/25/50fps content. Support depends on the use of a
|
||||
compatible monitor, GPU, and a sufficiently new kernel with drivers
|
||||
that support the feature.
|
||||
|
||||
:no: Do not attempt to enable VRR. (default)
|
||||
:yes: Attempt to enable VRR, whether the capability is reported or not.
|
||||
:auto: Attempt to enable VRR if support is reported.
|
||||
|
||||
``mediacodec_embed`` (Android)
|
||||
Renders ``IMGFMT_MEDIACODEC`` frames directly to an ``android.view.Surface``.
|
||||
Requires ``--hwdec=mediacodec`` for hardware decoding, along with
|
||||
@@ -677,8 +645,8 @@ Available video output drivers are:
|
||||
many of mpv's features (subtitle rendering, OSD/OSC, video filters, etc)
|
||||
are not available with this driver.
|
||||
|
||||
To use hardware decoding with ``--vo=gpu`` instead, use ``--hwdec=mediacodec``
|
||||
or ``mediacodec-copy`` along with ``--gpu-context=android``.
|
||||
To use hardware decoding with ``--vo=gpu`` instead, use
|
||||
``--hwdec=mediacodec-copy`` along with ``--gpu-context=android``.
|
||||
|
||||
``wlshm`` (Wayland only)
|
||||
Shared memory video output driver without hardware acceleration that works
|
||||
|
||||
@@ -377,7 +377,7 @@ without causing conflicts with other library users in the same process. To any
|
||||
piece of code, a "safe" library's API can simply be used, without having to
|
||||
worry about other API users that may be around somewhere.
|
||||
|
||||
Libraries are often not library safe, because they use global mutable state
|
||||
Libraries are often not library safe, because they they use global mutable state
|
||||
or other "global" resources. Typical examples include use of signals, simple
|
||||
global variables (like hsearch() in libc), or internal caches not protected by
|
||||
locks.
|
||||
@@ -481,7 +481,7 @@ VOs, AOs, demuxers, and more. The frontend usually calls "down" the usage
|
||||
hierarchy: mpctx almost on top, then things like vo/ao, and utility code on the
|
||||
very bottom.
|
||||
|
||||
"Callback hell" is when components call both up and down the hierarchy,
|
||||
"Callback hell" is when when components call both up and down the hierarchy,
|
||||
which for example leads to accidentally recursion, reentrancy problems, or
|
||||
locking nightmares. This is avoided by (mostly) calling only down the hierarchy.
|
||||
Basically the call graph forms a DAG. The other direction is handled by event
|
||||
|
||||
@@ -73,27 +73,11 @@ Changes to the default key bindings are indicated in
|
||||
|
||||
|
||||
Compiling with full features requires development files for several
|
||||
external libraries. One of the two build systems supported by mpv is required:
|
||||
[meson](https://mesonbuild.com/index.html) or [waf](https://waf.io/). Meson
|
||||
can be obtained from your distro or PyPI. Waf can be downloaded by using the
|
||||
`./bootstrap.py` script. It will get the latest version of waf that was tested
|
||||
with mpv. Some documentation about the differences between the build systems are
|
||||
located in [build-system-differences][build-system-differences].
|
||||
external libraries. Below is a list of some important requirements.
|
||||
|
||||
### Meson
|
||||
|
||||
After creating your build directory (e.g. `meson setup build`), you can view a list
|
||||
of all the build options via `meson configure build`. You could also just simply
|
||||
look at the `meson_options.txt` file. Logs are stored in `meson-logs` within
|
||||
your build directory.
|
||||
|
||||
Example:
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
meson install -C build
|
||||
|
||||
### Waf
|
||||
The mpv build system uses [waf](https://waf.io/), but we don't store it in the
|
||||
repository. The `./bootstrap.py` script will download the latest version
|
||||
of waf that was tested with the build system.
|
||||
|
||||
For a list of the available build options use `./waf configure --help`. If
|
||||
you think you have support for some feature installed but configure fails to
|
||||
@@ -230,4 +214,3 @@ Most activity happens on the IRC channel and the github issue tracker.
|
||||
[api-changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/client-api-changes.rst
|
||||
[restore-old-bindings]: https://github.com/mpv-player/mpv/blob/master/etc/restore-old-bindings.conf
|
||||
[contribute.md]: https://github.com/mpv-player/mpv/blob/master/DOCS/contribute.md
|
||||
[build-system-differences]: https://github.com/mpv-player/mpv/blob/master/DOCS/build-system-differences.md
|
||||
+99
-129
@@ -1,45 +1,24 @@
|
||||
Release 0.35.1
|
||||
Release 0.34.1
|
||||
==============
|
||||
|
||||
Bug fix release for the 0.35 branch.
|
||||
Bug fix release for the 0.34 branch.
|
||||
|
||||
Fixes and Minor Enhancements
|
||||
----------------------------
|
||||
|
||||
- ao_pipewire: log version and other useful debug info
|
||||
- wayland: error out if essential protocol support is missing
|
||||
- wayland: also log refresh rate on surface entrance
|
||||
- vo_gpu_next: fix undefined behavior on alpha-first formats
|
||||
- meson: prepend MPV_CONFDIR path with prefix
|
||||
- meson: unbreak dl check on BSDs without libdl
|
||||
- lcms: fix crash with lcms2-related options if lcms is disabled
|
||||
- meson: fix stdatomic detection on bsd
|
||||
- osc: don't spam window-controls bindings on every render
|
||||
- wayland: check for resize/move in touch event first
|
||||
- ao_coreaudio: use device's nominal sample rate for latency properties
|
||||
- ao_pipewire: properly clean up resources
|
||||
- filter_kernels: fix kaiser
|
||||
- hwdec/d3d11va: fix a possible memory leak
|
||||
- external_files: set log level for potential files to trace
|
||||
- vo_opengl: do not blindly reject all Microsoft's OpenGL implementations
|
||||
- ao_coreaudio: use AudioUnitReset as ao_driver.reset to prevent long restart
|
||||
- hwdec_drmprime: fix memory leak
|
||||
- vo: hwdec: fix libdrm-related memory leak
|
||||
- draw_bmp: ensure last slice width is less than total width
|
||||
- wayland: dispatch and wait for compositor events in uninit
|
||||
- demux: boost read EBU R128 gain values to ReplayGain's reference level
|
||||
- version.py/version.sh: bump copyright year
|
||||
- vulkan: fix build error for 32bit builds with clang
|
||||
- vo_wlshm: cleanup on failure
|
||||
- ra_d3d11: fix incorrect type
|
||||
- meson: also search for rst2html with .py extension
|
||||
- audio: fix crash during uninit with ao_lavc
|
||||
- mp_image: fix XYZ primaries default
|
||||
- vd_lavc: add "auto" choice for vd-lavc-dr
|
||||
- vo: implement VO_DR_FLAG_HOST_CACHED
|
||||
- x11: fix issue with xpresent timing feedback
|
||||
- player: fix autofit/geometry related segfault
|
||||
- ao_oss: add missing PATH_DEV_MIXER define
|
||||
- egl_helpers: fix context creation if GLES 3 is not available
|
||||
- audio: stop corrupting audio on underreads
|
||||
- wayland: fix a potential segfault on surface enter
|
||||
- vo_gpu: opengl: fix wrong glMemoryBarrier call
|
||||
- vo_gpu: opengl: create context at version 4.4 again
|
||||
- af_lavcac3enc: fix memory leak on no-op
|
||||
- subprocess: unblock/reset signals before running child process
|
||||
- wayland: avoid doing unneccesary window resizes
|
||||
|
||||
Release 0.35.0
|
||||
|
||||
Release 0.34.0
|
||||
==============
|
||||
|
||||
This release requires FFmpeg 4.0 or newer.
|
||||
@@ -48,9 +27,6 @@ For packagers: Note that mpv's build system is only supported on Python 3.
|
||||
If you use the `bootstrap.py` script it will take care of this, otherwise you
|
||||
need to explicitly invoke the build system using `python3 waf`.
|
||||
|
||||
This release adds the Meson build system as an alternative to waf.
|
||||
It is supposed to be feature-complete but please report any issues you encounter.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
@@ -58,39 +34,34 @@ Features
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- vo_gpu_next: add new libplacebo-based renderer
|
||||
- build: add meson build support
|
||||
- vo_gpu_next: forward Dolby Vision metadata to libplacebo
|
||||
- ao_pipewire: add PipeWire audio backend
|
||||
- ao_sndio: readd this audio output again
|
||||
- vo_gpu_next: apply film grain if such metadata is present
|
||||
- drm: context_drm_egl: add support for enabling VRR
|
||||
- demux: add support for R128 replaygain tags
|
||||
- x11: support X Present extension
|
||||
- af_rubberband: add support for new engine in rubberband 3.0.0
|
||||
- hwdec/drmprime: add drmprime hwdec-interop (commonly found on SoCs)
|
||||
- various: support binding functions keys beyond F12
|
||||
- audio: support hotplug events for multiple AOs
|
||||
- sub: use Unicode linebreaking for non-ASS subs and OSD
|
||||
- vo_gpu: hwdec: add Android hwdec utilizing AImageReader
|
||||
- vo_dmabuf_wayland: add wayland VO displaying dmabuf buffers (vaapi or drm hwdec only)
|
||||
- lua/console: add history deduplication
|
||||
- player: allow vo to be switched at runtime
|
||||
- input.conf syntax: support custom quotes in `XstringX` form & single quotes
|
||||
- ao_ass: readd OSSv4 audio output, default on *BSD
|
||||
- player: load cover art with the media filename
|
||||
- vo_gpu: vulkan: implement a VkDisplayKHR backed context
|
||||
- osc: seekbar hover/drag: display target chapter at the OSC title
|
||||
- stats.lua: add page 4 with a list of active key bindings
|
||||
- sub: add --sub-filter-jsre (JS regex)
|
||||
- vo_rpi: restore fullscreen handling
|
||||
- vo_tct: add resize capability
|
||||
- ytdl_hook.lua: search for yt-dlp by default (preferred over youtube-dl)
|
||||
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- filters: re-add vavpp hardware deinterlacing auto-filter (for --deinterlace)
|
||||
- swresample: don't forcibly clip audio on every conversion
|
||||
- ytdl_hook: always set HTTP headers to fix yt-dlp on certain sites
|
||||
- vo_sixel: many fixes and improvements
|
||||
- filters: switch from scaletempo to scaletempo2, used for `speed` option
|
||||
- audio/vo_pulse: fix various edge cases and issues
|
||||
- stats.lua: move internal performance info from page 4 to page 0
|
||||
- command: don't hardcode command lists to be repeatable
|
||||
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- libmpv: remove opengl_cb API and other deprecated symbols
|
||||
- lua: remove deprecated mp.suspend(), resume() and resume_all()
|
||||
- build: raise minimum libplacebo version requirement to v4.157.0
|
||||
- mac: drop build support for swift versions earlier than 4.1
|
||||
- vo_gpu: drop support for libplacebo older than v3.104.0
|
||||
|
||||
|
||||
Options and Commands
|
||||
@@ -99,98 +70,97 @@ Options and Commands
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- vo_gpu_next: add --target-colorspace-hint to facilitate HDR passthrough
|
||||
- vo_gpu_next: new tone mapping options 'auto', 'spline', 'bt.2446a'
|
||||
and add --tone-mapping-crosstalk, --inverse-tone-mapping
|
||||
- vo_gpu: add --gamut-mapping-mode and --tone-mapping-mode
|
||||
- options: add 'always' choice to --stop-screensaver
|
||||
- options: add --osd-playing-msg-duration
|
||||
- player: add --cover-art-whitelist option
|
||||
- x11: add --x11-present option
|
||||
- vo_sixel: add --vo-sixel-exit-clear
|
||||
- player: add --screen-name and --fs-screen-name
|
||||
- player/command: add albumart argument to video-add
|
||||
- command: add pid (process id), display-width and display-height properties
|
||||
- sub: add secondary-sub-text, -start, and -end properties; secondary-sub-visibility option
|
||||
- vo_gpu: add --icc-force-contrast
|
||||
- player: add append-play flag to loadlist
|
||||
- command: add support for secondary subs to sub-seek and sub-step
|
||||
- options: add watch-later-options to configure which options are saved
|
||||
- player: add track-list/N/image sub-property
|
||||
- input: add --no-input-builtin-bindings option
|
||||
- drm_common: add --drm-device option
|
||||
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- ao_openal: enable --openal-direct-channels by default
|
||||
- options: only apply --sub-visibility to primary subtitles
|
||||
- options: make --cover-art-auto=exact the default
|
||||
- vo_gpu/hwdec: rename and introduce legacy names for some interops
|
||||
- vo_sixel: change default dither to "auto"
|
||||
- vd_lavc: add VP8 to the default allowed hwdec codec list
|
||||
- vo_gpu: lower default deband threshold to preserve more detail
|
||||
- vo_gpu: adjust interpolation-threshold's default
|
||||
- demux: undeprecate --cache-secs
|
||||
- options: add `Uploader`, `Channel_URL` to --display-tags defaults
|
||||
- options: --audio-display determines cover priority
|
||||
- command: make current-window-scale writeable
|
||||
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
||||
- vo_gpu: deprecate --gamma-factor and --gamma-auto
|
||||
- win32: ignore and deprecate --fit-border
|
||||
- drm_common: deprecate selecting by card number in --drm-connector
|
||||
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- vo_gpu: remove --gamut-clipping, --gamut-warning, --tone-mapping-desaturate and
|
||||
--tone-mapping-desaturate-exponent (replacements available)
|
||||
- vulkan: remove --vulkan-disable-events
|
||||
- vo_gpu: remove --icc-contrast
|
||||
- stats.lua: remove script-opts for the main keys (i/I)
|
||||
- vo_gpu: opengl: remove --opengl-restrict
|
||||
|
||||
|
||||
Fixes and Minor Enhancements
|
||||
----------------------------
|
||||
|
||||
- context_drm_egl: use gbm_surface_create_with_modifiers
|
||||
- context_drm_egl: add support for BGR surface formats
|
||||
- vo_gpu: vulkan: open DRM render fd when using VK_KHR_display
|
||||
- client API: use symbol visibility attributes
|
||||
- vo_gpu: hwdec_vaapi: add dma-buf modifiers support
|
||||
- wayland: fix various issues that could lead to jitter
|
||||
- osc: fix cache displaying 60s in some cases
|
||||
- player: make --keep-open=always work with --loop-playlist
|
||||
- opengl: support driver debug message under OpenGL ES
|
||||
- vo_gpu: opengl: fixes for OpenGL ES version and extension handling
|
||||
- f_decoder_wrapper: support frame rotation metadata (used by JPEG)
|
||||
- wscript: switch shaderc checks to pkgconfig
|
||||
- vd_lavc: enable hwdec for prores by default
|
||||
- vo_gpu: add HOOKED_gather for custom shaders
|
||||
- wayland, x11: sanitize window title for valid UTF-8
|
||||
- win32: apply geometry position to content instead of window
|
||||
- filter_kernels: add cosine window
|
||||
- vo_gpu: hwdec_vaapi: don't probe formats for irrelevant endpoints
|
||||
- vo_gpu: hwdec: load hwdec interops on-demand by default
|
||||
- stats.lua: graphs: fix bad rendering due to division by 0
|
||||
- hwdec: warn on unsupported --hwdec option value
|
||||
- x11: fix --screen-name option
|
||||
- x11: avoid wasteful rendering when possible
|
||||
- video/image_writer: add JPEG XL support
|
||||
- stream_lavf: enable ipfs, ipns and rist protocol support
|
||||
- osc.lua: fix crash when calling osc-tracklist while idle
|
||||
- player: add jxl, tiff, tif to list of image extensions
|
||||
- various: switch to new AVChannelLayout structure
|
||||
- lua: command_native_async: always run callback asynchronously (edge case)
|
||||
- context_x11egl: remove supposed transparency workaround
|
||||
- vo_gpu: fix 3DLUT precision
|
||||
- drm: avoid drmModeAtomicCommit races by blocking
|
||||
- drm_common: skip cards that don't support KMS for autodetection
|
||||
- hwdec/dmabuf_interop_gl: support basic multi-plane formats
|
||||
- misc/random: switch to internal xoshiro rng implementation
|
||||
- ytdl_hook: improve track detection
|
||||
- ad_lavc: strip non-normalized floats
|
||||
- mpv.metainfo.xml: add XDG appstream metadata manifest
|
||||
- mac: avoid unnecessary unsafe conversions; fixes crash in debug builds
|
||||
- af_scaletempo2: fix crash when the number of channels increases
|
||||
- wayland: correctly handle non-CLOCK_MONOTONIC clocks
|
||||
- x11: fix --on-all-workspaces option
|
||||
- sd_ass: improve handling of subtitles with unknown duration
|
||||
- hwdec/vaapi: improve probing of supported sw formats
|
||||
- demux_mf: enable support for QOI, PHM and HDR images
|
||||
- demux_mkv: add AVS2 and AVS3 to tag list
|
||||
- TOOLS/lua/autoload: fix incorrect duplicate file loading behavior
|
||||
- demux/codec_tags: support more WAVEFORMATEXTENSIBLE tags
|
||||
- sd_ass: never mangle colours on RGB video
|
||||
- terminal: correctly process input when foregrounded
|
||||
- vo_wlshm: support presentation time
|
||||
- mac: fix a window positioning bug when exiting fullscreen
|
||||
- csputils: add mappings for DCI-P3 (ST.431-2) and P3-D65 (ST.432-1)
|
||||
- player: make resetting of track selection to "auto" work
|
||||
- stream_lavf: support rtsps
|
||||
- vo_wlshm: support big endian systems
|
||||
- demux_mf: add support for more image codecs
|
||||
- msg: fix really-quiet option to only affect terminal output
|
||||
- mac: fix traditional fullscreen on macOS 11
|
||||
- ao_pulse: fix misbehavior with PipeWire when setting volume or mute
|
||||
- stats.lua: include a filter's @label when displaying filters on page 1
|
||||
- wayland, win32: support the display-hidpi-scale property
|
||||
- win32: keep the window title-bar inside the screen
|
||||
- filter_kernels: fix incorrect constant for quadric window
|
||||
- command: add display-width/display-height property
|
||||
- edl: add a way to add tags
|
||||
- stream_file: disable readahead for remote files on macOS to fix stutter
|
||||
- osxbundle: fix slow and wasteful memory allocation that caused stutter
|
||||
- vo_gpu: fix extreme clipping with --gamut-clipping for HDR outputs
|
||||
- af_scaletempo2: speed up using vector calculations
|
||||
- recorder: fix muxing of certain codecs
|
||||
- win32: support the focused property
|
||||
- js: add mp.utils.append_file
|
||||
- subs: fix missing subtitles on last frame
|
||||
- stats.lua: show scaled resolution
|
||||
- osc: expose osc-visibility via shared-script-properties
|
||||
- terminal-unix: fix ^Z identification and ignore unknown CSI sequences
|
||||
- context_drm_egl: allow autoprobe selection
|
||||
- wayland: improve behavior with touch events
|
||||
- command: make current-window-scale writeable
|
||||
- vo_vdpau: don't treat preemption as an error to fix VT switching
|
||||
- wayland: read XCURSOR_THEME to get cursor theme
|
||||
- demux_playlist: extend maximum line size (again) to 2M
|
||||
- win32: call timeBeginPeriod on demand on Windows 10
|
||||
- build: allow easier selection of lua version/package
|
||||
- vo_gpu: fix distortion with certain rotated videos
|
||||
- drm_common: skip non-primary devices during automatic choosing
|
||||
- drm_common: support USB, SPI, Writeback and unknown connector types (future proofing)
|
||||
|
||||
|
||||
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.34.0..v0.35.1`
|
||||
A complete changelog can be seen by running `git log v0.33.0..v0.34.1`
|
||||
in the git repository or by visiting either
|
||||
https://github.com/mpv-player/mpv/compare/v0.34.0...v0.35.1 or
|
||||
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.34.0..v0.35.1
|
||||
https://github.com/mpv-player/mpv/compare/v0.33.0...v0.34.1 or
|
||||
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.33.0..v0.34.1
|
||||
@@ -69,7 +69,7 @@ def lib_name(lib):
|
||||
|
||||
def process_libraries(libs_dict, binary):
|
||||
libs_set = set(libs_dict)
|
||||
# Remove binary from libs_set to prevent a duplicate of the binary being
|
||||
# Remove binary from libs_set to prevent a duplicate of the binary being
|
||||
# added to the libs directory.
|
||||
libs_set.remove(binary)
|
||||
|
||||
|
||||
@@ -39,10 +39,5 @@ def file2string(infilename, infile, outfile):
|
||||
outfile.write('"' + ''.join(conv[c] for c in line) + '"\n')
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
outfile = sys.stdout
|
||||
else:
|
||||
outfile = open(sys.argv[2], "w")
|
||||
|
||||
with open(sys.argv[1], 'rb') as infile:
|
||||
file2string(sys.argv[1], infile, outfile)
|
||||
file2string(sys.argv[1], infile, sys.stdout)
|
||||
@@ -2,7 +2,7 @@
|
||||
-- filter including key bindings for adjusting parameters.
|
||||
--
|
||||
-- See https://ffmpeg.org/ffmpeg-filters.html#acompressor for explanation
|
||||
-- of the parameters.
|
||||
-- of the parameteres.
|
||||
|
||||
local mp = require 'mp'
|
||||
local options = require 'mp.options'
|
||||
|
||||
+12
-20
@@ -49,18 +49,15 @@ function SetUnion (a,b)
|
||||
end
|
||||
|
||||
EXTENSIONS_VIDEO = Set {
|
||||
'3g2', '3gp', 'avi', 'flv', 'm2ts', 'm4v', 'mj2', 'mkv', 'mov',
|
||||
'mp4', 'mpeg', 'mpg', 'ogv', 'rmvb', 'webm', 'wmv', 'y4m'
|
||||
'mkv', 'avi', 'mp4', 'ogv', 'webm', 'rmvb', 'flv', 'wmv', 'mpeg', 'mpg', 'm4v', '3gp'
|
||||
}
|
||||
|
||||
EXTENSIONS_AUDIO = Set {
|
||||
'aiff', 'ape', 'au', 'flac', 'm4a', 'mka', 'mp3', 'oga', 'ogg',
|
||||
'ogm', 'opus', 'wav', 'wma'
|
||||
'mp3', 'wav', 'ogm', 'flac', 'm4a', 'wma', 'ogg', 'opus'
|
||||
}
|
||||
|
||||
EXTENSIONS_IMAGES = Set {
|
||||
'avif', 'bmp', 'gif', 'j2k', 'jp2', 'jpeg', 'jpg', 'jxl', 'png',
|
||||
'svg', 'tga', 'tif', 'tiff', 'webp'
|
||||
'jpg', 'jpeg', 'png', 'tif', 'tiff', 'gif', 'webp', 'svg', 'bmp'
|
||||
}
|
||||
|
||||
EXTENSIONS = Set {}
|
||||
@@ -127,16 +124,6 @@ end
|
||||
|
||||
local autoloaded = nil
|
||||
|
||||
function get_playlist_filenames()
|
||||
local filenames = {}
|
||||
for n = 0, pl_count - 1, 1 do
|
||||
local filename = mp.get_property('playlist/'..n..'/filename')
|
||||
local _, file = utils.split_path(filename)
|
||||
filenames[file] = true
|
||||
end
|
||||
return filenames
|
||||
end
|
||||
|
||||
function find_and_add_entries()
|
||||
local path = mp.get_property("path", "")
|
||||
local dir, filename = utils.split_path(path)
|
||||
@@ -149,7 +136,7 @@ function find_and_add_entries()
|
||||
return
|
||||
end
|
||||
|
||||
pl_count = mp.get_property_number("playlist-count", 1)
|
||||
local pl_count = mp.get_property_number("playlist-count", 1)
|
||||
-- check if this is a manually made playlist
|
||||
if (pl_count > 1 and autoloaded == nil) or
|
||||
(pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil) then
|
||||
@@ -201,17 +188,22 @@ function find_and_add_entries()
|
||||
msg.trace("current file position in files: "..current)
|
||||
|
||||
local append = {[-1] = {}, [1] = {}}
|
||||
local filenames = get_playlist_filenames()
|
||||
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
|
||||
for i = 1, MAXENTRIES do
|
||||
local file = files[current + i * direction]
|
||||
local pl_e = pl[pl_current + i * direction]
|
||||
if file == nil or file[1] == "." then
|
||||
break
|
||||
end
|
||||
|
||||
local filepath = dir .. file
|
||||
-- skip files already in playlist
|
||||
if filenames[file] then break end
|
||||
if pl_e then
|
||||
-- If there's a playlist entry, and it's the same file, stop.
|
||||
msg.trace(pl_e.filename.." == "..filepath.." ?")
|
||||
if pl_e.filename == filepath then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if direction == -1 then
|
||||
if pl_current == 1 then -- never add additional entries in the middle
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Logic copied from compiler_swift.py in the waf build. This checks for the sdk
|
||||
# path, the sdk version, and the sdk build version. The sdk path is returned
|
||||
# along with what is selected as the sdk version.
|
||||
|
||||
import re
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
from distutils.version import StrictVersion
|
||||
from shutil import which
|
||||
from subprocess import check_output
|
||||
|
||||
def find_macos_sdk():
|
||||
sdk = os.environ.get('MACOS_SDK', '')
|
||||
sdk_version = os.environ.get('MACOS_SDK_VERSION', '0.0')
|
||||
xcrun = which('xcrun')
|
||||
|
||||
if not xcrun:
|
||||
return sdk,sdk_version
|
||||
|
||||
if not sdk:
|
||||
sdk = check_output([xcrun, '--sdk', 'macosx', '--show-sdk-path'],
|
||||
encoding="UTF-8")
|
||||
|
||||
# find macOS SDK paths and version
|
||||
if sdk_version == '0.0':
|
||||
# show-sdk-build-version: is not available on older command line tools, but returns a build version (eg 17A360)
|
||||
# show-sdk-version: is always available, but on older dev tools it's only the major version
|
||||
sdk_build_version = check_output([xcrun, '--sdk', 'macosx',
|
||||
'--show-sdk-build-version'], encoding="UTF-8")
|
||||
|
||||
sdk_version = check_output([xcrun, '--sdk', 'macosx', '--show-sdk-version'],
|
||||
encoding="UTF-8")
|
||||
|
||||
if sdk:
|
||||
build_version = '10.10.0'
|
||||
|
||||
# convert build version to a version string
|
||||
# first 2 two digits are the major version, starting with 15 which is 10.11 (offset of 4)
|
||||
# 1 char is the minor version, A => 0, B => 1 and ongoing
|
||||
# last digits are bugfix version, which are not relevant for us
|
||||
# eg 16E185 => 10.12.4, 17A360 => 10.13, 18B71 => 10.14.1
|
||||
if sdk_build_version and isinstance(sdk_build_version, str):
|
||||
verRe = re.compile("(\d+)(\D+)(\d+)")
|
||||
version_parts = verRe.search(sdk_build_version)
|
||||
major = int(version_parts.group(1)) - 4
|
||||
minor = string.ascii_lowercase.index(version_parts.group(2).lower())
|
||||
build_version = '10.' + str(major) + '.' + str(minor)
|
||||
# from 20 onwards macOS 11.0 starts
|
||||
if int(version_parts.group(1)) >= 20:
|
||||
build_version = '11.' + str(minor)
|
||||
|
||||
if not isinstance(sdk_version, str):
|
||||
sdk_version = '10.10.0'
|
||||
|
||||
# pick the higher version, always pick sdk over build if newer
|
||||
if StrictVersion(build_version) > StrictVersion(sdk_version):
|
||||
return sdk,build_version
|
||||
else:
|
||||
return sdk,sdk_version
|
||||
|
||||
return sdk,sdk_version
|
||||
|
||||
if __name__ == "__main__":
|
||||
sdk_info = find_macos_sdk()
|
||||
sys.stdout.write(','.join(sdk_info))
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Finds the macos swift library directory and prints the full path to stdout.
|
||||
# First argument is the path to the swift executable.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from shutil import which
|
||||
from subprocess import check_output
|
||||
|
||||
def find_swift_lib():
|
||||
swift_lib_dir = os.environ.get('SWIFT_LIB_DYNAMIC', '')
|
||||
if swift_lib_dir:
|
||||
return swift_lib_dir
|
||||
|
||||
# first check for lib dir relative to swift executable
|
||||
xcode_dir = os.path.dirname(os.path.dirname(sys.argv[1]))
|
||||
swift_lib_dir = os.path.join(xcode_dir, "lib", "swift", "macosx")
|
||||
|
||||
if os.path.isdir(swift_lib_dir):
|
||||
return swift_lib_dir
|
||||
|
||||
# fallback to xcode-select path
|
||||
xcode_select = which("xcode-select")
|
||||
if not xcode_select:
|
||||
sys.exit(1)
|
||||
|
||||
xcode_path = check_output([xcode_select, "-p"], encoding="UTF-8")
|
||||
|
||||
swift_lib_dir = os.path.join(xcode_path, "Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx")
|
||||
if os.path.isdir(swift_lib_dir):
|
||||
return swift_lib_dir
|
||||
|
||||
# last resort if we still haven't found a path
|
||||
swift_lib_dir = os.path.join(xcode_path, "usr/lib/swift/macosx")
|
||||
if not os.path.isdir(swift_lib_dir):
|
||||
sys.exit(1)
|
||||
return swift_lib_dir
|
||||
|
||||
if __name__ == "__main__":
|
||||
swift_lib_dir = find_swift_lib()
|
||||
sys.stdout.write(swift_lib_dir)
|
||||
+2
-7
@@ -459,15 +459,10 @@ if __name__ == "__main__":
|
||||
def parse_toplevel(s):
|
||||
parse_one(s, 0, None, 1 << 63)
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
outfile = sys.stdout
|
||||
else:
|
||||
outfile = open(sys.argv[2], "w")
|
||||
|
||||
if sys.argv[1] == '--generate-header':
|
||||
generate_C_header(outfile)
|
||||
generate_C_header(sys.stdout)
|
||||
elif sys.argv[1] == '--generate-definitions':
|
||||
generate_C_definitions(outfile)
|
||||
generate_C_definitions(sys.stdout)
|
||||
else:
|
||||
s = open(sys.argv[1], "rb")
|
||||
while 1:
|
||||
|
||||
@@ -223,7 +223,6 @@
|
||||
<string>udp</string>
|
||||
<string>smb</string>
|
||||
<string>srt</string>
|
||||
<string>rist</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ install:
|
||||
# Update non-core packages
|
||||
- C:\msys64\usr\bin\pacman -Suu --noconfirm --noprogressbar --ask=20
|
||||
# Install required MSYS2 packages
|
||||
- C:\msys64\usr\bin\pacman -S --noconfirm --noprogressbar --needed base-devel perl python pkgconf
|
||||
- C:\msys64\usr\bin\pacman -S --noconfirm --noprogressbar --needed base-devel perl python pkg-config
|
||||
# Now MSYS2 is up to date, do the rest of the install from a bash script
|
||||
- C:\msys64\usr\bin\bash -lc "cd && exec \"$APPVEYOR_BUILD_FOLDER\"/TOOLS/appveyor-install.sh"
|
||||
build_script:
|
||||
|
||||
+1
-64
@@ -18,12 +18,9 @@
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/mem.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "chmap.h"
|
||||
#include "chmap_avchannel.h"
|
||||
#include "fmt-conversion.h"
|
||||
#include "format.h"
|
||||
#include "aframe.h"
|
||||
@@ -124,16 +121,6 @@ struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame)
|
||||
if (!av_frame || av_frame->width > 0 || av_frame->height > 0)
|
||||
return NULL;
|
||||
|
||||
#if HAVE_AV_CHANNEL_LAYOUT
|
||||
if (!av_channel_layout_check(&av_frame->ch_layout))
|
||||
return NULL;
|
||||
|
||||
struct mp_chmap converted_map = { 0 };
|
||||
if (!mp_chmap_from_av_layout(&converted_map, &av_frame->ch_layout)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int format = af_from_avformat(av_frame->format);
|
||||
if (!format && av_frame->format != AV_SAMPLE_FMT_NONE)
|
||||
return NULL;
|
||||
@@ -145,15 +132,11 @@ struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame)
|
||||
abort();
|
||||
|
||||
frame->format = format;
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
mp_chmap_from_lavc(&frame->chmap, frame->av_frame->channel_layout);
|
||||
|
||||
// FFmpeg being a stupid POS again
|
||||
if (frame->chmap.num != frame->av_frame->channels)
|
||||
mp_chmap_from_channels(&frame->chmap, av_frame->channels);
|
||||
#else
|
||||
frame->chmap = converted_map;
|
||||
#endif
|
||||
|
||||
if (av_frame->opaque_ref) {
|
||||
struct avframe_opaque *op = (void *)av_frame->opaque_ref->data;
|
||||
@@ -221,16 +204,9 @@ void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src)
|
||||
|
||||
dst->av_frame->sample_rate = src->av_frame->sample_rate;
|
||||
dst->av_frame->format = src->av_frame->format;
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
dst->av_frame->channel_layout = src->av_frame->channel_layout;
|
||||
// FFmpeg being a stupid POS again
|
||||
dst->av_frame->channels = src->av_frame->channels;
|
||||
#else
|
||||
if (av_channel_layout_copy(&dst->av_frame->ch_layout,
|
||||
&src->av_frame->ch_layout) < 0)
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Copy "soft" attributes from src to dst, excluding things which affect
|
||||
@@ -339,21 +315,13 @@ bool mp_aframe_set_chmap(struct mp_aframe *frame, struct mp_chmap *in)
|
||||
return false;
|
||||
if (mp_aframe_is_allocated(frame) && in->num != frame->chmap.num)
|
||||
return false;
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
uint64_t lavc_layout = mp_chmap_to_lavc_unchecked(in);
|
||||
if (!lavc_layout && in->num)
|
||||
return false;
|
||||
#endif
|
||||
frame->chmap = *in;
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
frame->av_frame->channel_layout = lavc_layout;
|
||||
// FFmpeg being a stupid POS again
|
||||
frame->av_frame->channels = frame->chmap.num;
|
||||
#else
|
||||
mp_chmap_to_av_layout(&frame->av_frame->ch_layout, in);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -466,37 +434,6 @@ void mp_aframe_skip_samples(struct mp_aframe *f, int samples)
|
||||
f->pts += samples / mp_aframe_get_effective_rate(f);
|
||||
}
|
||||
|
||||
// sanitize a floating point sample value
|
||||
#define sanitizef(f) do { \
|
||||
if (!isnormal(f)) \
|
||||
(f) = 0; \
|
||||
} while (0)
|
||||
|
||||
void mp_aframe_sanitize_float(struct mp_aframe *mpa)
|
||||
{
|
||||
int format = af_fmt_from_planar(mp_aframe_get_format(mpa));
|
||||
if (format != AF_FORMAT_FLOAT && format != AF_FORMAT_DOUBLE)
|
||||
return;
|
||||
int num_planes = mp_aframe_get_planes(mpa);
|
||||
uint8_t **planes = mp_aframe_get_data_rw(mpa);
|
||||
if (!planes)
|
||||
return;
|
||||
for (int p = 0; p < num_planes; p++) {
|
||||
void *ptr = planes[p];
|
||||
int total = mp_aframe_get_total_plane_samples(mpa);
|
||||
switch (format) {
|
||||
case AF_FORMAT_FLOAT:
|
||||
for (int s = 0; s < total; s++)
|
||||
sanitizef(((float *)ptr)[s]);
|
||||
break;
|
||||
case AF_FORMAT_DOUBLE:
|
||||
for (int s = 0; s < total; s++)
|
||||
sanitizef(((double *)ptr)[s]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the timestamp of the sample just after the end of this frame.
|
||||
double mp_aframe_end_pts(struct mp_aframe *f)
|
||||
{
|
||||
@@ -700,7 +637,7 @@ int mp_aframe_pool_allocate(struct mp_aframe_pool *pool, struct mp_aframe *frame
|
||||
av_freep(&av_frame->extended_data); // sigh
|
||||
if (planes > AV_NUM_DATA_POINTERS) {
|
||||
av_frame->extended_data =
|
||||
av_calloc(planes, sizeof(av_frame->extended_data[0]));
|
||||
av_mallocz_array(planes, sizeof(av_frame->extended_data[0]));
|
||||
if (!av_frame->extended_data)
|
||||
abort();
|
||||
} else {
|
||||
|
||||
@@ -60,7 +60,6 @@ char *mp_aframe_format_str_buf(char *buf, size_t buf_size, struct mp_aframe *fmt
|
||||
#define mp_aframe_format_str(fmt) mp_aframe_format_str_buf((char[32]){0}, 32, (fmt))
|
||||
|
||||
void mp_aframe_skip_samples(struct mp_aframe *f, int samples);
|
||||
void mp_aframe_sanitize_float(struct mp_aframe *f);
|
||||
double mp_aframe_end_pts(struct mp_aframe *f);
|
||||
double mp_aframe_duration(struct mp_aframe *f);
|
||||
void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end);
|
||||
|
||||
@@ -470,23 +470,6 @@ char *mp_chmap_to_str_hr_buf(char *buf, size_t buf_size, const struct mp_chmap *
|
||||
return mp_chmap_to_str_buf(buf, buf_size, &map);
|
||||
}
|
||||
|
||||
mp_ch_layout_tuple *mp_iterate_builtin_layouts(void **opaque)
|
||||
{
|
||||
uintptr_t i = (uintptr_t)*opaque;
|
||||
|
||||
if (i >= MP_ARRAY_SIZE(std_layout_names) ||
|
||||
!std_layout_names[i][0])
|
||||
return NULL;
|
||||
|
||||
*opaque = (void *)(i + 1);
|
||||
|
||||
if (std_layout_names[i][1][0] == '\0') {
|
||||
return mp_iterate_builtin_layouts(opaque);
|
||||
}
|
||||
|
||||
return &std_layout_names[i];
|
||||
}
|
||||
|
||||
void mp_chmap_print_help(struct mp_log *log)
|
||||
{
|
||||
mp_info(log, "Speakers:\n");
|
||||
|
||||
@@ -75,8 +75,6 @@ struct mp_chmap {
|
||||
uint8_t speaker[MP_NUM_CHANNELS];
|
||||
};
|
||||
|
||||
typedef const char * const (mp_ch_layout_tuple)[2];
|
||||
|
||||
#define MP_SP(speaker) MP_SPEAKER_ID_ ## speaker
|
||||
|
||||
#define MP_CHMAP2(a, b) \
|
||||
@@ -131,19 +129,6 @@ char *mp_chmap_to_str_hr_buf(char *buf, size_t buf_size, const struct mp_chmap *
|
||||
|
||||
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
|
||||
|
||||
/**
|
||||
* Iterate over all built-in channel layouts which have mapped channels.
|
||||
*
|
||||
* @param opaque a pointer where the iteration state is stored. Must point
|
||||
* to nullptr to start the iteration.
|
||||
*
|
||||
* @return nullptr when the iteration is finished.
|
||||
* Otherwise a pointer to an array of two char pointers.
|
||||
* - [0] being the human-readable layout name.
|
||||
* - [1] being the string representation of the layout.
|
||||
*/
|
||||
mp_ch_layout_tuple *mp_iterate_builtin_layouts(void **opaque);
|
||||
|
||||
struct mp_log;
|
||||
void mp_chmap_print_help(struct mp_log *log);
|
||||
|
||||
|
||||
@@ -1,51 +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 <libavutil/channel_layout.h>
|
||||
|
||||
#include "chmap.h"
|
||||
#include "chmap_avchannel.h"
|
||||
|
||||
bool mp_chmap_from_av_layout(struct mp_chmap *dst, const AVChannelLayout *src)
|
||||
{
|
||||
*dst = (struct mp_chmap) {0};
|
||||
|
||||
switch (src->order) {
|
||||
case AV_CHANNEL_ORDER_UNSPEC:
|
||||
mp_chmap_from_channels(dst, src->nb_channels);
|
||||
return dst->num == src->nb_channels;
|
||||
case AV_CHANNEL_ORDER_NATIVE:
|
||||
mp_chmap_from_lavc(dst, src->u.mask);
|
||||
return dst->num == src->nb_channels;
|
||||
default:
|
||||
// TODO: handle custom layouts
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_chmap_to_av_layout(AVChannelLayout *dst, const struct mp_chmap *src)
|
||||
{
|
||||
*dst = (AVChannelLayout){
|
||||
.order = AV_CHANNEL_ORDER_UNSPEC,
|
||||
.nb_channels = src->num,
|
||||
};
|
||||
|
||||
// TODO: handle custom layouts
|
||||
if (!mp_chmap_is_unknown(src)) {
|
||||
av_channel_layout_from_mask(dst, mp_chmap_to_lavc(src));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libavutil/channel_layout.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "chmap.h"
|
||||
|
||||
#if HAVE_AV_CHANNEL_LAYOUT
|
||||
|
||||
bool mp_chmap_from_av_layout(struct mp_chmap *dst, const AVChannelLayout *src);
|
||||
|
||||
void mp_chmap_to_av_layout(AVChannelLayout *dst, const struct mp_chmap *src);
|
||||
|
||||
#endif
|
||||
+1
-21
@@ -26,11 +26,8 @@
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mpv_talloc.h"
|
||||
#include "audio/aframe.h"
|
||||
#include "audio/chmap_avchannel.h"
|
||||
#include "audio/fmt-conversion.h"
|
||||
#include "common/av_common.h"
|
||||
#include "common/codecs.h"
|
||||
@@ -109,22 +106,8 @@ static bool init(struct mp_filter *da, struct mp_codec_params *codec,
|
||||
lavc_context->pkt_timebase = ctx->codec_timebase;
|
||||
|
||||
if (opts->downmix && mpopts->audio_output_channels.num_chmaps == 1) {
|
||||
const struct mp_chmap *requested_layout =
|
||||
&mpopts->audio_output_channels.chmaps[0];
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
lavc_context->request_channel_layout =
|
||||
mp_chmap_to_lavc(requested_layout);
|
||||
#else
|
||||
AVChannelLayout av_layout = { 0 };
|
||||
mp_chmap_to_av_layout(&av_layout, requested_layout);
|
||||
|
||||
// Always try to set requested output layout - currently only something
|
||||
// supported by AC3, MLP/TrueHD, DTS and the fdk-aac wrapper.
|
||||
av_opt_set_chlayout(lavc_context, "downmix", &av_layout,
|
||||
AV_OPT_SEARCH_CHILDREN);
|
||||
|
||||
av_channel_layout_uninit(&av_layout);
|
||||
#endif
|
||||
mp_chmap_to_lavc(&mpopts->audio_output_channels.chmaps[0]);
|
||||
}
|
||||
|
||||
// Always try to set - option only exists for AC3 at the moment
|
||||
@@ -260,9 +243,6 @@ static int receive_frame(struct mp_filter *da, struct mp_frame *out)
|
||||
priv->trim_samples -= trim;
|
||||
}
|
||||
|
||||
// Strip possibly bogus float values like Infinity, NaN, denormalized
|
||||
mp_aframe_sanitize_float(mpframe);
|
||||
|
||||
if (mp_aframe_get_size(mpframe) > 0) {
|
||||
*out = MAKE_FRAME(MP_FRAME_AUDIO, mpframe);
|
||||
} else {
|
||||
|
||||
@@ -31,10 +31,7 @@
|
||||
#include <libavutil/bswap.h>
|
||||
#include <libavutil/mem.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio/aframe.h"
|
||||
#include "audio/chmap_avchannel.h"
|
||||
#include "audio/chmap_sel.h"
|
||||
#include "audio/fmt-conversion.h"
|
||||
#include "audio/format.h"
|
||||
@@ -50,7 +47,7 @@
|
||||
#define AC3_MAX_CHANNELS 6
|
||||
#define AC3_MAX_CODED_FRAME_SIZE 3840
|
||||
#define AC3_FRAME_SIZE (6 * 256)
|
||||
const static uint16_t ac3_bitrate_tab[19] = {
|
||||
const uint16_t ac3_bitrate_tab[19] = {
|
||||
32, 40, 48, 56, 64, 80, 96, 112, 128,
|
||||
160, 192, 224, 256, 320, 384, 448, 512, 576, 640
|
||||
};
|
||||
@@ -73,7 +70,6 @@ struct priv {
|
||||
|
||||
const struct AVCodec *lavc_acodec;
|
||||
struct AVCodecContext *lavc_actx;
|
||||
AVPacket *lavc_pkt;
|
||||
int bit_rate;
|
||||
int out_samples; // upper bound on encoded output per AC3 frame
|
||||
};
|
||||
@@ -107,13 +103,8 @@ static bool reinit(struct mp_filter *f)
|
||||
|
||||
// Put sample parameters
|
||||
s->lavc_actx->sample_fmt = af_to_avformat(format);
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
s->lavc_actx->channels = chmap.num;
|
||||
s->lavc_actx->channel_layout = mp_chmap_to_lavc(&chmap);
|
||||
#else
|
||||
mp_chmap_to_av_layout(&s->lavc_actx->ch_layout, &chmap);
|
||||
#endif
|
||||
s->lavc_actx->sample_rate = rate;
|
||||
s->lavc_actx->bit_rate = bit_rate;
|
||||
|
||||
@@ -143,7 +134,6 @@ static void destroy(struct mp_filter *f)
|
||||
struct priv *s = f->priv;
|
||||
|
||||
reset(f);
|
||||
av_packet_free(&s->lavc_pkt);
|
||||
avcodec_free_context(&s->lavc_actx);
|
||||
}
|
||||
|
||||
@@ -162,12 +152,13 @@ static void process(struct mp_filter *f)
|
||||
|
||||
bool err = true;
|
||||
struct mp_aframe *out = NULL;
|
||||
AVPacket *pkt = s->lavc_pkt;
|
||||
AVPacket pkt = {0};
|
||||
av_init_packet(&pkt);
|
||||
|
||||
// Send input as long as it wants.
|
||||
while (1) {
|
||||
if (avcodec_is_open(s->lavc_actx)) {
|
||||
int lavc_ret = avcodec_receive_packet(s->lavc_actx, pkt);
|
||||
int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt);
|
||||
if (lavc_ret >= 0)
|
||||
break;
|
||||
if (lavc_ret < 0 && lavc_ret != AVERROR(EAGAIN)) {
|
||||
@@ -226,12 +217,12 @@ static void process(struct mp_filter *f)
|
||||
|
||||
mp_aframe_copy_attributes(out, s->in_frame);
|
||||
|
||||
int frame_size = pkt->size;
|
||||
int frame_size = pkt.size;
|
||||
int header_len = 0;
|
||||
char hdr[8];
|
||||
|
||||
if (s->opts->add_iec61937_header && pkt->size > 5) {
|
||||
int bsmod = pkt->data[5] & 0x7;
|
||||
if (s->opts->add_iec61937_header && pkt.size > 5) {
|
||||
int bsmod = pkt.data[5] & 0x7;
|
||||
int len = frame_size;
|
||||
|
||||
frame_size = AC3_FRAME_SIZE * 2 * 2;
|
||||
@@ -252,10 +243,10 @@ static void process(struct mp_filter *f)
|
||||
goto error;
|
||||
char *buf = planes[0];
|
||||
memcpy(buf, hdr, header_len);
|
||||
memcpy(buf + header_len, pkt->data, pkt->size);
|
||||
memset(buf + header_len + pkt->size, 0,
|
||||
frame_size - (header_len + pkt->size));
|
||||
swap_16((uint16_t *)(buf + header_len), pkt->size / 2);
|
||||
memcpy(buf + header_len, pkt.data, pkt.size);
|
||||
memset(buf + header_len + pkt.size, 0,
|
||||
frame_size - (header_len + pkt.size));
|
||||
swap_16((uint16_t *)(buf + header_len), pkt.size / 2);
|
||||
mp_aframe_set_size(out, frame_size / sstride);
|
||||
mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_AUDIO, out));
|
||||
out = NULL;
|
||||
@@ -264,7 +255,7 @@ done:
|
||||
err = false;
|
||||
// fall through
|
||||
error:
|
||||
av_packet_unref(pkt);
|
||||
av_packet_unref(&pkt);
|
||||
talloc_free(out);
|
||||
if (err)
|
||||
mp_filter_internal_mark_failed(f);
|
||||
@@ -278,38 +269,6 @@ static const struct mp_filter_info af_lavcac3enc_filter = {
|
||||
.destroy = destroy,
|
||||
};
|
||||
|
||||
static void add_chmaps_to_autoconv(struct mp_filter *f,
|
||||
struct mp_autoconvert *conv,
|
||||
const struct AVCodec *codec)
|
||||
{
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
const uint64_t *lch = codec->channel_layouts;
|
||||
for (int n = 0; lch && lch[n]; n++) {
|
||||
struct mp_chmap chmap = {0};
|
||||
mp_chmap_from_lavc(&chmap, lch[n]);
|
||||
if (mp_chmap_is_valid(&chmap))
|
||||
mp_autoconvert_add_chmap(conv, &chmap);
|
||||
}
|
||||
#else
|
||||
const AVChannelLayout *lch = codec->ch_layouts;
|
||||
for (int n = 0; lch && lch[n].nb_channels; n++) {
|
||||
struct mp_chmap chmap = {0};
|
||||
|
||||
if (!mp_chmap_from_av_layout(&chmap, &lch[n])) {
|
||||
char layout[128] = {0};
|
||||
MP_VERBOSE(f, "Skipping unsupported channel layout: %s\n",
|
||||
av_channel_layout_describe(&lch[n],
|
||||
layout, 128) < 0 ?
|
||||
"undefined" : layout);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mp_chmap_is_valid(&chmap))
|
||||
mp_autoconvert_add_chmap(conv, &chmap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct mp_filter *af_lavcac3enc_create(struct mp_filter *parent,
|
||||
void *options)
|
||||
{
|
||||
@@ -339,23 +298,14 @@ static struct mp_filter *af_lavcac3enc_create(struct mp_filter *parent,
|
||||
goto error;
|
||||
}
|
||||
|
||||
s->lavc_pkt = av_packet_alloc();
|
||||
if (!s->lavc_pkt)
|
||||
goto error;
|
||||
|
||||
if (mp_set_avopts(f->log, s->lavc_actx, s->opts->avopts) < 0)
|
||||
goto error;
|
||||
|
||||
// For this one, we require the decoder to export lists of all supported
|
||||
// For this one, we require the decoder to expert lists of all supported
|
||||
// parameters. (Not all decoders do that, but the ones we're interested
|
||||
// in do.)
|
||||
if (!s->lavc_acodec->sample_fmts ||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
!s->lavc_acodec->channel_layouts
|
||||
#else
|
||||
!s->lavc_acodec->ch_layouts
|
||||
#endif
|
||||
)
|
||||
!s->lavc_acodec->channel_layouts)
|
||||
{
|
||||
MP_ERR(f, "Audio encoder doesn't list supported parameters.\n");
|
||||
goto error;
|
||||
@@ -387,7 +337,13 @@ static struct mp_filter *af_lavcac3enc_create(struct mp_filter *parent,
|
||||
mp_autoconvert_add_afmt(conv, mpfmt);
|
||||
}
|
||||
|
||||
add_chmaps_to_autoconv(f, conv, s->lavc_acodec);
|
||||
const uint64_t *lch = s->lavc_acodec->channel_layouts;
|
||||
for (int n = 0; lch && lch[n]; n++) {
|
||||
struct mp_chmap chmap = {0};
|
||||
mp_chmap_from_lavc(&chmap, lch[n]);
|
||||
if (mp_chmap_is_valid(&chmap))
|
||||
mp_autoconvert_add_chmap(conv, &chmap);
|
||||
}
|
||||
|
||||
// At least currently, the AC3 encoder doesn't export sample rates.
|
||||
mp_autoconvert_add_srate(conv, 48000);
|
||||
@@ -404,8 +360,6 @@ static struct mp_filter *af_lavcac3enc_create(struct mp_filter *parent,
|
||||
return f;
|
||||
|
||||
error:
|
||||
av_packet_free(&s->lavc_pkt);
|
||||
avcodec_free_context(&s->lavc_actx);
|
||||
talloc_free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
#include <rubberband/rubberband-c.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio/aframe.h"
|
||||
#include "audio/format.h"
|
||||
#include "common/common.h"
|
||||
@@ -33,7 +31,7 @@
|
||||
// command line options
|
||||
struct f_opts {
|
||||
int transients, detector, phase, window,
|
||||
smoothing, formant, pitch, channels, engine;
|
||||
smoothing, formant, pitch, channels;
|
||||
double scale;
|
||||
};
|
||||
|
||||
@@ -80,10 +78,7 @@ static bool init_rubberband(struct mp_filter *f)
|
||||
|
||||
int opts = p->opts->transients | p->opts->detector | p->opts->phase |
|
||||
p->opts->window | p->opts->smoothing | p->opts->formant |
|
||||
p->opts->pitch | p->opts->channels |
|
||||
#if HAVE_RUBBERBAND_3
|
||||
p->opts->engine |
|
||||
#endif
|
||||
p->opts->pitch | p-> opts->channels |
|
||||
RubberBandOptionProcessRealTime;
|
||||
|
||||
int rate = mp_aframe_get_rate(p->pending);
|
||||
@@ -336,9 +331,6 @@ const struct mp_user_filter_entry af_rubberband = {
|
||||
.transients = RubberBandOptionTransientsMixed,
|
||||
.formant = RubberBandOptionFormantPreserved,
|
||||
.channels = RubberBandOptionChannelsTogether,
|
||||
#if HAVE_RUBBERBAND_3
|
||||
.engine = RubberBandOptionEngineFiner,
|
||||
#endif
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
{"transients", OPT_CHOICE(transients,
|
||||
@@ -369,11 +361,6 @@ const struct mp_user_filter_entry af_rubberband = {
|
||||
{"channels", OPT_CHOICE(channels,
|
||||
{"apart", RubberBandOptionChannelsApart},
|
||||
{"together", RubberBandOptionChannelsTogether})},
|
||||
#if HAVE_RUBBERBAND_3
|
||||
{"engine", OPT_CHOICE(engine,
|
||||
{"finer", RubberBandOptionEngineFiner},
|
||||
{"faster", RubberBandOptionEngineFaster})},
|
||||
#endif
|
||||
{"pitch-scale", OPT_DOUBLE(scale), M_RANGE(0.01, 100)},
|
||||
{0}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,7 @@ const struct mp_user_filter_entry af_scaletempo2 = {
|
||||
.wsola_search_interval_ms = 30,
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
{"search-interval",
|
||||
{"search-interval",
|
||||
OPT_FLOAT(wsola_search_interval_ms), M_RANGE(1, 1000)},
|
||||
{"window-size",
|
||||
OPT_FLOAT(ola_window_size_ms), M_RANGE(1, 1000)},
|
||||
|
||||
@@ -472,8 +472,10 @@ static int frames_needed(struct mp_scaletempo2 *p)
|
||||
|
||||
static void resize_input_buffer(struct mp_scaletempo2 *p, int size)
|
||||
{
|
||||
p->input_buffer_size = size;
|
||||
p->input_buffer = realloc_2d(p->input_buffer, p->channels, size);
|
||||
if (size > p->input_buffer_size) {
|
||||
p->input_buffer_size = size;
|
||||
p->input_buffer = realloc_2d(p->input_buffer, p->channels, size);
|
||||
}
|
||||
}
|
||||
|
||||
int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p,
|
||||
@@ -485,8 +487,7 @@ int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p,
|
||||
if (total_fill == 0) return 0;
|
||||
|
||||
int required_size = total_fill + p->input_buffer_frames;
|
||||
if (required_size > p->input_buffer_size)
|
||||
resize_input_buffer(p, required_size);
|
||||
resize_input_buffer(p, required_size);
|
||||
|
||||
for (int i = 0; i < p->channels; ++i) {
|
||||
memcpy(p->input_buffer[i] + p->input_buffer_frames,
|
||||
@@ -742,9 +743,9 @@ void mp_scaletempo2_init(struct mp_scaletempo2 *p, int channels, int rate)
|
||||
p->channels = channels;
|
||||
|
||||
p->samples_per_second = rate;
|
||||
p->num_candidate_blocks = (int)(p->opts->wsola_search_interval_ms
|
||||
p->num_candidate_blocks = (int)(p->opts->wsola_search_interval_ms
|
||||
* p->samples_per_second / 1000);
|
||||
p->ola_window_size = (int)(p->opts->ola_window_size_ms
|
||||
p->ola_window_size = (int)(p->opts->ola_window_size_ms
|
||||
* p->samples_per_second / 1000);
|
||||
// Make sure window size in an even number.
|
||||
p->ola_window_size += p->ola_window_size & 1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// This filter was ported from Chromium
|
||||
// This filter was ported from Chromium
|
||||
// (https://chromium.googlesource.com/chromium/chromium/+/51ed77e3f37a9a9b80d6d0a8259e84a8ca635259/media/filters/audio_renderer_algorithm.cc)
|
||||
//
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
@@ -118,4 +118,4 @@ int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p,
|
||||
uint8_t **planes, int frame_size, bool final);
|
||||
int mp_scaletempo2_fill_buffer(struct mp_scaletempo2 *p,
|
||||
float **dest, int dest_size, float playback_rate);
|
||||
bool mp_scaletempo2_frames_available(struct mp_scaletempo2 *p);
|
||||
bool mp_scaletempo2_frames_available(struct mp_scaletempo2 *p);
|
||||
+4
-4
@@ -187,7 +187,7 @@ int af_format_conversion_score(int dst_format, int src_format)
|
||||
return score;
|
||||
}
|
||||
|
||||
struct mp_entry {
|
||||
struct entry {
|
||||
int fmt;
|
||||
int score;
|
||||
};
|
||||
@@ -195,7 +195,7 @@ struct mp_entry {
|
||||
static int cmp_entry(const void *a, const void *b)
|
||||
{
|
||||
#define CMP_INT(a, b) (a > b ? 1 : (a < b ? -1 : 0))
|
||||
return -CMP_INT(((struct mp_entry *)a)->score, ((struct mp_entry *)b)->score);
|
||||
return -CMP_INT(((struct entry *)a)->score, ((struct entry *)b)->score);
|
||||
}
|
||||
|
||||
// Return a list of sample format compatible to src_format, sorted by order
|
||||
@@ -207,11 +207,11 @@ static int cmp_entry(const void *a, const void *b)
|
||||
void af_get_best_sample_formats(int src_format, int *out_formats)
|
||||
{
|
||||
int num = 0;
|
||||
struct mp_entry e[AF_FORMAT_COUNT + 1];
|
||||
struct entry e[AF_FORMAT_COUNT + 1];
|
||||
for (int fmt = 1; fmt < AF_FORMAT_COUNT; fmt++) {
|
||||
int score = af_format_conversion_score(fmt, src_format);
|
||||
if (score > INT_MIN)
|
||||
e[num++] = (struct mp_entry){fmt, score};
|
||||
e[num++] = (struct entry){fmt, score};
|
||||
}
|
||||
qsort(e, num, sizeof(e[0]), cmp_entry);
|
||||
for (int n = 0; n < num; n++)
|
||||
|
||||
+10
-36
@@ -41,8 +41,6 @@ extern const struct ao_driver audio_out_audiounit;
|
||||
extern const struct ao_driver audio_out_coreaudio;
|
||||
extern const struct ao_driver audio_out_coreaudio_exclusive;
|
||||
extern const struct ao_driver audio_out_rsound;
|
||||
extern const struct ao_driver audio_out_pipewire;
|
||||
extern const struct ao_driver audio_out_sndio;
|
||||
extern const struct ao_driver audio_out_pulse;
|
||||
extern const struct ao_driver audio_out_jack;
|
||||
extern const struct ao_driver audio_out_openal;
|
||||
@@ -65,9 +63,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
|
||||
#if HAVE_COREAUDIO
|
||||
&audio_out_coreaudio,
|
||||
#endif
|
||||
#if HAVE_PIPEWIRE
|
||||
&audio_out_pipewire,
|
||||
#endif
|
||||
#if HAVE_PULSE
|
||||
&audio_out_pulse,
|
||||
#endif
|
||||
@@ -92,9 +87,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
|
||||
#endif
|
||||
#if HAVE_SDL2_AUDIO
|
||||
&audio_out_sdl,
|
||||
#endif
|
||||
#if HAVE_SNDIO
|
||||
&audio_out_sndio,
|
||||
#endif
|
||||
&audio_out_null,
|
||||
#if HAVE_COREAUDIO
|
||||
@@ -128,6 +120,7 @@ static bool get_desc(struct m_obj_desc *dst, int index)
|
||||
static const struct m_obj_list ao_obj_list = {
|
||||
.get_desc = get_desc,
|
||||
.description = "audio outputs",
|
||||
.allow_unknown_entries = true,
|
||||
.allow_trailer = true,
|
||||
.disallow_positional_parameters = true,
|
||||
.use_global_options = true,
|
||||
@@ -453,9 +446,8 @@ struct ao_hotplug {
|
||||
void *wakeup_ctx;
|
||||
// A single AO instance is used to listen to hotplug events. It wouldn't
|
||||
// make much sense to allow multiple AO drivers; all sane platforms have
|
||||
// a single audio API providing all events.
|
||||
// This is _not_ necessarily the same AO instance as used for playing
|
||||
// audio.
|
||||
// a single such audio API.
|
||||
// This is _not_ the same AO instance as used for playing audio.
|
||||
struct ao *ao;
|
||||
// cached
|
||||
struct ao_device_list *list;
|
||||
@@ -495,8 +487,7 @@ bool ao_hotplug_check_update(struct ao_hotplug *hp)
|
||||
}
|
||||
|
||||
// The return value is valid until the next call to this API.
|
||||
struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp,
|
||||
struct ao *playback_ao)
|
||||
struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
|
||||
{
|
||||
if (hp->list && !hp->needs_update)
|
||||
return hp->list;
|
||||
@@ -508,19 +499,6 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp,
|
||||
MP_TARRAY_APPEND(list, list->devices, list->num_devices,
|
||||
(struct ao_device_desc){"auto", "Autoselect device"});
|
||||
|
||||
// Try to use the same AO for hotplug handling as for playback.
|
||||
// Different AOs may not agree and the playback one is the only one the
|
||||
// user knows about and may even have configured explicitly.
|
||||
if (!hp->ao && playback_ao && playback_ao->driver->hotplug_init) {
|
||||
struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx,
|
||||
(char *)playback_ao->driver->name);
|
||||
if (playback_ao->driver->hotplug_init(ao) >= 0) {
|
||||
hp->ao = ao;
|
||||
} else {
|
||||
talloc_free(ao);
|
||||
}
|
||||
}
|
||||
|
||||
for (int n = 0; audio_out_drivers[n]; n++) {
|
||||
const struct ao_driver *d = audio_out_drivers[n];
|
||||
if (d == &audio_out_null)
|
||||
@@ -532,13 +510,10 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp,
|
||||
continue;
|
||||
|
||||
if (ao->driver->hotplug_init) {
|
||||
if (ao->driver->hotplug_init(ao) >= 0) {
|
||||
get_devices(ao, list);
|
||||
if (hp->ao)
|
||||
ao->driver->hotplug_uninit(ao);
|
||||
else
|
||||
hp->ao = ao; // keep this one
|
||||
}
|
||||
if (!hp->ao && ao->driver->hotplug_init(ao) >= 0)
|
||||
hp->ao = ao; // keep this one
|
||||
if (hp->ao && hp->ao->driver == d)
|
||||
get_devices(hp->ao, list);
|
||||
} else {
|
||||
get_devices(ao, list);
|
||||
}
|
||||
@@ -587,11 +562,10 @@ static void dummy_wakeup(void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void ao_print_devices(struct mpv_global *global, struct mp_log *log,
|
||||
struct ao *playback_ao)
|
||||
void ao_print_devices(struct mpv_global *global, struct mp_log *log)
|
||||
{
|
||||
struct ao_hotplug *hp = ao_hotplug_create(global, dummy_wakeup, NULL);
|
||||
struct ao_device_list *list = ao_hotplug_get_device_list(hp, playback_ao);
|
||||
struct ao_device_list *list = ao_hotplug_get_device_list(hp);
|
||||
mp_info(log, "List of detected audio devices:\n");
|
||||
for (int n = 0; n < list->num_devices; n++) {
|
||||
struct ao_device_desc *desc = &list->devices[n];
|
||||
|
||||
+2
-9
@@ -35,8 +35,6 @@ enum aocontrol {
|
||||
AOCONTROL_SET_MUTE,
|
||||
// Has char* as argument, which contains the desired stream title.
|
||||
AOCONTROL_UPDATE_STREAM_TITLE,
|
||||
// Has enum aocontrol_media_role* argument, which contains the current media role
|
||||
AOCONTROL_UPDATE_MEDIA_ROLE,
|
||||
};
|
||||
|
||||
// If set, then the queued audio data is the last. Note that after a while, new
|
||||
@@ -66,11 +64,6 @@ typedef struct ao_control_vol {
|
||||
float right;
|
||||
} ao_control_vol_t;
|
||||
|
||||
enum aocontrol_media_role {
|
||||
AOCONTROL_MEDIA_ROLE_MUSIC,
|
||||
AOCONTROL_MEDIA_ROLE_MOVIE,
|
||||
};
|
||||
|
||||
struct ao_device_desc {
|
||||
const char *name; // symbolic name; will be set on ao->device
|
||||
const char *desc; // verbose human readable name
|
||||
@@ -126,8 +119,8 @@ struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
|
||||
void *wakeup_ctx);
|
||||
void ao_hotplug_destroy(struct ao_hotplug *hp);
|
||||
bool ao_hotplug_check_update(struct ao_hotplug *hp);
|
||||
struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp, struct ao *playback_ao);
|
||||
struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp);
|
||||
|
||||
void ao_print_devices(struct mpv_global *global, struct mp_log *log, struct ao *playback_ao);
|
||||
void ao_print_devices(struct mpv_global *global, struct mp_log *log);
|
||||
|
||||
#endif /* MPLAYER_AUDIO_OUT_H */
|
||||
+14
-78
@@ -36,54 +36,6 @@ struct priv {
|
||||
double device_latency;
|
||||
};
|
||||
|
||||
static OSStatus au_get_ary(AudioUnit unit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void **data, UInt32 *outDataSize)
|
||||
{
|
||||
OSStatus err;
|
||||
|
||||
err = AudioUnitGetPropertyInfo(unit, inID, inScope, inElement, outDataSize, NULL);
|
||||
CHECK_CA_ERROR_SILENT_L(coreaudio_error);
|
||||
|
||||
*data = talloc_zero_size(NULL, *outDataSize);
|
||||
|
||||
err = AudioUnitGetProperty(unit, inID, inScope, inElement, *data, outDataSize);
|
||||
CHECK_CA_ERROR_SILENT_L(coreaudio_error_free);
|
||||
|
||||
return err;
|
||||
coreaudio_error_free:
|
||||
talloc_free(*data);
|
||||
coreaudio_error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static AudioChannelLayout *convert_layout(AudioChannelLayout *layout, UInt32* size)
|
||||
{
|
||||
AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
|
||||
AudioChannelLayout *new_layout;
|
||||
if (tag == kAudioChannelLayoutTag_UseChannelDescriptions)
|
||||
return layout;
|
||||
else if (tag == kAudioChannelLayoutTag_UseChannelBitmap)
|
||||
AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap,
|
||||
sizeof(UInt32), &layout->mChannelBitmap, size);
|
||||
else
|
||||
AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag,
|
||||
sizeof(AudioChannelLayoutTag), &tag, size);
|
||||
new_layout = talloc_zero_size(NULL, *size);
|
||||
if (!new_layout) {
|
||||
talloc_free(layout);
|
||||
return NULL;
|
||||
}
|
||||
if (tag == kAudioChannelLayoutTag_UseChannelBitmap)
|
||||
AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
|
||||
sizeof(UInt32), &layout->mChannelBitmap, size, new_layout);
|
||||
else
|
||||
AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
|
||||
sizeof(AudioChannelLayoutTag), &tag, size, new_layout);
|
||||
new_layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
talloc_free(layout);
|
||||
return new_layout;
|
||||
}
|
||||
|
||||
|
||||
static OSStatus render_cb_lpcm(void *ctx, AudioUnitRenderActionFlags *aflags,
|
||||
const AudioTimeStamp *ts, UInt32 bus,
|
||||
UInt32 frames, AudioBufferList *buffer_list)
|
||||
@@ -107,15 +59,12 @@ static bool init_audiounit(struct ao *ao)
|
||||
AudioStreamBasicDescription asbd;
|
||||
OSStatus err;
|
||||
uint32_t size;
|
||||
AudioChannelLayout *layout = NULL;
|
||||
struct priv *p = ao->priv;
|
||||
AVAudioSession *instance = AVAudioSession.sharedInstance;
|
||||
AVAudioSessionPortDescription *port = nil;
|
||||
NSInteger maxChannels = instance.maximumOutputNumberOfChannels;
|
||||
NSInteger prefChannels = MIN(maxChannels, ao->channels.num);
|
||||
|
||||
MP_VERBOSE(ao, "max channels: %ld, requested: %d\n", maxChannels, (int)ao->channels.num);
|
||||
|
||||
[instance setCategory:AVAudioSessionCategoryPlayback error:nil];
|
||||
[instance setMode:AVAudioSessionModeMoviePlayback error:nil];
|
||||
[instance setActive:YES error:nil];
|
||||
@@ -142,33 +91,23 @@ static bool init_audiounit(struct ao *ao)
|
||||
CHECK_CA_ERROR_L(coreaudio_error_component,
|
||||
"unable to initialize audio unit");
|
||||
|
||||
err = au_get_ary(p->audio_unit, kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Output,
|
||||
0, (void**)&layout, &size);
|
||||
CHECK_CA_ERROR_L(coreaudio_error_audiounit,
|
||||
"unable to retrieve audio unit channel layout");
|
||||
|
||||
MP_VERBOSE(ao, "AU channel layout tag: %x (%x)\n", layout->mChannelLayoutTag, layout->mChannelBitmap);
|
||||
|
||||
layout = convert_layout(layout, &size);
|
||||
if (!layout) {
|
||||
MP_ERR(ao, "unable to convert channel layout to list format\n");
|
||||
goto coreaudio_error_audiounit;
|
||||
}
|
||||
|
||||
for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++) {
|
||||
MP_VERBOSE(ao, "channel map: %i: %u\n", i, layout->mChannelDescriptions[i].mChannelLabel);
|
||||
}
|
||||
|
||||
if (af_fmt_is_spdif(ao->format) || instance.outputNumberOfChannels <= 2) {
|
||||
ao->channels = (struct mp_chmap)MP_CHMAP_INIT_STEREO;
|
||||
MP_VERBOSE(ao, "using stereo output\n");
|
||||
} else {
|
||||
ao->channels.num = (uint8_t)layout->mNumberChannelDescriptions;
|
||||
for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++) {
|
||||
ao->channels.speaker[i] =
|
||||
ca_label_to_mp_speaker_id(layout->mChannelDescriptions[i].mChannelLabel);
|
||||
port = instance.currentRoute.outputs.firstObject;
|
||||
if (port.channels.count == 2 &&
|
||||
port.channels[0].channelLabel == kAudioChannelLabel_Unknown) {
|
||||
// Special case when using an HDMI adapter. The iOS device will
|
||||
// perform SPDIF conversion for us, so send all available channels
|
||||
// using the AC3 mapping.
|
||||
ao->channels = (struct mp_chmap)MP_CHMAP6(FL, FC, FR, SL, SR, LFE);
|
||||
} else {
|
||||
ao->channels.num = (uint8_t)port.channels.count;
|
||||
for (AVAudioSessionChannelDescription *ch in port.channels) {
|
||||
ao->channels.speaker[ch.channelNumber - 1] =
|
||||
ca_label_to_mp_speaker_id(ch.channelLabel);
|
||||
}
|
||||
}
|
||||
MP_VERBOSE(ao, "using standard channel mapping\n");
|
||||
}
|
||||
|
||||
ca_fill_asbd(ao, &asbd);
|
||||
@@ -193,8 +132,6 @@ static bool init_audiounit(struct ao *ao)
|
||||
CHECK_CA_ERROR_L(coreaudio_error_audiounit,
|
||||
"unable to set render callback on audio unit");
|
||||
|
||||
talloc_free(layout);
|
||||
|
||||
return true;
|
||||
|
||||
coreaudio_error_audiounit:
|
||||
@@ -202,7 +139,6 @@ coreaudio_error_audiounit:
|
||||
coreaudio_error_component:
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
coreaudio_error:
|
||||
talloc_free(layout);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,7 +154,7 @@ static void start(struct ao *ao)
|
||||
struct priv *p = ao->priv;
|
||||
AVAudioSession *instance = AVAudioSession.sharedInstance;
|
||||
|
||||
p->device_latency = [instance outputLatency];
|
||||
p->device_latency = [instance outputLatency] + [instance IOBufferDuration];
|
||||
|
||||
OSStatus err = AudioOutputUnitStart(p->audio_unit);
|
||||
CHECK_CA_WARN("can't start audio unit");
|
||||
|
||||
@@ -314,11 +314,11 @@ coreaudio_error:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void reset(struct ao *ao)
|
||||
static void stop(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
OSStatus err = AudioUnitReset(p->audio_unit, kAudioUnitScope_Global, 0);
|
||||
CHECK_CA_WARN("can't reset audio unit");
|
||||
OSStatus err = AudioOutputUnitStop(p->audio_unit);
|
||||
CHECK_CA_WARN("can't stop audio unit");
|
||||
}
|
||||
|
||||
static void start(struct ao *ao)
|
||||
@@ -415,7 +415,7 @@ const struct ao_driver audio_out_coreaudio = {
|
||||
.uninit = uninit,
|
||||
.init = init,
|
||||
.control = control,
|
||||
.reset = reset,
|
||||
.reset = stop,
|
||||
.start = start,
|
||||
.hotplug_init = hotplug_init,
|
||||
.hotplug_uninit = hotplug_uninit,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstractions on the CoreAudio API to make property setting/getting suck less
|
||||
* Abstractions on the CoreAudio API to make property setting/getting suck les
|
||||
*/
|
||||
|
||||
#include "audio/out/ao_coreaudio_properties.h"
|
||||
|
||||
@@ -456,15 +456,7 @@ int64_t ca_get_device_latency_us(struct ao *ao, AudioDeviceID device)
|
||||
}
|
||||
}
|
||||
|
||||
double sample_rate = ao->samplerate;
|
||||
OSStatus err = CA_GET_O(device, kAudioDevicePropertyNominalSampleRate,
|
||||
&sample_rate);
|
||||
CHECK_CA_WARN("cannot get device sample rate, falling back to AO sample rate!");
|
||||
if (err == noErr) {
|
||||
MP_VERBOSE(ao, "Device sample rate: %f\n", sample_rate);
|
||||
}
|
||||
|
||||
return latency_frames / sample_rate * 1e6;
|
||||
return ca_frames_to_us(ao, latency_frames);
|
||||
}
|
||||
|
||||
static OSStatus ca_change_format_listener(
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "audio/out/ao.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define CA_CFSTR_ENCODING kCFStringEncodingUTF8
|
||||
#define CA_CFSTR_ENCODING kCFStringEncodingASCII
|
||||
|
||||
CFStringRef cfstr_from_cstr(char *str);
|
||||
char *cfstr_get_cstr(CFStringRef cfstr);
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "options/options.h"
|
||||
#include "common/common.h"
|
||||
#include "audio/aframe.h"
|
||||
#include "audio/chmap_avchannel.h"
|
||||
#include "audio/format.h"
|
||||
#include "audio/fmt-conversion.h"
|
||||
#include "filters/filter_internal.h"
|
||||
@@ -125,13 +124,8 @@ static int init(struct ao *ao)
|
||||
if (!ao_chmap_sel_adjust2(ao, &sel, &ao->channels, false))
|
||||
goto fail;
|
||||
mp_chmap_reorder_to_lavc(&ao->channels);
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
encoder->channels = ao->channels.num;
|
||||
encoder->channel_layout = mp_chmap_to_lavc(&ao->channels);
|
||||
#else
|
||||
mp_chmap_to_av_layout(&encoder->ch_layout, &ao->channels);
|
||||
#endif
|
||||
|
||||
encoder->sample_fmt = AV_SAMPLE_FMT_NONE;
|
||||
|
||||
|
||||
@@ -199,14 +199,8 @@ static int init(struct ao *ao)
|
||||
alListenerfv(AL_ORIENTATION, direction);
|
||||
|
||||
alGenSources(1, &source);
|
||||
if (p->direct_channels) {
|
||||
if (alIsExtensionPresent("AL_SOFT_direct_channels_remix")) {
|
||||
alSourcei(source,
|
||||
alGetEnumValue((ALchar*)"AL_DIRECT_CHANNELS_SOFT"),
|
||||
alcGetEnumValue(dev, "AL_REMIX_UNMATCHED_SOFT"));
|
||||
} else {
|
||||
MP_WARN(ao, "Direct channels aren't supported by this version of OpenAL\n");
|
||||
}
|
||||
if (p->direct_channels && alGetEnumValue((ALchar*)"AL_DIRECT_CHANNELS_SOFT")) {
|
||||
alSourcei(source, alGetEnumValue((ALchar*)"AL_DIRECT_CHANNELS_SOFT"), AL_TRUE);
|
||||
}
|
||||
|
||||
cur_buf = 0;
|
||||
@@ -391,7 +385,7 @@ const struct ao_driver audio_out_openal = {
|
||||
.priv_defaults = &(const struct priv) {
|
||||
.num_buffers = 4,
|
||||
.num_samples = 8192,
|
||||
.direct_channels = 1,
|
||||
.direct_channels = 0,
|
||||
},
|
||||
.options = (const struct m_option[]) {
|
||||
{"num-buffers", OPT_INT(num_buffers), M_RANGE(2, MAX_BUF)},
|
||||
|
||||
@@ -111,8 +111,6 @@ static int init(struct ao *ao)
|
||||
|
||||
// This AO only supports two channels at the moment
|
||||
mp_chmap_from_channels(&ao->channels, 2);
|
||||
// Upstream "Wilhelm" supports only 8000 <= rate <= 192000
|
||||
ao->samplerate = MPCLAMP(ao->samplerate, 8000, 192000);
|
||||
|
||||
CHK(slCreateEngine(&p->sl, 0, NULL, 0, NULL, NULL));
|
||||
CHK((*p->sl)->Realize(p->sl, SL_BOOLEAN_FALSE));
|
||||
|
||||
@@ -1,836 +0,0 @@
|
||||
/*
|
||||
* PipeWire audio output driver.
|
||||
* Copyright (C) 2021 Thomas Weißschuh <thomas@t-8ch.de>
|
||||
* Copyright (C) 2021 Oschowa <oschowa@web.de>
|
||||
* Copyright (C) 2020 Andreas Kempf <aakempf@gmail.com>
|
||||
*
|
||||
* 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 <pipewire/pipewire.h>
|
||||
#include <pipewire/global.h>
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/utils/result.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "options/m_config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "ao.h"
|
||||
#include "audio/format.h"
|
||||
#include "config.h"
|
||||
#include "generated/version.h"
|
||||
#include "internal.h"
|
||||
#include "osdep/timer.h"
|
||||
|
||||
// Added in Pipewire 0.3.33
|
||||
// remove the fallback when we require a newer version
|
||||
#ifndef PW_KEY_NODE_RATE
|
||||
#define PW_KEY_NODE_RATE "node.rate"
|
||||
#endif
|
||||
|
||||
// Added in Pipewire 0.3.44
|
||||
// remove the fallback when we require a newer version
|
||||
#ifndef PW_KEY_TARGET_OBJECT
|
||||
#define PW_KEY_TARGET_OBJECT "target.object"
|
||||
#endif
|
||||
|
||||
#if !PW_CHECK_VERSION(0, 3, 50)
|
||||
static inline int pw_stream_get_time_n(struct pw_stream *stream, struct pw_time *time, size_t size) {
|
||||
return pw_stream_get_time(stream, time);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct priv {
|
||||
struct pw_thread_loop *loop;
|
||||
struct pw_stream *stream;
|
||||
struct pw_core *core;
|
||||
struct spa_hook stream_listener;
|
||||
struct spa_hook core_listener;
|
||||
|
||||
bool muted;
|
||||
float volume[2];
|
||||
|
||||
struct {
|
||||
int buffer_msec;
|
||||
char *remote;
|
||||
} options;
|
||||
|
||||
struct {
|
||||
struct pw_registry *registry;
|
||||
struct spa_hook registry_listener;
|
||||
struct spa_list sinks;
|
||||
} hotplug;
|
||||
};
|
||||
|
||||
struct id_list {
|
||||
uint32_t id;
|
||||
struct spa_list node;
|
||||
};
|
||||
|
||||
static enum spa_audio_format af_fmt_to_pw(struct ao *ao, enum af_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case AF_FORMAT_U8: return SPA_AUDIO_FORMAT_U8;
|
||||
case AF_FORMAT_S16: return SPA_AUDIO_FORMAT_S16;
|
||||
case AF_FORMAT_S32: return SPA_AUDIO_FORMAT_S32;
|
||||
case AF_FORMAT_FLOAT: return SPA_AUDIO_FORMAT_F32;
|
||||
case AF_FORMAT_DOUBLE: return SPA_AUDIO_FORMAT_F64;
|
||||
case AF_FORMAT_U8P: return SPA_AUDIO_FORMAT_U8P;
|
||||
case AF_FORMAT_S16P: return SPA_AUDIO_FORMAT_S16P;
|
||||
case AF_FORMAT_S32P: return SPA_AUDIO_FORMAT_S32P;
|
||||
case AF_FORMAT_FLOATP: return SPA_AUDIO_FORMAT_F32P;
|
||||
case AF_FORMAT_DOUBLEP: return SPA_AUDIO_FORMAT_F64P;
|
||||
default:
|
||||
MP_WARN(ao, "Unhandled format %d\n", format);
|
||||
return SPA_AUDIO_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static enum spa_audio_channel mp_speaker_id_to_spa(struct ao *ao, enum mp_speaker_id mp_speaker_id)
|
||||
{
|
||||
switch (mp_speaker_id) {
|
||||
case MP_SPEAKER_ID_FL: return SPA_AUDIO_CHANNEL_FL;
|
||||
case MP_SPEAKER_ID_FR: return SPA_AUDIO_CHANNEL_FR;
|
||||
case MP_SPEAKER_ID_FC: return SPA_AUDIO_CHANNEL_FC;
|
||||
case MP_SPEAKER_ID_LFE: return SPA_AUDIO_CHANNEL_LFE;
|
||||
case MP_SPEAKER_ID_BL: return SPA_AUDIO_CHANNEL_RL;
|
||||
case MP_SPEAKER_ID_BR: return SPA_AUDIO_CHANNEL_RR;
|
||||
case MP_SPEAKER_ID_FLC: return SPA_AUDIO_CHANNEL_FLC;
|
||||
case MP_SPEAKER_ID_FRC: return SPA_AUDIO_CHANNEL_FRC;
|
||||
case MP_SPEAKER_ID_BC: return SPA_AUDIO_CHANNEL_RC;
|
||||
case MP_SPEAKER_ID_SL: return SPA_AUDIO_CHANNEL_SL;
|
||||
case MP_SPEAKER_ID_SR: return SPA_AUDIO_CHANNEL_SR;
|
||||
case MP_SPEAKER_ID_TC: return SPA_AUDIO_CHANNEL_TC;
|
||||
case MP_SPEAKER_ID_TFL: return SPA_AUDIO_CHANNEL_TFL;
|
||||
case MP_SPEAKER_ID_TFC: return SPA_AUDIO_CHANNEL_TFC;
|
||||
case MP_SPEAKER_ID_TFR: return SPA_AUDIO_CHANNEL_TFR;
|
||||
case MP_SPEAKER_ID_TBL: return SPA_AUDIO_CHANNEL_TRL;
|
||||
case MP_SPEAKER_ID_TBC: return SPA_AUDIO_CHANNEL_TRC;
|
||||
case MP_SPEAKER_ID_TBR: return SPA_AUDIO_CHANNEL_TRR;
|
||||
case MP_SPEAKER_ID_DL: return SPA_AUDIO_CHANNEL_FL;
|
||||
case MP_SPEAKER_ID_DR: return SPA_AUDIO_CHANNEL_FR;
|
||||
case MP_SPEAKER_ID_WL: return SPA_AUDIO_CHANNEL_FL;
|
||||
case MP_SPEAKER_ID_WR: return SPA_AUDIO_CHANNEL_FR;
|
||||
case MP_SPEAKER_ID_SDL: return SPA_AUDIO_CHANNEL_SL;
|
||||
case MP_SPEAKER_ID_SDR: return SPA_AUDIO_CHANNEL_SL;
|
||||
case MP_SPEAKER_ID_LFE2: return SPA_AUDIO_CHANNEL_LFE2;
|
||||
case MP_SPEAKER_ID_NA: return SPA_AUDIO_CHANNEL_NA;
|
||||
default:
|
||||
MP_WARN(ao, "Unhandled channel %d\n", mp_speaker_id);
|
||||
return SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static void on_process(void *userdata)
|
||||
{
|
||||
struct ao *ao = userdata;
|
||||
struct priv *p = ao->priv;
|
||||
struct pw_time time;
|
||||
struct pw_buffer *b;
|
||||
void *data[MP_NUM_CHANNELS];
|
||||
|
||||
if ((b = pw_stream_dequeue_buffer(p->stream)) == NULL) {
|
||||
MP_WARN(ao, "out of buffers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
struct spa_buffer *buf = b->buffer;
|
||||
|
||||
int bytes_per_channel = buf->datas[0].maxsize / ao->channels.num;
|
||||
int nframes = bytes_per_channel / ao->sstride;
|
||||
#if PW_CHECK_VERSION(0, 3, 49)
|
||||
if (b->requested != 0)
|
||||
nframes = MPMIN(b->requested, nframes);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < buf->n_datas; i++)
|
||||
data[i] = buf->datas[i].data;
|
||||
|
||||
pw_stream_get_time_n(p->stream, &time, sizeof(time));
|
||||
if (time.rate.denom == 0)
|
||||
time.rate.denom = ao->samplerate;
|
||||
if (time.rate.num == 0)
|
||||
time.rate.num = 1;
|
||||
|
||||
int64_t end_time = mp_time_us();
|
||||
/* time.queued is always going to be 0, so we don't need to care */
|
||||
end_time += (nframes * 1e6 / ao->samplerate) +
|
||||
((float) time.delay * SPA_USEC_PER_SEC * time.rate.num / time.rate.denom);
|
||||
|
||||
int samples = ao_read_data(ao, data, nframes, end_time);
|
||||
b->size = samples;
|
||||
|
||||
for (int i = 0; i < buf->n_datas; i++) {
|
||||
buf->datas[i].chunk->size = samples * ao->sstride;
|
||||
buf->datas[i].chunk->offset = 0;
|
||||
buf->datas[i].chunk->stride = ao->sstride;
|
||||
}
|
||||
|
||||
pw_stream_queue_buffer(p->stream, b);
|
||||
|
||||
MP_TRACE(ao, "queued %d of %d samples\n", samples, nframes);
|
||||
}
|
||||
|
||||
static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *param)
|
||||
{
|
||||
struct ao *ao = userdata;
|
||||
struct priv *p = ao->priv;
|
||||
const struct spa_pod *params[1];
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
|
||||
if (param == NULL || id != SPA_PARAM_Format)
|
||||
return;
|
||||
|
||||
int buffer_size = ao->device_buffer * af_fmt_to_bytes(ao->format) * ao->channels.num;
|
||||
|
||||
params[0] = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
|
||||
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(ao->num_planes),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_Int(buffer_size),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(ao->sstride));
|
||||
if (!params[0]) {
|
||||
MP_ERR(ao, "Could not build parameter pod\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pw_stream_update_params(p->stream, params, 1) < 0) {
|
||||
MP_ERR(ao, "Could not update stream parameters\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_state_changed(void *userdata, enum pw_stream_state old, enum pw_stream_state state, const char *error)
|
||||
{
|
||||
struct ao *ao = userdata;
|
||||
MP_DBG(ao, "Stream state changed: old_state=%d state=%d error=%s\n", old, state, error);
|
||||
|
||||
if (state == PW_STREAM_STATE_ERROR) {
|
||||
MP_WARN(ao, "Stream in error state, trying to reload...\n");
|
||||
ao_request_reload(ao);
|
||||
}
|
||||
|
||||
if (state == PW_STREAM_STATE_UNCONNECTED && old != PW_STREAM_STATE_UNCONNECTED) {
|
||||
MP_WARN(ao, "Stream disconnected, trying to reload...\n");
|
||||
ao_request_reload(ao);
|
||||
}
|
||||
}
|
||||
|
||||
static float spa_volume_to_mp_volume(float vol)
|
||||
{
|
||||
return vol * 100;
|
||||
}
|
||||
|
||||
static float mp_volume_to_spa_volume(float vol)
|
||||
{
|
||||
return vol / 100;
|
||||
}
|
||||
|
||||
static float volume_avg(float* vols, uint32_t n)
|
||||
{
|
||||
float sum = 0.0;
|
||||
for (int i = 0; i < n; i++)
|
||||
sum += vols[i];
|
||||
return sum / n;
|
||||
}
|
||||
|
||||
static void on_control_info(void *userdata, uint32_t id,
|
||||
const struct pw_stream_control *control)
|
||||
{
|
||||
struct ao *ao = userdata;
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
switch (id) {
|
||||
case SPA_PROP_mute:
|
||||
if (control->n_values == 1)
|
||||
p->muted = control->values[0] >= 0.5;
|
||||
break;
|
||||
case SPA_PROP_channelVolumes:
|
||||
if (control->n_values == 2) {
|
||||
p->volume[0] = control->values[0];
|
||||
p->volume[1] = control->values[1];
|
||||
} else if (control->n_values > 0) {
|
||||
float volume = volume_avg(control->values, control->n_values);
|
||||
p->volume[0] = volume;
|
||||
p->volume[1] = volume;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_stream_events stream_events = {
|
||||
.version = PW_VERSION_STREAM_EVENTS,
|
||||
.param_changed = on_param_changed,
|
||||
.process = on_process,
|
||||
.state_changed = on_state_changed,
|
||||
.control_info = on_control_info,
|
||||
};
|
||||
|
||||
static void uninit(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
if (p->loop)
|
||||
pw_thread_loop_stop(p->loop);
|
||||
spa_hook_remove(&p->stream_listener);
|
||||
spa_zero(p->stream_listener);
|
||||
if (p->stream)
|
||||
pw_stream_destroy(p->stream);
|
||||
p->stream = NULL;
|
||||
if (p->core) {
|
||||
pw_context_destroy(pw_core_get_context(p->core));
|
||||
}
|
||||
p->core = NULL;
|
||||
if (p->loop)
|
||||
pw_thread_loop_destroy(p->loop);
|
||||
p->loop = NULL;
|
||||
pw_deinit();
|
||||
}
|
||||
|
||||
struct registry_event_global_ctx {
|
||||
struct ao *ao;
|
||||
void (*sink_cb) (struct ao *ao, uint32_t id, const struct spa_dict *props, void *sink_cb_ctx);
|
||||
void *sink_cb_ctx;
|
||||
};
|
||||
|
||||
static bool is_sink_node(const char *type, const struct spa_dict *props)
|
||||
{
|
||||
if (strcmp(type, PW_TYPE_INTERFACE_Node) != 0)
|
||||
return false;
|
||||
|
||||
if (!props)
|
||||
return false;
|
||||
|
||||
const char *class = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
||||
if (!class || strcmp(class, "Audio/Sink") != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void for_each_sink_registry_event_global(void *data, uint32_t id,
|
||||
uint32_t permissions, const
|
||||
char *type, uint32_t version,
|
||||
const struct spa_dict *props)
|
||||
{
|
||||
struct registry_event_global_ctx *ctx = data;
|
||||
|
||||
if (!is_sink_node(type, props))
|
||||
return;
|
||||
|
||||
ctx->sink_cb(ctx->ao, id, props, ctx->sink_cb_ctx);
|
||||
}
|
||||
|
||||
|
||||
static const struct pw_registry_events for_each_sink_registry_events = {
|
||||
.version = PW_VERSION_REGISTRY_EVENTS,
|
||||
.global = for_each_sink_registry_event_global,
|
||||
};
|
||||
|
||||
static void for_each_sink_done(void *data, uint32_t it, int seq)
|
||||
{
|
||||
struct pw_thread_loop *loop = data;
|
||||
pw_thread_loop_signal(loop, false);
|
||||
}
|
||||
|
||||
static const struct pw_core_events for_each_sink_core_events = {
|
||||
.version = PW_VERSION_CORE_EVENTS,
|
||||
.done = for_each_sink_done,
|
||||
};
|
||||
|
||||
static int for_each_sink(struct ao *ao, void (cb) (struct ao *ao, uint32_t id,
|
||||
const struct spa_dict *props, void *ctx), void *cb_ctx)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
struct pw_registry *registry;
|
||||
struct spa_hook core_listener;
|
||||
int ret = -1;
|
||||
|
||||
pw_thread_loop_lock(priv->loop);
|
||||
|
||||
spa_zero(core_listener);
|
||||
if (pw_core_add_listener(priv->core, &core_listener, &for_each_sink_core_events, priv->loop) < 0)
|
||||
goto unlock_loop;
|
||||
|
||||
registry = pw_core_get_registry(priv->core, PW_VERSION_REGISTRY, 0);
|
||||
if (!registry)
|
||||
goto remove_core_listener;
|
||||
|
||||
pw_core_sync(priv->core, 0, 0);
|
||||
|
||||
struct spa_hook registry_listener;
|
||||
struct registry_event_global_ctx revents_ctx = {
|
||||
.ao = ao,
|
||||
.sink_cb = cb,
|
||||
.sink_cb_ctx = cb_ctx,
|
||||
};
|
||||
spa_zero(registry_listener);
|
||||
if (pw_registry_add_listener(registry, ®istry_listener, &for_each_sink_registry_events, &revents_ctx) < 0)
|
||||
goto destroy_registry;
|
||||
|
||||
pw_thread_loop_wait(priv->loop);
|
||||
|
||||
spa_hook_remove(®istry_listener);
|
||||
|
||||
ret = 0;
|
||||
|
||||
destroy_registry:
|
||||
pw_proxy_destroy((struct pw_proxy *)registry);
|
||||
|
||||
remove_core_listener:
|
||||
spa_hook_remove(&core_listener);
|
||||
|
||||
unlock_loop:
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void have_sink(struct ao *ao, uint32_t id, const struct spa_dict *props, void *ctx)
|
||||
{
|
||||
bool *b = ctx;
|
||||
*b = true;
|
||||
}
|
||||
|
||||
static bool session_has_sinks(struct ao *ao)
|
||||
{
|
||||
bool b = false;
|
||||
|
||||
if (for_each_sink(ao, have_sink, &b) < 0)
|
||||
MP_WARN(ao, "Could not list devices, sink detection may be wrong\n");
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static void on_error(void *data, uint32_t id, int seq, int res, const char *message)
|
||||
{
|
||||
struct ao *ao = data;
|
||||
|
||||
MP_WARN(ao, "Error during playback: %s, %s\n", spa_strerror(res), message);
|
||||
}
|
||||
|
||||
static void on_core_info(void *data, const struct pw_core_info *info)
|
||||
{
|
||||
struct ao *ao = data;
|
||||
|
||||
MP_VERBOSE(ao, "Core user: %s\n", info->user_name);
|
||||
MP_VERBOSE(ao, "Core host: %s\n", info->host_name);
|
||||
MP_VERBOSE(ao, "Core version: %s\n", info->version);
|
||||
MP_VERBOSE(ao, "Core name: %s\n", info->name);
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
.version = PW_VERSION_CORE_EVENTS,
|
||||
.error = on_error,
|
||||
.info = on_core_info,
|
||||
};
|
||||
|
||||
static int pipewire_init_boilerplate(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
struct pw_context *context;
|
||||
|
||||
pw_init(NULL, NULL);
|
||||
|
||||
MP_VERBOSE(ao, "Headers version: %s\n", pw_get_headers_version());
|
||||
MP_VERBOSE(ao, "Library version: %s\n", pw_get_library_version());
|
||||
|
||||
p->loop = pw_thread_loop_new("ao-pipewire", NULL);
|
||||
if (p->loop == NULL)
|
||||
return -1;
|
||||
|
||||
pw_thread_loop_lock(p->loop);
|
||||
|
||||
if (pw_thread_loop_start(p->loop) < 0)
|
||||
goto error;
|
||||
|
||||
context = pw_context_new(pw_thread_loop_get_loop(p->loop), NULL, 0);
|
||||
if (!context)
|
||||
goto error;
|
||||
|
||||
p->core = pw_context_connect(
|
||||
context,
|
||||
pw_properties_new(PW_KEY_REMOTE_NAME, p->options.remote, NULL),
|
||||
0);
|
||||
if (!p->core) {
|
||||
MP_WARN(ao, "Could not connect to context '%s': %s\n",
|
||||
p->options.remote, strerror(errno));
|
||||
pw_context_destroy(context);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pw_core_add_listener(p->core, &p->core_listener, &core_events, ao) < 0)
|
||||
goto error;
|
||||
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
|
||||
if (!session_has_sinks(ao)) {
|
||||
MP_VERBOSE(ao, "PipeWire does not have any audio sinks, skipping\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
const struct spa_pod *params[1];
|
||||
struct pw_properties *props = pw_properties_new(
|
||||
PW_KEY_MEDIA_TYPE, "Audio",
|
||||
PW_KEY_MEDIA_CATEGORY, "Playback",
|
||||
PW_KEY_NODE_NAME, ao->client_name,
|
||||
PW_KEY_NODE_DESCRIPTION, ao->client_name,
|
||||
PW_KEY_APP_NAME, ao->client_name,
|
||||
PW_KEY_APP_ID, ao->client_name,
|
||||
PW_KEY_APP_ICON_NAME, ao->client_name,
|
||||
PW_KEY_NODE_ALWAYS_PROCESS, "true",
|
||||
PW_KEY_TARGET_OBJECT, ao->device,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (pipewire_init_boilerplate(ao) < 0)
|
||||
goto error_props;
|
||||
|
||||
ao->device_buffer = p->options.buffer_msec * ao->samplerate / 1000;
|
||||
|
||||
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%d", ao->device_buffer, ao->samplerate);
|
||||
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", ao->samplerate);
|
||||
|
||||
enum spa_audio_format spa_format = af_fmt_to_pw(ao, ao->format);
|
||||
if (spa_format == SPA_AUDIO_FORMAT_UNKNOWN) {
|
||||
ao->format = AF_FORMAT_FLOATP;
|
||||
spa_format = SPA_AUDIO_FORMAT_F32P;
|
||||
}
|
||||
|
||||
struct spa_audio_info_raw audio_info = {
|
||||
.format = spa_format,
|
||||
.rate = ao->samplerate,
|
||||
.channels = ao->channels.num,
|
||||
};
|
||||
|
||||
for (int i = 0; i < ao->channels.num; i++)
|
||||
audio_info.position[i] = mp_speaker_id_to_spa(ao, ao->channels.speaker[i]);
|
||||
|
||||
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &audio_info);
|
||||
if (!params[0])
|
||||
goto error_props;
|
||||
|
||||
if (af_fmt_is_planar(ao->format)) {
|
||||
ao->num_planes = ao->channels.num;
|
||||
ao->sstride = af_fmt_to_bytes(ao->format);
|
||||
} else {
|
||||
ao->num_planes = 1;
|
||||
ao->sstride = ao->channels.num * af_fmt_to_bytes(ao->format);
|
||||
}
|
||||
|
||||
pw_thread_loop_lock(p->loop);
|
||||
|
||||
p->stream = pw_stream_new(
|
||||
p->core,
|
||||
"audio-src",
|
||||
props);
|
||||
if (p->stream == NULL) {
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pw_stream_add_listener(p->stream,
|
||||
&p->stream_listener,
|
||||
&stream_events, ao);
|
||||
|
||||
if (pw_stream_connect(p->stream,
|
||||
PW_DIRECTION_OUTPUT, PW_ID_ANY,
|
||||
PW_STREAM_FLAG_AUTOCONNECT |
|
||||
PW_STREAM_FLAG_INACTIVE |
|
||||
PW_STREAM_FLAG_MAP_BUFFERS |
|
||||
PW_STREAM_FLAG_RT_PROCESS,
|
||||
params, 1) < 0) {
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
|
||||
return 0;
|
||||
|
||||
error_props:
|
||||
pw_properties_free(props);
|
||||
error:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void reset(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
pw_thread_loop_lock(p->loop);
|
||||
pw_stream_set_active(p->stream, false);
|
||||
pw_stream_flush(p->stream, false);
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
}
|
||||
|
||||
static void start(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
pw_thread_loop_lock(p->loop);
|
||||
pw_stream_set_active(p->stream, true);
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
}
|
||||
|
||||
#define CONTROL_RET(r) (!r ? CONTROL_OK : CONTROL_ERROR)
|
||||
|
||||
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case AOCONTROL_GET_VOLUME: {
|
||||
struct ao_control_vol *vol = arg;
|
||||
vol->left = spa_volume_to_mp_volume(p->volume[0]);
|
||||
vol->right = spa_volume_to_mp_volume(p->volume[1]);
|
||||
return CONTROL_OK;
|
||||
}
|
||||
case AOCONTROL_GET_MUTE: {
|
||||
bool *muted = arg;
|
||||
*muted = p->muted;
|
||||
return CONTROL_OK;
|
||||
}
|
||||
case AOCONTROL_SET_VOLUME:
|
||||
case AOCONTROL_SET_MUTE:
|
||||
case AOCONTROL_UPDATE_STREAM_TITLE:
|
||||
case AOCONTROL_UPDATE_MEDIA_ROLE: {
|
||||
int ret;
|
||||
|
||||
pw_thread_loop_lock(p->loop);
|
||||
switch (cmd) {
|
||||
case AOCONTROL_SET_VOLUME: {
|
||||
struct ao_control_vol *vol = arg;
|
||||
uint8_t n = ao->channels.num;
|
||||
float values[MP_NUM_CHANNELS] = {0};
|
||||
if (n == 2) {
|
||||
values[0] = mp_volume_to_spa_volume(vol->left);
|
||||
values[1] = mp_volume_to_spa_volume(vol->right);
|
||||
} else {
|
||||
for (int i = 0; i < n; i++)
|
||||
values[i] = mp_volume_to_spa_volume(vol->left);
|
||||
}
|
||||
ret = CONTROL_RET(pw_stream_set_control(p->stream, SPA_PROP_channelVolumes, n, values, 0));
|
||||
break;
|
||||
}
|
||||
case AOCONTROL_SET_MUTE: {
|
||||
bool *muted = arg;
|
||||
float value = *muted ? 1.f : 0.f;
|
||||
ret = CONTROL_RET(pw_stream_set_control(p->stream, SPA_PROP_mute, 1, &value, 0));
|
||||
break;
|
||||
}
|
||||
case AOCONTROL_UPDATE_STREAM_TITLE: {
|
||||
char *title = arg;
|
||||
struct spa_dict_item items[1];
|
||||
items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_NAME, title);
|
||||
ret = CONTROL_RET(pw_stream_update_properties(p->stream, &SPA_DICT_INIT(items, MP_ARRAY_SIZE(items))));
|
||||
break;
|
||||
}
|
||||
case AOCONTROL_UPDATE_MEDIA_ROLE: {
|
||||
enum aocontrol_media_role *role = arg;
|
||||
struct spa_dict_item items[1];
|
||||
const char *role_str;
|
||||
switch (*role) {
|
||||
case AOCONTROL_MEDIA_ROLE_MOVIE:
|
||||
role_str = "Movie";
|
||||
break;
|
||||
case AOCONTROL_MEDIA_ROLE_MUSIC:
|
||||
role_str = "Music";
|
||||
break;
|
||||
default:
|
||||
MP_WARN(ao, "Unknown media role %d\n", *role);
|
||||
role_str = "";
|
||||
break;
|
||||
}
|
||||
items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_ROLE, role_str);
|
||||
ret = CONTROL_RET(pw_stream_update_properties(p->stream, &SPA_DICT_INIT(items, MP_ARRAY_SIZE(items))));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = CONTROL_NA;
|
||||
}
|
||||
pw_thread_loop_unlock(p->loop);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_device_to_list(struct ao *ao, uint32_t id, const struct spa_dict *props, void *ctx)
|
||||
{
|
||||
struct ao_device_list *list = ctx;
|
||||
const char *name = spa_dict_lookup(props, PW_KEY_NODE_NAME);
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
const char *description = spa_dict_lookup(props, PW_KEY_NODE_DESCRIPTION);
|
||||
|
||||
ao_device_list_add(list, ao, &(struct ao_device_desc){name, description});
|
||||
}
|
||||
|
||||
static void hotplug_registry_global_cb(void *data, uint32_t id,
|
||||
uint32_t permissions, const char *type,
|
||||
uint32_t version, const struct spa_dict *props)
|
||||
{
|
||||
struct ao *ao = data;
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (!is_sink_node(type, props))
|
||||
return;
|
||||
|
||||
pw_thread_loop_lock(priv->loop);
|
||||
struct id_list *item = talloc_size(ao, sizeof(*item));
|
||||
item->id = id;
|
||||
spa_list_init(&item->node);
|
||||
spa_list_append(&priv->hotplug.sinks, &item->node);
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
|
||||
ao_hotplug_event(ao);
|
||||
}
|
||||
|
||||
static void hotplug_registry_global_remove_cb(void *data, uint32_t id)
|
||||
{
|
||||
struct ao *ao = data;
|
||||
struct priv *priv = ao->priv;
|
||||
bool removed_sink = false;
|
||||
|
||||
struct id_list *e;
|
||||
|
||||
pw_thread_loop_lock(priv->loop);
|
||||
spa_list_for_each(e, &priv->hotplug.sinks, node) {
|
||||
if (e->id == id) {
|
||||
removed_sink = true;
|
||||
spa_list_remove(&e->node);
|
||||
talloc_free(e);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
|
||||
if (removed_sink)
|
||||
ao_hotplug_event(ao);
|
||||
}
|
||||
|
||||
static const struct pw_registry_events hotplug_registry_events = {
|
||||
.version = PW_VERSION_REGISTRY_EVENTS,
|
||||
.global = hotplug_registry_global_cb,
|
||||
.global_remove = hotplug_registry_global_remove_cb,
|
||||
};
|
||||
|
||||
|
||||
static int hotplug_init(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
int res = pipewire_init_boilerplate(ao);
|
||||
if (res)
|
||||
goto error_no_unlock;
|
||||
|
||||
pw_thread_loop_lock(priv->loop);
|
||||
|
||||
spa_memzero(&priv->hotplug, sizeof(priv->hotplug));
|
||||
spa_list_init(&priv->hotplug.sinks);
|
||||
|
||||
priv->hotplug.registry = pw_core_get_registry(priv->core, PW_VERSION_REGISTRY, 0);
|
||||
if (!priv->hotplug.registry) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pw_registry_add_listener(priv->hotplug.registry, &priv->hotplug.registry_listener, &hotplug_registry_events, ao) < 0) {
|
||||
pw_proxy_destroy((struct pw_proxy *)priv->hotplug.registry);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
|
||||
return res;
|
||||
|
||||
error:
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
error_no_unlock:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void hotplug_uninit(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
pw_thread_loop_lock(priv->loop);
|
||||
|
||||
spa_hook_remove(&priv->hotplug.registry_listener);
|
||||
pw_proxy_destroy((struct pw_proxy *)priv->hotplug.registry);
|
||||
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
uninit(ao);
|
||||
}
|
||||
|
||||
static void list_devs(struct ao *ao, struct ao_device_list *list)
|
||||
{
|
||||
ao_device_list_add(list, ao, &(struct ao_device_desc){});
|
||||
|
||||
if (for_each_sink(ao, add_device_to_list, list) < 0)
|
||||
MP_WARN(ao, "Could not list devices, list may be incomplete\n");
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
|
||||
const struct ao_driver audio_out_pipewire = {
|
||||
.description = "PipeWire audio output",
|
||||
.name = "pipewire",
|
||||
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.reset = reset,
|
||||
.start = start,
|
||||
|
||||
.control = control,
|
||||
|
||||
.hotplug_init = hotplug_init,
|
||||
.hotplug_uninit = hotplug_uninit,
|
||||
.list_devs = list_devs,
|
||||
|
||||
.priv_size = sizeof(struct priv),
|
||||
.priv_defaults = &(const struct priv)
|
||||
{
|
||||
.loop = NULL,
|
||||
.stream = NULL,
|
||||
.options.buffer_msec = 20,
|
||||
},
|
||||
.options_prefix = "pipewire",
|
||||
.options = (const struct m_option[]) {
|
||||
{"buffer", OPT_INT(options.buffer_msec), M_RANGE(1, 2000)},
|
||||
{"remote", OPT_STRING(options.remote) },
|
||||
{0}
|
||||
},
|
||||
};
|
||||
@@ -1,318 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
|
||||
* Copyright (c) 2013 Christian Neukirchen <chneukirchen@gmail.com>
|
||||
* Copyright (c) 2020 Rozhuk Ivan <rozhuk.im@gmail.com>
|
||||
* Copyright (c) 2021 Andrew Krasavin <noiseless-ak@yandex.ru>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <sndio.h>
|
||||
|
||||
#include "options/m_option.h"
|
||||
#include "common/msg.h"
|
||||
|
||||
#include "audio/format.h"
|
||||
#include "ao.h"
|
||||
#include "internal.h"
|
||||
|
||||
struct priv {
|
||||
struct sio_hdl *hdl;
|
||||
struct sio_par par;
|
||||
int delay;
|
||||
bool playing;
|
||||
int vol;
|
||||
int havevol;
|
||||
struct pollfd *pfd;
|
||||
};
|
||||
|
||||
|
||||
static const struct mp_chmap sndio_layouts[] = {
|
||||
{0}, /* empty */
|
||||
{1, {MP_SPEAKER_ID_FL}}, /* mono */
|
||||
MP_CHMAP2(FL, FR), /* stereo */
|
||||
{0}, /* 2.1 */
|
||||
MP_CHMAP4(FL, FR, BL, BR), /* 4.0 */
|
||||
{0}, /* 5.0 */
|
||||
MP_CHMAP6(FL, FR, BL, BR, FC, LFE), /* 5.1 */
|
||||
{0}, /* 6.1 */
|
||||
MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), /* 7.1 */
|
||||
/* Above is the fixed channel assignment for sndio, since we need to
|
||||
* fill all channels and cannot insert silence, not all layouts are
|
||||
* supported.
|
||||
* NOTE: MP_SPEAKER_ID_NA could be used to add padding channels. */
|
||||
};
|
||||
|
||||
static void uninit(struct ao *ao);
|
||||
|
||||
|
||||
/* Make libsndio call movecb(). */
|
||||
static void process_events(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
int n = sio_pollfd(p->hdl, p->pfd, POLLOUT);
|
||||
while (poll(p->pfd, n, 0) < 0 && errno == EINTR);
|
||||
|
||||
sio_revents(p->hdl, p->pfd);
|
||||
}
|
||||
|
||||
/* Call-back invoked to notify of the hardware position. */
|
||||
static void movecb(void *addr, int delta)
|
||||
{
|
||||
struct ao *ao = addr;
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
p->delay -= delta;
|
||||
}
|
||||
|
||||
/* Call-back invoked to notify about volume changes. */
|
||||
static void volcb(void *addr, unsigned newvol)
|
||||
{
|
||||
struct ao *ao = addr;
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
p->vol = newvol;
|
||||
}
|
||||
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
struct mp_chmap_sel sel = {0};
|
||||
size_t i;
|
||||
struct af_to_par {
|
||||
int format, bits, sig;
|
||||
};
|
||||
static const struct af_to_par af_to_par[] = {
|
||||
{AF_FORMAT_U8, 8, 0},
|
||||
{AF_FORMAT_S16, 16, 1},
|
||||
{AF_FORMAT_S32, 32, 1},
|
||||
};
|
||||
const struct af_to_par *ap;
|
||||
const char *device = ((ao->device) ? ao->device : SIO_DEVANY);
|
||||
|
||||
/* Opening device. */
|
||||
MP_VERBOSE(ao, "Using '%s' audio device.\n", device);
|
||||
p->hdl = sio_open(device, SIO_PLAY, 0);
|
||||
if (p->hdl == NULL) {
|
||||
MP_ERR(ao, "Can't open audio device %s.\n", device);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
sio_initpar(&p->par);
|
||||
|
||||
/* Selecting sound format. */
|
||||
ao->format = af_fmt_from_planar(ao->format);
|
||||
|
||||
p->par.bits = 16;
|
||||
p->par.sig = 1;
|
||||
p->par.le = SIO_LE_NATIVE;
|
||||
for (i = 0; i < MP_ARRAY_SIZE(af_to_par); i++) {
|
||||
ap = &af_to_par[i];
|
||||
if (ap->format == ao->format) {
|
||||
p->par.bits = ap->bits;
|
||||
p->par.sig = ap->sig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p->par.rate = ao->samplerate;
|
||||
|
||||
/* Channels count. */
|
||||
for (i = 0; i < MP_ARRAY_SIZE(sndio_layouts); i++) {
|
||||
mp_chmap_sel_add_map(&sel, &sndio_layouts[i]);
|
||||
}
|
||||
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
|
||||
goto err_out;
|
||||
|
||||
p->par.pchan = ao->channels.num;
|
||||
p->par.appbufsz = p->par.rate * 250 / 1000; /* 250ms buffer */
|
||||
p->par.round = p->par.rate * 10 / 1000; /* 10ms block size */
|
||||
|
||||
if (!sio_setpar(p->hdl, &p->par)) {
|
||||
MP_ERR(ao, "couldn't set params\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Get current sound params. */
|
||||
if (!sio_getpar(p->hdl, &p->par)) {
|
||||
MP_ERR(ao, "couldn't get params\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (p->par.bps > 1 && p->par.le != SIO_LE_NATIVE) {
|
||||
MP_ERR(ao, "swapped endian output not supported\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Update sound params. */
|
||||
if (p->par.bits == 8 && p->par.bps == 1 && !p->par.sig) {
|
||||
ao->format = AF_FORMAT_U8;
|
||||
} else if (p->par.bits == 16 && p->par.bps == 2 && p->par.sig) {
|
||||
ao->format = AF_FORMAT_S16;
|
||||
} else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4 && p->par.sig) {
|
||||
ao->format = AF_FORMAT_S32;
|
||||
} else {
|
||||
MP_ERR(ao, "couldn't set format\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
p->havevol = sio_onvol(p->hdl, volcb, ao);
|
||||
sio_onmove(p->hdl, movecb, ao);
|
||||
|
||||
p->pfd = talloc_array_ptrtype(p, p->pfd, sio_nfds(p->hdl));
|
||||
if (!p->pfd)
|
||||
goto err_out;
|
||||
|
||||
ao->device_buffer = p->par.bufsz;
|
||||
MP_VERBOSE(ao, "bufsz = %i, appbufsz = %i, round = %i\n",
|
||||
p->par.bufsz, p->par.appbufsz, p->par.round);
|
||||
|
||||
p->delay = 0;
|
||||
p->playing = false;
|
||||
if (!sio_start(p->hdl)) {
|
||||
MP_ERR(ao, "start: sio_start() fail.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uninit(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
if (p->hdl) {
|
||||
sio_close(p->hdl);
|
||||
p->hdl = NULL;
|
||||
}
|
||||
p->pfd = NULL;
|
||||
p->playing = false;
|
||||
}
|
||||
|
||||
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
ao_control_vol_t *vol = arg;
|
||||
|
||||
switch (cmd) {
|
||||
case AOCONTROL_GET_VOLUME:
|
||||
if (!p->havevol)
|
||||
return CONTROL_FALSE;
|
||||
vol->left = vol->right = p->vol * 100 / SIO_MAXVOL;
|
||||
break;
|
||||
case AOCONTROL_SET_VOLUME:
|
||||
if (!p->havevol)
|
||||
return CONTROL_FALSE;
|
||||
sio_setvol(p->hdl, vol->left * SIO_MAXVOL / 100);
|
||||
break;
|
||||
default:
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
return CONTROL_OK;
|
||||
}
|
||||
|
||||
static void reset(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
if (p->playing) {
|
||||
p->playing = false;
|
||||
|
||||
if (!sio_stop(p->hdl)) {
|
||||
MP_ERR(ao, "reset: couldn't sio_stop()\n");
|
||||
}
|
||||
p->delay = 0;
|
||||
if (!sio_start(p->hdl)) {
|
||||
MP_ERR(ao, "reset: sio_start() fail.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void start(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
p->playing = true;
|
||||
process_events(ao);
|
||||
}
|
||||
|
||||
static bool audio_write(struct ao *ao, void **data, int samples)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
const size_t size = (samples * ao->sstride);
|
||||
size_t rc;
|
||||
|
||||
rc = sio_write(p->hdl, data[0], size);
|
||||
if (rc != size) {
|
||||
MP_WARN(ao, "audio_write: unexpected partial write: required: %zu, written: %zu.\n",
|
||||
size, rc);
|
||||
reset(ao);
|
||||
p->playing = false;
|
||||
return false;
|
||||
}
|
||||
p->delay += samples;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_state(struct ao *ao, struct mp_pcm_state *state)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
process_events(ao);
|
||||
|
||||
/* how many samples we can play without blocking */
|
||||
state->free_samples = ao->device_buffer - p->delay;
|
||||
state->free_samples = state->free_samples / p->par.round * p->par.round;
|
||||
/* how many samples are already in the buffer to be played */
|
||||
state->queued_samples = p->delay;
|
||||
/* delay in seconds between first and last sample in buffer */
|
||||
state->delay = p->delay / (double)p->par.rate;
|
||||
|
||||
/* report unexpected EOF / underrun */
|
||||
if ((state->queued_samples && state->queued_samples &&
|
||||
(state->queued_samples < state->free_samples) &&
|
||||
p->playing) || sio_eof(p->hdl))
|
||||
{
|
||||
MP_VERBOSE(ao, "get_state: EOF/underrun detected.\n");
|
||||
MP_VERBOSE(ao, "get_state: free: %d, queued: %d, delay: %lf\n", \
|
||||
state->free_samples, state->queued_samples, state->delay);
|
||||
p->playing = false;
|
||||
state->playing = p->playing;
|
||||
ao_wakeup_playthread(ao);
|
||||
} else {
|
||||
state->playing = p->playing;
|
||||
}
|
||||
}
|
||||
|
||||
const struct ao_driver audio_out_sndio = {
|
||||
.name = "sndio",
|
||||
.description = "sndio audio output",
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.reset = reset,
|
||||
.start = start,
|
||||
.write = audio_write,
|
||||
.get_state = get_state,
|
||||
.priv_size = sizeof(struct priv),
|
||||
};
|
||||
+10
-13
@@ -193,7 +193,6 @@ int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us)
|
||||
|
||||
if (pos < samples && p->playing && !p->paused) {
|
||||
p->playing = false;
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
// For ao_drain().
|
||||
pthread_cond_broadcast(&p->wakeup);
|
||||
}
|
||||
@@ -459,7 +458,7 @@ void ao_uninit(struct ao *ao)
|
||||
{
|
||||
struct buffer_state *p = ao->buffer_state;
|
||||
|
||||
if (p && p->thread_valid) {
|
||||
if (p->thread_valid) {
|
||||
pthread_mutex_lock(&p->pt_lock);
|
||||
p->terminate = true;
|
||||
pthread_cond_broadcast(&p->pt_wakeup);
|
||||
@@ -472,19 +471,17 @@ void ao_uninit(struct ao *ao)
|
||||
if (ao->driver_initialized)
|
||||
ao->driver->uninit(ao);
|
||||
|
||||
if (p) {
|
||||
talloc_free(p->filter_root);
|
||||
talloc_free(p->queue);
|
||||
talloc_free(p->pending);
|
||||
talloc_free(p->convert_buffer);
|
||||
talloc_free(p->temp_buf);
|
||||
talloc_free(p->filter_root);
|
||||
talloc_free(p->queue);
|
||||
talloc_free(p->pending);
|
||||
talloc_free(p->convert_buffer);
|
||||
talloc_free(p->temp_buf);
|
||||
|
||||
pthread_cond_destroy(&p->wakeup);
|
||||
pthread_mutex_destroy(&p->lock);
|
||||
pthread_cond_destroy(&p->wakeup);
|
||||
pthread_mutex_destroy(&p->lock);
|
||||
|
||||
pthread_cond_destroy(&p->pt_wakeup);
|
||||
pthread_mutex_destroy(&p->pt_lock);
|
||||
}
|
||||
pthread_cond_destroy(&p->pt_wakeup);
|
||||
pthread_mutex_destroy(&p->pt_lock);
|
||||
|
||||
talloc_free(ao);
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,10 +5,10 @@
|
||||
import os, sys, stat, hashlib, subprocess
|
||||
from urllib.request import urlopen, URLError
|
||||
|
||||
WAFRELEASE = "waf-2.0.24"
|
||||
WAFRELEASE = "waf-2.0.20"
|
||||
WAFURLS = ["https://waf.io/" + WAFRELEASE,
|
||||
"https://www.freehackers.org/~tnagy/release/" + WAFRELEASE]
|
||||
SHA256HASH = "93909bca823a675f9f40af7c65b24887c3a3c0efdf411ff1978ba827194bdeb0"
|
||||
"http://www.freehackers.org/~tnagy/release/" + WAFRELEASE]
|
||||
SHA256HASH = "bf971e98edc2414968a262c6aa6b88541a26c3cd248689c89f4c57370955ee7f"
|
||||
|
||||
if os.path.exists("waf"):
|
||||
wafver = subprocess.check_output([sys.executable, './waf', '--version']).decode()
|
||||
|
||||
+1
-22
@@ -5,25 +5,6 @@ export CFLAGS="$CFLAGS -isystem/usr/local/include"
|
||||
export CXXFLAGS="$CXXFLAGS -isystem/usr/local/include"
|
||||
export LDFLAGS="$LDFLAGS -L/usr/local/lib"
|
||||
|
||||
meson setup build \
|
||||
-Dlibmpv=true \
|
||||
-Dlua=enabled \
|
||||
-Degl-drm=enabled \
|
||||
-Dopenal=enabled \
|
||||
-Dsdl2=enabled \
|
||||
-Dsndio=enabled \
|
||||
-Dvdpau=enabled \
|
||||
-Dvulkan=enabled \
|
||||
-Doss-audio=enabled \
|
||||
$(pkg info -q v4l_compat && echo -Ddvbin=enabled) \
|
||||
$(pkg info -q libdvdnav && echo -Ddvdnav=enabled) \
|
||||
$(pkg info -q libcdio-paranoia && echo -Dcdda=enabled) \
|
||||
$(pkg info -q pipewire && echo -Dpipewire=enabled) \
|
||||
$NULL
|
||||
|
||||
meson compile -C build
|
||||
./build/mpv
|
||||
|
||||
if [ ! -e "./waf" ] ; then
|
||||
python3 ./bootstrap.py
|
||||
fi
|
||||
@@ -34,14 +15,12 @@ python3 ./waf configure \
|
||||
--enable-egl-drm \
|
||||
--enable-openal \
|
||||
--enable-sdl2 \
|
||||
--enable-sndio \
|
||||
--enable-vaapi-wayland \
|
||||
--enable-vdpau \
|
||||
--enable-vulkan \
|
||||
--enable-oss-audio \
|
||||
$(pkg info -q v4l_compat && echo --enable-dvbin) \
|
||||
$(pkg info -q libdvdnav && echo --enable-dvdnav) \
|
||||
$(pkg info -q libcdio-paranoia && echo --enable-cdda) \
|
||||
$(pkg info -q pipewire && echo --enable-pipewire) \
|
||||
$NULL
|
||||
|
||||
python3 ./waf build
|
||||
+11
-28
@@ -10,35 +10,18 @@ if [[ -d "./build/${MPV_VARIANT}" ]] ; then
|
||||
rm -rf "./build/${MPV_VARIANT}"
|
||||
fi
|
||||
|
||||
if [[ $1 = "meson" ]]; then
|
||||
PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" \
|
||||
meson setup build \
|
||||
-Dprefix="${MPV_INSTALL_PREFIX}" \
|
||||
-Dlibmpv=true \
|
||||
-D{gl,iconv,lcms2,lua,jpeg,plain-gl,zlib}=enabled \
|
||||
-D{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl}=enabled
|
||||
|
||||
meson compile -C build -j4
|
||||
|
||||
meson install -C build
|
||||
./build/mpv
|
||||
if [[ ! -e "./waf" ]] ; then
|
||||
python3 ./bootstrap.py
|
||||
fi
|
||||
|
||||
if [[ $1 = "waf" ]]; then
|
||||
if [[ ! -e "./waf" ]] ; then
|
||||
python3 ./bootstrap.py
|
||||
fi
|
||||
PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" python3 \
|
||||
./waf configure \
|
||||
--variant="${MPV_VARIANT}" \
|
||||
--prefix="${MPV_INSTALL_PREFIX}" \
|
||||
--enable-{gl,iconv,lcms2,libmpv-shared,lua,jpeg,plain-gl,zlib} \
|
||||
--enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl} \
|
||||
--swift-flags="${CI_SWIFT_FLAGS}"
|
||||
|
||||
PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" python3 \
|
||||
./waf configure \
|
||||
--variant="${MPV_VARIANT}" \
|
||||
--prefix="${MPV_INSTALL_PREFIX}" \
|
||||
--enable-{gl,iconv,lcms2,libmpv-shared,lua,jpeg,plain-gl,zlib} \
|
||||
--enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl} \
|
||||
--swift-flags="${CI_SWIFT_FLAGS}"
|
||||
python3 ./waf build --variant="${MPV_VARIANT}" -j4
|
||||
|
||||
python3 ./waf build --variant="${MPV_VARIANT}" -j4
|
||||
|
||||
python3 ./waf install --variant="${MPV_VARIANT}"
|
||||
./build/mpv
|
||||
fi
|
||||
python3 ./waf install --variant="${MPV_VARIANT}"
|
||||
+25
-91
@@ -6,7 +6,7 @@ ln -snf . "$prefix_dir/usr"
|
||||
ln -snf . "$prefix_dir/local"
|
||||
|
||||
wget="wget -nc --progress=bar:force"
|
||||
gitclone="git clone --depth=10 --recursive"
|
||||
gitclone="git clone --depth=10"
|
||||
commonflags="--disable-static --enable-shared"
|
||||
|
||||
export PKG_CONFIG_SYSROOT_DIR="$prefix_dir"
|
||||
@@ -22,26 +22,6 @@ export RANLIB=$TARGET-ranlib
|
||||
export CFLAGS="-O2 -pipe -Wall -D_FORTIFY_SOURCE=2"
|
||||
export LDFLAGS="-fstack-protector-strong"
|
||||
|
||||
fam=x86_64
|
||||
[[ "$TARGET" == "i686-"* ]] && fam=x86
|
||||
cat >"$prefix_dir/crossfile" <<EOF
|
||||
[built-in options]
|
||||
buildtype = 'release'
|
||||
wrap_mode = 'nodownload'
|
||||
[binaries]
|
||||
c = '${CC}'
|
||||
cpp = '${CXX}'
|
||||
ar = '${AR}'
|
||||
strip = '${TARGET}-strip'
|
||||
pkgconfig = 'pkg-config'
|
||||
windres = '${TARGET}-windres'
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = '${fam}'
|
||||
cpu = '${TARGET%%-*}'
|
||||
endian = 'little'
|
||||
EOF
|
||||
|
||||
function builddir () {
|
||||
[ -d "$1/builddir" ] && rm -rf "$1/builddir"
|
||||
mkdir -p "$1/builddir"
|
||||
@@ -49,13 +29,8 @@ function builddir () {
|
||||
}
|
||||
|
||||
function makeplusinstall () {
|
||||
if [ -f build.ninja ]; then
|
||||
ninja
|
||||
DESTDIR="$prefix_dir" ninja install
|
||||
else
|
||||
make -j$(nproc)
|
||||
make DESTDIR="$prefix_dir" install
|
||||
fi
|
||||
make -j$(nproc)
|
||||
make DESTDIR="$prefix_dir" install
|
||||
}
|
||||
|
||||
function gettar () {
|
||||
@@ -67,7 +42,7 @@ function gettar () {
|
||||
|
||||
## iconv
|
||||
if [ ! -e "$prefix_dir/lib/libiconv.dll.a" ]; then
|
||||
ver=1.17
|
||||
ver=1.16
|
||||
gettar "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ver}.tar.gz"
|
||||
builddir libiconv-${ver}
|
||||
../configure --host=$TARGET $commonflags
|
||||
@@ -77,10 +52,9 @@ fi
|
||||
|
||||
## zlib
|
||||
if [ ! -e "$prefix_dir/lib/libz.dll.a" ]; then
|
||||
ver=1.2.12
|
||||
gettar "https://zlib.net/fossils/zlib-${ver}.tar.gz"
|
||||
ver=1.2.11
|
||||
gettar "https://zlib.net/zlib-${ver}.tar.gz"
|
||||
pushd zlib-${ver}
|
||||
make -fwin32/Makefile.gcc clean
|
||||
make -fwin32/Makefile.gcc PREFIX=$TARGET- SHARED_MODE=1 \
|
||||
DESTDIR="$prefix_dir" install \
|
||||
BINARY_PATH=/bin INCLUDE_PATH=/include LIBRARY_PATH=/lib
|
||||
@@ -94,7 +68,7 @@ if [ ! -e "$prefix_dir/lib/libavcodec.dll.a" ]; then
|
||||
../configure --pkg-config=pkg-config --target-os=mingw32 \
|
||||
--enable-cross-compile --cross-prefix=$TARGET- --arch=${TARGET%%-*} \
|
||||
$commonflags \
|
||||
--disable-{doc,programs,muxers,encoders,devices}
|
||||
--disable-{stripping,doc,programs,muxers,encoders,devices}
|
||||
makeplusinstall
|
||||
popd
|
||||
fi
|
||||
@@ -123,45 +97,37 @@ if [ ! -e "$prefix_dir/lib/libspirv-cross-c-shared.dll.a" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
## libplacebo
|
||||
if [ ! -e "$prefix_dir/lib/libplacebo.dll.a" ]; then
|
||||
[ -d libplacebo ] || $gitclone https://code.videolan.org/videolan/libplacebo.git
|
||||
builddir libplacebo
|
||||
meson .. --cross-file "$prefix_dir/crossfile"
|
||||
makeplusinstall
|
||||
popd
|
||||
fi
|
||||
|
||||
## freetype2
|
||||
if [ ! -e "$prefix_dir/lib/libfreetype.dll.a" ]; then
|
||||
ver=2.12.1
|
||||
gettar "https://download.savannah.gnu.org/releases/freetype/freetype-${ver}.tar.xz"
|
||||
ver=2.11.0
|
||||
gettar "https://download.savannah.gnu.org/releases/freetype/freetype-${ver}.tar.gz"
|
||||
builddir freetype-${ver}
|
||||
meson .. --cross-file "$prefix_dir/crossfile"
|
||||
ZLIB_LIBS="-L'$prefix_dir/lib' -lz" \
|
||||
../configure --host=$TARGET $commonflags --with-png=no
|
||||
makeplusinstall
|
||||
popd
|
||||
fi
|
||||
[ -f "$prefix_dir/lib/libfreetype.dll.a" ] || { echo "libtool fuckup"; exit 1; }
|
||||
|
||||
## fribidi
|
||||
if [ ! -e "$prefix_dir/lib/libfribidi.dll.a" ]; then
|
||||
ver=1.0.12
|
||||
ver=1.0.11
|
||||
gettar "https://github.com/fribidi/fribidi/releases/download/v${ver}/fribidi-${ver}.tar.xz"
|
||||
builddir fribidi-${ver}
|
||||
meson .. --cross-file "$prefix_dir/crossfile" \
|
||||
-D{tests,docs}=false
|
||||
../configure --host=$TARGET $commonflags
|
||||
makeplusinstall
|
||||
popd
|
||||
fi
|
||||
|
||||
## harfbuzz
|
||||
if [ ! -e "$prefix_dir/lib/libharfbuzz.dll.a" ]; then
|
||||
ver=5.3.0
|
||||
ver=3.0.0
|
||||
gettar "https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.tar.xz"
|
||||
builddir harfbuzz-${ver}
|
||||
meson .. --cross-file "$prefix_dir/crossfile" \
|
||||
-Dtests=disabled
|
||||
../configure --host=$TARGET $commonflags --with-icu=no
|
||||
makeplusinstall
|
||||
popd
|
||||
rm "$prefix_dir"/lib/*.la # fuck off
|
||||
fi
|
||||
|
||||
## libass
|
||||
@@ -176,53 +142,21 @@ fi
|
||||
|
||||
## luajit
|
||||
if [ ! -e "$prefix_dir/lib/libluajit-5.1.a" ]; then
|
||||
ver=2.1.0-beta3
|
||||
ver=2.0.5
|
||||
gettar "http://luajit.org/download/LuaJIT-${ver}.tar.gz"
|
||||
pushd LuaJIT-${ver}
|
||||
hostcc=cc
|
||||
hostcc=gcc
|
||||
[[ "$TARGET" == "i686-"* ]] && hostcc="$hostcc -m32"
|
||||
make TARGET_SYS=Windows clean
|
||||
make TARGET_SYS=Windows HOST_CC="$hostcc" CROSS=$TARGET- \
|
||||
make HOST_CC="$hostcc" CROSS=$TARGET- TARGET_SYS=Windows \
|
||||
BUILDMODE=static amalg
|
||||
make DESTDIR="$prefix_dir" INSTALL_DEP= FILE_T=luajit.exe install
|
||||
popd
|
||||
fi
|
||||
|
||||
## mpv
|
||||
PKG_CONFIG=pkg-config CFLAGS="-I'$prefix_dir/include'" LDFLAGS="-L'$prefix_dir/lib'" \
|
||||
python3 ./waf configure \
|
||||
--enable-libmpv-shared --lua=luajit \
|
||||
--enable-{shaderc,spirv-cross,d3d11}
|
||||
|
||||
[ -z "$1" ] && exit 0
|
||||
|
||||
CFLAGS+=" -I'$prefix_dir/include'"
|
||||
LDFLAGS+=" -L'$prefix_dir/lib'"
|
||||
export CFLAGS LDFLAGS
|
||||
rm -rf build
|
||||
|
||||
if [ "$1" = "meson" ]; then
|
||||
meson setup build --cross-file "$prefix_dir/crossfile" \
|
||||
--buildtype debugoptimized \
|
||||
-D{libmpv,tests}=true -Dlua=luajit \
|
||||
-D{shaderc,spirv-cross,d3d11,libplacebo}=enabled
|
||||
|
||||
ninja -C build --verbose
|
||||
elif [ "$1" = "waf" ]; then
|
||||
PKG_CONFIG=pkg-config ./waf configure \
|
||||
--enable-libmpv-shared --lua=luajit \
|
||||
--enable-{shaderc,spirv-cross,d3d11,libplacebo,tests}
|
||||
|
||||
./waf build --verbose
|
||||
fi
|
||||
|
||||
if [ "$2" = pack ]; then
|
||||
mkdir -p artifact
|
||||
echo "Copying:"
|
||||
cp -pv build/mpv.{com,exe} "$prefix_dir/bin/"*.dll artifact/
|
||||
# ship everything and the kitchen sink
|
||||
shopt -s nullglob
|
||||
for file in /usr/lib/gcc/$TARGET/*-posix/*.dll /usr/$TARGET/lib/*.dll; do
|
||||
cp -pv "$file" artifact/
|
||||
done
|
||||
echo "Archiving:"
|
||||
pushd artifact
|
||||
zip -9r "../mpv-git-$(date +%F)-$(git rev-parse --short HEAD)-${TARGET%%-*}.zip" -- *
|
||||
popd
|
||||
fi
|
||||
python3 ./waf build --verbose
|
||||
+10
-31
@@ -1,34 +1,13 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ "$1" = "meson" ]; then
|
||||
meson setup build \
|
||||
-Dcdda=enabled \
|
||||
-Ddvbin=enabled \
|
||||
-Ddvdnav=enabled \
|
||||
-Dlibarchive=enabled \
|
||||
-Dlibmpv=true \
|
||||
-Dmanpage-build=enabled \
|
||||
-Dpipewire=enabled \
|
||||
-Dshaderc=enabled \
|
||||
-Dtests=true \
|
||||
-Dvulkan=enabled
|
||||
meson compile -C build --verbose
|
||||
./build/mpv --no-config -v --unittest=all-simple
|
||||
fi
|
||||
|
||||
if [ "$1" = "waf" ]; then
|
||||
python3 ./waf configure \
|
||||
--enable-cdda \
|
||||
--enable-dvbin \
|
||||
--enable-dvdnav \
|
||||
--enable-libarchive \
|
||||
--enable-libmpv-shared \
|
||||
--enable-manpage-build \
|
||||
--enable-pipewire \
|
||||
--enable-shaderc \
|
||||
--enable-tests \
|
||||
--enable-vulkan
|
||||
python3 ./waf build --verbose
|
||||
./build/mpv -v --no-config -v --unittest=all-simple
|
||||
fi
|
||||
python3 ./waf configure \
|
||||
--enable-cdda \
|
||||
--enable-dvbin \
|
||||
--enable-dvdnav \
|
||||
--enable-libarchive \
|
||||
--enable-libmpv-shared \
|
||||
--enable-manpage-build \
|
||||
--enable-shaderc \
|
||||
--enable-vulkan
|
||||
python3 ./waf build --verbose
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio/chmap_avchannel.h"
|
||||
#include "common/common.h"
|
||||
#include "common/msg.h"
|
||||
#include "demux/packet.h"
|
||||
@@ -109,14 +108,9 @@ AVCodecParameters *mp_codec_params_to_av(struct mp_codec_params *c)
|
||||
avp->sample_rate = c->samplerate;
|
||||
avp->bit_rate = c->bitrate;
|
||||
avp->block_align = c->block_align;
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
avp->channels = c->channels.num;
|
||||
if (!mp_chmap_is_unknown(&c->channels))
|
||||
avp->channel_layout = mp_chmap_to_lavc(&c->channels);
|
||||
#else
|
||||
mp_chmap_to_av_layout(&avp->ch_layout, &c->channels);
|
||||
#endif
|
||||
|
||||
return avp;
|
||||
error:
|
||||
|
||||
@@ -32,18 +32,12 @@
|
||||
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/log.h>
|
||||
#include <libavutil/version.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavcodec/version.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavformat/version.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libswresample/version.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswscale/version.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
#include <libavfilter/version.h>
|
||||
|
||||
#if HAVE_LIBAVDEVICE
|
||||
#include <libavdevice/avdevice.h>
|
||||
|
||||
@@ -68,24 +68,6 @@ enum stream_type {
|
||||
STREAM_TYPE_COUNT,
|
||||
};
|
||||
|
||||
enum video_sync {
|
||||
VS_DEFAULT = 0,
|
||||
VS_DISP_RESAMPLE,
|
||||
VS_DISP_RESAMPLE_VDROP,
|
||||
VS_DISP_RESAMPLE_NONE,
|
||||
VS_DISP_ADROP,
|
||||
VS_DISP_VDROP,
|
||||
VS_DISP_NONE,
|
||||
VS_NONE,
|
||||
};
|
||||
|
||||
#define VS_IS_DISP(x) ((x) == VS_DISP_RESAMPLE || \
|
||||
(x) == VS_DISP_RESAMPLE_VDROP || \
|
||||
(x) == VS_DISP_RESAMPLE_NONE || \
|
||||
(x) == VS_DISP_ADROP || \
|
||||
(x) == VS_DISP_VDROP || \
|
||||
(x) == VS_DISP_NONE)
|
||||
|
||||
extern const char mpv_version[];
|
||||
extern const char mpv_builddate[];
|
||||
extern const char mpv_copyright[];
|
||||
|
||||
@@ -731,7 +731,6 @@ static void encoder_destroy(void *ptr)
|
||||
{
|
||||
struct encoder_context *p = ptr;
|
||||
|
||||
av_packet_free(&p->pkt);
|
||||
avcodec_free_context(&p->encoder);
|
||||
free_stream(p->twopass_bytebuffer);
|
||||
}
|
||||
@@ -911,9 +910,6 @@ bool encoder_init_codec_and_muxer(struct encoder_context *p,
|
||||
if (avcodec_parameters_from_context(p->info.codecpar, p->encoder) < 0)
|
||||
goto fail;
|
||||
|
||||
p->pkt = av_packet_alloc();
|
||||
MP_HANDLE_OOM(p->pkt);
|
||||
|
||||
encode_lavc_add_stream(p, p->encode_lavc_ctx, &p->info, on_ready, ctx);
|
||||
if (!p->mux_stream)
|
||||
goto fail;
|
||||
@@ -934,9 +930,11 @@ bool encoder_encode(struct encoder_context *p, AVFrame *frame)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
AVPacket *packet = p->pkt;
|
||||
for (;;) {
|
||||
status = avcodec_receive_packet(p->encoder, packet);
|
||||
AVPacket packet = {0};
|
||||
av_init_packet(&packet);
|
||||
|
||||
status = avcodec_receive_packet(p->encoder, &packet);
|
||||
if (status == AVERROR(EAGAIN))
|
||||
break;
|
||||
if (status < 0 && status != AVERROR_EOF)
|
||||
@@ -950,7 +948,7 @@ bool encoder_encode(struct encoder_context *p, AVFrame *frame)
|
||||
if (status == AVERROR_EOF)
|
||||
break;
|
||||
|
||||
encode_lavc_add_packet(p->mux_stream, packet);
|
||||
encode_lavc_add_packet(p->mux_stream, &packet);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -83,9 +83,7 @@ struct encoder_context {
|
||||
AVCodecContext *encoder;
|
||||
struct mux_stream *mux_stream;
|
||||
|
||||
// (essentially private)
|
||||
struct stream *twopass_bytebuffer;
|
||||
AVPacket *pkt;
|
||||
};
|
||||
|
||||
// Free with talloc_free(). (Keep in mind actual deinitialization requires
|
||||
|
||||
+1
-2
@@ -21,7 +21,6 @@
|
||||
#include "common/common.h"
|
||||
#include "common/global.h"
|
||||
#include "common/msg.h"
|
||||
#include "misc/random.h"
|
||||
#include "mpv_talloc.h"
|
||||
#include "options/path.h"
|
||||
|
||||
@@ -148,7 +147,7 @@ void playlist_shuffle(struct playlist *pl)
|
||||
for (int n = 0; n < pl->num_entries; n++)
|
||||
pl->entries[n]->original_index = n;
|
||||
for (int n = 0; n < pl->num_entries - 1; n++) {
|
||||
size_t j = (size_t)((pl->num_entries - n) * mp_rand_next_double());
|
||||
int j = (int)((double)(pl->num_entries - n) * rand() / (RAND_MAX + 1.0));
|
||||
MPSWAP(struct playlist_entry *, pl->entries[n], pl->entries[n + j]);
|
||||
}
|
||||
playlist_update_indexes(pl, 0, -1);
|
||||
|
||||
+1
-2
@@ -69,8 +69,7 @@ struct stat_entry {
|
||||
// Overflows only after I'm dead.
|
||||
static int64_t get_thread_cpu_time_ns(pthread_t thread)
|
||||
{
|
||||
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(_POSIX_THREAD_CPUTIME) && \
|
||||
!HAVE_WIN32_INTERNAL_PTHREADS
|
||||
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(_POSIX_THREAD_CPUTIME)
|
||||
clockid_t id;
|
||||
struct timespec tv;
|
||||
if (pthread_getcpuclockid(thread, &id) == 0 &&
|
||||
|
||||
+8
-78
@@ -44,69 +44,15 @@ static const char *lookup_tag(int type, uint32_t tag)
|
||||
return id == AV_CODEC_ID_NONE ? NULL : mp_codec_from_av_codec_id(id);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As seen in the following page:
|
||||
*
|
||||
* https://web.archive.org/web/20220406060153/
|
||||
* http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html
|
||||
*
|
||||
* Note that the GUID struct in the above citation has its
|
||||
* integers encoded in little-endian format, which means that
|
||||
* the unsigned short and unsigned long entries need to be
|
||||
* byte-flipped for this encoding.
|
||||
*
|
||||
* In theory only the first element of this array should be used,
|
||||
* however some encoders incorrectly encoded the GUID byte-for-byte
|
||||
* and thus the second one exists as a fallback.
|
||||
*/
|
||||
static const unsigned char guid_ext_base[][16] = {
|
||||
// MEDIASUBTYPE_BASE_GUID
|
||||
// Corresponds to WMMEDIASUBTYPE_Base.
|
||||
static const unsigned char guid_ext_base[16] =
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71},
|
||||
// SUBTYPE_AMBISONIC_B_FORMAT_PCM
|
||||
{0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xD3, 0x11,
|
||||
0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00}
|
||||
};
|
||||
|
||||
struct mp_waveformatex_guid {
|
||||
const char *codec;
|
||||
const unsigned char guid[16];
|
||||
};
|
||||
|
||||
static const struct mp_waveformatex_guid guid_ext_other[] = {
|
||||
{"ac3",
|
||||
{0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11,
|
||||
0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA}},
|
||||
{"adpcm_agm",
|
||||
{0x82, 0xEC, 0x1F, 0x6A, 0xCA, 0xDB, 0x19, 0x45,
|
||||
0xBD, 0xE7, 0x56, 0xD3, 0xB3, 0xEF, 0x98, 0x1D}},
|
||||
{"atrac3p",
|
||||
{0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44,
|
||||
0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62}},
|
||||
{"atrac9",
|
||||
{0xD2, 0x42, 0xE1, 0x47, 0xBA, 0x36, 0x8D, 0x4D,
|
||||
0x88, 0xFC, 0x61, 0x65, 0x4F, 0x8C, 0x83, 0x6C}},
|
||||
{"dfpwm",
|
||||
{0x3A, 0xC1, 0xFA, 0x38, 0x81, 0x1D, 0x43, 0x61,
|
||||
0xA4, 0x0D, 0xCE, 0x53, 0xCA, 0x60, 0x7C, 0xD1}},
|
||||
{"eac3",
|
||||
{0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42,
|
||||
0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD}},
|
||||
{"mp2",
|
||||
{0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11,
|
||||
0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA}}
|
||||
};
|
||||
0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71};
|
||||
|
||||
static void map_audio_pcm_tag(struct mp_codec_params *c)
|
||||
{
|
||||
// MS PCM, Extended
|
||||
if (c->codec_tag == 0xfffe && c->extradata_size >= 22) {
|
||||
// WAVEFORMATEXTENSIBLE.wBitsPerSample
|
||||
int bits_per_sample = AV_RL16(c->extradata);
|
||||
if (bits_per_sample)
|
||||
c->bits_per_coded_sample = bits_per_sample;
|
||||
|
||||
// WAVEFORMATEXTENSIBLE.dwChannelMask
|
||||
uint64_t chmask = AV_RL32(c->extradata + 2);
|
||||
struct mp_chmap chmap;
|
||||
@@ -116,23 +62,9 @@ static void map_audio_pcm_tag(struct mp_codec_params *c)
|
||||
|
||||
// WAVEFORMATEXTENSIBLE.SubFormat
|
||||
unsigned char *subformat = c->extradata + 6;
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(guid_ext_base); i++) {
|
||||
if (memcmp(subformat + 4, guid_ext_base[i] + 4, 12) == 0) {
|
||||
c->codec_tag = AV_RL32(subformat);
|
||||
c->codec = lookup_tag(c->type, c->codec_tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// extra subformat, not a base one
|
||||
if (c->codec_tag == 0xfffe) {
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(guid_ext_other); i++) {
|
||||
if (memcmp(subformat, &guid_ext_other[i].guid, 16) == 0) {
|
||||
c->codec = guid_ext_other[i].codec;
|
||||
c->codec_tag = mp_codec_to_av_codec_id(c->codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (memcmp(subformat + 4, guid_ext_base + 4, 12) == 0) {
|
||||
c->codec_tag = AV_RL32(subformat);
|
||||
c->codec = lookup_tag(c->type, c->codec_tag);
|
||||
}
|
||||
|
||||
// Compressed formats might use this.
|
||||
@@ -141,9 +73,6 @@ static void map_audio_pcm_tag(struct mp_codec_params *c)
|
||||
}
|
||||
|
||||
int bits = c->bits_per_coded_sample;
|
||||
if (!bits)
|
||||
return;
|
||||
|
||||
int bytes = (bits + 7) / 8;
|
||||
switch (c->codec_tag) {
|
||||
case 0x0: // Microsoft PCM
|
||||
@@ -160,7 +89,8 @@ static void map_audio_pcm_tag(struct mp_codec_params *c)
|
||||
void mp_set_codec_from_tag(struct mp_codec_params *c)
|
||||
{
|
||||
c->codec = lookup_tag(c->type, c->codec_tag);
|
||||
if (c->type == STREAM_AUDIO)
|
||||
|
||||
if (c->type == STREAM_AUDIO && c->bits_per_coded_sample)
|
||||
map_audio_pcm_tag(c);
|
||||
}
|
||||
|
||||
|
||||
+3
-23
@@ -1506,7 +1506,7 @@ static void find_backward_restart_pos(struct demux_stream *ds)
|
||||
// Or if preroll is involved, the first preroll packet.
|
||||
while (ds->reader_head != target) {
|
||||
if (!advance_reader_head(ds))
|
||||
MP_ASSERT_UNREACHABLE(); // target must be in list
|
||||
assert(0); // target must be in list
|
||||
}
|
||||
|
||||
double seek_pts;
|
||||
@@ -1685,7 +1685,7 @@ static void attempt_range_joining(struct demux_internal *in)
|
||||
// Try to find a join point, where packets obviously overlap. (It would be
|
||||
// better and faster to do this incrementally, but probably too complex.)
|
||||
// The current range can overlap arbitrarily with the next one, not only by
|
||||
// the seek overlap, but for arbitrary packet readahead as well.
|
||||
// by the seek overlap, but for arbitrary packet readahead as well.
|
||||
// We also drop the overlapping packets (if joining fails, we discard the
|
||||
// entire next range anyway, so this does no harm).
|
||||
for (int n = 0; n < in->num_streams; n++) {
|
||||
@@ -2942,24 +2942,6 @@ static struct replaygain_data *decode_rgain(struct mp_log *log,
|
||||
return talloc_dup(NULL, &rg);
|
||||
}
|
||||
|
||||
// The r128 replaygain tags declared in RFC 7845 for opus files. The tags
|
||||
// are generated with EBU-R128, which does not use peak meters. And the
|
||||
// values are stored as a Q7.8 fixed point number in dB.
|
||||
if (decode_gain(log, tags, "R128_TRACK_GAIN", &rg.track_gain) >= 0) {
|
||||
if (decode_gain(log, tags, "R128_ALBUM_GAIN", &rg.album_gain) < 0) {
|
||||
// Album gain is undefined; fall back to track gain.
|
||||
rg.album_gain = rg.track_gain;
|
||||
}
|
||||
rg.track_gain /= 256.;
|
||||
rg.album_gain /= 256.;
|
||||
|
||||
// Add 5dB to compensate for the different reference levels between
|
||||
// our reference of ReplayGain 2 (-18 LUFS) and EBU R128 (-23 LUFS).
|
||||
rg.track_gain += 5.;
|
||||
rg.album_gain += 5.;
|
||||
return talloc_dup(NULL, &rg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3410,10 +3392,8 @@ static struct demuxer *demux_open(struct stream *stream,
|
||||
check_levels = d_force;
|
||||
}
|
||||
for (int n = 0; demuxer_list[n]; n++) {
|
||||
if (strcmp(demuxer_list[n]->name, force_format) == 0) {
|
||||
if (strcmp(demuxer_list[n]->name, force_format) == 0)
|
||||
check_desc = demuxer_list[n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!check_desc) {
|
||||
mp_err(log, "Demuxer %s does not exist.\n", force_format);
|
||||
|
||||
+11
-40
@@ -36,12 +36,6 @@
|
||||
#include <libavutil/display.h>
|
||||
#include <libavutil/opt.h>
|
||||
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 43, 100)
|
||||
#include <libavutil/dovi_meta.h>
|
||||
#endif
|
||||
|
||||
#include "audio/chmap_avchannel.h"
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "common/tags.h"
|
||||
#include "common/av_common.h"
|
||||
@@ -263,6 +257,9 @@ typedef struct lavf_priv {
|
||||
|
||||
static void update_read_stats(struct demuxer *demuxer)
|
||||
{
|
||||
#if !HAVE_FFMPEG_AVIOCONTEXT_BYTES_READ
|
||||
return;
|
||||
#else
|
||||
lavf_priv_t *priv = demuxer->priv;
|
||||
|
||||
for (int n = 0; n < priv->num_nested; n++) {
|
||||
@@ -273,6 +270,7 @@ static void update_read_stats(struct demuxer *demuxer)
|
||||
nest->last_bytes = cur;
|
||||
demux_report_unbuffered_read_bytes(demuxer, new);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
|
||||
@@ -647,18 +645,6 @@ static int dict_get_decimal(AVDictionary *dict, const char *entry, int def)
|
||||
return def;
|
||||
}
|
||||
|
||||
static bool is_image(AVStream *st, bool attached_picture, const AVInputFormat *avif)
|
||||
{
|
||||
return st->nb_frames <= 1 && (
|
||||
attached_picture ||
|
||||
bstr_endswith0(bstr0(avif->name), "_pipe") ||
|
||||
strcmp(avif->name, "alias_pix") == 0 ||
|
||||
strcmp(avif->name, "gif") == 0 ||
|
||||
strcmp(avif->name, "image2pipe") == 0 ||
|
||||
(st->codecpar->codec_id == AV_CODEC_ID_AV1 && st->nb_frames == 1)
|
||||
);
|
||||
}
|
||||
|
||||
static void handle_new_stream(demuxer_t *demuxer, int i)
|
||||
{
|
||||
lavf_priv_t *priv = demuxer->priv;
|
||||
@@ -672,22 +658,10 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
|
||||
case AVMEDIA_TYPE_AUDIO: {
|
||||
sh = demux_alloc_sh_stream(STREAM_AUDIO);
|
||||
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
// probably unneeded
|
||||
mp_chmap_set_unknown(&sh->codec->channels, codec->channels);
|
||||
if (codec->channel_layout)
|
||||
mp_chmap_from_lavc(&sh->codec->channels, codec->channel_layout);
|
||||
#else
|
||||
if (!mp_chmap_from_av_layout(&sh->codec->channels, &codec->ch_layout)) {
|
||||
char layout[128] = {0};
|
||||
MP_WARN(demuxer,
|
||||
"Failed to convert channel layout %s to mpv one!\n",
|
||||
av_channel_layout_describe(&codec->ch_layout,
|
||||
layout, 128) < 0 ?
|
||||
"undefined" : layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
sh->codec->samplerate = codec->sample_rate;
|
||||
sh->codec->bitrate = codec->bit_rate;
|
||||
|
||||
@@ -730,7 +704,13 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
|
||||
sh->codec->disp_h = codec->height;
|
||||
if (st->avg_frame_rate.num)
|
||||
sh->codec->fps = av_q2d(st->avg_frame_rate);
|
||||
if (is_image(st, sh->attached_picture, priv->avif)) {
|
||||
if (st->nb_frames <= 1 && (
|
||||
sh->attached_picture ||
|
||||
bstr_endswith0(bstr0(priv->avif->name), "_pipe") ||
|
||||
strcmp(priv->avif->name, "alias_pix") == 0 ||
|
||||
strcmp(priv->avif->name, "gif") == 0 ||
|
||||
strcmp(priv->avif->name, "image2pipe") == 0
|
||||
)) {
|
||||
MP_VERBOSE(demuxer, "Assuming this is an image format.\n");
|
||||
sh->image = true;
|
||||
sh->codec->fps = priv->mf_fps;
|
||||
@@ -745,15 +725,6 @@ static void handle_new_stream(demuxer_t *demuxer, int i)
|
||||
sh->codec->rotate = (((int)(-r) % 360) + 360) % 360;
|
||||
}
|
||||
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 43, 100)
|
||||
if ((sd = av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF, NULL))) {
|
||||
const AVDOVIDecoderConfigurationRecord *cfg = (void *) sd;
|
||||
MP_VERBOSE(demuxer, "Found Dolby Vision config record: profile "
|
||||
"%d level %d\n", cfg->dv_profile, cfg->dv_level);
|
||||
av_format_inject_global_side_data(avfc);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This also applies to vfw-muxed mkv, but we can't detect these easily.
|
||||
sh->codec->avi_dts = matches_avinputformat_name(priv, "avi");
|
||||
|
||||
|
||||
@@ -291,8 +291,6 @@ static const struct {
|
||||
{ "db", "mjpeg" },
|
||||
{ "pcd", "photocd" },
|
||||
{ "pfm", "pfm" },
|
||||
{ "phm", "phm" },
|
||||
{ "hdr", "hdr" },
|
||||
{ "pcx", "pcx" },
|
||||
{ "png", "png" },
|
||||
{ "pns", "png" },
|
||||
@@ -321,7 +319,6 @@ static const struct {
|
||||
{ "pix", "brender_pix" },
|
||||
{ "exr", "exr" },
|
||||
{ "pic", "pictor" },
|
||||
{ "qoi", "qoi" },
|
||||
{ "xface", "xface" },
|
||||
{ "xwd", "xwd" },
|
||||
{0}
|
||||
|
||||
+1
-3
@@ -1362,8 +1362,6 @@ static const char *const mkv_video_tags[][2] = {
|
||||
{"V_SNOW", "snow"},
|
||||
{"V_AV1", "av1"},
|
||||
{"V_PNG", "png"},
|
||||
{"V_AVS2", "avs2"},
|
||||
{"V_AVS3", "avs3"},
|
||||
{0}
|
||||
};
|
||||
|
||||
@@ -2874,7 +2872,7 @@ static int read_next_block_into_queue(demuxer_t *demuxer)
|
||||
if (mkv_d->cluster_end != EBML_UINT_INVALID)
|
||||
mkv_d->cluster_end += stream_tell(s);
|
||||
}
|
||||
MP_ASSERT_UNREACHABLE();
|
||||
assert(0); // unreachable
|
||||
|
||||
add_block:
|
||||
index_block(demuxer, &block);
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ int ebml_resync_cluster(struct mp_log *log, stream_t *s)
|
||||
#define E_S(str, count) EVALARGS(E_SN, str, count, N)
|
||||
#define FN(id, name, multiple, N) { id, multiple, offsetof(struct ebml_ ## N, name), offsetof(struct ebml_ ## N, n_ ## name), &ebml_##name##_desc},
|
||||
#define F(id, name, multiple) EVALARGS(FN, id, name, multiple, N)
|
||||
#include "generated/ebml_defs.inc"
|
||||
#include "generated/ebml_defs.c"
|
||||
#undef EVALARGS
|
||||
#undef SN
|
||||
#undef S
|
||||
|
||||
+7
-5
@@ -39,7 +39,9 @@ void demux_packet_unref_contents(struct demux_packet *dp)
|
||||
{
|
||||
if (dp->avpacket) {
|
||||
assert(!dp->is_cached);
|
||||
av_packet_free(&dp->avpacket);
|
||||
av_packet_unref(dp->avpacket);
|
||||
talloc_free(dp->avpacket);
|
||||
dp->avpacket = NULL;
|
||||
dp->buffer = NULL;
|
||||
dp->len = 0;
|
||||
}
|
||||
@@ -68,12 +70,11 @@ struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt)
|
||||
.start = MP_NOPTS_VALUE,
|
||||
.end = MP_NOPTS_VALUE,
|
||||
.stream = -1,
|
||||
.avpacket = av_packet_alloc(),
|
||||
.avpacket = talloc_zero(dp, AVPacket),
|
||||
};
|
||||
av_init_packet(dp->avpacket);
|
||||
int r = -1;
|
||||
if (!dp->avpacket) {
|
||||
// error
|
||||
} else if (avpkt->data) {
|
||||
if (avpkt->data) {
|
||||
// We hope that this function won't need/access AVPacket input padding,
|
||||
// because otherwise new_demux_packet_from() wouldn't work.
|
||||
r = av_packet_ref(dp->avpacket, avpkt);
|
||||
@@ -81,6 +82,7 @@ struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt)
|
||||
r = av_new_packet(dp->avpacket, avpkt->size);
|
||||
}
|
||||
if (r < 0) {
|
||||
*dp->avpacket = (AVPacket){0};
|
||||
talloc_free(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+1
-7
@@ -5,18 +5,14 @@ Name[ca]=Reproductor multimèdia mpv
|
||||
Name[cs]=mpv přehrávač
|
||||
Name[da]=mpv-medieafspiller
|
||||
Name[fr]=Lecteur multimédia mpv
|
||||
Name[ja]=mpv メディアプレイヤー
|
||||
Name[pl]=Odtwarzacz mpv
|
||||
Name[ru]=Проигрыватель mpv
|
||||
Name[tr]=mpv Ortam Oynatıcı
|
||||
Name[zh_CN]=mpv 媒体播放器
|
||||
Name[zh_TW]=mpv 媒體播放器
|
||||
GenericName=Multimedia player
|
||||
GenericName[cs]=Multimediální přehrávač
|
||||
GenericName[da]=Multimedieafspiller
|
||||
GenericName[fr]=Lecteur multimédia
|
||||
GenericName[ja]=マルチメディアプレイヤー
|
||||
GenericName[tr]=Çoklu ortam oynatıcı
|
||||
GenericName[zh_CN]=多媒体播放器
|
||||
GenericName[zh_TW]=多媒體播放器
|
||||
Comment=Play movies and songs
|
||||
@@ -26,11 +22,9 @@ Comment[da]=Afspil film og sange
|
||||
Comment[de]=Filme und Musik abspielen
|
||||
Comment[es]=Reproduzca vídeos y canciones
|
||||
Comment[fr]=Lire des vidéos et des musiques
|
||||
Comment[ja]=映画や音楽を再生する
|
||||
Comment[it]=Lettore multimediale
|
||||
Comment[pl]=Odtwarzaj filmy i muzykę
|
||||
Comment[ru]=Воспроизвести фильмы и музыку
|
||||
Comment[tr]=Filmleri ve şarkıları oynatın
|
||||
Comment[zh_CN]=播放电影和歌曲
|
||||
Comment[zh_TW]=播放電影和歌曲
|
||||
Icon=mpv
|
||||
@@ -39,5 +33,5 @@ Exec=mpv --player-operation-mode=pseudo-gui -- %U
|
||||
Terminal=false
|
||||
Categories=AudioVideo;Audio;Video;Player;TV;
|
||||
MimeType=application/ogg;application/x-ogg;application/mxf;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/vnd.dolby.heaac.1;audio/vnd.dolby.heaac.2;audio/aiff;audio/x-aiff;audio/m4a;audio/x-m4a;application/x-extension-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/mpeg2;audio/mpeg3;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/musepack;audio/x-musepack;audio/ogg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg2;video/x-mpeg3;video/mp4v-es;video/x-m4v;video/mp4;application/x-extension-mp4;video/divx;video/vnd.divx;video/msvideo;video/x-msvideo;video/ogg;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;audio/x-ms-asf;application/vnd.ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/avi;video/x-flic;video/fli;video/x-flc;video/flv;video/x-flv;video/x-theora;video/x-theora+ogg;video/x-matroska;video/mkv;audio/x-matroska;application/x-matroska;video/webm;audio/webm;audio/vorbis;audio/x-vorbis;audio/x-vorbis+ogg;video/x-ogm;video/x-ogm+ogg;application/x-ogm;application/x-ogm-audio;application/x-ogm-video;application/x-shorten;audio/x-shorten;audio/x-ape;audio/x-wavpack;audio/x-tta;audio/AMR;audio/ac3;audio/eac3;audio/amr-wb;video/mp2t;audio/flac;audio/mp4;application/x-mpegurl;video/vnd.mpegurl;application/vnd.apple.mpegurl;audio/x-pn-au;video/3gp;video/3gpp;video/3gpp2;audio/3gpp;audio/3gpp2;video/dv;audio/dv;audio/opus;audio/vnd.dts;audio/vnd.dts.hd;audio/x-adpcm;application/x-cue;audio/m3u;
|
||||
X-KDE-Protocols=ftp,http,https,mms,rtmp,rtsp,sftp,smb,srt,rist
|
||||
X-KDE-Protocols=ftp,http,https,mms,rtmp,rtsp,sftp,smb,srt
|
||||
StartupWMClass=mpv
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>io.mpv.mpv</id>
|
||||
<name>mpv</name>
|
||||
<summary>A free, open source, and cross-platform media player</summary>
|
||||
<description>
|
||||
<p>mpv is a free (as in freedom) media player for the command line. It supports a wide variety of media file formats, audio and video codecs, and subtitle types.</p>
|
||||
<p>mpv has an OpenGL, Vulkan, and D3D11 based video output that is capable of many features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more.</p>
|
||||
<p>While mpv strives for minimalism and provides no real GUI, it has a small controller on top of the video for basic control.</p>
|
||||
<p>mpv can leverage most hardware decoding APIs on all platforms. Hardware decoding can be enabled at runtime on demand.</p>
|
||||
<p>Powerful scripting capabilities can make the player do almost anything. There is a large selection of user scripts on the wiki.</p>
|
||||
<p>A straightforward C API was designed from the ground up to make mpv usable as a library and facilitate easy integration into other applications.</p>
|
||||
</description>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0-or-later AND LGPL-2.0-or-later</project_license>
|
||||
<developer_name>mpv.io</developer_name>
|
||||
<launchable type="desktop-id">mpv.desktop</launchable>
|
||||
<content_rating type="oars-1.1" />
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://mpv.io/images/mpv-screenshot-34cd36ae.jpg</image>
|
||||
<caption>Main window</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">https://mpv.io/</url>
|
||||
<url type="bugtracker">https://github.com/mpv-player/mpv/issues</url>
|
||||
<url type="faq">https://github.com/mpv-player/mpv/wiki/FAQ</url>
|
||||
<url type="help">https://mpv.io/manual/stable</url>
|
||||
</component>
|
||||
@@ -82,11 +82,6 @@ static void deint_process(struct mp_filter *f)
|
||||
char *args[] = {"mode", "send_field", NULL};
|
||||
p->sub.filter =
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "yadif_cuda", args);
|
||||
} else if (img->imgfmt == IMGFMT_VAAPI) {
|
||||
char *args[] = {"deint", "motion-adaptive",
|
||||
"interlaced-only", "yes", NULL};
|
||||
p->sub.filter =
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "vavpp", args);
|
||||
} else {
|
||||
has_filter = false;
|
||||
}
|
||||
|
||||
+12
-36
@@ -191,40 +191,21 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
|
||||
dst_have_sw |= !is_hw;
|
||||
}
|
||||
|
||||
// Source is sw, all targets are hw -> try to upload.
|
||||
bool sw_to_hw = imgfmt_is_sw && dst_all_hw;
|
||||
// Source is hw, some targets are sw -> try to download.
|
||||
bool hw_to_sw = !imgfmt_is_sw && dst_have_sw;
|
||||
|
||||
if (dst_all_hw && num_fmts > 0) {
|
||||
bool upload_created = false;
|
||||
int sw_fmt = imgfmt_is_sw ? img->imgfmt : img->params.hw_subfmt;
|
||||
|
||||
for (int i = 0; i < num_fmts; i++) {
|
||||
// We can probably use this! Very lazy and very approximate.
|
||||
struct mp_hwupload *upload = mp_hwupload_create(conv, fmts[i]);
|
||||
if (upload) {
|
||||
mp_info(log, "HW-uploading to %s\n", mp_imgfmt_to_name(fmts[i]));
|
||||
filters[2] = upload->f;
|
||||
hwupload_fmt = mp_hwupload_find_upload_format(upload, sw_fmt);
|
||||
fmts = &hwupload_fmt;
|
||||
num_fmts = hwupload_fmt ? 1 : 0;
|
||||
hw_to_sw = false;
|
||||
|
||||
// We cannot do format conversions when transferring between
|
||||
// two hardware devices, so reject this format if that would be
|
||||
// required.
|
||||
if (!imgfmt_is_sw && hwupload_fmt != sw_fmt) {
|
||||
mp_err(log, "Format %s is not supported by %s\n",
|
||||
mp_imgfmt_to_name(sw_fmt),
|
||||
mp_imgfmt_to_name(p->imgfmts[i]));
|
||||
continue;
|
||||
}
|
||||
upload_created = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!upload_created) {
|
||||
mp_err(log, "Failed to create HW uploader for format %s\n",
|
||||
mp_imgfmt_to_name(sw_fmt));
|
||||
if (sw_to_hw && num_fmts > 0) {
|
||||
// We can probably use this! Very lazy and very approximate.
|
||||
struct mp_hwupload *upload = mp_hwupload_create(conv, fmts[0]);
|
||||
if (upload) {
|
||||
mp_info(log, "HW-uploading to %s\n", mp_imgfmt_to_name(fmts[0]));
|
||||
filters[2] = upload->f;
|
||||
hwupload_fmt = mp_hwupload_find_upload_format(upload, img->imgfmt);
|
||||
fmts = &hwupload_fmt;
|
||||
num_fmts = hwupload_fmt ? 1 : 0;
|
||||
hw_to_sw = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +235,6 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
|
||||
force_sws_params |= !mp_image_params_equal(&imgpar, &p->imgparams);
|
||||
need_sws |= force_sws_params;
|
||||
}
|
||||
if (!imgfmt_is_sw && dst_all_hw) {
|
||||
// This is a hw -> hw upload, so the sw format must already be
|
||||
// mutually understood. No conversion can be done.
|
||||
need_sws = false;
|
||||
}
|
||||
|
||||
if (need_sws) {
|
||||
// Create a new conversion filter.
|
||||
|
||||
@@ -594,14 +594,12 @@ static void fix_image_params(struct priv *p,
|
||||
if (m.p_w <= 0 || m.p_h <= 0)
|
||||
m.p_w = m.p_h = 1;
|
||||
|
||||
m.rotate = p->codec->rotate;
|
||||
m.stereo3d = p->codec->stereo_mode;
|
||||
|
||||
if (opts->video_rotate < 0) {
|
||||
m.rotate = 0;
|
||||
} else {
|
||||
// ffmpeg commit 535a835e51 says that frame rotate takes priority
|
||||
if (!m.rotate)
|
||||
m.rotate = p->codec->rotate;
|
||||
m.rotate = (m.rotate + opts->video_rotate) % 360;
|
||||
}
|
||||
|
||||
|
||||
+81
-127
@@ -15,9 +15,9 @@ struct priv {
|
||||
|
||||
AVBufferRef *hw_pool;
|
||||
|
||||
int last_source_fmt;
|
||||
int last_hw_output_fmt;
|
||||
int last_hw_input_fmt;
|
||||
int last_input_fmt;
|
||||
int last_upload_fmt;
|
||||
int last_sw_fmt;
|
||||
|
||||
// Hardware wrapper format, e.g. IMGFMT_VAAPI.
|
||||
int hw_imgfmt;
|
||||
@@ -35,84 +35,66 @@ struct priv {
|
||||
int *fmt_upload_index;
|
||||
int *fmt_upload_num;
|
||||
|
||||
// List of source formats that require hwmap instead of hwupload.
|
||||
int *map_fmts;
|
||||
int num_map_fmts;
|
||||
|
||||
struct mp_hwupload public;
|
||||
};
|
||||
|
||||
struct hwmap_pairs {
|
||||
int first_fmt;
|
||||
int second_fmt;
|
||||
struct ffmpeg_and_other_bugs {
|
||||
int imgfmt; // hw format
|
||||
const int *const whitelist_formats; // if non-NULL, allow only these
|
||||
// sw formats
|
||||
bool force_same_upload_fmt; // force upload fmt == sw fmt
|
||||
};
|
||||
|
||||
// We cannot discover which pairs of hardware formats need to use hwmap to
|
||||
// convert between the formats, so we need a lookup table.
|
||||
static const struct hwmap_pairs hwmap_pairs[] = {
|
||||
// This garbage is so complex and buggy. Hardcoding knowledge makes it work,
|
||||
// trying to use the dynamic information returned by the API does not. So fuck
|
||||
// this shit, I'll just whitelist the cases that work, what the fuck.
|
||||
static const struct ffmpeg_and_other_bugs shitlist[] = {
|
||||
{
|
||||
.first_fmt = IMGFMT_DRMPRIME,
|
||||
.second_fmt = IMGFMT_VAAPI,
|
||||
.imgfmt = IMGFMT_VAAPI,
|
||||
.whitelist_formats = (const int[]){IMGFMT_NV12, IMGFMT_P010, IMGFMT_BGRA,
|
||||
IMGFMT_ABGR, IMGFMT_RGB0, 0},
|
||||
.force_same_upload_fmt = true,
|
||||
},
|
||||
{0}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Find the closest supported format when hw uploading
|
||||
*
|
||||
* Some hardware types support implicit format conversion on upload. For these
|
||||
* types, it is possible for the set of formats that are accepts as inputs to
|
||||
* the upload process to differ from the set of formats that can be outputs of
|
||||
* the upload.
|
||||
*
|
||||
* hw_input_format -> hwupload -> hw_output_format
|
||||
*
|
||||
* Awareness of this is important because we can avoid doing software conversion
|
||||
* if our input_fmt is accepted as a hw_input_format even if it cannot be the
|
||||
* hw_output_format.
|
||||
*/
|
||||
static bool select_format(struct priv *p, int input_fmt,
|
||||
int *out_hw_input_fmt, int *out_hw_output_fmt)
|
||||
static bool select_format(struct priv *p, int input_fmt, int *out_sw_fmt,
|
||||
int *out_upload_fmt)
|
||||
{
|
||||
if (!input_fmt)
|
||||
return false;
|
||||
|
||||
// If the input format is a hw format, then we shouldn't be doing this
|
||||
// format selection here at all.
|
||||
if (IMGFMT_IS_HWACCEL(input_fmt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First find the closest hw input fmt. Some hwdec APIs return crazy lists of
|
||||
// First find the closest sw fmt. Some hwdec APIs return crazy lists of
|
||||
// "supported" formats, which then are not supported or crash (???), so
|
||||
// the this is a good way to avoid problems.
|
||||
// (Actually we should just have hardcoded everything instead of relying on
|
||||
// this fragile bullshit FFmpeg API and the fragile bullshit hwdec drivers.)
|
||||
int hw_input_fmt = mp_imgfmt_select_best_list(p->fmts, p->num_fmts, input_fmt);
|
||||
if (!hw_input_fmt)
|
||||
int sw_fmt = mp_imgfmt_select_best_list(p->fmts, p->num_fmts, input_fmt);
|
||||
if (!sw_fmt)
|
||||
return false;
|
||||
|
||||
// Dumb, but find index for p->fmts[index]==hw_input_fmt.
|
||||
// Dumb, but find index for p->fmts[index]==sw_fmt.
|
||||
int index = -1;
|
||||
for (int n = 0; n < p->num_fmts; n++) {
|
||||
if (p->fmts[n] == hw_input_fmt)
|
||||
if (p->fmts[n] == sw_fmt)
|
||||
index = n;
|
||||
}
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
// Now check the available output formats. This is the format our sw frame
|
||||
// will be in after the upload (probably).
|
||||
// Now check the available upload formats. This is the format our sw frame
|
||||
// has to be in, and which the upload API will take (probably).
|
||||
|
||||
int *upload_fmts = &p->upload_fmts[p->fmt_upload_index[index]];
|
||||
int num_upload_fmts = p->fmt_upload_num[index];
|
||||
|
||||
int hw_output_fmt = mp_imgfmt_select_best_list(upload_fmts, num_upload_fmts,
|
||||
int up_fmt = mp_imgfmt_select_best_list(upload_fmts, num_upload_fmts,
|
||||
input_fmt);
|
||||
if (!hw_output_fmt)
|
||||
if (!up_fmt)
|
||||
return false;
|
||||
|
||||
*out_hw_input_fmt = hw_input_fmt;
|
||||
*out_hw_output_fmt = hw_output_fmt;
|
||||
*out_sw_fmt = sw_fmt;
|
||||
*out_upload_fmt = up_fmt;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -122,15 +104,7 @@ int mp_hwupload_find_upload_format(struct mp_hwupload *u, int imgfmt)
|
||||
|
||||
int sw = 0, up = 0;
|
||||
select_format(p, imgfmt, &sw, &up);
|
||||
// In th case where the imgfmt is not natively supported, it must be
|
||||
// converted, either before or during upload. If the imgfmt is supported as
|
||||
// an hw input format, then prefer that, and if the upload has to do implict
|
||||
// conversion, that's fine. On the other hand, if the imgfmt is not a
|
||||
// supported input format, then pick the output format as the conversion
|
||||
// target to avoid doing two conversions (one before upload, and one during
|
||||
// upload). Note that for most hardware types, there is no ability to convert
|
||||
// during upload, and the two formats will always be the same.
|
||||
return imgfmt == sw ? sw : up;
|
||||
return up;
|
||||
}
|
||||
|
||||
static void process(struct mp_filter *f)
|
||||
@@ -151,66 +125,44 @@ static void process(struct mp_filter *f)
|
||||
}
|
||||
struct mp_image *src = frame.data;
|
||||
|
||||
/*
|
||||
* Just pass though HW frames in the same format. This shouldn't normally
|
||||
* occur as the upload filter will not be inserted when the formats already
|
||||
* match.
|
||||
*
|
||||
* Technically, we could have frames from different device contexts,
|
||||
* which would require an explicit transfer, but mpv doesn't let you
|
||||
* create that configuration.
|
||||
*/
|
||||
if (src->imgfmt == p->hw_imgfmt) {
|
||||
// As documented, just pass though HW frames.
|
||||
if (IMGFMT_IS_HWACCEL(src->imgfmt)) {
|
||||
mp_pin_in_write(f->ppins[1], frame);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src->imgfmt != p->last_source_fmt) {
|
||||
if (IMGFMT_IS_HWACCEL(src->imgfmt)) {
|
||||
// Because there cannot be any conversion of the sw format when the
|
||||
// input is a hw format, just pick the source sw format.
|
||||
p->last_hw_input_fmt = p->last_hw_output_fmt = src->params.hw_subfmt;
|
||||
} else {
|
||||
if (!select_format(p, src->imgfmt,
|
||||
&p->last_hw_input_fmt, &p->last_hw_output_fmt))
|
||||
{
|
||||
MP_ERR(f, "no hw upload format found\n");
|
||||
goto error;
|
||||
}
|
||||
if (src->imgfmt != p->last_hw_input_fmt) {
|
||||
// Should not fail; if it does, mp_hwupload_find_upload_format()
|
||||
// does not return the src->imgfmt format.
|
||||
MP_ERR(f, "input format is not an upload format\n");
|
||||
goto error;
|
||||
}
|
||||
if (src->w % 2 || src->h % 2) {
|
||||
MP_ERR(f, "non-mod 2 input frames unsupported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (src->imgfmt != p->last_input_fmt) {
|
||||
if (!select_format(p, src->imgfmt, &p->last_sw_fmt, &p->last_upload_fmt))
|
||||
{
|
||||
MP_ERR(f, "no hw upload format found\n");
|
||||
goto error;
|
||||
}
|
||||
p->last_source_fmt = src->imgfmt;
|
||||
if (src->imgfmt != p->last_upload_fmt) {
|
||||
// Should not fail; if it does, mp_hwupload_find_upload_format()
|
||||
// does not return the src->imgfmt format.
|
||||
MP_ERR(f, "input format not an upload format\n");
|
||||
goto error;
|
||||
}
|
||||
p->last_input_fmt = src->imgfmt;
|
||||
MP_INFO(f, "upload %s -> %s[%s]\n",
|
||||
mp_imgfmt_to_name(p->last_source_fmt),
|
||||
mp_imgfmt_to_name(p->last_input_fmt),
|
||||
mp_imgfmt_to_name(p->hw_imgfmt),
|
||||
mp_imgfmt_to_name(p->last_hw_output_fmt));
|
||||
mp_imgfmt_to_name(p->last_sw_fmt));
|
||||
}
|
||||
|
||||
if (!mp_update_av_hw_frames_pool(&p->hw_pool, p->av_device_ctx, p->hw_imgfmt,
|
||||
p->last_hw_output_fmt, src->w, src->h))
|
||||
p->last_sw_fmt, src->w, src->h))
|
||||
{
|
||||
MP_ERR(f, "failed to create frame pool\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct mp_image *dst;
|
||||
bool map_images = false;
|
||||
for (int n = 0; n < p->num_map_fmts; n++) {
|
||||
if (src->imgfmt == p->map_fmts[n]) {
|
||||
map_images = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (map_images)
|
||||
dst = mp_av_pool_image_hw_map(p->hw_pool, src);
|
||||
else
|
||||
dst = mp_av_pool_image_hw_upload(p->hw_pool, src);
|
||||
struct mp_image *dst = mp_av_pool_image_hw_upload(p->hw_pool, src);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
@@ -246,10 +198,10 @@ static const struct mp_filter_info hwupload_filter = {
|
||||
// So filter out all not explicitly supported formats.
|
||||
static bool vo_supports(struct mp_hwdec_ctx *ctx, int hw_fmt, int sw_fmt)
|
||||
{
|
||||
if (!ctx->hw_imgfmt)
|
||||
return true; // if unset, all formats are allowed
|
||||
if (ctx->hw_imgfmt != hw_fmt)
|
||||
return false;
|
||||
if (!ctx->supported_formats)
|
||||
return true; // if unset, all formats are allowed
|
||||
|
||||
for (int i = 0; ctx->supported_formats && ctx->supported_formats[i]; i++) {
|
||||
if (ctx->supported_formats[i] == sw_fmt)
|
||||
@@ -276,12 +228,6 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
|
||||
struct mp_hwdec_ctx *ctx = NULL;
|
||||
AVHWFramesConstraints *cstr = NULL;
|
||||
|
||||
struct hwdec_imgfmt_request params = {
|
||||
.imgfmt = hw_imgfmt,
|
||||
.probing = true,
|
||||
};
|
||||
hwdec_devices_request_for_img_fmt(info->hwdec_devs, ¶ms);
|
||||
|
||||
for (int n = 0; ; n++) {
|
||||
struct mp_hwdec_ctx *cur = hwdec_devices_get_n(info->hwdec_devs, n);
|
||||
if (!cur)
|
||||
@@ -305,7 +251,7 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
|
||||
}
|
||||
|
||||
if (!ctx) {
|
||||
MP_INFO(u->f, "no support for this hw format\n");
|
||||
MP_ERR(u->f, "no support for this hw format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -315,13 +261,11 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
|
||||
// supported formats. This should be relatively cheap as we don't create
|
||||
// any real frames (although some backends do for probing info).
|
||||
|
||||
for (int n = 0; hwmap_pairs[n].first_fmt; n++) {
|
||||
if (hwmap_pairs[n].first_fmt == hw_imgfmt) {
|
||||
MP_TARRAY_APPEND(p, p->map_fmts, p->num_map_fmts,
|
||||
hwmap_pairs[n].second_fmt);
|
||||
} else if (hwmap_pairs[n].second_fmt == hw_imgfmt) {
|
||||
MP_TARRAY_APPEND(p, p->map_fmts, p->num_map_fmts,
|
||||
hwmap_pairs[n].first_fmt);
|
||||
const struct ffmpeg_and_other_bugs *bugs = NULL;
|
||||
for (int n = 0; shitlist[n].imgfmt; n++) {
|
||||
if (shitlist[n].imgfmt == hw_imgfmt) {
|
||||
bugs = &shitlist[n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,12 +280,18 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
|
||||
mp_imgfmt_to_name(hw_imgfmt),
|
||||
mp_imgfmt_to_name(imgfmt));
|
||||
|
||||
if (IMGFMT_IS_HWACCEL(imgfmt)) {
|
||||
// If the enumerated format is a hardware format, we don't need to
|
||||
// do any further probing. It will be supported.
|
||||
MP_VERBOSE(u->f, " supports %s (a hardware format)\n",
|
||||
mp_imgfmt_to_name(imgfmt));
|
||||
continue;
|
||||
if (bugs && bugs->whitelist_formats) {
|
||||
bool found = false;
|
||||
for (int i = 0; bugs->whitelist_formats[i]; i++) {
|
||||
if (bugs->whitelist_formats[i] == imgfmt) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
MP_VERBOSE(u->f, "... skipping blacklisted format\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Creates an AVHWFramesContexts with the given parameters.
|
||||
@@ -369,6 +319,10 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt)
|
||||
if (!fmt)
|
||||
continue;
|
||||
MP_VERBOSE(u->f, " supports %s\n", mp_imgfmt_to_name(fmt));
|
||||
if (bugs && bugs->force_same_upload_fmt && imgfmt != fmt) {
|
||||
MP_VERBOSE(u->f, " ... skipping blacklisted format\n");
|
||||
continue;
|
||||
}
|
||||
if (!vo_supports(ctx, hw_imgfmt, fmt)) {
|
||||
MP_VERBOSE(u->f, " ... not supported by VO\n");
|
||||
continue;
|
||||
@@ -406,12 +360,12 @@ struct mp_hwupload *mp_hwupload_create(struct mp_filter *parent, int hw_imgfmt)
|
||||
mp_filter_add_pin(f, MP_PIN_OUT, "out");
|
||||
|
||||
if (!probe_formats(u, hw_imgfmt)) {
|
||||
MP_INFO(f, "hardware format not supported\n");
|
||||
goto fail;
|
||||
MP_ERR(f, "hardware format not supported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return u;
|
||||
fail:
|
||||
error:
|
||||
talloc_free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+19
-61
@@ -33,8 +33,6 @@
|
||||
#include <libavfilter/buffersink.h>
|
||||
#include <libavfilter/buffersrc.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/av_common.h"
|
||||
#include "common/tags.h"
|
||||
@@ -42,12 +40,10 @@
|
||||
|
||||
#include "audio/format.h"
|
||||
#include "audio/aframe.h"
|
||||
#include "audio/chmap_avchannel.h"
|
||||
#include "video/mp_image.h"
|
||||
#include "audio/fmt-conversion.h"
|
||||
#include "video/fmt-conversion.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/out/gpu/hwdec.h"
|
||||
|
||||
#include "f_lavfi.h"
|
||||
#include "filter.h"
|
||||
@@ -99,9 +95,6 @@ struct lavfi {
|
||||
double delay; // seconds of audio apparently buffered by filter
|
||||
|
||||
struct mp_lavfi public;
|
||||
|
||||
// Identify a specific hwdec_interop to use
|
||||
char *hwdec_interop;
|
||||
};
|
||||
|
||||
struct lavfi_pad {
|
||||
@@ -401,7 +394,7 @@ static bool init_pads(struct lavfi *c)
|
||||
} else if (pad->type == MP_FRAME_VIDEO) {
|
||||
dst_filter = avfilter_get_by_name("buffersink");
|
||||
} else {
|
||||
MP_ASSERT_UNREACHABLE();
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (!dst_filter)
|
||||
@@ -477,11 +470,7 @@ static bool init_pads(struct lavfi *c)
|
||||
params->sample_rate = mp_aframe_get_rate(fmt);
|
||||
struct mp_chmap chmap = {0};
|
||||
mp_aframe_get_chmap(fmt, &chmap);
|
||||
#if !HAVE_AV_CHANNEL_LAYOUT
|
||||
params->channel_layout = mp_chmap_to_lavc(&chmap);
|
||||
#else
|
||||
mp_chmap_to_av_layout(¶ms->ch_layout, &chmap);
|
||||
#endif
|
||||
pad->timebase = (AVRational){1, mp_aframe_get_rate(fmt)};
|
||||
filter_name = "abuffer";
|
||||
} else if (pad->type == MP_FRAME_VIDEO) {
|
||||
@@ -495,7 +484,7 @@ static bool init_pads(struct lavfi *c)
|
||||
params->frame_rate = av_d2q(fmt->nominal_fps, 1000000);
|
||||
filter_name = "buffer";
|
||||
} else {
|
||||
MP_ASSERT_UNREACHABLE();
|
||||
assert(0);
|
||||
}
|
||||
|
||||
params->time_base = pad->timebase;
|
||||
@@ -552,22 +541,11 @@ static void init_graph(struct lavfi *c)
|
||||
if (init_pads(c)) {
|
||||
struct mp_stream_info *info = mp_filter_find_stream_info(c->f);
|
||||
if (info && info->hwdec_devs) {
|
||||
struct mp_hwdec_ctx *hwdec_ctx = NULL;
|
||||
if (c->hwdec_interop) {
|
||||
int imgfmt =
|
||||
ra_hwdec_driver_get_imgfmt_for_name(c->hwdec_interop);
|
||||
hwdec_ctx = mp_filter_load_hwdec_device(c->f, imgfmt);
|
||||
} else {
|
||||
hwdec_ctx = hwdec_devices_get_first(info->hwdec_devs);
|
||||
}
|
||||
if (hwdec_ctx && hwdec_ctx->av_device_ref) {
|
||||
MP_VERBOSE(c, "Configuring hwdec_interop=%s for filter graph: %s\n",
|
||||
hwdec_ctx->driver_name, c->graph_string);
|
||||
for (int n = 0; n < c->graph->nb_filters; n++) {
|
||||
AVFilterContext *filter = c->graph->filters[n];
|
||||
filter->hw_device_ctx =
|
||||
av_buffer_ref(hwdec_ctx->av_device_ref);
|
||||
}
|
||||
struct mp_hwdec_ctx *hwdec = hwdec_devices_get_first(info->hwdec_devs);
|
||||
for (int n = 0; n < c->graph->nb_filters; n++) {
|
||||
AVFilterContext *filter = c->graph->filters[n];
|
||||
if (hwdec && hwdec->av_device_ref)
|
||||
filter->hw_device_ctx = av_buffer_ref(hwdec->av_device_ref);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -901,7 +879,6 @@ error:
|
||||
|
||||
struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent,
|
||||
enum mp_frame_type type, bool bidir,
|
||||
char *hwdec_interop,
|
||||
char **graph_opts, const char *graph)
|
||||
{
|
||||
struct lavfi *c = lavfi_alloc(parent);
|
||||
@@ -912,14 +889,12 @@ struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent,
|
||||
c->force_bidir = bidir;
|
||||
c->graph_opts = mp_dup_str_array(c, graph_opts);
|
||||
c->graph_string = talloc_strdup(c, graph);
|
||||
c->hwdec_interop = talloc_strdup(c, hwdec_interop);
|
||||
|
||||
return do_init(c);
|
||||
}
|
||||
|
||||
struct mp_lavfi *mp_lavfi_create_filter(struct mp_filter *parent,
|
||||
enum mp_frame_type type, bool bidir,
|
||||
char *hwdec_interop,
|
||||
char **graph_opts,
|
||||
const char *filter, char **filter_opts)
|
||||
{
|
||||
@@ -929,7 +904,6 @@ struct mp_lavfi *mp_lavfi_create_filter(struct mp_filter *parent,
|
||||
|
||||
c->force_type = type;
|
||||
c->force_bidir = bidir;
|
||||
c->hwdec_interop = talloc_strdup(c, hwdec_interop);
|
||||
c->graph_opts = mp_dup_str_array(c, graph_opts);
|
||||
c->graph_string = talloc_strdup(c, filter);
|
||||
c->direct_filter_opts = mp_dup_str_array(c, filter_opts);
|
||||
@@ -949,8 +923,6 @@ struct lavfi_user_opts {
|
||||
char **filter_opts;
|
||||
|
||||
int fix_pts;
|
||||
|
||||
char *hwdec_interop;
|
||||
};
|
||||
|
||||
static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options)
|
||||
@@ -958,11 +930,10 @@ static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options)
|
||||
struct lavfi_user_opts *opts = options;
|
||||
struct mp_lavfi *l;
|
||||
if (opts->is_bridge) {
|
||||
l = mp_lavfi_create_filter(parent, opts->type, true,
|
||||
opts->hwdec_interop, opts->avopts,
|
||||
l = mp_lavfi_create_filter(parent, opts->type, true, opts->avopts,
|
||||
opts->filter_name, opts->filter_opts);
|
||||
} else {
|
||||
l = mp_lavfi_create_graph(parent, opts->type, true, opts->hwdec_interop,
|
||||
l = mp_lavfi_create_graph(parent, opts->type, true,
|
||||
opts->avopts, opts->graph);
|
||||
}
|
||||
if (l) {
|
||||
@@ -973,19 +944,19 @@ static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options)
|
||||
return l ? l->f : NULL;
|
||||
}
|
||||
|
||||
static bool is_single_media_only(const AVFilterPad *pads, int media_type)
|
||||
{
|
||||
int count = avfilter_pad_count(pads);
|
||||
if (count != 1)
|
||||
return false;
|
||||
return avfilter_pad_get_type(pads, 0) == media_type;
|
||||
}
|
||||
|
||||
// Does it have exactly one video input and one video output?
|
||||
static bool is_usable(const AVFilter *filter, int media_type)
|
||||
{
|
||||
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(8, 3, 0)
|
||||
int nb_inputs = avfilter_filter_pad_count(filter, 0),
|
||||
nb_outputs = avfilter_filter_pad_count(filter, 1);
|
||||
#else
|
||||
int nb_inputs = avfilter_pad_count(filter->inputs),
|
||||
nb_outputs = avfilter_pad_count(filter->outputs);
|
||||
#endif
|
||||
return nb_inputs == 1 && nb_outputs == 1 &&
|
||||
avfilter_pad_get_type(filter->inputs, 0) == media_type &&
|
||||
avfilter_pad_get_type(filter->outputs, 0) == media_type;
|
||||
return is_single_media_only(filter->inputs, media_type) &&
|
||||
is_single_media_only(filter->outputs, media_type);
|
||||
}
|
||||
|
||||
bool mp_lavfi_is_usable(const char *name, int media_type)
|
||||
@@ -1123,9 +1094,6 @@ const struct mp_user_filter_entry af_lavfi = {
|
||||
{"graph", OPT_STRING(graph)},
|
||||
{"fix-pts", OPT_FLAG(fix_pts)},
|
||||
{"o", OPT_KEYVALUELIST(avopts)},
|
||||
{"hwdec_interop",
|
||||
OPT_STRING_VALIDATE(hwdec_interop,
|
||||
ra_hwdec_validate_drivers_only_opt)},
|
||||
{0}
|
||||
},
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT){
|
||||
@@ -1145,9 +1113,6 @@ const struct mp_user_filter_entry af_lavfi_bridge = {
|
||||
{"name", OPT_STRING(filter_name)},
|
||||
{"opts", OPT_KEYVALUELIST(filter_opts)},
|
||||
{"o", OPT_KEYVALUELIST(avopts)},
|
||||
{"hwdec_interop",
|
||||
OPT_STRING_VALIDATE(hwdec_interop,
|
||||
ra_hwdec_validate_drivers_only_opt)},
|
||||
{0}
|
||||
},
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT){
|
||||
@@ -1167,9 +1132,6 @@ const struct mp_user_filter_entry vf_lavfi = {
|
||||
.options = (const m_option_t[]){
|
||||
{"graph", OPT_STRING(graph)},
|
||||
{"o", OPT_KEYVALUELIST(avopts)},
|
||||
{"hwdec_interop",
|
||||
OPT_STRING_VALIDATE(hwdec_interop,
|
||||
ra_hwdec_validate_drivers_only_opt)},
|
||||
{0}
|
||||
},
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT){
|
||||
@@ -1189,10 +1151,6 @@ const struct mp_user_filter_entry vf_lavfi_bridge = {
|
||||
{"name", OPT_STRING(filter_name)},
|
||||
{"opts", OPT_KEYVALUELIST(filter_opts)},
|
||||
{"o", OPT_KEYVALUELIST(avopts)},
|
||||
{"hwdec_interop",
|
||||
OPT_STRING_VALIDATE(hwdec_interop,
|
||||
ra_hwdec_validate_drivers_only_opt)},
|
||||
|
||||
{0}
|
||||
},
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT){
|
||||
|
||||
@@ -18,7 +18,6 @@ struct mp_lavfi {
|
||||
// graph: a libavfilter graph specification
|
||||
struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent,
|
||||
enum mp_frame_type type, bool bidir,
|
||||
char *hwdec_interop,
|
||||
char **graph_opts, const char *graph);
|
||||
|
||||
// Unlike mp_lavfi_create_graph(), this creates a single filter, using explicit
|
||||
@@ -27,7 +26,6 @@ struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent,
|
||||
// (which are applied with mp_set_avopts()).
|
||||
struct mp_lavfi *mp_lavfi_create_filter(struct mp_filter *parent,
|
||||
enum mp_frame_type type, bool bidir,
|
||||
char *hwdec_interop,
|
||||
char **graph_opts,
|
||||
const char *filter, char **filter_opts);
|
||||
|
||||
|
||||
@@ -106,16 +106,16 @@ static void check_in_format_change(struct mp_user_filter *u,
|
||||
|
||||
if (u == p->input) {
|
||||
p->public.input_params = img->params;
|
||||
|
||||
// Unfortunately there's no good place to update these.
|
||||
// But a common case is enabling HW decoding, which
|
||||
// might init some support of them in the VO, and update
|
||||
// the VO's format list.
|
||||
update_output_caps(p);
|
||||
} else if (u == p->output) {
|
||||
p->public.output_params = img->params;
|
||||
}
|
||||
|
||||
// Unfortunately there's no good place to update these.
|
||||
// But a common case is enabling HW decoding, which
|
||||
// might init some support of them in the VO, and update
|
||||
// the VO's format list.
|
||||
update_output_caps(p);
|
||||
|
||||
p->public.reconfig_happened = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +327,26 @@ static void reset(struct mp_filter *f)
|
||||
close_lavrr(p);
|
||||
}
|
||||
|
||||
static void extra_output_conversion(struct mp_aframe *mpa)
|
||||
{
|
||||
int format = af_fmt_from_planar(mp_aframe_get_format(mpa));
|
||||
int num_planes = mp_aframe_get_planes(mpa);
|
||||
uint8_t **planes = mp_aframe_get_data_rw(mpa);
|
||||
if (!planes)
|
||||
return;
|
||||
for (int p = 0; p < num_planes; p++) {
|
||||
void *ptr = planes[p];
|
||||
int total = mp_aframe_get_total_plane_samples(mpa);
|
||||
if (format == AF_FORMAT_FLOAT) {
|
||||
for (int s = 0; s < total; s++)
|
||||
((float *)ptr)[s] = av_clipf(((float *)ptr)[s], -1.0f, 1.0f);
|
||||
} else if (format == AF_FORMAT_DOUBLE) {
|
||||
for (int s = 0; s < total; s++)
|
||||
((double *)ptr)[s] = MPCLAMP(((double *)ptr)[s], -1.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This relies on the tricky way mpa was allocated.
|
||||
static bool reorder_planes(struct mp_aframe *mpa, int *reorder,
|
||||
struct mp_chmap *newmap)
|
||||
@@ -431,6 +451,8 @@ static struct mp_frame filter_resample_output(struct priv *p,
|
||||
goto error;
|
||||
}
|
||||
|
||||
extra_output_conversion(out);
|
||||
|
||||
if (in) {
|
||||
mp_aframe_copy_attributes(out, in);
|
||||
p->current_pts = mp_aframe_end_pts(in);
|
||||
|
||||
+1
-1
@@ -250,7 +250,7 @@ static void fixed_aframe_size_process(struct mp_filter *f)
|
||||
int in_samples = mp_aframe_get_size(p->in);
|
||||
int copy = MPMIN(in_samples, p->samples - p->out_written);
|
||||
if (!mp_aframe_copy_samples(p->out, p->out_written, p->in, 0, copy))
|
||||
MP_ASSERT_UNREACHABLE();
|
||||
assert(0);
|
||||
mp_aframe_skip_samples(p->in, copy);
|
||||
p->out_written += copy;
|
||||
}
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ struct mp_filter *mp_compute_frame_duration_create(struct mp_filter *parent);
|
||||
|
||||
// Given the filters[0..num_filters] array, connect in with the input of the
|
||||
// first filter, connect the output of the first filter to the input to the
|
||||
// second filter, etc., until out. All filters are assumed to be bidirectional,
|
||||
// second filter, etc., until out. All filters are assumed to be bidrectional,
|
||||
// with input on pin 0 and output on pin 1. NULL entries are skipped.
|
||||
void mp_chain_filters(struct mp_pin *in, struct mp_pin *out,
|
||||
struct mp_filter **filters, int num_filters);
|
||||
@@ -68,10 +68,10 @@ void mp_subfilter_destroy(struct mp_subfilter *sub);
|
||||
// The filter is destroyed with talloc_free(sub->filter).
|
||||
bool mp_subfilter_drain_destroy(struct mp_subfilter *sub);
|
||||
|
||||
// A bidirectional filter which passes through all data.
|
||||
// A bidrectional filter which passes through all data.
|
||||
struct mp_filter *mp_bidir_nop_filter_create(struct mp_filter *parent);
|
||||
|
||||
// A bidirectional filter which does not connect its pins. Instead, the user is,
|
||||
// A bidrectional filter which does not connect its pins. Instead, the user is,
|
||||
// by convention, allowed to access the filter's private pins, and use them
|
||||
// freely. (This is sometimes convenient, such as when you need to pass a single
|
||||
// filter instance to other code, and you don't need a full "proper" filter.)
|
||||
|
||||
+5
-12
@@ -1,15 +1,12 @@
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <libavutil/hwcontext.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/global.h"
|
||||
#include "common/msg.h"
|
||||
#include "osdep/atomic.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/img_format.h"
|
||||
|
||||
#include "filter.h"
|
||||
#include "filter_internal.h"
|
||||
@@ -375,7 +372,7 @@ static struct mp_pin *find_connected_end(struct mp_pin *p)
|
||||
return other;
|
||||
p = other->user_conn;
|
||||
}
|
||||
MP_ASSERT_UNREACHABLE();
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// With p being part of a connection, create the pin_connection and set all
|
||||
@@ -400,7 +397,7 @@ static void init_connection(struct mp_pin *p)
|
||||
if (out->manual_connection)
|
||||
assert(out->manual_connection->in->runner == runner);
|
||||
|
||||
// Logically, the ends are always manual connections. A pin chain without
|
||||
// Logicaly, the ends are always manual connections. A pin chain without
|
||||
// manual connections at the ends is still disconnected (or if this
|
||||
// attempted to extend an existing connection, becomes dangling and gets
|
||||
// disconnected).
|
||||
@@ -685,19 +682,15 @@ struct mp_stream_info *mp_filter_find_stream_info(struct mp_filter *f)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mp_hwdec_ctx *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt)
|
||||
struct AVBufferRef *mp_filter_load_hwdec_device(struct mp_filter *f, int avtype)
|
||||
{
|
||||
struct mp_stream_info *info = mp_filter_find_stream_info(f);
|
||||
if (!info || !info->hwdec_devs)
|
||||
return NULL;
|
||||
|
||||
struct hwdec_imgfmt_request params = {
|
||||
.imgfmt = imgfmt,
|
||||
.probing = false,
|
||||
};
|
||||
hwdec_devices_request_for_img_fmt(info->hwdec_devs, ¶ms);
|
||||
hwdec_devices_request_all(info->hwdec_devs);
|
||||
|
||||
return hwdec_devices_get_by_imgfmt(info->hwdec_devs, imgfmt);
|
||||
return hwdec_devices_get_lavc(info->hwdec_devs, avtype);
|
||||
}
|
||||
|
||||
static void filter_wakeup(struct mp_filter *f, bool mark_only)
|
||||
|
||||
+2
-1
@@ -408,7 +408,8 @@ struct mp_stream_info {
|
||||
// Search for a parent filter (including f) that has this set, and return it.
|
||||
struct mp_stream_info *mp_filter_find_stream_info(struct mp_filter *f);
|
||||
|
||||
struct mp_hwdec_ctx *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt);
|
||||
struct AVBufferRef;
|
||||
struct AVBufferRef *mp_filter_load_hwdec_device(struct mp_filter *f, int avtype);
|
||||
|
||||
// Perform filtering. This runs until the filter graph is blocked (due to
|
||||
// missing external input or unread output). It returns whether any outside
|
||||
|
||||
@@ -67,6 +67,7 @@ const struct m_obj_list af_obj_list = {
|
||||
.get_desc = get_af_desc,
|
||||
.description = "audio filters",
|
||||
.allow_disable_entries = true,
|
||||
.allow_unknown_entries = true,
|
||||
.check_unknown_entry = check_af_lavfi,
|
||||
.print_help_list = print_af_help_list,
|
||||
.print_unknown_entry_help = print_af_lavfi_help,
|
||||
@@ -123,6 +124,7 @@ const struct m_obj_list vf_obj_list = {
|
||||
.get_desc = get_vf_desc,
|
||||
.description = "video filters",
|
||||
.allow_disable_entries = true,
|
||||
.allow_unknown_entries = true,
|
||||
.check_unknown_entry = check_vf_lavfi,
|
||||
.print_help_list = print_vf_help_list,
|
||||
.print_unknown_entry_help = print_vf_lavfi_help,
|
||||
@@ -155,7 +157,7 @@ struct mp_filter *mp_create_user_filter(struct mp_filter *parent,
|
||||
if (strncmp(name, "lavfi-", 6) == 0)
|
||||
name += 6;
|
||||
struct mp_lavfi *l =
|
||||
mp_lavfi_create_filter(parent, frame_type, true, NULL, NULL, name, args);
|
||||
mp_lavfi_create_filter(parent, frame_type, true, NULL, name, args);
|
||||
if (l)
|
||||
f = l->f;
|
||||
goto done;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
input = join_paths(source_root, 'TOOLS', 'osxbundle',
|
||||
'mpv.app', 'Contents', 'Resources', 'icon.icns')
|
||||
osxbundle = custom_target('osxbundle',
|
||||
input: input,
|
||||
output: 'icon.icns.inc',
|
||||
command: [file2string, '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
sources += osxbundle
|
||||
@@ -1,20 +0,0 @@
|
||||
icons = ['16', '32', '64', '128']
|
||||
foreach size: icons
|
||||
name = 'mpv-icon-8bit-'+size+'x'+size+'.png'
|
||||
icon = custom_target(name,
|
||||
input: join_paths(source_root, 'etc', name),
|
||||
output: name + '.inc',
|
||||
command: [file2string, '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
sources += icon
|
||||
endforeach
|
||||
|
||||
etc_files = ['input.conf', 'builtin.conf']
|
||||
foreach file: etc_files
|
||||
etc_file = custom_target(file,
|
||||
input: join_paths(source_root, 'etc', file),
|
||||
output: file + '.inc',
|
||||
command: [file2string, '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
sources += etc_file
|
||||
endforeach
|
||||
@@ -1,25 +0,0 @@
|
||||
ebml_defs = custom_target('ebml_defs.inc',
|
||||
output: 'ebml_defs.inc',
|
||||
command: [matroska, '--generate-definitions', '@OUTPUT@'],
|
||||
)
|
||||
|
||||
ebml_types = custom_target('ebml_types.h',
|
||||
output: 'ebml_types.h',
|
||||
command: [matroska, '--generate-header', '@OUTPUT@'],
|
||||
)
|
||||
|
||||
version_h = custom_target('version.h',
|
||||
output: 'version.h',
|
||||
command: [version_py, '@OUTPUT@'],
|
||||
build_always_stale: true,
|
||||
)
|
||||
|
||||
sources += [ebml_defs, ebml_types, version_h]
|
||||
|
||||
# Meson doesn't allow having multiple build targets with the same name in the same file.
|
||||
# Just generate the com in here for windows builds.
|
||||
if win32 and get_option('cplayer')
|
||||
wrapper_sources= '../osdep/win32-console-wrapper.c'
|
||||
executable('mpv', wrapper_sources, c_args: '-municode', link_args: '-municode',
|
||||
name_suffix: 'com', install: true)
|
||||
endif
|
||||
@@ -1,57 +0,0 @@
|
||||
# custom swift targets
|
||||
bridge = join_paths(source_root, 'osdep/macOS_swift_bridge.h')
|
||||
header = join_paths(build_root, 'osdep/macOS_swift.h')
|
||||
module = join_paths(build_root, 'osdep/macOS_swift.swiftmodule')
|
||||
target = join_paths(build_root, 'osdep/macOS_swift.o')
|
||||
|
||||
swift_flags = ['-frontend', '-c', '-sdk', macos_sdk_path,
|
||||
'-enable-objc-interop', '-emit-objc-header', '-parse-as-library']
|
||||
|
||||
if swift_ver.version_compare('>=6.0')
|
||||
swift_flags += ['-swift-version', '5']
|
||||
endif
|
||||
|
||||
if get_option('debug')
|
||||
swift_flags += '-g'
|
||||
endif
|
||||
|
||||
if get_option('optimization') != '0'
|
||||
swift_flags += '-O'
|
||||
endif
|
||||
|
||||
if macos_10_11_features.allowed()
|
||||
swift_flags += ['-D', 'HAVE_MACOS_10_11_FEATURES']
|
||||
endif
|
||||
|
||||
if macos_10_14_features.allowed()
|
||||
swift_flags += ['-D', 'HAVE_MACOS_10_14_FEATURES']
|
||||
endif
|
||||
|
||||
extra_flags = get_option('swift-flags').split()
|
||||
swift_flags += extra_flags
|
||||
|
||||
swift_compile = [swift_prog, swift_flags, '-module-name', 'macOS_swift',
|
||||
'-emit-module-path', '@OUTPUT0@', '-import-objc-header', bridge,
|
||||
'-emit-objc-header-path', '@OUTPUT1@', '-o', '@OUTPUT2@',
|
||||
'@INPUT@', '-I.', '-I' + source_root]
|
||||
|
||||
swift_targets = custom_target('swift_targets',
|
||||
input: swift_sources,
|
||||
output: ['macOS_swift.swiftmodule', 'macOS_swift.h', 'macOS_swift.o'],
|
||||
command: swift_compile,
|
||||
)
|
||||
sources += swift_targets
|
||||
|
||||
swift_lib_dir_py = find_program(join_paths(tools_directory, 'macos-swift-lib-directory.py'))
|
||||
swift_lib_dir = run_command(swift_lib_dir_py, swift_prog.full_path(), check: true).stdout()
|
||||
message('Detected Swift library directory: ' + swift_lib_dir)
|
||||
|
||||
# linker flags
|
||||
swift_link_flags = ['-L' + swift_lib_dir, '-Xlinker', '-rpath',
|
||||
'-Xlinker', swift_lib_dir, '-rdynamic', '-Xlinker',
|
||||
'-add_ast_path', '-Xlinker', module]
|
||||
if swift_ver.version_compare('>=5.0')
|
||||
swift_link_flags += ['-Xlinker', '-rpath', '-Xlinker',
|
||||
'/usr/lib/swift', '-L/usr/lib/swift']
|
||||
endif
|
||||
add_project_link_arguments(swift_link_flags, language: ['c', 'objc'])
|
||||
@@ -1,6 +0,0 @@
|
||||
defaults_js = custom_target('defaults.js',
|
||||
input: join_paths(source_root, 'player', 'javascript', 'defaults.js'),
|
||||
output: 'defaults.js.inc',
|
||||
command: [file2string, '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
sources += defaults_js
|
||||
@@ -1,10 +0,0 @@
|
||||
lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',
|
||||
'ytdl_hook.lua', 'stats.lua', 'console.lua', 'auto_profiles.lua']
|
||||
foreach file: lua_files
|
||||
lua_file = custom_target(file,
|
||||
input: join_paths(source_root, 'player', 'lua', file),
|
||||
output: file + '.inc',
|
||||
command: [file2string, '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
sources += lua_file
|
||||
endforeach
|
||||
@@ -1,6 +0,0 @@
|
||||
osd_font = custom_target('osd_font.otf',
|
||||
input: join_paths(source_root, 'sub', 'osd_font.otf'),
|
||||
output: 'osd_font.otf.inc',
|
||||
command: [file2string, '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
sources += osd_font
|
||||
@@ -1,36 +0,0 @@
|
||||
wl_protocol_dir = wayland['deps'][2].get_variable(pkgconfig: 'pkgdatadir', internal: 'pkgdatadir')
|
||||
protocols = [[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
|
||||
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml']]
|
||||
wl_protocols_source = []
|
||||
wl_protocols_headers = []
|
||||
|
||||
features += {'wayland_protocols_1_24': wayland['deps'][2].version().version_compare('>=1.24')}
|
||||
|
||||
foreach p: protocols
|
||||
xml = join_paths(p)
|
||||
wl_protocols_source += custom_target(xml.underscorify() + '_c',
|
||||
input: xml,
|
||||
output: '@BASENAME@.c',
|
||||
command: [wayland['scanner'], 'private-code', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
wl_protocols_headers += custom_target(xml.underscorify() + '_h',
|
||||
input: xml,
|
||||
output: '@BASENAME@.h',
|
||||
command: [wayland['scanner'], 'client-header', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
endforeach
|
||||
|
||||
lib_client_protocols = static_library('protocols',
|
||||
wl_protocols_source + wl_protocols_headers,
|
||||
dependencies: wayland['deps'][0])
|
||||
|
||||
client_protocols = declare_dependency(link_with: lib_client_protocols,
|
||||
sources: wl_protocols_headers)
|
||||
|
||||
dependencies += [client_protocols, wayland['deps']]
|
||||
|
||||
sources += ['video/out/wayland_common.c']
|
||||
@@ -64,18 +64,6 @@ static const struct key_name key_names[] = {
|
||||
{ MP_KEY_F+10, "F10" },
|
||||
{ MP_KEY_F+11, "F11" },
|
||||
{ MP_KEY_F+12, "F12" },
|
||||
{ MP_KEY_F+13, "F13" },
|
||||
{ MP_KEY_F+14, "F14" },
|
||||
{ MP_KEY_F+15, "F15" },
|
||||
{ MP_KEY_F+16, "F16" },
|
||||
{ MP_KEY_F+17, "F17" },
|
||||
{ MP_KEY_F+18, "F18" },
|
||||
{ MP_KEY_F+19, "F19" },
|
||||
{ MP_KEY_F+20, "F20" },
|
||||
{ MP_KEY_F+21, "F21" },
|
||||
{ MP_KEY_F+22, "F22" },
|
||||
{ MP_KEY_F+23, "F23" },
|
||||
{ MP_KEY_F+24, "F24" },
|
||||
{ MP_KEY_KP0, "KP0" },
|
||||
{ MP_KEY_KP1, "KP1" },
|
||||
{ MP_KEY_KP2, "KP2" },
|
||||
|
||||
Loaded 100 of 300 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user