Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
777295ce28 | ||
|
|
d50be0a2a6 | ||
|
|
2d8e26bb72 | ||
|
|
7ee275095f | ||
|
|
5a5b219853 | ||
|
|
608bed1aed | ||
|
|
636b62fc1a | ||
|
|
78195cd742 | ||
|
|
e7fc048eca | ||
|
|
0ab7d01425 | ||
|
|
bd0b661183 | ||
|
|
0989d8358c | ||
|
|
c979ee34e1 | ||
|
|
bb00774514 | ||
|
|
ef41a98a79 | ||
|
|
b18c2d9fe2 | ||
|
|
8f5ebdbe59 | ||
|
|
e8616fea50 | ||
|
|
00997484f1 | ||
|
|
ea556e5398 | ||
|
|
a3fc0b2015 | ||
|
|
2db094203d | ||
|
|
958858f920 | ||
|
|
bd271ae1cc | ||
|
|
c71644b595 | ||
|
|
9b18ed8d8b | ||
|
|
5dce714dfe | ||
|
|
25a0709972 | ||
|
|
6cf2f634b3 | ||
|
|
e165ccbf3b | ||
|
|
f78c0692e2 | ||
|
|
59f456cdd3 | ||
|
|
0e35c230f4 | ||
|
|
9ae80929ea | ||
|
|
98d1358e6e | ||
|
|
e71d68cdae | ||
|
|
950ef5b75b | ||
|
|
0075f8e0cf | ||
|
|
49275b2879 |
No files matched your search
@@ -1,23 +0,0 @@
|
||||
### mpv version and platform
|
||||
|
||||
If you're not using git master or the latest release, update.
|
||||
|
||||
### Reproduction steps
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Log file
|
||||
|
||||
Make a log file made with -v or --log-file=output.txt, paste it to
|
||||
http://sprunge.us or a similar site, and replace this text with a link to it.
|
||||
|
||||
Providing a log file is strongly encouraged. It is very helpful for reproducing
|
||||
bugs or getting important technical context. Without a log it might not be
|
||||
possible to analyze and fix certain bugs.
|
||||
|
||||
### Sample files
|
||||
|
||||
Sample files needed to reproduce this issue can be uploaded to https://0x0.st/
|
||||
or similar sites. (Only needed if the issue cannot be reproduced without it.)
|
||||
@@ -1,7 +0,0 @@
|
||||
Ideally, you shouldn't need enter any text here, and your commit messages should
|
||||
explain your changes sufficiently (especially why they are needed). Read
|
||||
https://github.com/mpv-player/mpv/blob/master/DOCS/contribute.md for coding
|
||||
style and development conventions. Remove this text block, but if you haven't
|
||||
agreed to it before, leave the following sentence in place:
|
||||
|
||||
I agree that my changes can be relicensed to LGPL 2.1 or later.
|
||||
+7
-9
@@ -14,22 +14,20 @@
|
||||
/input/input_conf.h
|
||||
/tags
|
||||
/TAGS
|
||||
/video/out/gl_video_shaders.h
|
||||
/video/out/x11_icon.inc
|
||||
/demux/ebml_defs.c
|
||||
/demux/ebml_types.h
|
||||
/sub/osd_font.h
|
||||
/player/lua/*.inc
|
||||
/player/builtin_conf.inc
|
||||
/DOCS/man/mpv.1
|
||||
/DOCS/man/mpv.aux
|
||||
/DOCS/man/mpv.log
|
||||
/DOCS/man/mpv.out
|
||||
/DOCS/man/mpv.pdf
|
||||
/DOCS/man/mpv.toc
|
||||
/DOCS/man/*/mpv.1
|
||||
/DOCS/man/*/mpv.aux
|
||||
/DOCS/man/*/mpv.log
|
||||
/DOCS/man/*/mpv.out
|
||||
/DOCS/man/*/mpv.pdf
|
||||
/DOCS/man/*/mpv.toc
|
||||
|
||||
/waf
|
||||
/waf-*
|
||||
/waf3-*
|
||||
/build
|
||||
/.waf*
|
||||
/.lock-waf_*
|
||||
|
||||
+11
-46
@@ -1,65 +1,30 @@
|
||||
language: c
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
env:
|
||||
matrix:
|
||||
- LIBAV=libav-stable
|
||||
- LIBAV=libav-git
|
||||
- LIBAV=ffmpeg-stable
|
||||
- LIBAV=ffmpeg-git
|
||||
global:
|
||||
# Coverity token
|
||||
- secure: "H21mSRlMhk4BKS0xHZvCFGJxteCP0hRVUxTuNfM2Z9HBsyutuLEYMtViLO86VtM+Tqla3xXPzUdS4ozLwI72Ax/5ZUDXACROj73yW6QhFB5D6rLut12+FjqC7M33Qv2hl0xwgNBmR5dsm1ToP37+Wn+ecJQNvN8fkTXF+HVzOEw="
|
||||
# Travis token for mpv.io
|
||||
- secure: "nlTVLJK6kRhtXvhKCoJ3YdFGHuKaq/eHowfPw25hqRWuBOZd+HjHY5KIYjV7SxuKFDpJE4GpNcvA3Q31nsqomxpkLYgrwjg6TSazN7ZP+x85ZgV1QGFebrPfGm2n5UR5CAPAwFoeF3pZheLi4bajVzwq1fWW+x3grS188P9OZso="
|
||||
- LIBAV=libav-stable
|
||||
- LIBAV=libav-git
|
||||
- LIBAV=ffmpeg-stable
|
||||
- LIBAV=ffmpeg-git
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- ci
|
||||
- coverity_scan
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: LIBAV=libav-stable
|
||||
- os: osx
|
||||
env: LIBAV=libav-git
|
||||
- os: osx
|
||||
env: LIBAV=ffmpeg-git
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
env: LIBAV=ffmpeg-stable
|
||||
- os: linux
|
||||
compiler: clang
|
||||
|
||||
before_install: TOOLS/travis-deps libass-stable $LIBAV
|
||||
before_install: ./travis-deps libass-stable $LIBAV
|
||||
script:
|
||||
- ./bootstrap.py
|
||||
- ./waf configure
|
||||
- ./waf build
|
||||
after_script: TOOLS/travis-rebuild-website
|
||||
|
||||
notifications-policy: ¬ifications-policy
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#mpv-devel"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "mpv-player/mpv"
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: mpv-team@googlegroups.com
|
||||
build_command_prepend: "./bootstrap.py && ./waf configure"
|
||||
build_command: "./waf build"
|
||||
branch_pattern: coverity_scan
|
||||
- "irc.freenode.org#mpv-player-dev"
|
||||
<<: *notifications-policy
|
||||
@@ -2,15 +2,9 @@ mpv is a fork of mplayer2, which is a fork of MPlayer.
|
||||
|
||||
mpv as a whole is licensed as GPL version 2 or later (see LICENSE). Most source
|
||||
files are GPLv2+, but some files are available under a more liberal license,
|
||||
such as LGPLv2.1+, BSD, MIT, ISC, and possibly others. Look at the copyright
|
||||
such as LGPLv2+, BSD, MIT, ISC, and possibly others. Look at the copyright
|
||||
header of each source file, and grep the sources for "Copyright" if you need
|
||||
to know details. Files without Copyright notice are licensed as LGPLv2.1+.
|
||||
|
||||
All new contributions must be LGPLv2.1+ licensed, or if the changes are done on
|
||||
GPL code, must come with the implicit agreement that the project can relicense
|
||||
the code to LGPLv2.1+ at a later point without asking the contributor. (This
|
||||
is a safeguard for making potential relicensing of the project to LGPLv2.1+
|
||||
easier.) Using a more liberal license compatible to LGPLv2.1+ is also ok.
|
||||
to know details. Files without Copyright notice are licensed as LGPLv2+.
|
||||
|
||||
For information about authors and contributors, consult the git log, which
|
||||
contains the complete SVN and CVS history as well.
|
||||
@@ -23,5 +17,3 @@ MPlayer as a whole is licensed under GPLv2 (incompatible to GPLv3!), because
|
||||
some files are licensed to GPLv2 (and _not_ any later version of the license).
|
||||
In particular, this affects the file libmpdemux/demux_ty_osd.c. It is disabled
|
||||
under mplayer2, and has been removed from mpv.
|
||||
|
||||
"v2.1+" in this context means "version 2.1 or later".
|
||||
@@ -1,160 +0,0 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
This file lists all changes that can cause compatibility issues when using
|
||||
mpv through the client API (libmpv and ``client.h``). Since the client API
|
||||
interfaces to input handling (commands, properties) as well as command line
|
||||
options, you should also look at ``interface-changes.rst``.
|
||||
|
||||
Normally, changes to the C API that are incompatible to previous iterations
|
||||
receive a major version bump (i.e. the first version number is increased),
|
||||
while C API additions bump the minor version (i.e. the second number is
|
||||
increased). Changes to properties/commands/options may also lead to a minor
|
||||
version bump, in particular if they are incompatible.
|
||||
|
||||
The version number is the same as used for MPV_CLIENT_API_VERSION (see
|
||||
``client.h`` how to convert between major/minor version numbers and the flat
|
||||
32 bit integer).
|
||||
|
||||
Also, read the section ``Compatibility`` in ``client.h``.
|
||||
|
||||
Options, commands, properties
|
||||
=============================
|
||||
|
||||
Changes to these are not listed here, but in ``interface-changes.rst``. (Before
|
||||
client API version 1.17, they were listed here partially.)
|
||||
|
||||
This listing includes changes to the bare C API and behavior only, not what
|
||||
you can access with them.
|
||||
|
||||
API changes
|
||||
===========
|
||||
|
||||
::
|
||||
|
||||
--- mpv 0.21.0 ---
|
||||
1.23 - deprecate setting "no-" options via mpv_set_option*(). For example,
|
||||
instead of "no-video=" you should set "video=no".
|
||||
- do not override the SIGPIPE signal handler anymore. This was done as
|
||||
workaround for the FFmpeg TLS code, which has been fixed long ago.
|
||||
- deprecate mpv_suspend() and mpv_resume(). They will be stubbed out
|
||||
in mpv 0.22.0.
|
||||
- make mpv_set_property() work to some degree before mpv_initialize().
|
||||
It can now be used instead of mpv_set_option().
|
||||
- semi-deprecate mpv_set_option()/mpv_set_option_string(). You should
|
||||
use mpv_set_property() instead. There are some deprecated properties
|
||||
which conflict with some options (see client.h remarks on
|
||||
mpv_set_option()), for which mpv_set_option() might still be required.
|
||||
In future mpv releases, the conflicting deprecated options/properties
|
||||
will be removed, and mpv_set_option() will internally translate API
|
||||
calls to mpv_set_property().
|
||||
- qthelper.hpp: deprecate get_property_variant, set_property_variant,
|
||||
mpv_set_option, command_variant, and replace them with get_property,
|
||||
set_property, command.
|
||||
--- mpv 0.19.0 ---
|
||||
1.22 - add stream_cb API for custom protocols
|
||||
--- mpv 0.18.1 ---
|
||||
---- - remove "status" log level from mpv_request_log_messages() docs. This
|
||||
is 100% equivalent to "v". The behavior is still the same, thus no
|
||||
actual API change.
|
||||
--- mpv 0.18.0 ---
|
||||
1.21 - mpv_set_property() changes behavior with MPV_FORMAT_NODE. Before this
|
||||
change it rejected mpv_nodes with format==MPV_FORMAT_STRING if the
|
||||
property was not a string or did not have special mechanisms in place
|
||||
the function failed. Now it always invokes the option string parser,
|
||||
and mpv_node with a basic data type works exactly as if the function
|
||||
is invoked with that type directly. This new behavior is equivalent
|
||||
to mpv_set_option().
|
||||
This also affects the mp.set_property_native() Lua function.
|
||||
- generally, setting choice options/properties with "yes"/"no" options
|
||||
can now be set as MPV_FORMAT_FLAG
|
||||
- reading a choice property as MPV_FORMAT_NODE will now return a
|
||||
MPV_FORMAT_FLAG value if the choice is "yes" (true) or "no" (false)
|
||||
This implicitly affects Lua and JSON IPC interfaces as well.
|
||||
- big changes to vo-cmdline on vo_opengl and vo_opengl_hq (but not
|
||||
vo_opengl_cb): options are now normally not reset, but applied on top
|
||||
of the current options. The special undocumented value "-" still
|
||||
works, but now resets all options to before any vo-cmdline command
|
||||
has been called.
|
||||
--- mpv 0.12.0 ---
|
||||
1.20 - deprecate "GL_MP_D3D_interfaces"/"glMPGetD3DInterface", and introduce
|
||||
"GL_MP_MPGetNativeDisplay"/"glMPGetNativeDisplay" (this is a
|
||||
backwards-compatible rename)
|
||||
--- mpv 0.11.0 ---
|
||||
--- mpv 0.10.0 ---
|
||||
1.19 - add "GL_MP_D3D_interfaces" pseudo extension to make it possible to
|
||||
use DXVA2 in OpenGL fullscreen mode in some situations
|
||||
- mpv_request_log_messages() now accepts "terminal-default" as parameter
|
||||
1.18 - add MPV_END_FILE_REASON_REDIRECT, and change behavior of
|
||||
MPV_EVENT_END_FILE accordingly
|
||||
- a bunch of interface-changes.rst changes
|
||||
1.17 - mpv_initialize() now blocks SIGPIPE (details see client.h)
|
||||
--- mpv 0.9.0 ---
|
||||
1.16 - add mpv_opengl_cb_report_flip()
|
||||
- introduce mpv_opengl_cb_draw() and deprecate mpv_opengl_cb_render()
|
||||
- add MPV_FORMAT_BYTE_ARRAY
|
||||
1.15 - mpv_initialize() will now load config files. This requires setting
|
||||
the "config" and "config-dir" options. In particular, it will load
|
||||
mpv.conf.
|
||||
- minor backwards-compatible change to the "seek" and "screenshot"
|
||||
commands (new flag syntax, old additional args deprecated)
|
||||
--- mpv 0.8.0 ---
|
||||
1.14 - add mpv_wait_async_requests()
|
||||
- the --msg-level option changes its native type from a flat string to
|
||||
a key-value list (setting/reading the option as string still works)
|
||||
1.13 - add MPV_EVENT_QUEUE_OVERFLOW
|
||||
1.12 - add class Handle to qthelper.hpp
|
||||
- improve opengl_cb.h API uninitialization behavior, and fix the qml
|
||||
example
|
||||
- add mpv_create_client() function
|
||||
1.11 - add OpenGL rendering interop API - allows an application to combine
|
||||
its own and mpv's OpenGL rendering
|
||||
Warning: this API is not stable yet - anything in opengl_cb.h might
|
||||
be changed in completely incompatible ways in minor API bumps
|
||||
--- mpv 0.7.0 ---
|
||||
1.10 - deprecate/disable everything directly related to script_dispatch
|
||||
(most likely affects nobody)
|
||||
1.9 - add enum mpv_end_file_reason for mpv_event_end_file.reason
|
||||
- add MPV_END_FILE_REASON_ERROR and the mpv_event_end_file.error field
|
||||
for slightly better error reporting on playback failure
|
||||
- add --stop-playback-on-init-failure option, and make it the default
|
||||
behavior for libmpv only
|
||||
- add qthelper.hpp set_option_variant()
|
||||
- mark the following events as deprecated:
|
||||
MPV_EVENT_TRACKS_CHANGED
|
||||
MPV_EVENT_TRACK_SWITCHED
|
||||
MPV_EVENT_PAUSE
|
||||
MPV_EVENT_UNPAUSE
|
||||
MPV_EVENT_METADATA_UPDATE
|
||||
MPV_EVENT_CHAPTER_CHANGE
|
||||
They are handled better with mpv_observe_property() as mentioned in
|
||||
the documentation comments. They are not removed and still work.
|
||||
1.8 - add qthelper.hpp
|
||||
1.7 - add mpv_command_node(), mpv_command_node_async()
|
||||
1.6 - modify "core-idle" property behavior
|
||||
- MPV_EVENT_LOG_MESSAGE now always sends complete lines
|
||||
- introduce numeric log levels (mpv_log_level)
|
||||
--- mpv 0.6.0 ---
|
||||
1.5 - change in X11 and "--wid" behavior again. The previous change didn't
|
||||
work as expected, and now the behavior can be explicitly controlled
|
||||
with the "input-x11-keyboard" option. This is only a temporary
|
||||
measure until XEmbed is implemented and confirmed working.
|
||||
Note: in 1.6, "input-x11-keyboard" was renamed to "input-vo-keyboard",
|
||||
although the old option name still works.
|
||||
1.4 - subtle change in X11 and "--wid" behavior
|
||||
(this change was added to 0.5.2, and broke some things, see #1090)
|
||||
--- mpv 0.5.0 ---
|
||||
1.3 - add MPV_MAKE_VERSION()
|
||||
1.2 - remove "stream-time-pos" property (no replacement)
|
||||
1.1 - remap dvdnav:// to dvd://
|
||||
- add "--cache-file", "--cache-file-size"
|
||||
- add "--colormatrix-primaries" (and property)
|
||||
- add "primaries" sub-field to image format properties
|
||||
- add "playback-time" property
|
||||
- extend the "--start" option; a leading "+", which was previously
|
||||
insignificant is now significant
|
||||
- add "cache-free" and "cache-used" properties
|
||||
- OSX: the "coreaudio" AO spdif code is split into a separate AO
|
||||
--- mpv 0.4.0 ---
|
||||
1.0 - the API is declared stable
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static inline void check_error(int status)
|
||||
{
|
||||
if (status < 0) {
|
||||
printf("mpv API error: %s\n", mpv_error_string(status));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libmpv/client.h"
|
||||
#include "shared.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
printf("pass a single media file as argument\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mpv_handle *ctx = mpv_create();
|
||||
if (!ctx) {
|
||||
printf("failed creating context\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Enable default key bindings, so the user can actually interact with
|
||||
// the player (and e.g. close the window).
|
||||
check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes"));
|
||||
int val = 1;
|
||||
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
|
||||
|
||||
// Done setting up options.
|
||||
check_error(mpv_initialize(ctx));
|
||||
|
||||
// Play this file.
|
||||
const char *cmd[] = {"loadfile", argv[1], NULL};
|
||||
check_error(mpv_command(ctx, cmd));
|
||||
|
||||
// Let it play, and wait until the user quits.
|
||||
while (1) {
|
||||
mpv_event *event = mpv_wait_event(ctx, 10000);
|
||||
printf("event: %s\n", mpv_event_name(event->event_id));
|
||||
if (event->event_id == MPV_EVENT_SHUTDOWN)
|
||||
break;
|
||||
}
|
||||
|
||||
mpv_terminate_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
Compiling for Windows
|
||||
=====================
|
||||
|
||||
Compiling for Windows is supported with MinGW-w64. This can be used to produce
|
||||
both 32-bit and 64-bit executables, and it works for building on Windows and
|
||||
cross-compiling from Linux and Cygwin. MinGW-w64 is available from:
|
||||
http://mingw-w64.sourceforge.net.
|
||||
|
||||
While building a complete MinGW-w64 toolchain yourself is possible, there are a
|
||||
few build environments and scripts to help ease the process, such as MSYS2 and
|
||||
MXE. Note that MinGW environments included in Linux distributions are often
|
||||
broken, outdated and useless, and usually don't use MinGW-w64.
|
||||
|
||||
**Warning**: the original MinGW (http://www.mingw.org) is unsupported.
|
||||
|
||||
Cross-compilation
|
||||
=================
|
||||
|
||||
When cross-compiling, you have to run mpv's configure with these arguments:
|
||||
|
||||
```bash
|
||||
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
|
||||
```
|
||||
|
||||
[MXE](http://mxe.cc) makes it very easy to bootstrap a complete MingGW-w64
|
||||
environment from a Linux machine. See a working example below.
|
||||
|
||||
Alternatively, you can try [mingw-w64-cmake](https://github.com/lachs0r/mingw-w64-cmake),
|
||||
which bootstraps a MinGW-w64 environment and builds mpv and dependencies.
|
||||
|
||||
Example with MXE
|
||||
----------------
|
||||
|
||||
```bash
|
||||
# Before starting, make sure you install MXE prerequisites. MXE will download
|
||||
# and build all target dependencies, but no host dependencies. For example,
|
||||
# you need a working compiler, or MXE can't build the crosscompiler.
|
||||
#
|
||||
# Refer to
|
||||
#
|
||||
# http://mxe.cc/#requirements
|
||||
#
|
||||
# Scroll down for disto/OS-specific instructions to install them.
|
||||
|
||||
# Download MXE. Note that compiling the required packages requires about 1.4 GB
|
||||
# or more!
|
||||
|
||||
cd /opt
|
||||
git clone https://github.com/mxe/mxe mxe
|
||||
cd mxe
|
||||
|
||||
# Set build options.
|
||||
|
||||
# The JOBS environment variable controls threads to use when building. DO NOT
|
||||
# use the regular `make -j4` option with MXE as it will slow down the build.
|
||||
# Alternatively, you can set this in the make command by appending "JOBS=4"
|
||||
# to the end of command:
|
||||
echo "JOBS := 4" >> settings.mk
|
||||
|
||||
# The MXE_TARGET environment variable builds MinGW-w64 for 32 bit targets.
|
||||
# Alternatively, you can specify this in the make command by appending
|
||||
# "MXE_TARGETS=i686-w64-mingw32" to the end of command:
|
||||
echo "MXE_TARGETS := i686-w64-mingw32.static" >> settings.mk
|
||||
|
||||
# If you want to build 64 bit version, use this:
|
||||
# echo "MXE_TARGETS := x86_64-w64-mingw32.static" >> settings.mk
|
||||
|
||||
# Build required packages. The following provide a minimum required to build
|
||||
# a reasonable mpv binary (though not an absolute minimum).
|
||||
|
||||
make gcc ffmpeg libass jpeg lua
|
||||
|
||||
# Add MXE binaries to $PATH
|
||||
export PATH=/opt/mxe/usr/bin/:$PATH
|
||||
|
||||
# Build mpv. The target will be used to automatically select the name of the
|
||||
# build tools involved (e.g. it will use i686-w64-mingw32.static-gcc).
|
||||
|
||||
cd ..
|
||||
git clone https://github.com/mpv-player/mpv.git
|
||||
cd mpv
|
||||
python ./bootstrap.py
|
||||
DEST_OS=win32 TARGET=i686-w64-mingw32.static ./waf configure
|
||||
# Or, if 64 bit version,
|
||||
# DEST_OS=win32 TARGET=x86_64-w64-mingw32.static ./waf configure
|
||||
./waf build
|
||||
```
|
||||
|
||||
Native compilation with MSYS2
|
||||
=============================
|
||||
|
||||
For Windows developers looking to get started quickly, MSYS2 can be used to
|
||||
compile mpv natively on a Windows machine. The MSYS2 repositories have binary
|
||||
packages for most of mpv's dependencies, so the process should only involve
|
||||
building mpv itself.
|
||||
|
||||
To build 64-bit mpv on Windows:
|
||||
|
||||
Installing MSYS2
|
||||
----------------
|
||||
|
||||
1. Download an installer from https://msys2.github.io/
|
||||
|
||||
It doesn't matter whether the i686 or the x86_64 version is used. Both can
|
||||
build 32-bit and 64-bit binaries when running on a 64-bit version of Windows.
|
||||
|
||||
2. Start a MinGW-w64 shell (``mingw64.exe``). Note that this is different
|
||||
from the MSYS2 shell that is started from the final installation dialog.
|
||||
|
||||
For a 32-bit build, use ``mingw32.exe``.
|
||||
|
||||
Updating MSYS2
|
||||
--------------
|
||||
|
||||
To prevent errors during post-install, the MSYS2 core runtime must be updated
|
||||
separately.
|
||||
|
||||
```bash
|
||||
# Check for core updates. If instructed, close the shell window and reopen it
|
||||
# before continuing.
|
||||
pacman -Syu
|
||||
|
||||
# Update everything else
|
||||
pacman -Su
|
||||
```
|
||||
|
||||
Installing mpv dependencies
|
||||
---------------------------
|
||||
|
||||
```bash
|
||||
# Install MSYS2 build dependencies and a MinGW-w64 compiler
|
||||
pacman -S git mingw-w64-x86_64-pkg-config python mingw-w64-x86_64-gcc
|
||||
|
||||
# Install the most important MinGW-w64 dependencies. libass, libbluray and
|
||||
# lcms2 are also pulled in as dependencies of ffmpeg.
|
||||
pacman -S mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-lua51
|
||||
|
||||
# Install additional (optional) dependencies
|
||||
pacman -S mingw-w64-x86_64-libdvdnav mingw-w64-x86_64-libguess mingw-w64-x86_64-angleproject-git
|
||||
```
|
||||
|
||||
For a 32-bit build, install ``mingw-w64-i686-*`` packages instead.
|
||||
|
||||
Building mpv
|
||||
------------
|
||||
|
||||
Clone the latest mpv from git and install waf:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mpv-player/mpv.git && cd mpv
|
||||
./bootstrap.py
|
||||
```
|
||||
|
||||
Finally, compile and install mpv. Binaries will be installed to
|
||||
``/mingw64/bin``.
|
||||
|
||||
```bash
|
||||
# For a 32-bit build, use --prefix=/mingw32 instead
|
||||
./waf configure CC=gcc.exe --check-c-compiler=gcc --prefix=/mingw64
|
||||
./waf install
|
||||
```
|
||||
|
||||
Or, compile and install both libmpv and mpv:
|
||||
|
||||
```bash
|
||||
./waf configure CC=gcc.exe --check-c-compiler=gcc --enable-libmpv-shared --prefix=/mingw64
|
||||
./waf install
|
||||
|
||||
# waf installs libmpv to the wrong directory, so fix it up
|
||||
mv -f /mingw64/bin/pkgconfig/mpv.pc /mingw64/lib/pkgconfig/
|
||||
mv -f /mingw64/bin/libmpv.dll.a /mingw64/lib/
|
||||
sed -i 's_/mingw64/bin_/mingw64/lib_' /mingw64/lib/pkgconfig/mpv.pc
|
||||
rmdir /mingw64/bin/pkgconfig
|
||||
```
|
||||
|
||||
Linking libmpv with MSVC programs
|
||||
---------------------------------
|
||||
|
||||
You can build C++ programs in Visual Studio and link them with libmpv. To do
|
||||
this, you need a Visual Studio which supports ``stdint.h`` (recent ones do),
|
||||
and you need to create a import library for the mpv DLL:
|
||||
|
||||
```bash
|
||||
lib /def:mpv.def /name:mpv-1.dll /out:mpv.lib /MACHINE:X64
|
||||
```
|
||||
|
||||
The string in the ``/name:`` parameter must match the filename of the DLL (this
|
||||
is simply the filename the MSVC linker will use). The ``mpv.def`` can be
|
||||
retrieved from the mpv build directory, or can be produced by MingGW's
|
||||
gendef.exe helper from the mpv DLL.
|
||||
|
||||
Static linking is not possible.
|
||||
|
||||
Running mpv
|
||||
-----------
|
||||
|
||||
If you want to run mpv from the MinGW-w64 shell, you will find the experience
|
||||
much more pleasant if you use the ``winpty`` utility
|
||||
|
||||
```bash
|
||||
pacman -S winpty
|
||||
winpty mpv.com ToS-4k-1920.mov
|
||||
```
|
||||
|
||||
If you want to move / copy ``mpv.exe`` and ``mpv.com`` to somewhere other than
|
||||
``/mingw64/bin/`` for use outside the MinGW-w64 shell, they will still depend on
|
||||
DLLs in that folder. The simplest solution is to add ``C:\msys64\mingw64\bin``
|
||||
to the windows system ``%PATH%``. Beware though that this can cause problems or
|
||||
confusion in Cygwin if that is also installed on the machine.
|
||||
|
||||
Use of the ANGLE OpenGL backend requires a copy of ``d3dcompiler_43.dll`` (yes,
|
||||
exactly 43) in the path or in the same folder as mpv. It must be of the same
|
||||
architecture (x86_64 / i686) as the mpv you compiled. You can find a copy in the
|
||||
official mpv builds:
|
||||
|
||||
https://mpv.srsfckn.biz/mpv-x86_64-20160118.7z
|
||||
|
||||
https://mpv.srsfckn.biz/mpv-i686-20160118.7z
|
||||
+5
-15
@@ -4,8 +4,8 @@ How to contribute
|
||||
General
|
||||
-------
|
||||
|
||||
The main contact for mpv development is IRC, specifically #mpv
|
||||
and #mpv-devel on Freenode.
|
||||
The main contact for mpv development is IRC, specifically #mpv-player and
|
||||
#mpv-player-dev on Freenode.
|
||||
|
||||
Sending patches
|
||||
---------------
|
||||
@@ -14,11 +14,6 @@ Sending patches
|
||||
``git format-patch``. diffs posted as pastebins (especially if the http link
|
||||
returns HTML) just cause extra work for everyone, because they lack commit
|
||||
message and authorship information.
|
||||
- All new code must be LGPLv2.1+ licensed, or come with the implicit agreement
|
||||
that it will be relicensed to LGPLv2.1+ later (see ``Copyright`` in the
|
||||
repository root directory).
|
||||
- When creating pull requests, be sure to test your changes. If you didn't,
|
||||
please say so in the pull request message.
|
||||
- Write informative commit messages. Use present tense to describe the
|
||||
situation with the patch applied, and past tense for the situation before
|
||||
the change.
|
||||
@@ -29,8 +24,8 @@ Sending patches
|
||||
|
||||
For example, you fixed a crash in af_volume.c:
|
||||
|
||||
- Bad: ``fixed the bug (wtf?)``
|
||||
- Good: ``af_volume: fix crash due to null pointer access``
|
||||
Bad: ``fixed the bug (wtf?)``
|
||||
Good: ``af_volume: fix crash due to null pointer access``
|
||||
|
||||
Having a prefix gives context, and is especially useful when trying to find
|
||||
a specific change by looking at the history, or when running ``git blame``.
|
||||
@@ -55,10 +50,7 @@ Sending patches
|
||||
something like reformatting a whole file, and hiding an actual functional
|
||||
change in the same commit.
|
||||
- If you add a new command line option, document it in options.rst. If you
|
||||
add a new input property, document it in input.rst. Changes to the user
|
||||
interface (options, properties, commands) should be documented in
|
||||
interface-changes.rst. Changes to libmpv should be documented in
|
||||
client-api-changes.rst.
|
||||
add a new input property, document it in input.rst.
|
||||
|
||||
Code formatting
|
||||
---------------
|
||||
@@ -126,8 +118,6 @@ mpv uses C99 with K&R formatting, with some exceptions.
|
||||
very_long_condition_b)
|
||||
{
|
||||
code();
|
||||
} else {
|
||||
...
|
||||
}
|
||||
```
|
||||
- Remove any trailing whitespace.
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
Cross Compiling to Windows
|
||||
==========================
|
||||
|
||||
Cross compiling mpv to Windows is supported with MinGW-w64. This can be used to
|
||||
produce both 32 bit and 64 bit executables. MinGW-w64 is available from
|
||||
http://mingw-w64.sourceforge.net.
|
||||
|
||||
You have to run mpv's configure with these arguments:
|
||||
|
||||
```bash
|
||||
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
|
||||
```
|
||||
|
||||
While building a complete MinGW-w64 toolchain yourself is possible, people have
|
||||
created scripts to help ease the process. These are the two recommended methods:
|
||||
|
||||
- Using [mingw-w64-cmake](https://github.com/lachs0r/mingw-w64-cmake) to setup
|
||||
a MinGW-w64 environment. We recommend you to try this first before MXE.
|
||||
mingw-w64-cmake will also build mpv and its dependencies.
|
||||
- Alternatively, you can use MXE: http://mxe.cc. With MXE, you have to manually
|
||||
set the target to MinGW-w64 (even if you compile to 32 bit). A working example
|
||||
below.
|
||||
|
||||
**Warning**: the original MinGW (http://www.mingw.org) is unsupported.
|
||||
|
||||
Note that MinGW environments included in Linux distributions are often broken,
|
||||
outdated and useless, and usually don't use MinGW-w64.
|
||||
|
||||
Example with MXE
|
||||
----------------
|
||||
|
||||
```bash
|
||||
# Download MXE. Note that compiling the required packages requires about 1.4 GB
|
||||
# or more!
|
||||
|
||||
cd /opt
|
||||
git clone https://github.com/mxe/mxe mingw
|
||||
cd mingw
|
||||
|
||||
# Set build options.
|
||||
|
||||
# The JOBS environment variable controls threads to use when building. DO NOT
|
||||
# use the regular `make -j4` option with MXE as it will slow down the build.
|
||||
# Alternatively, you can set this in the make command by appending "JOBS=4"
|
||||
# to the end of command:
|
||||
echo "JOBS := 4" >> settings.mk
|
||||
|
||||
# The MXE_TARGET environment variable builds MinGW-w64 for 32 bit targets.
|
||||
# Alternatively, you can specify this in the make command by appending
|
||||
# "MXE_TARGETS=i686-w64-mingw32" to the end of command:
|
||||
echo "MXE_TARGETS := i686-w64-mingw32" >> settings.mk
|
||||
|
||||
# If you want to build 64 bit version, use this:
|
||||
# echo "MXE_TARGETS := x86_64-w64-mingw32" >> settings.mk
|
||||
|
||||
# Build required packages. The following provide a minimum required to build
|
||||
# mpv.
|
||||
|
||||
make gcc ffmpeg libass jpeg pthreads
|
||||
|
||||
# Add MXE binaries to $PATH
|
||||
export PATH=/opt/mingw/usr/bin/:$PATH
|
||||
|
||||
# Build mpv. The target will be used to automatically select the name of the
|
||||
# build tools involved (e.g. it will use i686-w64-mingw32-gcc).
|
||||
|
||||
cd ..
|
||||
git clone https://github.com/mpv-player/mpv.git
|
||||
cd mpv
|
||||
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
|
||||
# Or, if 64 bit version,
|
||||
# DEST_OS=win32 TARGET=x86_64-w64-mingw32 ./waf configure
|
||||
./waf build
|
||||
```
|
||||
+4
-3
@@ -27,12 +27,13 @@ The general simplified syntax is::
|
||||
<filename>,<start in seconds>,<length in seconds>
|
||||
|
||||
If the start time is omitted, 0 is used. If the length is omitted, the
|
||||
estimated remaining duration of the source file is used.
|
||||
estimated duration of the source file is used.
|
||||
|
||||
Note::
|
||||
|
||||
Usage of relative or absolute paths as well as any protocol prefixes may be
|
||||
prevented for security reasons.
|
||||
mpv can't use ordered chapter files or libquvi-resolved URLs in EDL
|
||||
entries. Usage of relative or absolute paths as well as any protocol
|
||||
prefixes is prevented for security reasons.
|
||||
|
||||
|
||||
Syntax of mpv EDL files
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ from the input video. Note that not all codecs and not all formats support VFR
|
||||
encoding, and some which do have bugs when a target bitrate is specified - use
|
||||
-ofps or -oautofps to force CFR encoding in these cases.
|
||||
|
||||
Of course, the options can be stored in a profile, like this .config/mpv/mpv.conf
|
||||
Of course, the options can be stored in a profile, like this .mpv/config
|
||||
section::
|
||||
|
||||
[myencprofile]
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
mpv provides access to its internals via the following means:
|
||||
|
||||
- options
|
||||
- commands
|
||||
- properties
|
||||
- events
|
||||
|
||||
All of these are important for interfacing both with end users and API users
|
||||
(which include Lua scripts, libmpv, and the JSON IPC). As such, they constitute
|
||||
a large part of the user interface and APIs.
|
||||
|
||||
This document lists changes to them. New changes are added to the top.
|
||||
|
||||
Interface changes
|
||||
=================
|
||||
|
||||
::
|
||||
|
||||
--- mpv 0.21.0 ---
|
||||
- setting certain options at runtime will now take care of updating them
|
||||
property (see for example issue #3281). On the other hand, it will also
|
||||
do runtime verification and reject option changes that do not work
|
||||
(example: setting the "vf" option to a filter during playback, which fails
|
||||
to initialize - the option value will remain at its old value). In general,
|
||||
"set name value" should be mostly equivalent to "set options/name value"
|
||||
in cases where the "name" property is not deprecated and "options/name"
|
||||
exists - deviations from this are either bugs, or documented as caveats
|
||||
in the "Inconsistencies between options and properties" manpage section.
|
||||
- deprecate _all_ --vo and --ao suboptions. Generally, all suboptions are
|
||||
replaced by global options, which do exactly the same. For example,
|
||||
"--vo=opengl:scale=nearest" turns into "--scale=nearest". In some cases,
|
||||
the global option is prefixed, e.g. "--vo=opengl:pbo" turns into
|
||||
"--opengl-pbo".
|
||||
Most of the exact replacements are documented here:
|
||||
https://github.com/mpv-player/mpv/wiki/Option-replacement-list
|
||||
- remove --vo=opengl-hq. Set --profile=opengl-hq instead. Note that this
|
||||
profile does not force the VO. This means if you use the --vo option to
|
||||
set another VO, it won't work. But this also means it can be used with
|
||||
opengl-cb.
|
||||
- remove the --vo=opengl "pre-shaders", "post-shaders" and "scale-shader"
|
||||
sub-options: they were deprecated in favor of "user-shaders"
|
||||
- deprecate --vo-defaults (no replacement)
|
||||
- remove the vo-cmdline command. You can set OpenGL renderer options
|
||||
directly via properties instead.
|
||||
- deprecate the device/sink options on all AOs. Use --audio-device instead.
|
||||
- deprecate "--ao=wasapi:exclusive" and "--ao=coreaudio:exclusive",
|
||||
use --audio-exclusive instead.
|
||||
- subtle changes in how "--no-..." options are treated mean that they are
|
||||
not accessible under "options/..." anymore (instead, these are resolved
|
||||
at parsing time). This does not affect options which start with "--no-",
|
||||
but do not use the mechanism for negation options.
|
||||
(Also see client API change for API version 1.23.)
|
||||
- rename the following properties
|
||||
- "demuxer" -> "current-demuxer"
|
||||
- "fps" -> "container-fps"
|
||||
- "idle" -> "idle-active"
|
||||
- "cache" -> "cache-percent"
|
||||
the old names are deprecated and will change behavior in mpv 0.22.0.
|
||||
- remove deprecated "hwdec-active" and "hwdec-detected" properties
|
||||
- deprecate the ao and vo auto-profiles (they never made any sense)
|
||||
- deprecate "--vo=direct3d_shaders" - use "--vo=direct3d" instead.
|
||||
Change "--vo=direct3d" to always use shaders by default.
|
||||
- deprecate --playlist-pos option, renamed to --playlist-start
|
||||
- deprecate the --chapter option, as it is redundant with --start/--end,
|
||||
and conflicts with the semantics of the "chapter" property
|
||||
- rename --sub-text-* to --sub-* and --ass-* to --sub-ass-* (old options
|
||||
deprecated)
|
||||
- incompatible change to cdda:// protocol options: the part after cdda://
|
||||
now always sets the device, not the span or speed to be played. No
|
||||
separating extra "/" is needed. The hidden --cdda-device options is also
|
||||
deleted (it was redundant with the documented --cdrom-device).
|
||||
- deprecate --vo=rpi. It will be removed in mpv 0.22.0. Its functionality
|
||||
was folded into --vo=opengl, which now uses RPI hardware decoding by
|
||||
treating it as a hardware overlay (without applying GL filtering). Also
|
||||
to be changed in 0.22.0: the --fs flag will be reset to "no" by default
|
||||
(like on the other platforms).
|
||||
- deprecate --mute=auto (informally has been since 0.18.1)
|
||||
- deprecate "resume" and "suspend" IPC commands. They will be completely
|
||||
removed in 0.22.0.
|
||||
- deprecate mp.suspend(), mp.resume(), mp.resume_all() Lua scripting
|
||||
commands, as well as setting mp.use_suspend. They will be completely
|
||||
removed in 0.22.0.
|
||||
- the "seek" command's absolute seek mode will now interpret negative
|
||||
seek times as relative from the end of the file (and clamps seeks that
|
||||
still go before 0)
|
||||
- add almost all options to the property list, meaning you can change
|
||||
options without adding "options/" to the property name (a new section
|
||||
has been added to the manpage describing some conflicting behavior
|
||||
between options and properties)
|
||||
- implement changing sub-speed during playback
|
||||
- make many previously fixed options changeable at runtime (for example
|
||||
--terminal, --osc, --ytdl, can all be enable/disabled after
|
||||
mpv_initialize() - this can be extended to other still fixed options
|
||||
on user requests)
|
||||
--- mpv 0.20.0 ---
|
||||
- add --image-display-duration option - this also means that image duration
|
||||
is not influenced by --mf-fps anymore in the general case (this is an
|
||||
incompatible change)
|
||||
--- mpv 0.19.0 ---
|
||||
- deprecate "balance" option/property (no replacement)
|
||||
--- mpv 0.18.1 ---
|
||||
- deprecate --heartbeat-cmd
|
||||
- remove --softvol=no capability:
|
||||
- deprecate --softvol, it now does nothing
|
||||
- --volume, --mute, and the corresponding properties now always control
|
||||
softvol, and behave as expected without surprises (e.g. you can set
|
||||
them normally while no audio is initialized)
|
||||
- rename --softvol-max to --volume-max (deprecated alias is added)
|
||||
- the --volume-restore-data option and property are removed without
|
||||
replacement. They were _always_ internal, and used for watch-later
|
||||
resume/restore. Now --volume/--mute are saved directly instead.
|
||||
- the previous point means resuming files with older watch-later configs
|
||||
will print an error about missing --volume-restore-data (which you can
|
||||
ignore), and will not restore the previous value
|
||||
- as a consequence, volume controls will no longer control PulseAudio
|
||||
per-application value, or use the system mixer's per-application
|
||||
volume processing
|
||||
- system or per-application volume can still be controlled with the
|
||||
ao-volume and ao-mute properties (there are no command line options)
|
||||
--- mpv 0.18.0 ---
|
||||
- now ab-loops are active even if one of the "ab-loop-a"/"-b" properties is
|
||||
unset ("no"), in which case the start of the file is used if the A loop
|
||||
point is unset, and the end of the file for an unset B loop point
|
||||
- deprecate --sub-ass=no option by --ass-style-override=strip
|
||||
(also needs --embeddedfonts=no)
|
||||
- add "hwdec-interop" and "hwdec-current" properties
|
||||
- deprecated "hwdec-active" and "hwdec-detected" properties (to be removed
|
||||
in mpv 0.20.0)
|
||||
- choice option/property values that are "yes" or "no" will now be returned
|
||||
as booleans when using the mpv_node functions in the client API, the
|
||||
"native" property accessors in Lua, and the JSON API. They can be set as
|
||||
such as well.
|
||||
- the VO opengl fbo-format sub-option does not accept "rgb" or "rgba"
|
||||
anymore
|
||||
- all VO opengl prescalers have been removed (replaced by user scripts)
|
||||
--- mpv 0.17.0 ---
|
||||
- deprecate "track-list/N/audio-channels" property (use
|
||||
"track-list/N/demux-channel-count" instead)
|
||||
- remove write access to "stream-pos", and change semantics for read access
|
||||
- Lua scripts now don't suspend mpv by default while script code is run
|
||||
- add "cache-speed" property
|
||||
- rename --input-unix-socket to --input-ipc-server, and make it work on
|
||||
Windows too
|
||||
- change the exact behavior of the "video-zoom" property
|
||||
- --video-unscaled no longer disables --video-zoom and --video-aspect
|
||||
To force the old behavior, set --video-zoom=0 and --video-aspect=0
|
||||
--- mpv 0.16.0 ---
|
||||
- change --audio-channels default to stereo (use --audio-channels=auto to
|
||||
get the old default)
|
||||
- add --audio-normalize-downmix
|
||||
- change the default downmix behavior (--audio-normalize-downmix=yes to get
|
||||
the old default)
|
||||
- VO opengl custom shaders must now use "sample_pixel" as function name,
|
||||
instead of "sample"
|
||||
- change VO opengl scaler-resizes-only default to enabled
|
||||
- add VO opengl "interpolation-threshold" suboption (introduces new default
|
||||
behavior, which can change e.g. ``--video-sync=display-vdrop`` to the
|
||||
worse, but is usually what you want)
|
||||
- make "volume" and "mute" properties changeable even if no audio output is
|
||||
active (this gives not-ideal behavior if --softvol=no is used)
|
||||
- add "volume-max" and "mixer-active" properties
|
||||
- ignore --input-cursor option for events injected by input commands like
|
||||
"mouse", "keydown", etc.
|
||||
--- mpv 0.15.0 ---
|
||||
- change "yadif" video filter defaults
|
||||
--- mpv 0.14.0 ---
|
||||
- vo_opengl interpolation now requires --video-sync=display-... to be set
|
||||
- change some vo_opengl defaults (including changing tscale)
|
||||
- add "vsync-ratio", "estimated-display-fps" properties
|
||||
- add --rebase-start-time option
|
||||
This is a breaking change to start time handling. Instead of making start
|
||||
time handling an aspect of different options and properties (like
|
||||
"time-pos" vs. "playback-time"), make it dependent on the new option. For
|
||||
compatibility, the "time-start" property now always returns 0, so code
|
||||
which attempted to handle rebasing manually will not break.
|
||||
--- mpv 0.13.0 ---
|
||||
- remove VO opengl-cb frame queue suboptions (no replacement)
|
||||
--- mpv 0.12.0 ---
|
||||
- remove --use-text-osd (useless; fontconfig isn't a requirement anymore,
|
||||
and text rendering is also lazily initialized)
|
||||
- some time properties (at least "playback-time", "time-pos",
|
||||
"time-remaining", "playtime-remaining") now are unavailable if the time
|
||||
is unknown, instead of just assuming that the internal playback position
|
||||
is 0
|
||||
- add --audio-fallback-to-null option
|
||||
- replace vf_format outputlevels suboption with "video-output-levels" global
|
||||
property/option; also remove "colormatrix-output-range" property
|
||||
- vo_opengl: remove sharpen3/sharpen5 scale filters, add sharpen sub-option
|
||||
--- mpv 0.11.0 ---
|
||||
- add "af-metadata" property
|
||||
--- mpv 0.10.0 ---
|
||||
- add --video-aspect-method option
|
||||
- add --playlist-pos option
|
||||
- add --video-sync* options
|
||||
"display-sync-active" property
|
||||
"vo-missed-frame-count" property
|
||||
"audio-speed-correction" and "video-speed-correction" properties
|
||||
- remove --demuxer-readahead-packets and --demuxer-readahead-bytes
|
||||
add --demuxer-max-packets and --demuxer-max-bytes
|
||||
(the new options are not replacement and have very different semantics)
|
||||
- change "video-aspect" property: always settable, even if no video is
|
||||
running; always return the override - if no override is set, return
|
||||
the video's aspect ratio
|
||||
- remove disc-nav (DVD, BD) related properties and commands
|
||||
- add "option-info/<name>/set-locally" property
|
||||
- add --cache-backbuffer; change --cache-default default to 75MB
|
||||
the new total cache size is the sum of backbuffer and the cache size
|
||||
specified by --cache-default or --cache
|
||||
- add ``track-list/N/audio-channels`` property
|
||||
- change --screenshot-tag-colorspace default value
|
||||
- add --stretch-image-subs-to-screen
|
||||
- add "playlist/N/title" property
|
||||
- add --video-stereo-mode=no to disable auto-conversions
|
||||
- add --force-seekable, and change default seekability in some cases
|
||||
- add vf yadif/vavpp/vdpaupp interlaced-only suboptions
|
||||
Also, the option is enabled by default (Except vf_yadif, which has
|
||||
it enabled only if it's inserted by the deinterlace property.)
|
||||
- add --hwdec-preload
|
||||
- add ao coreaudio exclusive suboption
|
||||
- add ``track-list/N/forced`` property
|
||||
- add audio-params/channel-count and ``audio-params-out/channel-count props.
|
||||
- add af volume replaygain-fallback suboption
|
||||
- add video-params/stereo-in property
|
||||
- add "keypress", "keydown", and "keyup" commands
|
||||
- deprecate --ad-spdif-dtshd and enabling passthrough via --ad
|
||||
add --audio-spdif as replacement
|
||||
- remove "get_property" command
|
||||
- remove --slave-broken
|
||||
- add vo opengl custom shader suboptions (source-shader, scale-shader,
|
||||
pre-shaders, post-shaders)
|
||||
- completely change how the hwdec properties work:
|
||||
- "hwdec" now reflects the --hwdec option
|
||||
- "hwdec-detected" does partially what the old "hwdec" property did
|
||||
(and also, "detected-hwdec" is removed)
|
||||
- "hwdec-active" is added
|
||||
- add protocol-list property
|
||||
- deprecate audio-samplerate and audio-channels properties
|
||||
(audio-params sub-properties are the replacement)
|
||||
- add audio-params and audio-out-params properties
|
||||
- deprecate "audio-format" property, replaced with "audio-codec-name"
|
||||
- deprecate --media-title, replaced with --force-media-title
|
||||
- deprecate "length" property, replaced with "duration"
|
||||
- change volume property:
|
||||
- the value 100 is now always "unchanged volume" - with softvol, the
|
||||
range is 0 to --softvol-max, without it is 0-100
|
||||
- the minimum value of --softvol-max is raised to 100
|
||||
- remove vo opengl npot suboption
|
||||
- add relative seeking by percentage to "seek" command
|
||||
- add playlist_shuffle command
|
||||
- add --force-window=immediate
|
||||
- add ao coreaudio change-physical-format suboption
|
||||
- remove vo opengl icc-cache suboption, add icc-cache-dir suboption
|
||||
- add --screenshot-directory
|
||||
- add --screenshot-high-bit-depth
|
||||
- add --screenshot-jpeg-source-chroma
|
||||
- default action for "rescan_external_files" command changes
|
||||
--- mpv 0.9.0 ---
|
||||
@@ -1,7 +1,5 @@
|
||||
-- Rebuild the terminal status line as a lua script
|
||||
-- Rebuild the status line as a lua script
|
||||
-- Be aware that this will require more cpu power!
|
||||
-- Also, this is based on a rather old version of the
|
||||
-- builtin mpv status line.
|
||||
|
||||
-- Add a string to the status line
|
||||
function atsl(s)
|
||||
@@ -30,7 +28,7 @@ function update_status_line()
|
||||
atsl(mp.get_property_osd("time-pos"))
|
||||
|
||||
atsl(" / ");
|
||||
atsl(mp.get_property_osd("duration"));
|
||||
atsl(mp.get_property_osd("length"));
|
||||
|
||||
atsl(" (")
|
||||
atsl(mp.get_property_osd("percent-pos", -1))
|
||||
+248
-79
@@ -11,10 +11,6 @@ syntax is:
|
||||
|
||||
To get a full list of available audio filters, see ``--af=help``.
|
||||
|
||||
Also, keep in mind that most actual filters are available via the ``lavfi``
|
||||
wrapper, which gives you access to most of libavfilter's filters. This
|
||||
includes all filters that have been ported from MPlayer to libavfilter.
|
||||
|
||||
You can also set defaults for each filter. The defaults are applied before the
|
||||
normal filter parameters.
|
||||
|
||||
@@ -63,14 +59,11 @@ Available filters are:
|
||||
(If you just want to set defaults for this filter that will be used
|
||||
even by automatically inserted lavrresample instances, you should
|
||||
prefer setting them with ``--af-defaults=lavrresample:...``.)
|
||||
``normalize=<yes|no|auto>``
|
||||
Whether to normalize when remixing channel layouts (default: auto).
|
||||
``auto`` uses the value set by ``--audio-normalize-downmix``.
|
||||
``o=<string>``
|
||||
Set AVOptions on the SwrContext or AVAudioResampleContext. These should
|
||||
be documented by FFmpeg or Libav.
|
||||
|
||||
``lavcac3enc[=options]``
|
||||
``lavcac3enc[=tospdif[:bitrate[:minchn]]]``
|
||||
Encode multi-channel audio to AC-3 at runtime using libavcodec. Supports
|
||||
16-bit native-endian input format, maximum 6 channels. The output is
|
||||
big-endian when outputting a raw AC-3 stream, native-endian when
|
||||
@@ -79,17 +72,15 @@ Available filters are:
|
||||
|
||||
``tospdif=<yes|no>``
|
||||
Output raw AC-3 stream if ``no``, output to S/PDIF for
|
||||
pass-through if ``yes`` (default).
|
||||
passthrough if ``yes`` (default).
|
||||
|
||||
``bitrate=<rate>``
|
||||
The bitrate use for the AC-3 stream. Set it to 384 to get 384 kbps.
|
||||
|
||||
The default is 640. Some receivers might not be able to handle this.
|
||||
|
||||
Valid values: 32, 40, 48, 56, 64, 80, 96, 112, 128,
|
||||
160, 192, 224, 256, 320, 384, 448, 512, 576, 640.
|
||||
|
||||
The special value ``auto`` selects a default bitrate based on the
|
||||
The special value ``default`` selects a default bitrate based on the
|
||||
input channel number:
|
||||
|
||||
:1ch: 96
|
||||
@@ -99,13 +90,62 @@ Available filters are:
|
||||
:5ch: 448
|
||||
:6ch: 448
|
||||
|
||||
``minch=<n>``
|
||||
If the input channel number is less than ``<minch>``, the filter will
|
||||
detach itself (default: 3).
|
||||
``minchn=<n>``
|
||||
If the input channel number is less than ``<minchn>``, the filter will
|
||||
detach itself (default: 5).
|
||||
|
||||
``encoder=<name>``
|
||||
Select the libavcodec encoder used. Currently, this should be an AC-3
|
||||
encoder, and using another codec will fail horribly.
|
||||
``sweep[=speed]``
|
||||
Produces a sine sweep.
|
||||
|
||||
``<0.0-1.0>``
|
||||
Sine function delta, use very low values to hear the sweep.
|
||||
|
||||
``sinesuppress[=freq:decay]``
|
||||
Remove a sine at the specified frequency. Useful to get rid of the 50/60Hz
|
||||
noise on low quality audio equipment. It only works on mono input.
|
||||
|
||||
``<freq>``
|
||||
The frequency of the sine which should be removed (in Hz) (default:
|
||||
50)
|
||||
``<decay>``
|
||||
Controls the adaptivity (a larger value will make the filter adapt to
|
||||
amplitude and phase changes quicker, a smaller value will make the
|
||||
adaptation slower) (default: 0.0001). Reasonable values are around
|
||||
0.001.
|
||||
|
||||
``bs2b[=option1:option2:...]``
|
||||
Bauer stereophonic to binaural transformation using libbs2b. Improves the
|
||||
headphone listening experience by making the sound similar to that from
|
||||
loudspeakers, allowing each ear to hear both channels and taking into
|
||||
account the distance difference and the head shadowing effect. It is
|
||||
applicable only to 2-channel audio.
|
||||
|
||||
``fcut=<300-1000>``
|
||||
Set cut frequency in Hz.
|
||||
``feed=<10-150>``
|
||||
Set feed level for low frequencies in 0.1*dB.
|
||||
``profile=<value>``
|
||||
Several profiles are available for convenience:
|
||||
|
||||
:default: will be used if nothing else was specified (fcut=700,
|
||||
feed=45)
|
||||
:cmoy: Chu Moy circuit implementation (fcut=700, feed=60)
|
||||
:jmeier: Jan Meier circuit implementation (fcut=650, feed=95)
|
||||
|
||||
If ``fcut`` or ``feed`` options are specified together with a profile, they
|
||||
will be applied on top of the selected profile.
|
||||
|
||||
``hrtf[=flag]``
|
||||
Head-related transfer function: Converts multichannel audio to 2-channel
|
||||
output for headphones, preserving the spatiality of the sound.
|
||||
|
||||
==== ===================================
|
||||
Flag Meaning
|
||||
==== ===================================
|
||||
m matrix decoding of the rear channel
|
||||
s 2-channel matrix decoding
|
||||
0 no matrix decoding (default)
|
||||
==== ===================================
|
||||
|
||||
``equalizer=g1:g2:g3:...:g10``
|
||||
10 octave band graphic equalizer, implemented using 10 IIR band-pass
|
||||
@@ -142,7 +182,7 @@ Available filters are:
|
||||
|
||||
``mpv --af=equalizer=11:11:10:5:0:-12:0:5:12:12 media.avi``
|
||||
Would amplify the sound in the upper and lower frequency region
|
||||
while canceling it almost completely around 1 kHz.
|
||||
while canceling it almost completely around 1kHz.
|
||||
|
||||
``channels=nch[:routes]``
|
||||
Can be used for adding, removing, routing and copying audio channels. If
|
||||
@@ -164,7 +204,7 @@ Available filters are:
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``mpv --af=channels=4:[0-1,1-0,2-2,3-3] media.avi``
|
||||
``mpv --af=channels=4:[0-1,1-0,0-2,1-3] media.avi``
|
||||
Would change the number of channels to 4 and set up 4 routes that
|
||||
swap channel 0 and channel 1 and leave channel 2 and 3 intact.
|
||||
Observe that if media containing two channels were played back,
|
||||
@@ -183,21 +223,14 @@ Available filters are:
|
||||
automatically up- and downmix standard channel layouts.
|
||||
|
||||
``format=format:srate:channels:out-format:out-srate:out-channels``
|
||||
Does not do any format conversion itself. Rather, it may cause the
|
||||
filter system to insert necessary conversion filters before or after this
|
||||
filter if needed. It is primarily useful for controlling the audio format
|
||||
going into other filters. To specify the format for audio output, see
|
||||
``--audio-format``, ``--audio-samplerate``, and ``--audio-channels``. This
|
||||
filter is able to force a particular format, whereas ``--audio-*``
|
||||
may be overridden by the ao based on output compatibility.
|
||||
Force a specific audio format/configuration without actually changing the
|
||||
audio data. Keep in mind that the filter system might auto-insert actual
|
||||
conversion filters before or after this filter if needed.
|
||||
|
||||
All parameters are optional. The first 3 parameters restrict what the filter
|
||||
accepts as input. They will therefore cause conversion filters to be
|
||||
inserted before this one. The ``out-`` parameters tell the filters or audio
|
||||
outputs following this filter how to interpret the data without actually
|
||||
doing a conversion. Setting these will probably just break things unless you
|
||||
really know you want this for some reason, such as testing or dealing with
|
||||
broken media.
|
||||
accepts as input. The ``out-`` parameters change the audio format, without
|
||||
actually doing a conversion. The data will be 'reinterpreted' by the
|
||||
filters or audio outputs following this filter.
|
||||
|
||||
``<format>``
|
||||
Force conversion to this format. Use ``--af=format=format=help`` to get
|
||||
@@ -217,9 +250,22 @@ Available filters are:
|
||||
|
||||
``<out-channels>``
|
||||
|
||||
*NOTE*: this filter used to be named ``force``. The old ``format`` filter
|
||||
used to do conversion itself, unlike this one which lets the filter system
|
||||
handle the conversion.
|
||||
See also ``--audio-format``, ``--audio-samplerate``, and
|
||||
``--audio-channels`` for related options. Keep in mind that
|
||||
``--audio-channels`` does not actually force the number of
|
||||
channels in most cases, while this filter can do this.
|
||||
|
||||
*NOTE*: this filter used to be named ``force``. Also, unlike the old
|
||||
``format`` filter, this does not do any actual conversion anymore.
|
||||
Conversion is done by other, automatically inserted filters.
|
||||
|
||||
``convert24``
|
||||
Filter for internal use only. Converts between 24-bit and 32-bit sample
|
||||
formats.
|
||||
|
||||
``convertsignendian``
|
||||
Filter for internal use only. Converts between signed/unsigned formats
|
||||
and formats with different endian.
|
||||
|
||||
``volume[=<volumedb>[:...]]``
|
||||
Implements software volume control. Use this filter with caution since it
|
||||
@@ -231,8 +277,8 @@ Available filters are:
|
||||
once for every audio stream.
|
||||
|
||||
``<volumedb>``
|
||||
Sets the desired gain in dB for all channels in the stream from -200 dB
|
||||
to +60 dB, where -200 dB mutes the sound completely and +60 dB equals a
|
||||
Sets the desired gain in dB for all channels in the stream from -200dB
|
||||
to +60dB, where -200dB mutes the sound completely and +60dB equals a
|
||||
gain of 1000 (default: 0).
|
||||
``replaygain-track``
|
||||
Adjust volume gain according to the track-gain replaygain value stored
|
||||
@@ -245,10 +291,6 @@ Available filters are:
|
||||
``replaygain-clip=yes|no``
|
||||
Prevent clipping caused by replaygain by automatically lowering the
|
||||
gain (default). Use ``replaygain-clip=no`` to disable this.
|
||||
``replaygain-fallback``
|
||||
Gain in dB to apply if the file has no replay gain tags. This option
|
||||
is always applied if the replaygain logic is somehow inactive. If this
|
||||
is applied, no other replaygain options are applied.
|
||||
``softclip``
|
||||
Turns soft clipping on. Soft-clipping can make the
|
||||
sound more smooth if very high volume levels are used. Enable this
|
||||
@@ -269,7 +311,7 @@ Available filters are:
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=volume=10.1 media.avi``
|
||||
Would amplify the sound by 10.1 dB and hard-clip if the sound level
|
||||
Would amplify the sound by 10.1dB and hard-clip if the sound level
|
||||
is too high.
|
||||
|
||||
``pan=n:[<matrix>]``
|
||||
@@ -312,12 +354,121 @@ Available filters are:
|
||||
``mpv '--af=format=channels=5.1' '--audio-channels=5.1'`` would always force
|
||||
remixing audio to 5.1 and output it like this.
|
||||
|
||||
This filter supports the following ``af-command`` commands:
|
||||
``sub[=fc:ch]``
|
||||
Adds a subwoofer channel to the audio stream. The audio data used for
|
||||
creating the subwoofer channel is an average of the sound in channel 0 and
|
||||
channel 1. The resulting sound is then low-pass filtered by a 4th order
|
||||
Butterworth filter with a default cutoff frequency of 60Hz and added to a
|
||||
separate channel in the audio stream.
|
||||
|
||||
``set-matrix``
|
||||
Set the ``<matrix>`` argument dynamically. This can be used to change
|
||||
the mixing matrix at runtime, without reinitializing the entire filter
|
||||
chain.
|
||||
.. warning::
|
||||
|
||||
Disable this filter when you are playing media with an LFE channel
|
||||
(e.g. 5.1 surround sound), otherwise this filter will disrupt the sound
|
||||
to the subwoofer.
|
||||
|
||||
``<fc>``
|
||||
cutoff frequency in Hz for the low-pass filter (20Hz to 300Hz)
|
||||
(default: 60Hz) For the best result try setting the cutoff frequency
|
||||
as low as possible. This will improve the stereo or surround sound
|
||||
experience.
|
||||
``<ch>``
|
||||
Determines the channel number in which to insert the sub-channel
|
||||
audio. Channel number can be between 0 and 7 (default: 5). Observe
|
||||
that the number of channels will automatically be increased to <ch> if
|
||||
necessary.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=sub=100:4 --audio-channels=5 media.avi``
|
||||
Would add a subwoofer channel with a cutoff frequency of 100Hz to
|
||||
output channel 4.
|
||||
|
||||
``center``
|
||||
Creates a center channel from the front channels. May currently be low
|
||||
quality as it does not implement a high-pass filter for proper extraction
|
||||
yet, but averages and halves the channels instead.
|
||||
|
||||
``<ch>``
|
||||
Determines the channel number in which to insert the center channel.
|
||||
Channel number can be between 0 and 7 (default: 5). Observe that the
|
||||
number of channels will automatically be increased to ``<ch>`` if
|
||||
necessary.
|
||||
|
||||
``surround[=delay]``
|
||||
Decoder for matrix encoded surround sound like Dolby Surround. Some files
|
||||
with 2-channel audio actually contain matrix encoded surround sound.
|
||||
|
||||
``<delay>``
|
||||
delay time in ms for the rear speakers (0 to 1000) (default: 20) This
|
||||
delay should be set as follows: If d1 is the distance from the
|
||||
listening position to the front speakers and d2 is the distance from
|
||||
the listening position to the rear speakers, then the delay should be
|
||||
set to 15ms if d1 <= d2 and to 15 + 5*(d1-d2) if d1 > d2.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=surround=15 --audio-channels=4 media.avi``
|
||||
Would add surround sound decoding with 15ms delay for the sound to
|
||||
the rear speakers.
|
||||
|
||||
``delay[=[ch1,ch2,...]]``
|
||||
Delays the sound to the loudspeakers such that the sound from the
|
||||
different channels arrives at the listening position simultaneously. It is
|
||||
only useful if you have more than 2 loudspeakers.
|
||||
|
||||
``[ch1,ch2,...]``
|
||||
The delay in ms that should be imposed on each channel (floating point
|
||||
number between 0 and 1000).
|
||||
|
||||
To calculate the required delay for the different channels, do as follows:
|
||||
|
||||
1. Measure the distance to the loudspeakers in meters in relation to your
|
||||
listening position, giving you the distances s1 to s5 (for a 5.1
|
||||
system). There is no point in compensating for the subwoofer (you will
|
||||
not hear the difference anyway).
|
||||
|
||||
2. Subtract the distances s1 to s5 from the maximum distance, i.e.
|
||||
``s[i] = max(s) - s[i]; i = 1...5``.
|
||||
|
||||
3. Calculate the required delays in ms as ``d[i] = 1000*s[i]/342; i =
|
||||
1...5``.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=delay=[10.5,10.5,0,0,7,0] media.avi``
|
||||
Would delay front left and right by 10.5ms, the two rear channels
|
||||
and the subwoofer by 0ms and the center channel by 7ms.
|
||||
|
||||
``export=mmapped_file:nsamples]``
|
||||
Exports the incoming signal to other processes using memory mapping
|
||||
(``mmap()``). Memory mapped areas contain a header::
|
||||
|
||||
int nch /* number of channels */
|
||||
int size /* buffer size */
|
||||
unsigned long long counter /* Used to keep sync, updated every time
|
||||
new data is exported. */
|
||||
|
||||
The rest is payload (non-interleaved) 16-bit data.
|
||||
|
||||
``<mmapped_file>``
|
||||
File to map data to (required)
|
||||
``<nsamples>``
|
||||
number of samples per channel (default: 512).
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=export=/tmp/mpv-af_export:1024 media.avi``
|
||||
Would export 1024 samples per channel to ``/tmp/mpv-af_export``.
|
||||
|
||||
``extrastereo[=mul]``
|
||||
(Linearly) increases the difference between left and right channels which
|
||||
adds some sort of "live" effect to playback.
|
||||
|
||||
``<mul>``
|
||||
Sets the difference coefficient (default: 2.5). 0.0 means mono sound
|
||||
(average of both channels), with 1.0 sound will be unchanged, with
|
||||
-1.0 left and right channels will be swapped.
|
||||
|
||||
``drc[=method:target]``
|
||||
Applies dynamic range compression. This maximizes the volume by compressing
|
||||
@@ -342,6 +493,45 @@ Available filters are:
|
||||
This filter can cause distortion with audio signals that have a very
|
||||
large dynamic range.
|
||||
|
||||
``ladspa=file:label:[<control0>,<control1>,...]``
|
||||
Load a LADSPA (Linux Audio Developer's Simple Plugin API) plugin. This
|
||||
filter is reentrant, so multiple LADSPA plugins can be used at once.
|
||||
|
||||
``<file>``
|
||||
Specifies the LADSPA plugin library file.
|
||||
|
||||
.. note::
|
||||
|
||||
See also the note about the ``LADSPA_PATH`` variable in the
|
||||
`ENVIRONMENT VARIABLES`_ section.
|
||||
``<label>``
|
||||
Specifies the filter within the library. Some libraries contain only
|
||||
one filter, but others contain many of them. Entering 'help' here
|
||||
will list all available filters within the specified library, which
|
||||
eliminates the use of 'listplugins' from the LADSPA SDK.
|
||||
``[<control0>,<control1>,...]``
|
||||
Controls are zero or more ``,`` separated floating point values that
|
||||
determine the behavior of the loaded plugin (for example delay,
|
||||
threshold or gain).
|
||||
In verbose mode (add ``-v`` to the mpv command line), all
|
||||
available controls and their valid ranges are printed. This eliminates
|
||||
the use of 'analyseplugin' from the LADSPA SDK.
|
||||
Note that ``,`` is already used by the option parser to separate
|
||||
filters, so you must quote the list of values with ``[...]`` or
|
||||
similar.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=ladspa='/usr/lib/ladspa/delay.so':delay_5s:[0.5,0.2] media.avi``
|
||||
Does something.
|
||||
|
||||
``karaoke``
|
||||
Simple voice removal filter exploiting the fact that voice is usually
|
||||
recorded with mono gear and later 'center' mixed onto the final audio
|
||||
stream. Beware that this filter will turn your signal into mono. Works
|
||||
well for 2 channel tracks; do not bother trying it on anything but 2
|
||||
channel stereo.
|
||||
|
||||
``scaletempo[=option1:option2:...]``
|
||||
Scales audio tempo without altering pitch, optionally synced to playback
|
||||
speed (default).
|
||||
@@ -374,10 +564,9 @@ Available filters are:
|
||||
Scale tempo in sync with speed (default).
|
||||
pitch
|
||||
Reverses effect of filter. Scales pitch without altering tempo.
|
||||
Add this to your ``input.conf`` to step by musical semi-tones::
|
||||
|
||||
[ multiply speed 0.9438743126816935
|
||||
] multiply speed 1.059463094352953
|
||||
Add ``[ speed_mult 0.9438743126816935`` and ``] speed_mult
|
||||
1.059463094352953`` to your ``input.conf`` to step by musical
|
||||
semi-tones.
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -399,40 +588,19 @@ Available filters are:
|
||||
tempo.
|
||||
|
||||
``mpv --af=scaletempo=stride=30:overlap=.50:search=10 media.ogg``
|
||||
Would tweak the quality and performance parameters.
|
||||
Would tweak the quality and performace parameters.
|
||||
|
||||
``mpv --af=format=float,scaletempo media.ogg``
|
||||
Would make scaletempo use float code. Maybe faster on some
|
||||
platforms.
|
||||
|
||||
``mpv --af=scaletempo=scale=1.2:speed=pitch audio.ogg``
|
||||
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.
|
||||
|
||||
``rubberband``
|
||||
High quality pitch correction with librubberband. This can be used in place
|
||||
of ``scaletempo``, and will be used to adjust audio pitch when playing
|
||||
at speed different from normal. It can also be used to adjust audio pitch
|
||||
without changing playback speed.
|
||||
|
||||
``<pitch-scale>``
|
||||
Sets the pitch scaling factor. Frequencies are multiplied by this value.
|
||||
|
||||
This filter has a number of additional sub-options. You can list them with
|
||||
``mpv --af=rubberband=help``. This will also show the default values
|
||||
for each option. The options are not documented here, because they are
|
||||
merely passed to librubberband. Look at the librubberband documentation
|
||||
to learn what each option does:
|
||||
http://breakfastquay.com/rubberband/code-doc/classRubberBand_1_1RubberBandStretcher.html
|
||||
(The mapping of the mpv rubberband filter sub-option names and values to
|
||||
those of librubberband follows a simple pattern: ``"Option" + Name + Value``.)
|
||||
|
||||
This filter supports the following ``af-command`` commands:
|
||||
|
||||
``set-pitch``
|
||||
Set the ``<pitch-scale>`` argument dynamically. This can be used to
|
||||
change the playback pitch at runtime. Note that speed is controlled
|
||||
using the standard ``speed`` property, not ``af-command``.
|
||||
|
||||
``lavfi=graph``
|
||||
Filter audio using FFmpeg's libavfilter.
|
||||
Filter audio using ffmpeg's libavfilter.
|
||||
|
||||
``<graph>``
|
||||
Libavfilter graph. See ``lavfi`` video filter for details - the graph
|
||||
@@ -445,3 +613,4 @@ Available filters are:
|
||||
|
||||
``o=<string>``
|
||||
AVOptions.
|
||||
|
||||
+111
-125
@@ -4,82 +4,105 @@ AUDIO OUTPUT DRIVERS
|
||||
Audio output drivers are interfaces to different audio output facilities. The
|
||||
syntax is:
|
||||
|
||||
``--ao=<driver1,driver2,...[,]>``
|
||||
``--ao=<driver1[:suboption1[=value]:...],driver2,...[,]>``
|
||||
Specify a priority list of audio output drivers to be used.
|
||||
|
||||
If the list has a trailing ',', mpv will fall back on drivers not contained
|
||||
in the list.
|
||||
in the list. Suboptions are optional and can mostly be omitted.
|
||||
|
||||
You can also set defaults for each driver. The defaults are applied before the
|
||||
normal driver parameters.
|
||||
|
||||
``--ao-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
|
||||
Set defaults for each driver.
|
||||
|
||||
Deprecated. No replacement.
|
||||
|
||||
.. note::
|
||||
|
||||
See ``--ao=help`` for a list of compiled-in audio output drivers. The
|
||||
driver ``--ao=alsa`` is preferred. ``--ao=pulse`` is preferred on systems
|
||||
where PulseAudio is used. On BSD systems, ``--ao=oss`` or ``--ao=sndio``
|
||||
may work (the latter being experimental).
|
||||
where PulseAudio is used. On Windows, ``--ao=wasapi`` is preferred,
|
||||
though it might cause trouble sometimes, in which case ``--ao=dsound``
|
||||
should be used. On BSD systems, ``--ao=oss`` or `--ao=sndio`` may work
|
||||
(the latter being experimental). On OSX systems, use ``--ao=coreaudio``.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
- ``--ao=alsa,oss,`` Try the ALSA driver, then the OSS driver, then others.
|
||||
- ``--ao=alsa:no-block:device=[hw:0,3]`` Sets noblock-mode and the
|
||||
device-name as first card, fourth device.
|
||||
|
||||
Available audio output drivers are:
|
||||
|
||||
``alsa`` (Linux only)
|
||||
ALSA audio output driver
|
||||
|
||||
See `ALSA audio output options`_ for options specific to this AO.
|
||||
``device=<device>``
|
||||
Sets the device name. For ac3 output via S/PDIF, use an "iec958" or
|
||||
"spdif" device, unless you really know how to set it correctly.
|
||||
``no-block``
|
||||
Sets noblock-mode.
|
||||
``resample=yes``
|
||||
Enable ALSA resampling plugin. (This is disabled by default, because
|
||||
some drivers report incorrect audio delay in some cases.)
|
||||
``mixer-device=<device>``
|
||||
Set the mixer device used with ``--no-softvol`` (default: ``default``).
|
||||
``mixer-name=<name>``
|
||||
Set the name of the mixer element (default: ``Master``). This is for
|
||||
example ``PCM`` or ``Master``.
|
||||
``mixer-index=<number>``
|
||||
Set the index of the mixer channel (default: 0). Consider the output of
|
||||
"``amixer scontrols``", then the index is the number that follows the
|
||||
name of the element.
|
||||
|
||||
.. warning::
|
||||
.. note::
|
||||
|
||||
To get multichannel/surround audio, use ``--audio-channels=auto``. The
|
||||
default for this option is ``auto-safe``, which makes this audio otuput
|
||||
explicitly reject multichannel output, as there is no way to detect
|
||||
whether a certain channel layout is actually supported.
|
||||
MPlayer and mplayer2 required you to replace any ',' with '.' and
|
||||
any ':' with '=' in the ALSA device name. mpv does not do this anymore.
|
||||
Instead, quote the device name:
|
||||
|
||||
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.
|
||||
``--ao=alsa:device=[plug:surround50]``
|
||||
|
||||
Note that the ``[`` and ``]`` simply quote the device name. With some
|
||||
shells (like zsh), you have to quote the option string to prevent the
|
||||
shell from interpreting the brackets instead of passing them to mpv.
|
||||
|
||||
``oss``
|
||||
OSS audio output driver
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--oss-device``
|
||||
``<dsp-device>``
|
||||
Sets the audio output device (default: ``/dev/dsp``).
|
||||
Deprecated, use ``--audio-device``.
|
||||
``--oss-mixer-device``
|
||||
``<mixer-device>``
|
||||
Sets the audio mixer device (default: ``/dev/mixer``).
|
||||
``--oss-mixer-channel``
|
||||
``<mixer-channel>``
|
||||
Sets the audio mixer channel (default: ``pcm``). Other valid values
|
||||
include **vol, pcm, line**. For a complete list of options look for
|
||||
``SOUND_DEVICE_NAMES`` in ``/usr/include/linux/soundcard.h``.
|
||||
|
||||
``jack``
|
||||
JACK (Jack Audio Connection Kit) audio output driver.
|
||||
JACK (Jack Audio Connection Kit) audio output driver
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--jack-port=<name>``
|
||||
``port=<name>``
|
||||
Connects to the ports with the given name (default: physical ports).
|
||||
``--jack-name=<client>``
|
||||
``name=<client>``
|
||||
Client name that is passed to JACK (default: ``mpv``). Useful
|
||||
if you want to have certain connections established automatically.
|
||||
``--jack-autostart=<yes|no>``
|
||||
``(no-)autostart``
|
||||
Automatically start jackd if necessary (default: disabled). Note that
|
||||
this tends to be unreliable and will flood stdout with server messages.
|
||||
``--jack-connect=<yes|no>``
|
||||
``(no-)connect``
|
||||
Automatically create connections to output ports (default: enabled).
|
||||
When enabled, the maximum number of output channels will be limited to
|
||||
the number of available output ports.
|
||||
``--jack-std-channel-layout=<waveext|any>``
|
||||
Select the standard channel layout (default: waveext). JACK itself has no
|
||||
``std-channel-layout=alsa|waveext|any``
|
||||
Select the standard channel layout (default: alsa). JACK itself has no
|
||||
notion of channel layouts (i.e. assigning which speaker a given
|
||||
channel is supposed to map to) - it just takes whatever the application
|
||||
outputs, and reroutes it to whatever the user defines. This means the
|
||||
user and the application are in charge of dealing with the channel
|
||||
layout. ``waveext`` uses WAVE_FORMAT_EXTENSIBLE order, which, even
|
||||
layout. ``alsa`` uses the old MPlayer layout, which is inspired by
|
||||
ALSA's standard layouts. In this mode, ao_jack will refuse to play 3
|
||||
or 7 channels (because these do not really have a defined meaning in
|
||||
MPlayer). ``waveext`` uses WAVE_FORMAT_EXTENSIBLE order, which, even
|
||||
though it was defined by Microsoft, is the standard on many systems.
|
||||
The value ``any`` makes JACK accept whatever comes from the audio
|
||||
filter chain, regardless of channel layout and without reordering. This
|
||||
@@ -87,32 +110,12 @@ Available audio output drivers are:
|
||||
with fixed setups.
|
||||
|
||||
``coreaudio`` (Mac OS X only)
|
||||
Native Mac OS X audio output driver using AudioUnits and the CoreAudio
|
||||
sound server.
|
||||
Native Mac OS X audio output driver
|
||||
|
||||
Automatically redirects to ``coreaudio_exclusive`` when playing compressed
|
||||
formats.
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--coreaudio-change-physical-format=<yes|no>``
|
||||
Change the physical format to one similar to the requested audio format
|
||||
(default: no). This has the advantage that multichannel audio output
|
||||
will actually work. The disadvantage is that it will change the
|
||||
system-wide audio settings. This is equivalent to changing the ``Format``
|
||||
setting in the ``Audio Devices`` dialog in the ``Audio MIDI Setup``
|
||||
utility. Note that this does not affect the selected speaker setup.
|
||||
|
||||
``--coreaudio-exclusive``
|
||||
Deprecated, use ``--audio-exclusive``.
|
||||
Use exclusive mode access. This merely redirects to
|
||||
``coreaudio_exclusive``, but should be preferred over using that AO
|
||||
directly.
|
||||
|
||||
|
||||
``coreaudio_exclusive`` (Mac OS X only)
|
||||
Native Mac OS X audio output driver using direct device access and
|
||||
exclusive mode (bypasses the sound server).
|
||||
``device_id=<id>``
|
||||
ID of output device to use (0 = default device)
|
||||
``help``
|
||||
List all available output devices with their IDs.
|
||||
|
||||
``openal``
|
||||
Experimental OpenAL audio output driver
|
||||
@@ -123,30 +126,38 @@ Available audio output drivers are:
|
||||
``pulse``
|
||||
PulseAudio audio output driver
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--pulse-host=<host>``, ``--pulse-sink=<sink>``
|
||||
``[<host>][:<output sink>]``
|
||||
Specify the host and optionally output sink to use. An empty <host>
|
||||
string uses a local connection, "localhost" uses network transfer
|
||||
(most likely not what you want).
|
||||
Deprecated, use ``--audio-device``.
|
||||
|
||||
``--pulse-buffer=<1-2000|native>``
|
||||
``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. Default: 250.
|
||||
|
||||
``--pulse-latency-hacks=<yes|no>``
|
||||
Enable hacks to workaround PulseAudio timing bugs (default: no). If
|
||||
enabled, mpv will do elaborate latency calculations on its own. If
|
||||
disabled, it will use PulseAudio automatically updated timing
|
||||
information. Disabling this might help with e.g. networked audio or
|
||||
some plugins, while enabling it might help in some unknown situations
|
||||
(it used to be required to get good behavior on old PulseAudio versions).
|
||||
``portaudio``
|
||||
PortAudio audio output driver. This works on all platforms, and has
|
||||
extensive MS Windows support.
|
||||
|
||||
If you have stuttering video when using pulse, try to enable this
|
||||
option. (Or try to update PulseAudio.)
|
||||
.. note:: This driver is not very useful. It was added in the hope of
|
||||
providing portable audio API across all platforms, but turned
|
||||
out semi-broken and underfeatured.
|
||||
|
||||
``device``
|
||||
Specify the subdevice to use. Giving ``help`` as device name lists all
|
||||
devices found by PortAudio. Devices can be given as numeric values,
|
||||
starting from ``1``.
|
||||
|
||||
``dsound`` (Windows only)
|
||||
DirectX DirectSound audio output driver
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``device=<devicenum>``
|
||||
Sets the device number to use. Playing a file with ``-v`` will show a
|
||||
list of available devices.
|
||||
|
||||
``sdl``
|
||||
SDL 1.2+ audio output driver. Should work on any platform supported by SDL
|
||||
@@ -157,70 +168,53 @@ Available audio output drivers are:
|
||||
environments, such as systems where none of the other drivers
|
||||
are available.
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--sdl-buflen=<length>``
|
||||
``buflen=<length>``
|
||||
Sets the audio buffer length in seconds. Is used only as a hint by the
|
||||
sound system. Playing a file with ``-v`` will show the requested and
|
||||
obtained exact buffer size. A value of 0 selects the sound system
|
||||
default.
|
||||
|
||||
``--sdl-bufcnt=<count>``
|
||||
``bufcnt=<count>``
|
||||
Sets the number of extra audio buffers in mpv. Usually needs not be
|
||||
changed.
|
||||
|
||||
``null``
|
||||
Produces no audio output but maintains video playback speed. You can use
|
||||
``--ao=null --ao-null-untimed`` for benchmarking.
|
||||
Produces no audio output but maintains video playback speed. Use
|
||||
``--ao=null:untimed`` for benchmarking.
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-null-untimed``
|
||||
``untimed``
|
||||
Do not simulate timing of a perfect audio device. This means audio
|
||||
decoding will go as fast as possible, instead of timing it to the
|
||||
system clock.
|
||||
|
||||
``--ao-null-buffer``
|
||||
``buffer``
|
||||
Simulated buffer length in seconds.
|
||||
|
||||
``--ao-null-outburst``
|
||||
``outburst``
|
||||
Simulated chunk size in samples.
|
||||
|
||||
``--ao-null-speed``
|
||||
``speed``
|
||||
Simulated audio playback speed as a multiplier. Usually, a real audio
|
||||
device will not go exactly as fast as the system clock. It will deviate
|
||||
just a little, and this option helps to simulate this.
|
||||
just a little, and this option helps simulating this.
|
||||
|
||||
``--ao-null-latency``
|
||||
``latency``
|
||||
Simulated device latency. This is additional to EOF.
|
||||
|
||||
``--ao-null-broken-eof``
|
||||
``broken-eof``
|
||||
Simulate broken audio drivers, which always add the fixed device
|
||||
latency to the reported audio playback position.
|
||||
|
||||
``--ao-null-broken-delay``
|
||||
Simulate broken audio drivers, which don't report latency correctly.
|
||||
|
||||
``--ao-null-channel-layouts``
|
||||
If not empty, this is a ``,`` separated list of channel layouts the
|
||||
AO allows. This can be used to test channel layout selection.
|
||||
|
||||
``pcm``
|
||||
Raw PCM/WAVE file writer audio output
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-pcm-waveheader=<yes|no>``
|
||||
``(no-)waveheader``
|
||||
Include or do not include the WAVE header (default: included). When
|
||||
not included, raw PCM will be generated.
|
||||
``--ao-pcm-file=<filename>``
|
||||
``file=<filename>``
|
||||
Write the sound to ``<filename>`` instead of the default
|
||||
``audiodump.wav``. If ``no-waveheader`` is specified, the default is
|
||||
``audiodump.pcm``.
|
||||
``--ao-pcm-append=<yes|no>``
|
||||
Append to the file, instead of overwriting it. Always use this with the
|
||||
``no-waveheader`` option - with ``waveheader`` it's broken, because
|
||||
it will write a WAVE header every time the file is opened.
|
||||
|
||||
``rsound``
|
||||
Audio output to an RSound daemon
|
||||
@@ -229,19 +223,14 @@ Available audio output drivers are:
|
||||
confused with RoarAudio, which is something completely
|
||||
different.
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--rsound-host=<name/path>``
|
||||
``host=<name/path>``
|
||||
Set the address of the server (default: localhost). Can be either a
|
||||
network hostname for TCP connections or a Unix domain socket path
|
||||
starting with '/'.
|
||||
``--rsound-port=<number>``
|
||||
``port=<number>``
|
||||
Set the TCP port used for connecting to the server (default: 12345).
|
||||
Not used if connecting to a Unix domain socket.
|
||||
|
||||
These options are deprecated. If anyone cares enough, their functionality
|
||||
can be added back using ``--audio-device``.
|
||||
|
||||
``sndio``
|
||||
Audio output to the OpenBSD sndio sound system
|
||||
|
||||
@@ -250,28 +239,25 @@ Available audio output drivers are:
|
||||
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
|
||||
layouts.)
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
|
||||
``--ao-sndio-device=<device>``
|
||||
``device=<device>``
|
||||
sndio device to use (default: ``$AUDIODEVICE``, resp. ``snd0``).
|
||||
Deprecated, use ``--audio-device``.
|
||||
|
||||
``wasapi``
|
||||
Audio output to the Windows Audio Session API.
|
||||
|
||||
The following global options are supported by this audio output:
|
||||
``device=<id>``
|
||||
Uses the requested endpoint instead of the system's default audio
|
||||
endpoint. Both the number and the ID String are valid; the ID String
|
||||
is guaranteed to not change unless the driver is uninstalled.
|
||||
|
||||
``--ao-wasapi-exclusive``
|
||||
Deprecated, use ``--audio-exclusive``.
|
||||
Also supports searching active devices by name. If more than one
|
||||
device matches the name, refuses loading it.
|
||||
|
||||
To get a list of the valid devices, give ``help`` as the id. The
|
||||
list is the same as the ``list`` suboption, but stops the player
|
||||
initialization.
|
||||
``exclusive``
|
||||
Requests exclusive, direct hardware access. By definition prevents
|
||||
sound playback of any other program until mpv exits.
|
||||
``--ao-wasapi-device=<id>``
|
||||
Deprecated, use ``--audio-device``.
|
||||
|
||||
Uses the requested endpoint instead of the system's default audio
|
||||
endpoint. Both an ordinal number (0,1,2,...) and the GUID
|
||||
String are valid; the GUID string is guaranteed to not change
|
||||
unless the driver is uninstalled.
|
||||
|
||||
Also supports searching active devices by human-readable name. If more
|
||||
than one device matches the name, refuses loading it.
|
||||
``list``
|
||||
Lists all audio endpoints (output devices) present in the system.
|
||||
+368
-15
@@ -1,18 +1,371 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
CHANGES FROM OTHER VERSIONS OF MPLAYER
|
||||
======================================
|
||||
|
||||
There is no real changelog, but you can look at the following things:
|
||||
**mpv** is based on mplayer2, which in turn is based on the original MPlayer
|
||||
(also called mplayer, mplayer-svn, mplayer1). Many changes have been made, a
|
||||
large part of which is incompatible or completely changes how the player
|
||||
behaves. Although there are still many similarities to its ancestors, **mpv**
|
||||
should generally be treated as a completely different program.
|
||||
|
||||
* The release changelog, which should contain most user-visible changes,
|
||||
including new features and bug fixes:
|
||||
.. note::
|
||||
These lists are incomplete.
|
||||
|
||||
https://github.com/mpv-player/mpv/releases
|
||||
* The git log, which is the "real" changelog
|
||||
* The files ``client-api-changes.rst`` and ``interface-changes.rst`` in the
|
||||
``DOCS`` sub directoryon the git repository, which document API and user
|
||||
interface changes (the latter usually documents breaking changes only, rather
|
||||
than additions).
|
||||
* The file ``mplayer-changes.rst`` in the ``DOCS`` sub directory on the git
|
||||
repository, which used to be in place of this section. It documents some
|
||||
changes that happened since mplayer2 forked off MPlayer. (Not updated
|
||||
anymore.)
|
||||
General Changes for MPlayer to mpv
|
||||
----------------------------------
|
||||
|
||||
* Switch to GPLv2+. (Technically speaking, MPlayer as a whole seems to be
|
||||
GPLv2-only, while mplayer2 is GPLv3+ - see ``Copyright`` file for details.)
|
||||
* Removal of the internal GUI, MEncoder, OSD menu, video kernel drivers for
|
||||
Linux 2.4 (including VIDIX)
|
||||
* Large internal cleanups
|
||||
* Removal of support for dead platforms
|
||||
* New buildsystem
|
||||
* No embedded copy of ffmpeg and other libraries
|
||||
* Better pause handling (do not unpause on a command)
|
||||
* Better MKV support (such as ordered chapters)
|
||||
* vo_vdpau improvements
|
||||
* Precise seeking support
|
||||
* Native OpenGL backend for OSX
|
||||
* General OSX improvements
|
||||
* Improvements in audio/video sync handling
|
||||
* Cleaned up terminal output
|
||||
* Gapless audio support (``--gapless-audio``)
|
||||
* Improved responsiveness on user input
|
||||
* Support for modifier keys (alt, shift, ctrl) in input.conf
|
||||
* OSS4 volume control
|
||||
* More correct color reproduction (color matrix generation)
|
||||
* Use libass for subtitle rendering by default (better quality)
|
||||
* Generally preferring ffmpeg/libav over internal demuxers and decoders
|
||||
* Improvements when playing multiple files (``--fixed-vo``)
|
||||
* Screenshot improvements (instant screenshots without 1-frame delay, allow
|
||||
taking screenshots even with hardware decoding)
|
||||
* Improved support for PulseAudio
|
||||
* Generally improved MS Windows support (dealing with unicode filenames,
|
||||
improved ``--vo=direct3d``, improved window handling)
|
||||
* Better OSD rendering (using libass). This has full unicode support, and
|
||||
languages like Arabic should be better supported.
|
||||
* Cleaned up terminal output (nicer status line, less useless noise)
|
||||
* Support for playing URLs of popular streaming sites directly
|
||||
(e.g. ``mpv https://www.youtube.com/watch?v=...``)
|
||||
* Improved OpenGL output (``--vo=opengl-hq``)
|
||||
* Make ``--softvol`` default (**mpv** is not a mixer control panel)
|
||||
* Improved support for .cue files
|
||||
* Screenshot improvements (can save screenshots as JPG or PNG, configurable
|
||||
filenames, support for taking screenshots with or without subtitles - the
|
||||
``screenshot`` video filter is not needed anymore, and should not be put
|
||||
into the mpv config file)
|
||||
* Removal of teletext support
|
||||
* Removal of most builtin demuxers, using libavformat instead
|
||||
* Removal of builtin network support, using libavformat instead (also,
|
||||
support https via libavformat)
|
||||
* Replace image VOs (``--vo=jpeg`` etc.) with ``--vo=image``
|
||||
* Do not lose settings when playing a new file in the same player instance
|
||||
* New location for config files, new name for the binary.
|
||||
* Slave mode compatibility broken (see below)
|
||||
* Encoding functionality (replacement for mencoder, see ``DOCS/encoding.rst``)
|
||||
* Remove ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding can
|
||||
handle these use cases. For yuv4mpeg, for example, use:
|
||||
``mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop``.
|
||||
* Image subtitles (DVDs etc.) are rendered in color and use more correct
|
||||
positioning (color can be disabled with ``--sub-gray``)
|
||||
* Wayland support
|
||||
* Support for precise scrolling which scales the parameter of commands. If the
|
||||
input doesn't support precise scrolling the scale factor stays 1.
|
||||
* OSX: Cocoa event loop is independent from mplayer's event loop, so user
|
||||
actions like accessing menus and live resizing do not block the playback.
|
||||
* OSX: Apple Remote support.
|
||||
* OSX: Media Keys support.
|
||||
* Windows: Added WASAPI audio output.
|
||||
* New OSD bar with chapter marks and not positioned in the middle of the video
|
||||
(though this can be customized with the ``--osd-bar-align-y`` option).
|
||||
* Allow customizing whether a key binding for seeking shows the video time, the
|
||||
OSD bar, or nothing (see section `Input Command Prefixes`_).
|
||||
* Display list of chapters and audio/subtitle tracks on OSD (see section
|
||||
`Properties`_).
|
||||
* ``--keep-open`` option to stop the player from closing the window and
|
||||
exiting after playback ends.
|
||||
* Re-enable screensaver while the player is paused.
|
||||
* Matroska edition switching at runtime.
|
||||
* Support for libavfilter (for video->video and audio->audio). This allows
|
||||
using most of FFmpeg's filters, which improve greatly on the old MPlayer
|
||||
filters in features, performance, and correctness.
|
||||
* Improved downmixing and output of surround audio. Instead of using hardcoded
|
||||
pan filters to do remixing, use libavresample. Channel maps are used to
|
||||
identify the channel layout, so e.g. ``3.0`` and ``2.1`` audio can be
|
||||
distinguished.
|
||||
* Allow resuming playback at a later point with ``Shift+q``, also see
|
||||
``quit_watch_later`` input command.
|
||||
* Support mapping multiple commands to one key.
|
||||
* Allow changing/adjusting video filters at runtime. (This is also used to make
|
||||
the ``D`` key insert vf_yadif if deinterlacing is not supported otherwise.)
|
||||
* Native VAAPI support
|
||||
* OSX: VDA support using libavcodec hwaccel API insted of FFmpeg's decoder. Up
|
||||
to 2-2.5x reduction in CPU usage.
|
||||
* Make hardware decoding in general work with the ``opengl`` video output.
|
||||
* Lua scripting (see `LUA SCRIPTING`_)
|
||||
* A client API, that allows embedding **mpv** into applications
|
||||
(see ``libmpv/client.h`` in the sources)
|
||||
* General bug fixes and removal of long-standing issues
|
||||
* General code cleanups (including refactoring or rewrites of many parts)
|
||||
* Many more changes
|
||||
|
||||
Detailed Listing of User-visible Changes
|
||||
----------------------------------------
|
||||
|
||||
This listing is about changed command line switches, slave commands, and similar
|
||||
things. Completely removed features are not listed.
|
||||
|
||||
Command Line Switches
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* There is a new command line syntax, which is generally preferred over the old
|
||||
syntax. ``-optname optvalue`` becomes ``--optname=optvalue``.
|
||||
|
||||
The old syntax will not be removed. However, the new syntax is mentioned in
|
||||
all documentation and so on, and unlike the old syntax is not ambiguous,
|
||||
so it is a good thing to know about this change.
|
||||
* In general, negating switches like ``-noopt`` now have to be written as
|
||||
``-no-opt`` or ``--no-opt``.
|
||||
* Per-file options are not the default anymore. You can explicitly specify
|
||||
file-local options. See ``Usage`` section.
|
||||
* Many options have been renamed, removed or changed semantics. Some options
|
||||
that are required for a good playback experience with MPlayer are now
|
||||
superfluous or even worse than the defaults, so make sure to read the manual
|
||||
before trying to use your existing configuration with **mpv**.
|
||||
* Table of renamed/replaced switches:
|
||||
|
||||
=========================== ========================================
|
||||
Old New
|
||||
=========================== ========================================
|
||||
``-no<opt>`` ``--no-<opt>`` (add a dash)
|
||||
``-a52drc level`` ``--ad-lavc-ac3drc=level``
|
||||
``-ac spdifac3`` ``--ad=spdif:ac3`` (see ``--ad=help``)
|
||||
``-af volnorm`` ``--af=drc`` (renamed)
|
||||
``-afm hwac3`` ``--ad=spdif:ac3,spdif:dts``
|
||||
``-ao alsa:device=hw=0.3`` ``--ao=alsa:device=[hw:0,3]``
|
||||
``-aspect`` ``--video-aspect``
|
||||
``-ass-bottom-margin`` ``--vf=sub=bottom:top``
|
||||
``-ass`` ``--sub-ass``
|
||||
``-audiofile-cache`` (removed; the main cache settings are used)
|
||||
``-audiofile`` ``--audio-file``
|
||||
``-benchmark`` ``--untimed`` (no stats)
|
||||
``-capture`` ``--stream-capture=<filename>``
|
||||
``-channels`` ``--audio-channels`` (changed semantics)
|
||||
``-cursor-autohide-delay`` ``--cursor-autohide``
|
||||
``-delay`` ``--audio-delay``
|
||||
``-dumpstream`` ``--stream-dump=<filename>``
|
||||
``-dvdangle`` ``--dvd-angle``
|
||||
``-endpos`` ``--length``
|
||||
``-font`` ``--osd-font``
|
||||
``-forcedsubsonly`` ``--sub-forced-only``
|
||||
``-forceidx`` ``--index``
|
||||
``-format`` ``--audio-format``
|
||||
``-fsmode-dontuse`` (removed)
|
||||
``-fstype`` ``--x11-netwm`` (changed semantics)
|
||||
``-hardframedrop`` ``--framedrop=hard``
|
||||
``-identify`` (removed; use TOOLS/mpv_identify.sh)
|
||||
``-idx`` ``--index``
|
||||
``-lavdopts ...`` ``--vd-lavc-...``
|
||||
``-lavfdopts`` ``--demuxer-lavf-...``
|
||||
``-lircconf`` ``--input-lirc-conf``
|
||||
``-loop 0`` ``--loop=inf``
|
||||
``-mixer-channel`` AO suboptions (``alsa``, ``oss``)
|
||||
``-mixer`` AO suboptions (``alsa``, ``oss``)
|
||||
``-mouse-movements`` ``--input-cursor``
|
||||
``-msgcolor`` ``--msg-color``
|
||||
``-msglevel`` ``--msg-level`` (changed semantics)
|
||||
``-msgmodule`` ``--msg-module``
|
||||
``-name`` ``--x11-name``
|
||||
``-noar`` ``--no-input-appleremote``
|
||||
``-noautosub`` ``--no-sub-auto``
|
||||
``-noconsolecontrols`` ``--no-input-terminal``
|
||||
``-nojoystick`` ``--no-input-joystick``
|
||||
``-nosound`` ``--no-audio``
|
||||
``-osdlevel`` ``--osd-level``
|
||||
``-panscanrange`` ``--video-zoom``, ``--video-pan-x/y``
|
||||
``-playing-msg`` ``--term-playing-msg``
|
||||
``-pp ...`` ``'--vf=pp=[...]'``
|
||||
``-pphelp`` ``--vf=pp:help``
|
||||
``-rawaudio ...`` ``--demuxer-rawaudio-...``
|
||||
``-rawvideo ...`` ``--demuxer-rawvideo-...``
|
||||
``-spugauss`` ``--sub-gauss``
|
||||
``-srate`` ``--audio-samplerate``
|
||||
``-ss`` ``--start``
|
||||
``-ssf <sub>`` ``--sws-...``
|
||||
``-stop-xscreensaver`` ``--stop-screensaver``
|
||||
``-sub-fuzziness`` ``--sub-auto``
|
||||
``-sub`` ``--sub-file``
|
||||
``-subcp`` ``--sub-codepage``
|
||||
``-subdelay`` ``--sub-delay``
|
||||
``-subfile`` ``--sub-file``
|
||||
``-subfont-*`` ``--sub-text-*``, ``--osd-*``
|
||||
``-subfont-text-scale`` ``--sub-scale``
|
||||
``-subfont`` ``--sub-text-font``
|
||||
``-subfps`` ``--sub-fps``
|
||||
``-subpos`` ``--sub-pos``
|
||||
``-sws`` ``--sws-scaler``
|
||||
``-tvscan`` ``--tv-scan``
|
||||
``-use-filename-title`` ``--title='${filename}'``
|
||||
``-vc ffh264vdpau`` (etc.) ``--hwdec=vdpau``
|
||||
``-vobsub`` ``--sub-file`` (pass the .idx file)
|
||||
``-x W``, ``-y H`` ``--geometry=WxH`` + ``--no-keepaspect``
|
||||
``-xineramascreen`` ``--screen`` (different values)
|
||||
``-xy W`` ``--autofit=W``
|
||||
``-zoom`` Inverse available as ``--video-unscaled``
|
||||
``dvdnav://`` ``dvdnav://menu``
|
||||
``dvd://1`` ``dvd://0`` (0-based offset)
|
||||
=========================== ========================================
|
||||
|
||||
.. note::
|
||||
|
||||
``-opt val`` becomes ``--opt=val``.
|
||||
|
||||
.. note::
|
||||
|
||||
Quite some video filters, video outputs, audio filters, audio outputs, had
|
||||
changes in their option parsing. These aren't mentioned in the table above.
|
||||
|
||||
Also, some video and audio filters have been removed, and you have to use
|
||||
libavfilter (using ``--vf=lavfi=[...]`` or ``--af=lavfi=[...]``) to get
|
||||
them back.
|
||||
|
||||
input.conf and Slave Commands
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Table of renamed input commands:
|
||||
|
||||
This lists only commands that are not always gracefully handled by the
|
||||
internal legacy translation layer. If an input.conf contains any legacy
|
||||
commands, a warning will be printed when starting the player. The warnings
|
||||
also show the replacement commands.
|
||||
|
||||
Properties containing ``_`` to separate words use ``-`` instead.
|
||||
|
||||
+--------------------------------+----------------------------------------+
|
||||
| Old | New |
|
||||
+================================+========================================+
|
||||
| ``pt_step 1 [0|1]`` | ``playlist_next [weak|force]`` |
|
||||
| | (translation layer cannot deal with |
|
||||
| | whitespace) |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``pt_step -1 [0|1]`` | ``playlist_prev [weak|force] (same)`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``switch_ratio [<ratio>]`` | ``set video-aspect <ratio>`` |
|
||||
| | |
|
||||
| | ``set video-aspect 0`` (reset aspect) |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``step_property_osd <prop>`` | ``cycle <prop> <step>`` (wraps), |
|
||||
| ``<step> <dir>`` | ``add <prop> <step>`` (clamps). |
|
||||
| | ``<dir>`` parameter unsupported. Use |
|
||||
| | a negative ``<step>`` instead. |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``step_property <prop>`` | Prefix ``cycle`` or ``add`` with |
|
||||
| ``<step> <dir>`` | ``no-osd``: ``no-osd cycle <prop>`` |
|
||||
| | ``<step>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``osd_show_property_text`` | ``show_text <text>`` |
|
||||
| ``<text>`` | The property expansion format string |
|
||||
| | syntax slightly changed. |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``osd_show_text`` | Now does the same as |
|
||||
| | ``osd_show_property_text``. Use the |
|
||||
| | ``raw`` prefix to disable property |
|
||||
| | expansion. |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``show_tracks`` | ``show_text ${track-list}`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``show_chapters`` | ``show_text ${chapter-list}`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``af_switch``, ``af_add``, ... | ``af set|add|...`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_start_scan`` | ``set tv-scan yes`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_set_channel <val>`` | ``set tv-channel <val>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_step_channel`` | ``cycle tv-channel`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``dvb_set_channel <v1> <v2>`` | ``set dvb-channel <v1>-<v2>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``dvb_step_channel`` | ``cycle dvb-channel`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_set_freq <val>`` | ``set tv-freq <val>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_step_freq`` | ``cycle tv-freq`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_set_norm <norm>`` | ``set tv-norm <norm>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_step_norm`` | ``cycle tv-norm`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
|
||||
.. note::
|
||||
|
||||
Due to lack of hardware and users using the TV/DVB/PVR features, and
|
||||
due to the need to cleanup the related command code, it's possible
|
||||
that the new commands are buggy or behave worse. This can be improved
|
||||
if testers are available. Otherwise, some of the TV code will be
|
||||
removed at some point.
|
||||
|
||||
Slave mode
|
||||
~~~~~~~~~~
|
||||
|
||||
* Slave mode is broken. This mode is entirely insane in the ``old`` versions of
|
||||
MPlayer. A proper slave mode application needed tons of code and hacks to get
|
||||
it right. The main problem is that slave mode is a bad and incomplete
|
||||
interface, and to get around that, applications parsed output messages
|
||||
intended for users. It is hard to know which messages exactly are parsed by
|
||||
slave mode applications. This makes it virtually impossible to improve
|
||||
terminal output intended for users without possibly breaking something.
|
||||
|
||||
This is absolutely insane, and **mpv** will not try to keep slave mode
|
||||
compatible. If you are a developer of a slave mode application, contact us,
|
||||
and a new and better protocol can be developed.
|
||||
|
||||
``--identify`` was already removed (``TOOLS/mpv_identify.sh`` is provided
|
||||
instead), and ``--slave-broken`` might be removed in the future.
|
||||
|
||||
* **mpv** also provides a client API, which can be used to embed the player
|
||||
by loading it as shared library. (See ``libmpv/client.h`` in the sources.)
|
||||
It might also be possible to implement a custom slave mode-like protocol
|
||||
using Lua scripting.
|
||||
|
||||
* A slave protocol is planned, but nothing has emerged yet.
|
||||
|
||||
Policy for Removed Features
|
||||
---------------------------
|
||||
|
||||
**mpv** is in active development. If something is in the way of more important
|
||||
development (such as fixing bugs or implementing new features), we sometimes
|
||||
remove features. Usually this happens only with old features that either seem
|
||||
to be useless, or are not used by anyone. Often these are obscure, or
|
||||
"inherited", or were marked experimental, but never received any particular
|
||||
praise by any users.
|
||||
|
||||
Sometimes, features are replaced by something new. The new code will be either
|
||||
simpler or more powerful, but doesn't necessarily provide everything the old
|
||||
feature did.
|
||||
|
||||
We can not exclude that we accidentally remove features that are actually
|
||||
popular. Generally, we do not know how much a specific functionality is used.
|
||||
If you miss a feature and think it should be re-added, please open an issue
|
||||
on the mpv bug tracker. Hopefully, a solution can be found. Often, it turns
|
||||
out that re-adding something is not much of a problem, or that there are
|
||||
better alternatives.
|
||||
|
||||
Why this Fork?
|
||||
--------------
|
||||
|
||||
mplayer2 is practically dead, and mpv started out as a branch containing
|
||||
new/experimental development. (Some of it was merged right *after* the fork
|
||||
was made public, seemingly as an acknowledgment that development, or at
|
||||
least merging, should have been more active.)
|
||||
|
||||
MPlayer is focused on not breaking anything, but is stuck with a horrible
|
||||
codebase resistant to cleanup. (Unless you do what mpv did - merciless and
|
||||
consequent pruning of bad, old code.) Cleanup and keeping broken things
|
||||
conflict, so the kind of development mpv strives for can't be done within
|
||||
MPlayer due to clashing development policies.
|
||||
|
||||
Additionally, mplayer2 already had lots of changes over MPlayer, which would
|
||||
have needed to be backported to the MPlayer codebase. This would not only
|
||||
have been hard (several years of diverging development), but also would have
|
||||
been impossible due to the aforementioned MPlayer development policy.
|
||||
+7
-7
@@ -38,7 +38,7 @@ You can encode files from one format/codec to another using this facility.
|
||||
|
||||
``--oautofps``
|
||||
Sets the output format time base to the guessed frame rate of the input
|
||||
video (simulates MEncoder behavior, useful for AVI; may cause frame drops).
|
||||
video (simulates mencoder behavior, useful for AVI; may cause frame drops).
|
||||
Note that not all codecs and not all formats support VFR encoding, and some
|
||||
which do have bugs when a target bitrate is specified - use ``--ofps`` or
|
||||
``--oautofps`` to force CFR encoding in these cases.
|
||||
@@ -74,7 +74,7 @@ You can encode files from one format/codec to another using this facility.
|
||||
.. admonition:: Example
|
||||
|
||||
"``--oac=libmp3lame --oacopts=b=128000``"
|
||||
selects 128 kbps MP3 encoding.
|
||||
selects 128kbps MP3 encoding.
|
||||
|
||||
Options are managed in lists. There are a few commands to manage the
|
||||
options list.
|
||||
@@ -93,8 +93,8 @@ You can encode files from one format/codec to another using this facility.
|
||||
Completely empties the options list.
|
||||
|
||||
``--oafirst``
|
||||
Force the audio stream to become the first stream in the output.
|
||||
By default, the order is unspecified.
|
||||
Force the audio stream to become the first stream in the output. By default
|
||||
the order is unspecified.
|
||||
|
||||
``--ovc=<codec>``
|
||||
Specifies the output video codec. This can be a comma separated list of
|
||||
@@ -111,7 +111,7 @@ You can encode files from one format/codec to another using this facility.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``"--ovc=mpeg4 --ovcopts=qscale=5"``
|
||||
``"--ovc=mpeg4 --oacopts=qscale=5"``
|
||||
selects constant quantizer scale 5 for MPEG-4 encoding.
|
||||
|
||||
``"--ovc=libx264 --ovcopts=crf=23"``
|
||||
@@ -134,8 +134,8 @@ You can encode files from one format/codec to another using this facility.
|
||||
Completely empties the options list.
|
||||
|
||||
``--ovfirst``
|
||||
Force the video stream to become the first stream in the output.
|
||||
By default, the order is unspecified.
|
||||
Force the video stream to become the first stream in the output. By default
|
||||
the order is unspecified.
|
||||
|
||||
``--ocopyts``
|
||||
Copies input pts to the output video (not supported by some output
|
||||
|
||||
+319
-1221
File diff suppressed because it is too large.
Load diff
@@ -1,274 +0,0 @@
|
||||
JSON IPC
|
||||
========
|
||||
|
||||
mpv can be controlled by external programs using the JSON-based IPC protocol.
|
||||
It can be enabled by specifying the path to a unix socket or a named pipe using
|
||||
the option ``--input-ipc-server``. Clients can connect to this socket and send
|
||||
commands to the player or receive events from it.
|
||||
|
||||
.. warning::
|
||||
|
||||
This is not intended to be a secure network protocol. It is explicitly
|
||||
insecure: there is no authentication, no encryption, and the commands
|
||||
themselves are insecure too. For example, the ``run`` command is exposed,
|
||||
which can run arbitrary system commands. The use-case is controlling the
|
||||
player locally. This is not different from the MPlayer slave protocol.
|
||||
|
||||
Socat example
|
||||
-------------
|
||||
|
||||
You can use the ``socat`` tool to send commands (and receive replies) from the
|
||||
shell. Assuming mpv was started with:
|
||||
|
||||
::
|
||||
|
||||
mpv file.mkv --input-ipc-server=/tmp/mpvsocket
|
||||
|
||||
Then you can control it using socat:
|
||||
|
||||
::
|
||||
|
||||
> echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpvsocket
|
||||
{"data":190.482000,"error":"success"}
|
||||
|
||||
In this case, socat copies data between stdin/stdout and the mpv socket
|
||||
connection.
|
||||
|
||||
See the ``--idle`` option how to make mpv start without exiting immediately or
|
||||
playing a file.
|
||||
|
||||
It's also possible to send input.conf style text-only commands:
|
||||
|
||||
::
|
||||
|
||||
> echo 'show-text ${playback-time}' | socat - /tmp/mpvsocket
|
||||
|
||||
But you won't get a reply over the socket. (This particular command shows the
|
||||
playback time on the player's OSD.)
|
||||
|
||||
Command Prompt example
|
||||
----------------------
|
||||
|
||||
Unfortunately, it's not as easy to test the IPC protocol on Windows, since
|
||||
Windows ports of socat (in Cygwin and MSYS2) don't understand named pipes. In
|
||||
the absence of a simple tool to send and receive from bidirectional pipes, the
|
||||
``echo`` command can be used to send commands, but not receive replies from the
|
||||
command prompt.
|
||||
|
||||
Assuming mpv was started with:
|
||||
|
||||
::
|
||||
|
||||
mpv file.mkv --input-ipc-server=\\.\pipe\mpvsocket
|
||||
|
||||
You can send commands from a command prompt:
|
||||
|
||||
::
|
||||
|
||||
echo show-text ${playback-time} >\\.\pipe\mpvsocket
|
||||
|
||||
To be able to simultaneously read and write from the IPC pipe, like on Linux,
|
||||
it's necessary to write an external program that uses overlapped file I/O (or
|
||||
some wrapper like .NET's NamedPipeClientStream.)
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
Clients can execute commands on the player by sending JSON messages of the
|
||||
following form:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["command_name", "param1", "param2", ...] }
|
||||
|
||||
where ``command_name`` is the name of the command to be executed, followed by a
|
||||
list of parameters. Parameters must be formatted as native JSON values
|
||||
(integers, strings, booleans, ...). Every message **must** be terminated with
|
||||
``\n``. Additionally, ``\n`` must not appear anywhere inside the message. In
|
||||
practice this means that messages should be minified before being sent to mpv.
|
||||
|
||||
mpv will then send back a reply indicating whether the command was run
|
||||
correctly, and an additional field holding the command-specific return data (it
|
||||
can also be null).
|
||||
|
||||
::
|
||||
|
||||
{ "error": "success", "data": null }
|
||||
|
||||
mpv will also send events to clients with JSON messages of the following form:
|
||||
|
||||
::
|
||||
|
||||
{ "event": "event_name" }
|
||||
|
||||
where ``event_name`` is the name of the event. Additional event-specific fields
|
||||
can also be present. See `List of events`_ for a list of all supported events.
|
||||
|
||||
Because events can occur at any time, it may be difficult at times to determine
|
||||
which response goes with which command. Commands may optionally include a
|
||||
``request_id`` which, if provided in the command request, will be copied
|
||||
verbatim into the response. mpv does not intrepret the ``request_id`` in any
|
||||
way; it is solely for the use of the requester.
|
||||
|
||||
For example, this request:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["get_property", "time-pos"], "request_id": 100 }
|
||||
|
||||
Would generate this response:
|
||||
|
||||
::
|
||||
|
||||
{ "error": "success", "data": 1.468135, "request_id": 100 }
|
||||
|
||||
All commands, replies, and events are separated from each other with a line
|
||||
break character (``\n``).
|
||||
|
||||
If the first character (after skipping whitespace) is not ``{``, the command
|
||||
will be interpreted as non-JSON text command, as they are used in input.conf
|
||||
(or ``mpv_command_string()`` in the client API). Additionally, lines starting
|
||||
with ``#`` and empty lines are ignored.
|
||||
|
||||
Currently, embedded 0 bytes terminate the current line, but you should not
|
||||
rely on this.
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
In addition to the commands described in `List of Input Commands`_, a few
|
||||
extra commands can also be used as part of the protocol:
|
||||
|
||||
``client_name``
|
||||
Return the name of the client as string. This is the string ``ipc-N`` with
|
||||
N being an integer number.
|
||||
|
||||
``get_time_us``
|
||||
Return the current mpv internal time in microseconds as a number. This is
|
||||
basically the system time, with an arbitrary offset.
|
||||
|
||||
``get_property``
|
||||
Return the value of the given property. The value will be sent in the data
|
||||
field of the replay message.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["get_property", "volume"] }
|
||||
{ "data": 50.0, "error": "success" }
|
||||
|
||||
``get_property_string``
|
||||
Like ``get_property``, but the resulting data will always be a string.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["get_property_string", "volume"] }
|
||||
{ "data": "50.000000", "error": "success" }
|
||||
|
||||
``set_property``
|
||||
Set the given property to the given value. See `Properties`_ for more
|
||||
information about properties.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["set_property", "pause", true] }
|
||||
{ "error": "success" }
|
||||
|
||||
``set_property_string``
|
||||
Like ``set_property``, but the argument value must be passed as string.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["set_property_string", "pause", "yes"] }
|
||||
{ "error": "success" }
|
||||
|
||||
``observe_property``
|
||||
Watch a property for changes. If the given property is changed, then an
|
||||
event of type ``property-change`` will be generated
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["observe_property", 1, "volume"] }
|
||||
{ "error": "success" }
|
||||
{ "event": "property-change", "id": 1, "data": 52.0, "name": "volume" }
|
||||
|
||||
``observe_property_string``
|
||||
Like ``observe_property``, but the resulting data will always be a string.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["observe_property_string", 1, "volume"] }
|
||||
{ "error": "success" }
|
||||
{ "event": "property-change", "id": 1, "data": "52.000000", "name": "volume" }
|
||||
|
||||
``unobserve_property``
|
||||
Undo ``observe_property`` or ``observe_property_string``. This requires the
|
||||
numeric id passed to the observed command as argument.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ "command": ["unobserve_property", 1] }
|
||||
{ "error": "success" }
|
||||
|
||||
``request_log_messages``
|
||||
Enable output of mpv log messages. They will be received as events. The
|
||||
parameter to this command is the log-level (see ``mpv_request_log_messages``
|
||||
C API function).
|
||||
|
||||
Log message output is meant for humans only (mostly for debugging).
|
||||
Attempting to retrieve information by parsing these messages will just
|
||||
lead to breakages with future mpv releases. Instead, make a feature request,
|
||||
and ask for a proper event that returns the information you need.
|
||||
|
||||
``enable_event``, ``disable_event``
|
||||
Enables or disables the named event. Mirrors the ``mpv_request_event`` C
|
||||
API function. If the string ``all`` is used instead of an event name, all
|
||||
events are enabled or disabled.
|
||||
|
||||
By default, most events are enabled, and there is not much use for this
|
||||
command.
|
||||
|
||||
``suspend``
|
||||
Deprecated, will be removed completely in 0.21.0.
|
||||
|
||||
Suspend the mpv main loop. There is a long-winded explanation of this in
|
||||
the C API function ``mpv_suspend()``. In short, this prevents the player
|
||||
from displaying the next video frame, so that you don't get blocked when
|
||||
trying to access the player.
|
||||
|
||||
``resume``
|
||||
Deprecated, will be removed completely in 0.21.0.
|
||||
|
||||
Undo one ``suspend`` call. ``suspend`` increments an internal counter, and
|
||||
``resume`` decrements it. When 0 is reached, the player is actually resumed.
|
||||
|
||||
``get_version``
|
||||
Returns the client API version the C API of the remote mpv instance
|
||||
provides.
|
||||
|
||||
See also: ``DOCS/client-api-changes.rst``.
|
||||
|
||||
UTF-8
|
||||
-----
|
||||
|
||||
Normally, all strings are in UTF-8. Sometimes it can happen that strings are
|
||||
in some broken encoding (often happens with file tags and such, and filenames
|
||||
on many Unixes are not required to be in UTF-8 either). This means that mpv
|
||||
sometimes sends invalid JSON. If that is a problem for the client application's
|
||||
parser, it should filter the raw data for invalid UTF-8 sequences and perform
|
||||
the desired replacement, before feeding the data to its JSON parser.
|
||||
|
||||
mpv will not attempt to construct invalid UTF-8 with broken escape sequences.
|
||||
@@ -1,16 +0,0 @@
|
||||
EMBEDDING INTO OTHER PROGRAMS (LIBMPV)
|
||||
======================================
|
||||
|
||||
mpv can be embedded into other programs as video/audio playback backend. The
|
||||
recommended way to do so is using libmpv. See ``libmpv/client.h`` in the mpv
|
||||
source code repository. This provides a C API. Bindings for other languages
|
||||
might be available (see wiki).
|
||||
|
||||
Since libmpv merely allows access to underlying mechanisms that can control
|
||||
mpv, further documentation is spread over a few places:
|
||||
|
||||
- https://github.com/mpv-player/mpv/blob/master/libmpv/client.h
|
||||
- http://mpv.io/manual/master/#options
|
||||
- http://mpv.io/manual/master/#list-of-input-commands
|
||||
- http://mpv.io/manual/master/#properties
|
||||
- https://github.com/mpv-player/mpv-examples/tree/master/libmpv
|
||||
+84
-284
@@ -1,16 +1,10 @@
|
||||
LUA SCRIPTING
|
||||
=============
|
||||
|
||||
mpv can load Lua scripts. Scripts passed to the ``--script`` option, or found in
|
||||
the ``scripts`` subdirectory of the mpv configuration directory (usually
|
||||
``~/.config/mpv/scripts/``) will be loaded on program start. mpv also appends the
|
||||
``scripts`` subdirectory to the end of Lua's path so you can import scripts from
|
||||
there too. Since it's added to the end, don't name scripts you want to import
|
||||
the same as Lua libraries because they will be overshadowed by them.
|
||||
|
||||
mpv provides the built-in module ``mp``, which contains functions to send
|
||||
commands to the mpv core and to retrieve information about playback state, user
|
||||
settings, file information, and so on.
|
||||
mpv can load Lua scripts. Scripts in ``~/.mpv/lua/`` will be loaded on program
|
||||
start, or if passed to ``--lua``. mpv provides the builtin module ``mp``, which
|
||||
provides functions to send commands to the mpv core and to retrieve information
|
||||
about playback state, user settings, file information, and so on.
|
||||
|
||||
These scripts can be used to control mpv in a similar way to slave mode.
|
||||
Technically, the Lua code uses the client API internally.
|
||||
@@ -22,24 +16,23 @@ A script which leaves fullscreen mode when the player is paused:
|
||||
|
||||
::
|
||||
|
||||
function on_pause_change(name, value)
|
||||
if value == true then
|
||||
mp.set_property("fullscreen", "no")
|
||||
end
|
||||
function on_pause()
|
||||
mp.set_property("fullscreen", "no")
|
||||
end
|
||||
mp.observe_property("pause", "bool", on_pause_change)
|
||||
mp.register_event("pause", on_pause)
|
||||
|
||||
This script provides a pretty weird feature, but Lua scripting was made to
|
||||
allow users implement features which are not going to be added to the mpv core.
|
||||
|
||||
Details on the script initialization and lifecycle
|
||||
--------------------------------------------------
|
||||
Mode of operation
|
||||
-----------------
|
||||
|
||||
Your script will be loaded by the player at program start from the ``scripts``
|
||||
configuration subdirectory, or from a path specified with the ``--script``
|
||||
option. Some scripts are loaded internally (like ``--osc``). Each script runs in
|
||||
its own thread. Your script is first run "as is", and once that is done, the event loop
|
||||
is entered. This event loop will dispatch events received by mpv and call your
|
||||
own event handlers which you have registered with ``mp.register_event``, or
|
||||
timers added with ``mp.add_timeout`` or similar.
|
||||
Your script will be loaded by the player at program start from ``~/.mpv/lua/``,
|
||||
or ``--lua``, or in some cases, internally (like ``--osc``). Each script runs
|
||||
in its own thread. Your script is first run "as is", and once that is done,
|
||||
the event loop is entered. This event loop will dispatch events received by mpv
|
||||
and call your own event handlers which you have registered with
|
||||
``mp.register_event``, or timers added with ``mp.add_timeout`` or similar.
|
||||
|
||||
When the player quits, all scripts will be asked to terminate. This happens via
|
||||
a ``shutdown`` event, which by default will make the event loop return. If your
|
||||
@@ -54,15 +47,6 @@ The event loop will wait for events and dispatch events registered with
|
||||
``mp.register_event``. It will also handle timers added with ``mp.add_timeout``
|
||||
and similar (by waiting with a timeout).
|
||||
|
||||
Since mpv 0.6.0, the player will wait until the script is fully loaded before
|
||||
continuing normal operation. The player considers a script as fully loaded as
|
||||
soon as it starts waiting for mpv events (or it exits). In practice this means
|
||||
the player will more or less hang until the script returns from the main chunk
|
||||
(and ``mp_event_loop`` is called), or the script calls ``mp_event_loop`` or
|
||||
``mp.dispatch_events`` directly. This is done to make it possible for a script
|
||||
to fully setup event handlers etc. before playback actually starts. In older
|
||||
mpv versions, this happened asynchronously.
|
||||
|
||||
mp functions
|
||||
------------
|
||||
|
||||
@@ -73,10 +57,6 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
Run the given command. This is similar to the commands used in input.conf.
|
||||
See `List of Input Commands`_.
|
||||
|
||||
By default, this will show something on the OSD (depending on the command),
|
||||
as if it was used in ``input.conf``. See `Input Command Prefixes`_ how
|
||||
to influence OSD usage per command.
|
||||
|
||||
Returns ``true`` on success, or ``nil, error`` on error.
|
||||
|
||||
``mp.commandv(arg1, arg2, ...)``
|
||||
@@ -94,22 +74,6 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
These two commands are equivalent, except that the first version breaks
|
||||
if the filename contains spaces or certain special characters.
|
||||
|
||||
Note that properties are *not* expanded. You can use either ``mp.command``,
|
||||
the ``expand-properties`` prefix, or the ``mp.get_property`` family of
|
||||
functions.
|
||||
|
||||
Unlike ``mp.command``, this will not use OSD by default either (except
|
||||
for some OSD-specific commands).
|
||||
|
||||
``mp.command_native(table [,def])``
|
||||
Similar to ``mp.commandv``, but pass the argument list as table. This has
|
||||
the advantage that in at least some cases, arguments can be passed as
|
||||
native types.
|
||||
|
||||
Returns a result table on success (usually empty), or ``def, error`` on
|
||||
error. ``def`` is the second parameter provided to the function, and is
|
||||
nil if it's missing.
|
||||
|
||||
``mp.get_property(name [,def])``
|
||||
Return the value of the given property as string. These are the same
|
||||
properties as used in input.conf. See `Properties`_ for a list of
|
||||
@@ -130,9 +94,9 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
will always result in a string.
|
||||
|
||||
``mp.get_property_bool(name [,def])``
|
||||
Similar to ``mp.get_property``, but return the property value as Boolean.
|
||||
Similar to ``mp.get_property``, but return the property value as boolean.
|
||||
|
||||
Returns a Boolean on success, or ``def, error`` on error.
|
||||
Returns a boolean on success, or ``def, error`` on error.
|
||||
|
||||
``mp.get_property_number(name [,def])``
|
||||
Similar to ``mp.get_property``, but return the property value as number.
|
||||
@@ -145,7 +109,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
|
||||
``mp.get_property_native(name [,def])``
|
||||
Similar to ``mp.get_property``, but return the property value using the best
|
||||
Lua type for the property. Most time, this will return a string, Boolean,
|
||||
Lua type for the property. Most time, this will return a string, boolean,
|
||||
or number. Some properties (for example ``chapter-list``) are returned as
|
||||
tables.
|
||||
|
||||
@@ -160,7 +124,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
|
||||
``mp.set_property_bool(name, value)``
|
||||
Similar to ``mp.set_property``, but set the given property to the given
|
||||
Boolean value.
|
||||
boolean value.
|
||||
|
||||
``mp.set_property_number(name, value)``
|
||||
Similar to ``mp.set_property``, but set the given property to the given
|
||||
@@ -175,7 +139,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
Similar to ``mp.set_property``, but set the given property using its native
|
||||
type.
|
||||
|
||||
Since there are several data types which cannot represented natively in
|
||||
Since there are several data types which can not represented natively in
|
||||
Lua, this might not always work as expected. For example, while the Lua
|
||||
wrapper can do some guesswork to decide whether a Lua table is an array
|
||||
or a map, this would fail with empty tables. Also, there are not many
|
||||
@@ -188,41 +152,25 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
Return the current mpv internal time in seconds as a number. This is
|
||||
basically the system time, with an arbitrary offset.
|
||||
|
||||
``mp.add_key_binding(key, name|fn [,fn [,flags]])``
|
||||
``mp.add_key_binding(key, name|fn [,fn])``
|
||||
Register callback to be run on a key binding. The binding will be mapped to
|
||||
the given ``key``, which is a string describing the physical key. This uses
|
||||
the same key names as in input.conf, and also allows combinations
|
||||
(e.g. ``ctrl+a``). If the key is empty or ``nil``, no physical key is
|
||||
registered, but the user still can create own bindings (see below).
|
||||
(e.g. ``ctrl+a``).
|
||||
|
||||
After calling this function, key presses will cause the function ``fn`` to
|
||||
be called (unless the user remapped the key with another binding).
|
||||
be called (unless the user overmapped the key with another binding).
|
||||
|
||||
The ``name`` argument should be a short symbolic string. It allows the user
|
||||
to remap the key binding via input.conf using the ``script-message``
|
||||
to remap the key binding via input.conf using the ``script_message``
|
||||
command, and the name of the key binding (see below for
|
||||
an example). The name should be unique across other bindings in the same
|
||||
script - if not, the previous binding with the same name will be
|
||||
overwritten. You can omit the name, in which case a random name is generated
|
||||
internally.
|
||||
|
||||
The last argument is used for optional flags. This is a table, which can
|
||||
have the following entries:
|
||||
|
||||
``repeatable``
|
||||
If set to ``true``, enables key repeat for this specific binding.
|
||||
|
||||
``complex``
|
||||
If set to ``true``, then ``fn`` is called on both key up and down
|
||||
events (as well as key repeat, if enabled), with the first
|
||||
argument being a table. This table has an ``event`` entry, which
|
||||
is set to one of the strings ``down``, ``repeat``, ``up`` or
|
||||
``press`` (the latter if key up/down can't be tracked). It further
|
||||
has an ``is_mouse`` entry, which tells whether the event was caused
|
||||
by a mouse button.
|
||||
|
||||
Internally, key bindings are dispatched via the ``script-message-to`` or
|
||||
``script-binding`` input commands and ``mp.register_script_message``.
|
||||
Internally, key bindings are dispatched via the ``script_message_to`` input
|
||||
command and ``mp.register_script_message``.
|
||||
|
||||
Trying to map multiple commands to a key will essentially prefer a random
|
||||
binding, while the other bindings are not called. It is guaranteed that
|
||||
@@ -245,18 +193,18 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
|
||||
::
|
||||
|
||||
y script-binding something
|
||||
y script_message something
|
||||
|
||||
|
||||
This will print the message when the key ``y`` is pressed. (``x`` will
|
||||
still work, unless the user remaps it.)
|
||||
still work, unless the user overmaps it.)
|
||||
|
||||
You can also explicitly send a message to a named script only. Assume the
|
||||
above script was using the filename ``fooscript.lua``:
|
||||
|
||||
::
|
||||
|
||||
y script-binding fooscript/something
|
||||
y script_message_to fooscript something
|
||||
|
||||
``mp.add_forced_key_binding(...)``
|
||||
This works almost the same as ``mp.add_key_binding``, but registers the
|
||||
@@ -334,6 +282,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
the timer is re-added after the function fn is run.
|
||||
|
||||
Returns a timer object. The timer object provides the following methods:
|
||||
|
||||
``stop()``
|
||||
Disable the timer. Does nothing if the timer is already disabled.
|
||||
This will remember the current elapsed time when stopping, so that
|
||||
@@ -350,51 +299,16 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
with ``add_timeout()``), this starts the timer from the beginning,
|
||||
using the initially configured timeout.
|
||||
|
||||
``is_enabled()``
|
||||
Whether the timer is currently enabled or was previously disabled
|
||||
(e.g. by ``stop()`` or ``kill()``).
|
||||
|
||||
``timeout`` (RW)
|
||||
This field contains the current timeout period. This value is not
|
||||
updated as time progresses. It's only used to calculate when the
|
||||
timer should fire next when the timer expires.
|
||||
|
||||
If you write this, you can call ``t:kill() ; t:resume()`` to reset
|
||||
the current timeout to the new one. (``t:stop()`` won't use the
|
||||
new timeout.)
|
||||
|
||||
``oneshot`` (RW)
|
||||
Whether the timer is periodic (``false``) or fires just once
|
||||
(``true``). This value is used when the timer expires (but before
|
||||
the timer callback function fn is run).
|
||||
|
||||
Note that these are method, and you have to call them using ``:`` instead
|
||||
of ``.`` (Refer to http://www.lua.org/manual/5.2/manual.html#3.4.9 .)
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
seconds = 0
|
||||
timer = mp.add_periodic_timer(1, function()
|
||||
print("called every second")
|
||||
# stop it after 10 seconds
|
||||
seconds = seconds + 1
|
||||
if seconds >= 10 then
|
||||
timer:kill()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
``mp.get_opt(key)``
|
||||
Return a setting from the ``--script-opts`` option. It's up to the user and
|
||||
Return a setting from the ``--lua-opts`` option. It's up to the user and
|
||||
the script how this mechanism is used. Currently, all scripts can access
|
||||
this equally, so you should be careful about collisions.
|
||||
|
||||
``mp.get_script_name()``
|
||||
Return the name of the current script. The name is usually made of the
|
||||
filename of the script, with directory and file extension removed. If
|
||||
there are several scripts which would have the same name, it's made unique
|
||||
there are several script which would have the same name, it's made unique
|
||||
by appending a number.
|
||||
|
||||
.. admonition:: Example
|
||||
@@ -412,28 +326,26 @@ These also live in the ``mp`` module, but are documented separately as they
|
||||
are useful only in special situations.
|
||||
|
||||
``mp.suspend()``
|
||||
This function has been deprecated in mpv 0.21.0 (no replacement).
|
||||
|
||||
Suspend the mpv main loop. There is a long-winded explanation of this in
|
||||
the C API function ``mpv_suspend()``. In short, this prevents the player
|
||||
from displaying the next video frame, so that you don't get blocked when
|
||||
trying to access the player.
|
||||
|
||||
Before mpv 0.17.0, this was automatically called by the event handler.
|
||||
This is automatically called by the event handler.
|
||||
|
||||
``mp.resume()``
|
||||
This function has been deprecated in mpv 0.21.0 (no replacement).
|
||||
|
||||
Undo one ``mp.suspend()`` call. ``mp.suspend()`` increments an internal
|
||||
counter, and ``mp.resume()`` decrements it. When 0 is reached, the player
|
||||
is actually resumed.
|
||||
|
||||
``mp.resume_all()``
|
||||
This function has been deprecated in mpv 0.21.0 (no replacement).
|
||||
|
||||
This resets the internal suspend counter and resumes the player. (It's
|
||||
like calling ``mp.resume()`` until the player is actually resumed.)
|
||||
|
||||
You might want to call this if you're about to do something that takes a
|
||||
long time, but doesn't really need access to the player (like a network
|
||||
operation). Note that you still can access the player at any time.
|
||||
|
||||
``mp.get_wakeup_pipe()``
|
||||
Calls ``mpv_get_wakeup_pipe()`` and returns the read end of the wakeup
|
||||
pipe. (See ``client.h`` for details.)
|
||||
@@ -447,7 +359,7 @@ are useful only in special situations.
|
||||
control what the Lua script does (instead of being called by the default
|
||||
event loop), you can set the global variable ``mp_event_loop`` to your
|
||||
own function running the event loop. From your event loop, you should call
|
||||
``mp.dispatch_events()`` to dequeue and dispatch mpv events.
|
||||
``mp.dispatch_events()`` to unqueue and dispatch mpv events.
|
||||
|
||||
If the ``allow_wait`` parameter is set to ``true``, the function will block
|
||||
until the next event is received or the next timer expires. Otherwise (and
|
||||
@@ -456,12 +368,7 @@ are useful only in special situations.
|
||||
``mp.get_wakeup_pipe()`` if you're interested in properly working
|
||||
notification of new events and working timers.
|
||||
|
||||
``mp.register_idle(fn)``
|
||||
Register an event loop idle handler. Idle handlers are called before the
|
||||
script goes to sleep after handling all new events. This can be used for
|
||||
example to delay processing of property change events: if you're observing
|
||||
multiple properties at once, you might not want to act on each property
|
||||
change, but only when all change notifications have been received.
|
||||
This function calls ``mp.suspend()`` and ``mp.resume_all()`` on its own.
|
||||
|
||||
``mp.enable_messages(level)``
|
||||
Set the minimum log level of which mpv message output to receive. These
|
||||
@@ -471,9 +378,9 @@ are useful only in special situations.
|
||||
The level is a string, see ``msg.log`` for allowed log levels.
|
||||
|
||||
``mp.register_script_message(name, fn)``
|
||||
This is a helper to dispatch ``script-message`` or ``script-message-to``
|
||||
invocations to Lua functions. ``fn`` is called if ``script-message`` or
|
||||
``script-message-to`` (with this script as destination) is run
|
||||
This is a helper to dispatch ``script_message`` or ``script_message_to``
|
||||
invocations to Lua functions. ``fn`` is called if ``script_message`` or
|
||||
``script_message_to`` (with this script as destination) is run
|
||||
with ``name`` as first parameter. The other parameters are passed to ``fn``.
|
||||
If a message with the given name is already registered, it's overwritten.
|
||||
|
||||
@@ -530,8 +437,8 @@ Example implementation::
|
||||
optionB = -0.5,
|
||||
optionC = true,
|
||||
}
|
||||
read_options(options, "myscript")
|
||||
print(options.optionA)
|
||||
options.read_options(options, "myscript")
|
||||
print(option.optionA)
|
||||
|
||||
|
||||
The config file will be stored in ``lua-settings/identifier.conf`` in mpv's user
|
||||
@@ -546,28 +453,21 @@ Example config::
|
||||
optionC=no
|
||||
|
||||
|
||||
Command-line options are read from the ``--script-opts`` parameter. To avoid
|
||||
Command-line options are read from the ``--lua-opts`` parameter. To avoid
|
||||
collisions, all keys have to be prefixed with ``identifier-``.
|
||||
|
||||
Example command-line::
|
||||
|
||||
--script-opts=myscript-optionA=TEST,myscript-optionB=0,myscript-optionC=yes
|
||||
--lua-opts=myscript-optionA=TEST:myscript-optionB=0:myscript-optionC=yes
|
||||
|
||||
|
||||
mp.utils functions
|
||||
------------------
|
||||
mp.utils options
|
||||
----------------
|
||||
|
||||
This built-in module provides generic helper functions for Lua, and have
|
||||
strictly speaking nothing to do with mpv or video/audio playback. They are
|
||||
provided for convenience. Most compensate for Lua's scarce standard library.
|
||||
|
||||
Be warned that any of these functions might disappear any time. They are not
|
||||
strictly part of the guaranteed API.
|
||||
|
||||
``utils.getcwd()``
|
||||
Returns the directory that mpv was launched from. On error, ``nil, error``
|
||||
is returned.
|
||||
|
||||
``utils.readdir(path [, filter])``
|
||||
Enumerate all entries at the given path on the filesystem, and return them
|
||||
as array. Each entry is a directory entry (without the path).
|
||||
@@ -604,85 +504,6 @@ strictly part of the guaranteed API.
|
||||
Return the concatenation of the 2 paths. Tries to be clever. For example,
|
||||
if ```p2`` is an absolute path, p2 is returned without change.
|
||||
|
||||
``utils.subprocess(t)``
|
||||
Runs an external process and waits until it exits. Returns process status
|
||||
and the captured output.
|
||||
|
||||
The parameter ``t`` is a table. The function reads the following entries:
|
||||
|
||||
``args``
|
||||
Array of strings. The first array entry is the executable. This
|
||||
can be either an absolute path, or a filename with no path
|
||||
components, in which case the ``PATH`` environment variable is
|
||||
used to resolve the executable. The other array elements are
|
||||
passed as command line arguments.
|
||||
|
||||
``cancellable``
|
||||
Optional. If set to ``true`` (default), then if the user stops
|
||||
playback or goes to the next file while the process is running,
|
||||
the process will be killed.
|
||||
|
||||
``max_size``
|
||||
Optional. The maximum size in bytes of the data that can be captured
|
||||
from stdout. (Default: 16 MB.)
|
||||
|
||||
The function returns a table as result with the following entries:
|
||||
|
||||
``status``
|
||||
The raw exit status of the process. It will be negative on error.
|
||||
|
||||
``stdout``
|
||||
Captured output stream as string, limited to ``max_size``.
|
||||
|
||||
``error``
|
||||
``nil`` on success. The string ``killed`` if the process was
|
||||
terminated in an unusual way. The string ``init`` if the process
|
||||
could not be started.
|
||||
|
||||
On Windows, ``killed`` is only returned when the process has been
|
||||
killed by mpv as a result of ``cancellable`` being set to ``true``.
|
||||
|
||||
``killed_by_us``
|
||||
Set to ``true`` if the process has been killed by mpv as a result
|
||||
of ``cancellable`` being set to ``true``.
|
||||
|
||||
``utils.subprocess_detached(t)``
|
||||
Runs an external process and detaches it from mpv's control.
|
||||
|
||||
The parameter ``t`` is a table. The function reads the following entries:
|
||||
|
||||
``args``
|
||||
Array of strings of the same semantics as the ``args`` used in the
|
||||
``subprocess`` function.
|
||||
|
||||
The function returns ``nil``.
|
||||
|
||||
``utils.parse_json(str [, trail])``
|
||||
Parses the given string argument as JSON, and returns it as a Lua table. On
|
||||
error, returns ``nil, error``. (Currently, ``error`` is just a string
|
||||
reading ``error``, because there is no fine-grained error reporting of any
|
||||
kind.)
|
||||
|
||||
The returned value uses similar conventions as ``mp.get_property_native()``
|
||||
to distinguish empty objects and arrays.
|
||||
|
||||
If the ``trail`` parameter is ``true`` (or any value equal to ``true``),
|
||||
then trailing non-whitespace text is tolerated by the function, and the
|
||||
trailing text is returned as 3rd return value. (The 3rd return value is
|
||||
always there, but with ``trail`` set, no error is raised.)
|
||||
|
||||
``utils.format_json(v)``
|
||||
Format the given Lua table (or value) as a JSON string and return it. On
|
||||
error, returns ``nil, error``. (Errors usually only happen on value types
|
||||
incompatible with JSON.)
|
||||
|
||||
The argument value uses similar conventions as ``mp.set_property_native()``
|
||||
to distinguish empty objects and arrays.
|
||||
|
||||
``utils.to_string(v)``
|
||||
Turn the given value into a string. Formats tables and their contents. This
|
||||
doesn't do anything special; it is only needed because Lua is terrible.
|
||||
|
||||
Events
|
||||
------
|
||||
|
||||
@@ -700,7 +521,7 @@ Example:
|
||||
print("start of playback!")
|
||||
end
|
||||
|
||||
mp.register_event("file-loaded", my_fn)
|
||||
mp.register_event("playback-start", my_fn)
|
||||
|
||||
|
||||
|
||||
@@ -715,49 +536,37 @@ List of events
|
||||
Happens after a file was unloaded. Typically, the player will load the
|
||||
next file right away, or quit if this was the last file.
|
||||
|
||||
The event has the ``reason`` field, which takes one of these values:
|
||||
|
||||
``eof``
|
||||
The file has ended. This can (but doesn't have to) include
|
||||
incomplete files or broken network connections under
|
||||
circumstances.
|
||||
|
||||
``stop``
|
||||
Playback was ended by a command.
|
||||
|
||||
``quit``
|
||||
Playback was ended by sending the quit command.
|
||||
|
||||
``error``
|
||||
An error happened. In this case, an ``error`` field is present with
|
||||
the error string.
|
||||
|
||||
``redirect``
|
||||
Happens with playlists and similar. Details see
|
||||
``MPV_END_FILE_REASON_REDIRECT`` in the C API.
|
||||
|
||||
``unknown``
|
||||
Unknown. Normally doesn't happen, unless the Lua API is out of sync
|
||||
with the C API. (Likewise, it could happen that your script gets
|
||||
reason strings that did not exist yet at the time your script was
|
||||
written.)
|
||||
|
||||
``file-loaded``
|
||||
Happens after a file was loaded and begins playback.
|
||||
|
||||
``seek``
|
||||
Happens on seeking. (This might include cases when the player seeks
|
||||
internally, even without user interaction. This includes e.g. segment
|
||||
changes when playing ordered chapters Matroska files.)
|
||||
Happens on seeking (including ordered chapter segment changes).
|
||||
|
||||
``playback-restart``
|
||||
Start of playback after seek or after file was loaded.
|
||||
|
||||
``tracks-changed``
|
||||
The list of video/audio/sub tracks was updated. (This happens on playback
|
||||
start, and very rarely during playback.)
|
||||
|
||||
``track-switched``
|
||||
A video/audio/subtitle track was switched on or off. This usually happens
|
||||
when the user (or a script) changes the subtitle track and so on.
|
||||
|
||||
``idle``
|
||||
Idle mode is entered. This happens when playback ended, and the player was
|
||||
started with ``--idle`` or ``--force-window``. This mode is implicitly ended
|
||||
when the ``start-file`` or ``shutdown`` events happen.
|
||||
|
||||
``pause``
|
||||
Playback was paused. This also happens when for example the player is
|
||||
paused on low network cache. Then the event type indicates the pause state
|
||||
(like the property "pause" as opposed to the "core-idle" property), and you
|
||||
might receive multiple ``pause`` events in a row.
|
||||
|
||||
``unpause``
|
||||
Playback was unpaused. See above for details.
|
||||
|
||||
``tick``
|
||||
Called after a video frame was displayed. This is a hack, and you should
|
||||
avoid using it. Use timers instead and maybe watch pausing/unpausing events
|
||||
@@ -765,7 +574,7 @@ List of events
|
||||
|
||||
``shutdown``
|
||||
Sent when the player quits, and the script should terminate. Normally
|
||||
handled automatically. See `Details on the script initialization and lifecycle`_.
|
||||
handled automatically. See `Mode of operation`_.
|
||||
|
||||
``log-message``
|
||||
Receives messages enabled with ``mp.enable_messages``. The message data
|
||||
@@ -784,8 +593,13 @@ List of events
|
||||
(undocumented) existing ones.
|
||||
|
||||
``text``
|
||||
The log message. The text will end with a newline character. Sometimes
|
||||
it can contain multiple lines.
|
||||
The log message. Note that this is the direct output of a printf()
|
||||
style output API. The text will contain embedded newlines, and it's
|
||||
possible that a single message contains multiple lines, or that a
|
||||
message contains a partial line.
|
||||
|
||||
It's safe to display messages only if they end with a newline character,
|
||||
and to buffer them otherwise.
|
||||
|
||||
Keep in mind that these messages are meant to be hints for humans. You
|
||||
should not parse them, and prefix/level/text of messages might change
|
||||
@@ -800,6 +614,9 @@ List of events
|
||||
``command-reply``
|
||||
Undocumented (not useful for Lua scripts).
|
||||
|
||||
``script-input-dispatch``
|
||||
Undocumented (used internally).
|
||||
|
||||
``client-message``
|
||||
Undocumented (used internally).
|
||||
|
||||
@@ -809,25 +626,8 @@ List of events
|
||||
``audio-reconfig``
|
||||
Happens on audio output or filter reconfig.
|
||||
|
||||
The following events also happen, but are deprecated: ``tracks-changed``,
|
||||
``track-switched``, ``pause``, ``unpause``, ``metadata-update``,
|
||||
``chapter-change``. Use ``mp.observe_property()`` instead.
|
||||
``metadata-update``
|
||||
Metadata (like file tags) was updated.
|
||||
|
||||
Extras
|
||||
------
|
||||
|
||||
This documents experimental features, or features that are "too special" to
|
||||
guarantee a stable interface.
|
||||
|
||||
``mp.add_hook(type, priority, fn)``
|
||||
Add a hook callback for ``type`` (a string identifying a certain kind of
|
||||
hook). These hooks allow the player to call script functions and wait for
|
||||
their result (normally, the Lua scripting interface is asynchronous from
|
||||
the point of view of the player core). ``priority`` is an arbitrary integer
|
||||
that allows ordering among hooks of the same kind. Using the value 50 is
|
||||
recommended as neutral default value. ``fn`` is the function that will be
|
||||
called during execution of the hook.
|
||||
|
||||
See `Hooks`_ for currently existing hooks and what they do - only the hook
|
||||
list is interesting; handling hook execution is done by the Lua script
|
||||
function automatically.
|
||||
``chapter-change``
|
||||
The current chapter possibly changed.
|
||||
+152
-435
@@ -2,7 +2,7 @@ mpv
|
||||
###
|
||||
|
||||
##############
|
||||
a media player
|
||||
a movie player
|
||||
##############
|
||||
|
||||
:Copyright: GPLv2+
|
||||
@@ -12,13 +12,14 @@ a media player
|
||||
SYNOPSIS
|
||||
========
|
||||
|
||||
| **mpv** [options] [file|URL|PLAYLIST|-]
|
||||
| **mpv** [options] [file|URL|-]
|
||||
| **mpv** [options] --playlist=PLAYLIST
|
||||
| **mpv** [options] files
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
**mpv** is a media player based on MPlayer and mplayer2. It supports a wide variety of video
|
||||
**mpv** is a movie player based on MPlayer and mplayer2. It supports a wide variety of video
|
||||
file formats, audio and video codecs, and subtitle types. Special input URL
|
||||
types are available to read input from a variety of sources other than disk
|
||||
files. Depending on platform, a variety of different video and audio output
|
||||
@@ -32,29 +33,22 @@ INTERACTIVE CONTROL
|
||||
===================
|
||||
|
||||
mpv has a fully configurable, command-driven control layer which allows you
|
||||
to control mpv using keyboard, mouse, or remote control (there is no
|
||||
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`` for
|
||||
a list of default bindings. User ``input.conf`` files and Lua scripts can
|
||||
define additional key bindings.
|
||||
to control mpv using keyboard, mouse, joystick or remote control (with
|
||||
LIRC). See the ``--input-`` options for ways to customize it.
|
||||
|
||||
Keyboard Control
|
||||
----------------
|
||||
|
||||
LEFT and RIGHT
|
||||
Seek backward/forward 5 seconds. Shift+arrow does a 1 second exact seek
|
||||
Seek backward/forward 10 seconds. Shift+arrow does a 1 second exact seek
|
||||
(see ``--hr-seek``).
|
||||
|
||||
UP and DOWN
|
||||
Seek forward/backward 1 minute. Shift+arrow does a 5 second exact seek (see
|
||||
``--hr-seek``).
|
||||
|
||||
Ctrl+LEFT and Ctrl+RIGHT
|
||||
Seek to the previous/next subtitle. Subject to some restrictions and
|
||||
might not always work; see ``sub-seek`` command.
|
||||
PGUP and PGDWN
|
||||
Seek forward/backward 10 minutes.
|
||||
|
||||
[ and ]
|
||||
Decrease/increase current playback speed by 10%.
|
||||
@@ -69,32 +63,41 @@ BACKSPACE
|
||||
Go backward/forward in the playlist.
|
||||
|
||||
ENTER
|
||||
Go forward in the playlist.
|
||||
Go forward in the playlist, even over the end.
|
||||
|
||||
p / SPACE
|
||||
Pause (pressing again unpauses).
|
||||
|
||||
\.
|
||||
Step forward. Pressing once will pause, every consecutive press will
|
||||
Step forward. Pressing once will pause movie, every consecutive press will
|
||||
play one frame and then go into pause mode again.
|
||||
|
||||
,
|
||||
Step backward. Pressing once will pause, every consecutive press will
|
||||
Step backward. Pressing once will pause movie, every consecutive press will
|
||||
play one frame in reverse and then go into pause mode again.
|
||||
|
||||
q
|
||||
q / ESC
|
||||
Stop playing and quit.
|
||||
|
||||
Q
|
||||
Like ``q``, but store the current playback position. Playing the same file
|
||||
later will resume at the old playback position if possible.
|
||||
|
||||
U
|
||||
Stop playing (and quit if ``--idle`` is not used).
|
||||
|
||||
\+ and -
|
||||
Adjust audio delay by +/- 0.1 seconds.
|
||||
|
||||
/ and *
|
||||
Decrease/increase volume.
|
||||
|
||||
9 and 0
|
||||
Decrease/increase volume.
|
||||
|
||||
( and )
|
||||
Adjust audio balance in favor of left/right channel.
|
||||
|
||||
m
|
||||
Mute sound.
|
||||
|
||||
@@ -104,23 +107,24 @@ m
|
||||
\#
|
||||
Cycle through the available audio tracks.
|
||||
|
||||
TAB (MPEG-TS and libavformat only)
|
||||
Cycle through the available programs.
|
||||
|
||||
f
|
||||
Toggle fullscreen (see also ``--fs``).
|
||||
|
||||
ESC
|
||||
Exit fullscreen mode.
|
||||
|
||||
T
|
||||
Toggle stay-on-top (see also ``--ontop``).
|
||||
|
||||
w and e
|
||||
Decrease/increase pan-and-scan range.
|
||||
|
||||
o (also P)
|
||||
Show progression bar, elapsed time and total duration on the OSD.
|
||||
o
|
||||
Toggle OSD states: none / seek / seek + timer / seek + timer + total time.
|
||||
|
||||
O
|
||||
Toggle OSD states between normal and playback time/duration.
|
||||
d
|
||||
Toggle frame dropping states: none / skip display / skip decoding (see
|
||||
``--framedrop``).
|
||||
|
||||
v
|
||||
Toggle subtitle visibility.
|
||||
@@ -128,26 +132,15 @@ v
|
||||
j and J
|
||||
Cycle through the available subtitles.
|
||||
|
||||
F
|
||||
Toggle displaying "forced subtitles".
|
||||
|
||||
x and z
|
||||
Adjust subtitle delay by +/- 0.1 seconds.
|
||||
|
||||
l
|
||||
Set/clear A-B loop points. See ``ab-loop`` command for details.
|
||||
|
||||
L
|
||||
Toggle infinite looping.
|
||||
|
||||
Ctrl + and Ctrl -
|
||||
Adjust audio delay by +/- 0.1 seconds.
|
||||
|
||||
u
|
||||
Switch between applying no style overrides to SSA/ASS subtitles, and
|
||||
overriding them almost completely with the normal subtitle style. See
|
||||
``--sub-ass-style-override`` for more info.
|
||||
|
||||
V
|
||||
Toggle subtitle VSFilter aspect compatibility mode. See
|
||||
``--sub-ass-vsfilter-aspect-compat`` for more info.
|
||||
``--ass-vsfilter-aspect-compat`` for more info.
|
||||
|
||||
r and t
|
||||
Move subtitles up/down.
|
||||
@@ -159,27 +152,25 @@ S
|
||||
Take a screenshot, without subtitles. (Whether this works depends on VO
|
||||
driver support.)
|
||||
|
||||
Ctrl s
|
||||
Take a screenshot, as the window shows it (with subtitles, OSD, and scaled
|
||||
video).
|
||||
|
||||
I
|
||||
Show filename on the OSD.
|
||||
|
||||
PGUP and PGDWN
|
||||
P
|
||||
Show progression bar, elapsed time and total duration on the OSD.
|
||||
|
||||
! and @
|
||||
Seek to the beginning of the previous/next chapter. In most cases,
|
||||
"previous" will actually go to the beginning of the current chapter; see
|
||||
``--chapter-seek-threshold``.
|
||||
|
||||
Shift+PGUP and Shift+PGDWN
|
||||
Seek backward or forward by 10 minutes. (This used to be mapped to
|
||||
PGUP/PGDWN without Shift.)
|
||||
|
||||
d
|
||||
D (``--vo=vdpau``, ``--vf=yadif`` only)
|
||||
Activate/deactivate deinterlacer.
|
||||
|
||||
A
|
||||
Cycle aspect ratio override.
|
||||
Cycle through the available DVD angles.
|
||||
|
||||
c
|
||||
Change YUV colorspace.
|
||||
|
||||
(The following keys are valid only when using a video output that supports the
|
||||
corresponding adjustment, or the software equalizer (``--vf=eq``).)
|
||||
@@ -196,20 +187,24 @@ corresponding adjustment, or the software equalizer (``--vf=eq``).)
|
||||
7 and 8
|
||||
Adjust saturation.
|
||||
|
||||
Alt+0 (and command+0 on OSX)
|
||||
Resize video window to half its original size.
|
||||
(The following keys are valid only on OSX.)
|
||||
|
||||
Alt+1 (and command+1 on OSX)
|
||||
Resize video window to its original size.
|
||||
command + 0
|
||||
Resize movie window to half its original size.
|
||||
(On other platforms, you can bind keys to change the ``window-scale``
|
||||
property.)
|
||||
|
||||
Alt+2 (and command+2 on OSX)
|
||||
Resize video window to double its original size.
|
||||
command + 1
|
||||
Resize movie window to its original size.
|
||||
|
||||
command + f (OSX only)
|
||||
command + 2
|
||||
Resize movie window to double its original size.
|
||||
|
||||
command + f
|
||||
Toggle fullscreen (see also ``--fs``).
|
||||
|
||||
command + [ and command + ] (OSX only)
|
||||
Set video window alpha.
|
||||
command + [ and command + ]
|
||||
Set movie window alpha.
|
||||
|
||||
(The following keys are valid if you have a keyboard with multimedia keys.)
|
||||
|
||||
@@ -226,10 +221,13 @@ PREVIOUS and NEXT
|
||||
support.)
|
||||
|
||||
h and k
|
||||
Select previous/next tv-channel.
|
||||
Select previous/next channel.
|
||||
|
||||
H and K
|
||||
Select previous/next dvb-channel.
|
||||
n
|
||||
Change norm.
|
||||
|
||||
u
|
||||
Change channel list.
|
||||
|
||||
Mouse Control
|
||||
-------------
|
||||
@@ -251,66 +249,23 @@ is the same as ``--no-fs``.
|
||||
If an option is marked as *(XXX only)*, it will only work in combination with
|
||||
the *XXX* option or if *XXX* is compiled in.
|
||||
|
||||
Escaping spaces and other special characters
|
||||
--------------------------------------------
|
||||
.. note::
|
||||
|
||||
Keep in mind that the shell will partially parse and mangle the arguments you
|
||||
pass to mpv. For example, you might need to quote or escape options and
|
||||
filenames:
|
||||
The suboption parser (used for example for ``--ao=pcm`` suboptions)
|
||||
supports a special kind of string-escaping intended for use with external
|
||||
GUIs.
|
||||
|
||||
``mpv "filename with spaces.mkv" --title="window title"``
|
||||
|
||||
It gets more complicated if the suboption parser is involved. The suboption
|
||||
parser puts several options into a single string, and passes them to a
|
||||
component at once, instead of using multiple options on the level of the
|
||||
command line.
|
||||
|
||||
The suboption parser can quote strings with ``"`` and ``[...]``.
|
||||
Additionally, there is a special form of quoting with ``%n%`` described below.
|
||||
|
||||
For example, assume the hypothetical ``foo`` filter can take multiple options:
|
||||
|
||||
``mpv test.mkv --vf=foo:option1=value1:option2:option3=value3,bar``
|
||||
|
||||
This passes ``option1`` and ``option3`` to the ``foo`` filter, with ``option2``
|
||||
as flag (implicitly ``option2=yes``), and adds a ``bar`` filter after that. If
|
||||
an option contains spaces or characters like ``,`` or ``:``, you need to quote
|
||||
them:
|
||||
|
||||
``mpv '--vf=foo:option1="option value with spaces",bar'``
|
||||
|
||||
Shells may actually strip some quotes from the string passed to the commandline,
|
||||
so the example quotes the string twice, ensuring that mpv receives the ``"``
|
||||
quotes.
|
||||
|
||||
The ``[...]`` form of quotes wraps everything between ``[`` and ``]``. It's
|
||||
useful with shells that don't interpret these characters in the middle of
|
||||
an argument (like bash). These quotes are balanced (since mpv 0.9.0): the ``[``
|
||||
and ``]`` nest, and the quote terminates on the last ``]`` that has no matching
|
||||
``[`` within the string. (For example, ``[a[b]c]`` results in ``a[b]c``.)
|
||||
|
||||
The fixed-length quoting syntax is intended for use with external
|
||||
scripts and programs.
|
||||
|
||||
It is started with ``%`` and has the following format::
|
||||
It has the following format::
|
||||
|
||||
%n%string_of_length_n
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``mpv '--vf=foo:option1=%11%quoted text' test.avi``
|
||||
``mpv --ao=pcm:file=%10%C:test.wav test.avi``
|
||||
|
||||
Or in a script:
|
||||
|
||||
``mpv --vf=foo:option1=%`expr length "$NAME"`%"$NAME" test.avi``
|
||||
|
||||
Suboptions passed to the client API are also subject to escaping. Using
|
||||
``mpv_set_option_string()`` is exactly like passing ``--name=data`` to the
|
||||
command line (but without shell processing of the string). Some options
|
||||
support passing values in a more structured way instead of flat strings, and
|
||||
can avoid the suboption parsing mess. For example, ``--vf`` supports
|
||||
``MPV_FORMAT_NODE``, which lets you pass suboptions as a nested data structure
|
||||
of maps and arrays.
|
||||
``mpv --ao=pcm:file=%`expr length "$NAME"`%"$NAME" test.avi``
|
||||
|
||||
Paths
|
||||
-----
|
||||
@@ -320,41 +275,19 @@ example, paths starting with ``-`` will be interpreted as options. Likewise,
|
||||
if a path contains the sequence ``://``, the string before that might be
|
||||
interpreted as protocol prefix, even though ``://`` can be part of a legal
|
||||
UNIX path. To avoid problems with arbitrary paths, you should be sure that
|
||||
absolute paths passed to mpv start with ``/``, and prefix relative paths with
|
||||
``./``.
|
||||
|
||||
Using the ``file://`` pseudo-protocol is discouraged, because it involves
|
||||
strange URL unescaping rules.
|
||||
absolute paths passed to mpv start with ``/``, and relative paths with ``./``.
|
||||
|
||||
The name ``-`` itself is interpreted as stdin, and will cause mpv to disable
|
||||
console controls. (Which makes it suitable for playing data piped to stdin.)
|
||||
|
||||
The special argument ``--`` can be used to stop mpv from interpreting the
|
||||
following arguments as options.
|
||||
|
||||
When using the client API, you should strictly avoid using ``mpv_command_string``
|
||||
for invoking the ``loadfile`` command, and instead prefer e.g. ``mpv_command``
|
||||
to avoid the need for filename escaping.
|
||||
|
||||
For paths passed to suboptions, the situation is further complicated by the
|
||||
need to escape special characters. To work this around, the path can be
|
||||
additionally wrapped in the fixed-length syntax, e.g. ``%n%string_of_length_n``
|
||||
(see above).
|
||||
additionally wrapped in the ``%n%string_of_length_n`` syntax (see above).
|
||||
|
||||
Some mpv options interpret paths starting with ``~``. Currently, the prefix
|
||||
``~~/`` expands to the mpv configuration directory (usually ``~/.config/mpv/``).
|
||||
``~~/`` expands to the mpv configuration directory (usually ``~/.mpv/``).
|
||||
``~/`` expands to the user's home directory. (The trailing ``/`` is always
|
||||
required.) There are the following paths as well:
|
||||
|
||||
================ ===============================================================
|
||||
Name Meaning
|
||||
================ ===============================================================
|
||||
``~~home/`` same as ``~~/``
|
||||
``~~global/`` the global config path, if available (not on win32)
|
||||
``~~osxbundle/`` the OSX bundle resource path (OSX only)
|
||||
``~~desktop/`` the path to the desktop (win32, OSX)
|
||||
================ ===============================================================
|
||||
|
||||
required.)
|
||||
|
||||
Per-File Options
|
||||
----------------
|
||||
@@ -396,45 +329,6 @@ file stops playing. If option ``--c`` is changed during playback of
|
||||
``file2.mkv``, it is reset when advancing to ``file3.mkv``. This only affects
|
||||
file-local options. The option ``--a`` is never reset here.
|
||||
|
||||
|
||||
Playing DVDs
|
||||
------------
|
||||
|
||||
DVDs can be played with the ``dvd://[title]`` syntax. The optional
|
||||
title specifier is a number which selects between separate video
|
||||
streams on the DVD. If no title is given (``dvd://``) then the longest
|
||||
title is selected automatically by the library. This is usually what
|
||||
you want. mpv does not support DVD menus.
|
||||
|
||||
DVDs which have been copied on to a hard drive or other mounted
|
||||
filesystem (by e.g. the ``dvdbackup`` tool) are accommodated by
|
||||
specifying the path to the local copy: ``--dvd-device=PATH``.
|
||||
Alternatively, running ``mpv PATH`` should auto-detect a DVD directory
|
||||
tree and play the longest title.
|
||||
|
||||
.. note::
|
||||
|
||||
mpv uses a different default DVD library than MPlayer. MPlayer
|
||||
uses libdvdread by default, and mpv uses libdvdnav by default.
|
||||
Both libraries are developed in parallel, but libdvdnav is
|
||||
intended to support more sophisticated DVD features such as menus
|
||||
and multi-angle playback. mpv uses libdvdnav for files specified
|
||||
as either ``dvd://...`` or ``dvdnav://...``. To use libdvdread,
|
||||
which will produce behavior more like MPlayer, specify
|
||||
``dvdread://...`` instead. Some users have experienced problems
|
||||
when using libdvdnav, in which playback gets stuck in a DVD menu
|
||||
stream. These problems are reported to go away when auto-selecting
|
||||
the title (``dvd://`` rather than ``dvd://1``) or when using
|
||||
libdvdread (e.g. ``dvdread://0``).
|
||||
|
||||
DVDs use image-based subtitles. Image subtitles are implemented as
|
||||
a bitmap video stream which can be superimposed over the main
|
||||
movie. mpv's subtitle styling and positioning options and keyboard
|
||||
shortcuts generally do not work with image-based subtitles.
|
||||
Exceptions include options like ``--stretch-dvd-subs`` and
|
||||
``--stretch-image-subs-to-screen``.
|
||||
|
||||
|
||||
CONFIGURATION FILES
|
||||
===================
|
||||
|
||||
@@ -444,12 +338,10 @@ Location and Syntax
|
||||
You can put all of the options in configuration files which will be read every
|
||||
time mpv is run. The system-wide configuration file 'mpv.conf' is in your
|
||||
configuration directory (e.g. ``/etc/mpv`` or ``/usr/local/etc/mpv``), the
|
||||
user-specific one is ``~/.config/mpv/mpv.conf``. For details and platform
|
||||
specifics (in particular Windows paths) see the `FILES`_ section.
|
||||
|
||||
user-specific one is ``~/.mpv/config``.
|
||||
User-specific options override system-wide options and options given on the
|
||||
command line override either. The syntax of the configuration files is
|
||||
``option=value``. Everything after a *#* is considered a comment. Options
|
||||
``option=<value>``; everything after a *#* is considered a comment. Options
|
||||
that work without values can be enabled by setting them to *yes* and disabled by
|
||||
setting them to *no*. Even suboptions can be specified in this way.
|
||||
|
||||
@@ -462,17 +354,6 @@ setting them to *no*. Even suboptions can be specified in this way.
|
||||
# Use quotes for text that can contain spaces:
|
||||
status-msg="Time: ${time-pos}"
|
||||
|
||||
Escaping spaces and special characters
|
||||
--------------------------------------
|
||||
|
||||
This is done like with command line options. The shell is not involved here,
|
||||
but option values still need to be quoted as a whole if it contains certain
|
||||
characters like spaces. A config entry can be quoted with ``"``,
|
||||
as well as with the fixed-length syntax (``%n%``) mentioned before. This is like
|
||||
passing the exact contents of the quoted string as command line option. C-style
|
||||
escapes are currently _not_ interpreted on this level, although some options do
|
||||
this manually. (This is a mess and should probably be changed at some point.)
|
||||
|
||||
Putting Command Line Options into the Configuration File
|
||||
--------------------------------------------------------
|
||||
|
||||
@@ -492,13 +373,13 @@ File-specific Configuration Files
|
||||
---------------------------------
|
||||
|
||||
You can also write file-specific configuration files. If you wish to have a
|
||||
configuration file for a file called 'video.avi', create a file named
|
||||
'video.avi.conf' with the file-specific options in it and put it in
|
||||
``~/.config/mpv/``. You can also put the configuration file in the same directory
|
||||
as the file to be played. Both require you to set the ``--use-filedir-conf``
|
||||
configuration file for a file called 'movie.avi', create a file named
|
||||
'movie.avi.conf' with the file-specific options in it and put it in
|
||||
``~/.mpv/``. You can also put the configuration file in the same directory
|
||||
as the file to be played, as long as you give the ``--use-filedir-conf``
|
||||
option (either on the command line or in your global config file). If a
|
||||
file-specific configuration file is found in the same directory, no
|
||||
file-specific configuration is loaded from ``~/.config/mpv``. In addition, the
|
||||
file-specific configuration is loaded from ``~/.mpv``. In addition, the
|
||||
``--use-filedir-conf`` option enables directory-specific configuration files.
|
||||
For this, mpv first tries to load a mpv.conf from the same directory
|
||||
as the file played and then tries to load any file-specific configuration.
|
||||
@@ -514,125 +395,44 @@ description (shown by ``--profile=help``) can be defined with the
|
||||
``profile-desc`` option. To end the profile, start another one or use the
|
||||
profile name ``default`` to continue with normal options.
|
||||
|
||||
.. admonition:: Example mpv config file with profiles
|
||||
.. admonition:: Example mpv profile
|
||||
|
||||
::
|
||||
|
||||
# normal top-level option
|
||||
fullscreen=yes
|
||||
|
||||
# a profile that can be enabled with --profile=big-cache
|
||||
[big-cache]
|
||||
cache=123400
|
||||
demuxer-readahead-secs=20
|
||||
|
||||
[slow]
|
||||
profile-desc="some profile name"
|
||||
# reference a builtin profile
|
||||
profile=opengl-hq
|
||||
|
||||
[fast]
|
||||
vo=vdpau
|
||||
|
||||
# using a profile again extends it
|
||||
[slow]
|
||||
framedrop=no
|
||||
# you can also include other profiles
|
||||
profile=big-cache
|
||||
|
||||
|
||||
Auto profiles
|
||||
-------------
|
||||
|
||||
Some profiles are loaded automatically. The following example demonstrates this:
|
||||
|
||||
.. admonition:: Auto profile loading
|
||||
|
||||
::
|
||||
[vo.vdpau]
|
||||
# Use hardware decoding (might break playback of some h264 files)
|
||||
hwdec=vdpau
|
||||
|
||||
[protocol.dvd]
|
||||
profile-desc="profile for dvd:// streams"
|
||||
vf=pp=hb/vb/dr/al/fd
|
||||
alang=en
|
||||
|
||||
[extension.flv]
|
||||
profile-desc="profile for .flv files"
|
||||
vf=flip
|
||||
|
||||
The profile name follows the schema ``type.name``, where type can be
|
||||
``protocol`` for the input/output protocol in use (see ``--list-protocols``),
|
||||
and ``extension`` for the extension of the path of the currently played file
|
||||
(*not* the file format).
|
||||
[ao.alsa]
|
||||
device=spdif
|
||||
|
||||
This feature is very limited, and there are no other auto profiles.
|
||||
|
||||
TAKING SCREENSHOTS
|
||||
==================
|
||||
|
||||
Screenshots of the currently played file can be taken using the 'screenshot'
|
||||
input mode command, which is by default bound to the ``s`` key. Files named
|
||||
``mpv-shotNNNN.jpg`` will be saved in the working directory, using the first
|
||||
available number - no files will be overwritten. In pseudo-GUI mode, the
|
||||
screenshot will be saved somewhere else. See `PSEUDO GUI MODE`_.
|
||||
``shotNNNN.jpg`` will be saved in the working directory, using the first
|
||||
available number - no files will be overwritten.
|
||||
|
||||
A screenshot will usually contain the unscaled video contents at the end of the
|
||||
video filter chain and subtitles. By default, ``S`` takes screenshots without
|
||||
subtitles, while ``s`` includes subtitles.
|
||||
|
||||
Unlike with MPlayer, the ``screenshot`` video filter is not required. This
|
||||
filter was never required in mpv, and has been removed.
|
||||
|
||||
TERMINAL STATUS LINE
|
||||
====================
|
||||
|
||||
During playback, mpv shows the playback status on the terminal. It looks like
|
||||
something like this:
|
||||
|
||||
``AV: 00:03:12 / 00:24:25 (13%) A-V: -0.000``
|
||||
|
||||
The status line can be overridden with the ``--term-status-msg`` option.
|
||||
|
||||
The following is a list of things that can show up in the status line. Input
|
||||
properties, that can be used to get the same information manually, are also
|
||||
listed.
|
||||
|
||||
- ``AV:`` or ``V:`` (video only) or ``A:`` (audio only)
|
||||
- The current time position in ``HH:MM:SS`` format (``playback-time`` property)
|
||||
- The total file duration (absent if unknown) (``length`` property)
|
||||
- Playback speed, e.g. `` x2.0``. Only visible if the speed is not normal. This
|
||||
is the user-requested speed, and not the actual speed (usually they should
|
||||
be the same, unless playback is too slow). (``speed`` property.)
|
||||
- Playback percentage, e.g. ``(13%)``. How much of the file has been played.
|
||||
Normally calculated out of playback position and duration, but can fallback
|
||||
to other methods (like byte position) if these are not available.
|
||||
(``percent-pos`` property.)
|
||||
- The audio/video sync as ``A-V: 0.000``. This is the difference between
|
||||
audio and video time. Normally it should be 0 or close to 0. If it's growing,
|
||||
it might indicate a playback problem. (``avsync`` property.)
|
||||
- Total A/V sync change, e.g. ``ct: -0.417``. Normally invisible. Can show up
|
||||
if there is audio "missing", or not enough frames can be dropped. Usually
|
||||
this will indicate a problem. (``total-avsync-change`` property.)
|
||||
- Encoding state in ``{...}``, only shown in encoding mode.
|
||||
- Display sync state. If display sync is active (``display-sync-active``
|
||||
property), this shows ``DS: 2.500/13``, where the first number is average
|
||||
number of vsyncs per video frame (e.g. 2.5 when playing 24Hz videos on 60Hz
|
||||
screens), which might jitter if the ratio doesn't round off, or there are
|
||||
mistimed frames (``vsync-ratio``), and the second number of estimated number
|
||||
of vsyncs which took too long (``vo-delayed-frame-count`` property). The
|
||||
latter is a heuristic, as it's generally not possible to determine this with
|
||||
certainty.
|
||||
- Dropped frames, e.g. ``Dropped: 4``. Shows up only if the count is not 0. Can
|
||||
grow if the video framerate is higher than that of the display, or if video
|
||||
rendering is too slow. May also be incremented on "hiccups" and when the video
|
||||
frame couldn't be displayed on time. (``vo-drop-frame-count`` property.)
|
||||
If the decoder drops frames, the number of decoder-dropped frames is appended
|
||||
to the display as well, e.g.: ``Dropped: 4/34``. This happens only if
|
||||
decoder frame dropping is enabled with the ``--framedrop`` options.
|
||||
(``drop-frame-count`` property.)
|
||||
- Cache state, e.g. ``Cache: 2s+134KB``. Visible if the stream cache is enabled.
|
||||
The first value shows the amount of video buffered in the demuxer in seconds,
|
||||
the second value shows *additional* data buffered in the stream cache in
|
||||
kilobytes. (``demuxer-cache-duration`` and ``cache-used`` properties.)
|
||||
|
||||
The ``screenshot`` video filter is not required when using a recommended GUI
|
||||
video output driver. It should normally not be added to the config file, as
|
||||
taking screenshots is handled by the VOs, and adding the screenshot filter will
|
||||
break hardware decoding. (The filter may still be useful for taking screenshots
|
||||
at a certain point within the video chain when using multiple video filters.)
|
||||
|
||||
PROTOCOLS
|
||||
=========
|
||||
@@ -642,10 +442,6 @@ PROTOCOLS
|
||||
be specified. mpv will never attempt to guess whether a filename is
|
||||
actually a network address. A protocol prefix is always required.
|
||||
|
||||
Note that not all prefixes are documented here. Undocumented prefixes are
|
||||
either aliases to documented protocols, or are just redirections to
|
||||
protocols implemented and documented in FFmpeg.
|
||||
|
||||
``-``
|
||||
Play data from stdin.
|
||||
|
||||
@@ -653,13 +449,17 @@ PROTOCOLS
|
||||
Play a path from Samba share.
|
||||
|
||||
``bd://[title][/device]`` ``--bluray-device=PATH``
|
||||
Play a Blu-ray disc. Currently, this does not accept ISO files. Instead,
|
||||
you must mount the ISO file as filesystem, and point ``--bluray-device``
|
||||
to the mounted directory directly.
|
||||
Play a Blu-Ray disc. Currently, this does not accept iso files. Instead,
|
||||
you must mount the iso file as filesystem, and point ``--bluray-device``
|
||||
to the mounted directly.
|
||||
|
||||
``bdnav://[title][/device]``
|
||||
Play a Blu-Ray disc, with navigation features enabled. This feature is
|
||||
permanently experimental.
|
||||
|
||||
``dvd://[title|[starttitle]-endtitle][/device]`` ``--dvd-device=PATH``
|
||||
Play a DVD. DVD menus are not supported. If no title is given, the longest
|
||||
title is auto-selected.
|
||||
Play a DVD. If you want dvdnav menus, use ``dvd://menu``. If no title
|
||||
is given, the longest title is auto-selected.
|
||||
|
||||
``dvdnav://`` is an old alias for ``dvd://`` and does exactly the same
|
||||
thing.
|
||||
@@ -681,7 +481,7 @@ PROTOCOLS
|
||||
``mf://[filemask|@listfile]`` ``--mf-...``
|
||||
Play a series of images as video.
|
||||
|
||||
``cdda://[device]`` ``--cdrom-device=PATH`` ``--cdda-...``
|
||||
``cdda://track[-endtrack][:speed][/device]`` ``--cdrom-device=PATH`` ``--cdda-...``
|
||||
Play CD.
|
||||
|
||||
``lavf://...``
|
||||
@@ -704,66 +504,15 @@ PROTOCOLS
|
||||
``PATH`` itself should start with a third ``/`` to make the path an
|
||||
absolute path.
|
||||
|
||||
``fd://123``
|
||||
Read data from the given file descriptor (for example 123). This is similar
|
||||
to piping data to stdin via ``-``, but can use an arbitrary file descriptor.
|
||||
|
||||
``edl://[edl specification as in edl-mpv.rst]``
|
||||
Stitch together parts of multiple files and play them.
|
||||
|
||||
``null://``
|
||||
Simulate an empty file. If opened for writing, it will discard all data.
|
||||
The ``null`` demuxer will specifically pass autoprobing if this protocol
|
||||
is used (while it's not automatically invoked for empty files).
|
||||
Simulate an empty file.
|
||||
|
||||
``memory://data``
|
||||
Use the ``data`` part as source data.
|
||||
|
||||
``hex://data``
|
||||
Like ``memory://``, but the string is interpreted as hexdump.
|
||||
|
||||
PSEUDO GUI MODE
|
||||
===============
|
||||
|
||||
mpv has no official GUI, other than the OSC (`ON SCREEN CONTROLLER`_), which
|
||||
is not a full GUI and is not meant to be. However, to compensate for the lack
|
||||
of expected GUI behavior, mpv will in some cases start with some settings
|
||||
changed to behave slightly more like a GUI mode.
|
||||
|
||||
Currently this happens only in the following cases:
|
||||
|
||||
- if started using the ``mpv.desktop`` file on Linux (e.g. started from menus
|
||||
or file associations provided by desktop environments)
|
||||
- if started from explorer.exe on Windows (technically, if it was started on
|
||||
Windows, and all of the stdout/stderr/stdin handles are unset)
|
||||
- started out of the bundle on OSX
|
||||
- if you manually use ``--player-operation-mode=pseudo-gui`` on the command line
|
||||
|
||||
This mode applies options from the builtin profile ``builtin-pseudo-gui``, but
|
||||
only if these haven't been set in the user's config file or on the command line.
|
||||
Also, for compatibility with the old pseudo-gui behavior, the options in the
|
||||
``pseudo-gui`` profile are applied unconditionally. In addition, the profile
|
||||
makes sure to enable the pseudo-GUI mode, so that ``--profile=pseudo-gui``
|
||||
works like in older mpv releases. The profiles are currently defined as follows:
|
||||
|
||||
::
|
||||
|
||||
[builtin-pseudo-gui]
|
||||
terminal=no
|
||||
force-window=yes
|
||||
idle=once
|
||||
screenshot-directory=~~desktop/
|
||||
[pseudo-gui]
|
||||
player-operation-mode=pseudo-gui
|
||||
|
||||
.. warning::
|
||||
|
||||
Currently, you can extend the ``pseudo-gui`` profile in the config file the
|
||||
normal way. This is deprecated. In future mpv releases, the behavior might
|
||||
change, and not apply your additional settings, and/or use a different
|
||||
profile name.
|
||||
|
||||
|
||||
.. include:: options.rst
|
||||
|
||||
.. include:: ao.rst
|
||||
@@ -782,32 +531,23 @@ works like in older mpv releases. The profiles are currently defined as follows:
|
||||
|
||||
.. include:: lua.rst
|
||||
|
||||
.. include:: ipc.rst
|
||||
|
||||
.. include:: changes.rst
|
||||
|
||||
.. include:: libmpv.rst
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
=====================
|
||||
|
||||
There are a number of environment variables that can be used to control the
|
||||
behavior of mpv.
|
||||
|
||||
``HOME``, ``XDG_CONFIG_HOME``
|
||||
Used to determine mpv config directory. If ``XDG_CONFIG_HOME`` is not set,
|
||||
``$HOME/.config/mpv`` is used.
|
||||
``HOME``
|
||||
Used to determine mpv config directory: ``$HOME/.mpv``
|
||||
|
||||
``$HOME/.mpv`` is always added to the list of config search paths with a
|
||||
lower priority.
|
||||
|
||||
``XDG_CONFIG_DIRS``
|
||||
If set, XDG-style system configuration directories are used. Otherwise,
|
||||
the UNIX convention (``PREFIX/etc/mpv/``) is used.
|
||||
``TERM``
|
||||
Used to determine terminal type.
|
||||
|
||||
``MPV_HOME``
|
||||
Directory where mpv looks for user settings. Overrides ``HOME``, and mpv
|
||||
will try to load the config file as ``$MPV_HOME/mpv.conf``.
|
||||
will try to load the config file as ``$MPV_HOME/config``.
|
||||
|
||||
``MPV_VERBOSE`` (see also ``-v`` and ``--msg-level``)
|
||||
Set the initial verbosity level across all message modules (default: 0).
|
||||
@@ -815,7 +555,8 @@ behavior of mpv.
|
||||
of ``--v`` options passed to the command line.
|
||||
|
||||
``MPV_LEAK_REPORT``
|
||||
If set to ``1``, enable internal talloc leak reporting.
|
||||
If set to ``1``, enable internal talloc leak reporting. Note that this can
|
||||
cause trouble with multithreading, so only developers should use this.
|
||||
|
||||
``LADSPA_PATH``
|
||||
Specifies the search path for LADSPA plugins. If it is unset, fully
|
||||
@@ -855,7 +596,7 @@ libdvdcss:
|
||||
|
||||
key
|
||||
is the default method. libdvdcss will use a set of calculated
|
||||
player keys to try to get the disc key. This can fail if the drive
|
||||
player keys to try and get the disc key. This can fail if the drive
|
||||
does not recognize any of the player keys.
|
||||
|
||||
disc
|
||||
@@ -908,8 +649,6 @@ If errors happen, the following exit codes can be returned:
|
||||
immediately after initialization.
|
||||
:3: There were some files that could be played, and some files which
|
||||
couldn't (using the definition of success from above).
|
||||
:4: Quit due to a signal, Ctrl+c in a VO window (by default), or from the
|
||||
default quit key bindings in encoding mode.
|
||||
|
||||
Note that quitting the player manually will always lead to exit code 0,
|
||||
overriding the exit code that would be returned normally. Also, the ``quit``
|
||||
@@ -918,86 +657,64 @@ input command can take an exit code: in this case, that exit code is returned.
|
||||
FILES
|
||||
=====
|
||||
|
||||
For Windows-specifics, see `FILES ON WINDOWS`_ section.
|
||||
|
||||
``/usr/local/etc/mpv/mpv.conf``
|
||||
mpv system-wide settings (depends on ``--prefix`` passed to configure - mpv
|
||||
in default configuration will use ``/usr/local/etc/mpv/`` as config
|
||||
directory, while most Linux distributions will set it to ``/etc/mpv/``).
|
||||
mpv system-wide settings (depends on ``--prefix`` passed to configure)
|
||||
|
||||
``~/.config/mpv/mpv.conf``
|
||||
mpv user settings (see `CONFIGURATION FILES`_ section)
|
||||
``~/.mpv/config``
|
||||
mpv user settings
|
||||
|
||||
``~/.config/mpv/input.conf``
|
||||
key bindings (see `INPUT.CONF`_ section)
|
||||
``~/.mpv/input.conf``
|
||||
input bindings (see ``--input-keylist`` for the full list)
|
||||
|
||||
``~/.config/mpv/scripts/``
|
||||
All files in this directory are loaded as if they were passed to the
|
||||
``--script`` option. They are loaded in alphabetical order, and sub-directories
|
||||
``~/.mpv/lua/``
|
||||
All files in this directly are loaded as if they were passed to the
|
||||
``--lua`` option. They are loaded in alphabetical order, and sub-directories
|
||||
and files with no ``.lua`` extension are ignored. The ``--load-scripts=no``
|
||||
option disables loading these files.
|
||||
|
||||
``~/.config/mpv/watch_later/``
|
||||
Contains temporary config files needed for resuming playback of files with
|
||||
the watch later feature. See for example the ``Q`` key binding, or the
|
||||
``quit-watch-later`` input command.
|
||||
|
||||
Each file is a small config file which is loaded if the corresponding media
|
||||
file is loaded. It contains the playback position and some (not necessarily
|
||||
all) settings that were changed during playback. The filenames are hashed
|
||||
from the full paths of the media files. It's in general not possible to
|
||||
extract the media filename from this hash. However, you can set the
|
||||
``--write-filename-in-watch-later-config`` option, and the player will
|
||||
add the media filename to the contents of the resume config file.
|
||||
EXAMPLES OF MPV USAGE
|
||||
=====================
|
||||
|
||||
``~/.config/mpv/lua-settings/osc.conf``
|
||||
This is loaded by the OSC script. See the `ON SCREEN CONTROLLER`_ docs
|
||||
for details.
|
||||
Blu-ray playback:
|
||||
- ``mpv bd:////path/to/disc``
|
||||
- ``mpv bd:// --bluray-device=/path/to/disc``
|
||||
|
||||
Other files in this directory are specific to the corresponding scripts
|
||||
as well, and the mpv core doesn't touch them.
|
||||
Play in Japanese with English subtitles:
|
||||
``mpv dvd://1 --alang=ja --slang=en``
|
||||
|
||||
Note that the environment variables ``$XDG_CONFIG_HOME`` and ``$MPV_HOME`` can
|
||||
override the standard directory ``~/.config/mpv/``.
|
||||
Play only chapters 5, 6, 7:
|
||||
``mpv dvd://1 --chapter=5-7``
|
||||
|
||||
Also, the old config location at ``~/.mpv/`` is still read, and if the XDG
|
||||
variant does not exist, will still be preferred.
|
||||
Play only titles 5, 6, 7:
|
||||
``mpv dvd://5-7``
|
||||
|
||||
FILES ON WINDOWS
|
||||
================
|
||||
Play a multiangle DVD:
|
||||
``mpv dvd://1 --dvd-angle=2``
|
||||
|
||||
On win32 (if compiled with MinGW, but not Cygwin), the default config file
|
||||
locations are different. They are generally located under ``%APPDATA%/mpv/``.
|
||||
For example, the path to mpv.conf is ``%APPDATA%/mpv/mpv.conf``, which maps to
|
||||
a system and user-specific path, for example
|
||||
Play from a different DVD device:
|
||||
``mpv dvd://1 --dvd-device=/dev/dvd2``
|
||||
|
||||
``C:\users\USERNAME\AppData\Roaming\mpv\mpv.conf``
|
||||
Play DVD video from a directory with VOB files:
|
||||
``mpv dvd://1 --dvd-device=/path/to/directory/``
|
||||
|
||||
You can find the exact path by running ``echo %APPDATA%\mpv\mpv.conf`` in cmd.exe.
|
||||
Stream from HTTP:
|
||||
``mpv http://example.com/example.avi``
|
||||
|
||||
Other config files (such as ``input.conf``) are in the same directory. See the
|
||||
`FILES`_ section above.
|
||||
Stream using RTSP:
|
||||
``mpv rtsp://server.example.com/streamName``
|
||||
|
||||
The environment variable ``$MPV_HOME`` completely overrides these, like on
|
||||
UNIX.
|
||||
Play a libavfilter graph:
|
||||
``mpv avdevice://lavfi:mandelbrot``
|
||||
|
||||
If a directory named ``portable_config`` next to the mpv.exe exists, all
|
||||
config will be loaded from this directory only. Watch later config files are
|
||||
written to this directory as well. (This exists on Windows only and is redundant
|
||||
with ``$MPV_HOME``. However, since Windows is very scripting unfriendly, a
|
||||
wrapper script just setting ``$MPV_HOME``, like you could do it on other
|
||||
systems, won't work. ``portable_config`` is provided for convenience to get
|
||||
around this restriction.)
|
||||
AUTHORS
|
||||
=======
|
||||
|
||||
Config files located in the same directory as ``mpv.exe`` are loaded with
|
||||
lower priority. Some config files are loaded only once, which means that
|
||||
e.g. of 2 ``input.conf`` files located in two config directories, only the
|
||||
one from the directory with higher priority will be loaded.
|
||||
mpv is a MPlayer fork based on mplayer2, which in turn is a fork of MPlayer.
|
||||
|
||||
A third config directory with the lowest priority is the directory named ``mpv``
|
||||
in the same directory as ``mpv.exe``. This used to be the directory with the
|
||||
highest priority, but is now discouraged to use and might be removed in the
|
||||
future.
|
||||
MPlayer was initially written by Arpad Gereoffy. See the ``AUTHORS`` file for
|
||||
a list of some of the many other contributors.
|
||||
|
||||
Note that mpv likes to mix ``/`` and ``\`` path separators for simplicity.
|
||||
kernel32.dll accepts this, but cmd.exe does not.
|
||||
MPlayer is (C) 2000-2013 The MPlayer Team
|
||||
|
||||
This man page was written mainly by Gabucino, Jonas Jermann and Diego Biurrun.
|
||||
+2207
-4190
File diff suppressed because it is too large.
Load diff
+110
-119
@@ -5,7 +5,7 @@ The On Screen Controller (short: OSC) is a minimal GUI integrated with mpv to
|
||||
offer basic mouse-controllability. It is intended to make interaction easier
|
||||
for new users and to enable precise and direct seeking.
|
||||
|
||||
The OSC is enabled by default if mpv was compiled with Lua support. It can be
|
||||
The OSC is enabled by default if mpv was compiled with lua support. It can be
|
||||
disabled entirely using the ``--osc=no`` option.
|
||||
|
||||
Using the OSC
|
||||
@@ -20,25 +20,22 @@ The Interface
|
||||
|
||||
::
|
||||
|
||||
+---------+----------+----------------------------+-------------+
|
||||
| pl prev | pl next | title | cache |
|
||||
+------+--+---+------+---------+-----------+------+-------+-----+
|
||||
| play | skip | skip | time | seekbar | time | audio | sub |
|
||||
| | back | frwd | elapsed | | left | | |
|
||||
+------+------+------+---------+-----------+------+-------+-----+
|
||||
+------------------+-----------+--------------------+
|
||||
| playlist prev | title | playlist next |
|
||||
+-------+------+---+--+------+-+----+------+--------+
|
||||
| audio | skip | seek | | seek | skip | full |
|
||||
+-------+ back | back | play | frwd | frwd | screen |
|
||||
| sub | | | | | | |
|
||||
+-------+------+------+------+------+------+--------+
|
||||
| seekbar |
|
||||
+----------------+--------------+-------------------+
|
||||
| time passed | cache status | time remaining |
|
||||
+----------------+--------------+-------------------+
|
||||
|
||||
|
||||
pl prev
|
||||
playlist prev
|
||||
============= ================================================
|
||||
left-click play previous file in playlist
|
||||
right-click show playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
pl next
|
||||
============= ================================================
|
||||
left-click play next file in playlist
|
||||
right-click show playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
@@ -50,47 +47,10 @@ title
|
||||
right-click show filename
|
||||
============= ================================================
|
||||
|
||||
cache
|
||||
| Shows current cache fill status
|
||||
|
||||
play
|
||||
playlist next
|
||||
============= ================================================
|
||||
left-click toggle play/pause
|
||||
============= ================================================
|
||||
|
||||
skip back
|
||||
============= ================================================
|
||||
left-click go to beginning of chapter / previous chapter
|
||||
right-click show chapters
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
skip frwd
|
||||
============= ================================================
|
||||
left-click go to next chapter
|
||||
right-click show chapters
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
time elapsed
|
||||
| Shows current playback position timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle displaying timecodes with milliseconds
|
||||
============= ================================================
|
||||
|
||||
seekbar
|
||||
| Indicates current playback position and position of chapters
|
||||
|
||||
============= ================================================
|
||||
left-click seek to position
|
||||
============= ================================================
|
||||
|
||||
time left
|
||||
| Shows remaining playback time timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle between total and remaining time
|
||||
left-click play next file in playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
audio and sub
|
||||
@@ -102,15 +62,75 @@ audio and sub
|
||||
shift+L-click show available audio/sub tracks
|
||||
============= ================================================
|
||||
|
||||
Key Bindings
|
||||
~~~~~~~~~~~~
|
||||
skip back
|
||||
============= ================================================
|
||||
left-click go to beginning of chapter / previous chapter
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
These key bindings are active by default if nothing else is already bound to
|
||||
these keys. In case of collision, the function needs to be bound to a
|
||||
different key. See the `Script Commands`_ section.
|
||||
seek back
|
||||
============= ================================================
|
||||
left-click skip back 5 seconds
|
||||
right-click skip back 30 seconds
|
||||
shift-L-click skip back 1 frame
|
||||
============= ================================================
|
||||
|
||||
play
|
||||
============= ================================================
|
||||
left-click toggle play/pause
|
||||
============= ================================================
|
||||
|
||||
seek frwd
|
||||
============= ================================================
|
||||
left-click skip forward 10 seconds
|
||||
right-click skip forward 60 seconds
|
||||
shift-L-click skip forward 1 frame
|
||||
============= ================================================
|
||||
|
||||
skip frwd
|
||||
============= ================================================
|
||||
left-click go to next chapter
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
fullscreen
|
||||
============= ================================================
|
||||
left-click toggle fullscreen
|
||||
============= ================================================
|
||||
|
||||
seekbar
|
||||
| Indicates current playback position and position of chapters
|
||||
|
||||
============= ================================================
|
||||
left-click seek to position
|
||||
============= ================================================
|
||||
|
||||
time passed
|
||||
| Shows current playback position timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle displaying timecodes with milliseconds
|
||||
============= ================================================
|
||||
|
||||
cache status
|
||||
| Shows current cache fill status (only visible when below 45%)
|
||||
|
||||
time remaining
|
||||
| Shows remaining playback time timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle between total and remaining time
|
||||
============= ================================================
|
||||
|
||||
Keybindings
|
||||
~~~~~~~~~~~
|
||||
|
||||
These keybindings are active by default if nothing else is already bound to
|
||||
these keys. In case of collosision, the function needs to be bound to a
|
||||
different key. See `Script Commands`_ section.
|
||||
|
||||
============= ================================================
|
||||
del Cycles visibility between never / auto (mouse-move) / always
|
||||
del Hide the OSC permanently until mpv is restarted.
|
||||
============= ================================================
|
||||
|
||||
Configuration
|
||||
@@ -118,7 +138,7 @@ Configuration
|
||||
|
||||
The OSC offers limited configuration through a config file
|
||||
``lua-settings/osc.conf`` placed in mpv's user dir and through the
|
||||
``--script-opts`` command-line option. Options provided through the command-line
|
||||
``--lua-opts`` command-line option. Options provided through the command-line
|
||||
will override those from the config file.
|
||||
|
||||
Config Syntax
|
||||
@@ -141,7 +161,7 @@ To avoid collisions with other scripts, all options need to be prefixed with
|
||||
|
||||
Example::
|
||||
|
||||
--script-opts=osc-optionA=value1,osc-optionB=value2
|
||||
--lua-opts=osc-optionA=value1:osc-optionB=value2
|
||||
|
||||
|
||||
Configurable Options
|
||||
@@ -149,40 +169,35 @@ Configurable Options
|
||||
|
||||
``showwindowed``
|
||||
| Default: yes
|
||||
| Enable the OSC when windowed
|
||||
| Show OSC when windowed?
|
||||
|
||||
``showfullscreen``
|
||||
| Default: yes
|
||||
| Enable the OSC when fullscreen
|
||||
| Show OSC when fullscreen?
|
||||
|
||||
``scalewindowed``
|
||||
| Default: 1.5
|
||||
| Scale factor of the OSC when windowed
|
||||
| Default: 1
|
||||
| Scaling of the controller when windowed
|
||||
|
||||
``scalefullscreen``
|
||||
| Default: 1.5
|
||||
| Scale factor of the OSC when fullscreen
|
||||
| Default: 1
|
||||
| Scaling of the controller when fullscreen
|
||||
|
||||
``scaleforcedwindow``
|
||||
| Default: 2.0
|
||||
| Scale factor of the OSC when rendered on a forced (dummy) window
|
||||
| Default: 2
|
||||
| Scaling of the controller when rendered on a forced (dummy) window
|
||||
|
||||
``vidscale``
|
||||
| Default: yes
|
||||
| Scale the OSC with the video
|
||||
| ``no`` tries to keep the OSC size constant as much as the window size allows
|
||||
| Scale the controller with the video?
|
||||
|
||||
``valign``
|
||||
| Default: 0.8
|
||||
| Vertical alignment, -1 (top) to 1 (bottom)
|
||||
|
||||
``halign``
|
||||
| Default: 0.0
|
||||
| Horizontal alignment, -1 (left) to 1 (right)
|
||||
|
||||
``barmargin``
|
||||
| Default: 0
|
||||
| Margin from bottom (bottombar) or top (topbar), in pixels
|
||||
| Horizontal alignment, -1 (left) to 1 (right)
|
||||
|
||||
``boxalpha``
|
||||
| Default: 80
|
||||
@@ -190,52 +205,29 @@ Configurable Options
|
||||
|
||||
``hidetimeout``
|
||||
| Default: 500
|
||||
| Duration in ms until the OSC hides if no mouse movement, must not be
|
||||
negative
|
||||
| Duration in ms until the OSC hides if no mouse movement, negative value
|
||||
disables auto-hide
|
||||
|
||||
``fadeduration``
|
||||
| Default: 200
|
||||
| Duration of fade out in ms, 0 = no fade
|
||||
|
||||
``deadzonesize``
|
||||
| Default: 1
|
||||
| Default: 0
|
||||
| Size of the deadzone. The deadzone is an area that makes the mouse act
|
||||
like leaving the window. Movement there won't make the OSC show up and
|
||||
it will hide immediately if the mouse enters it. The deadzone starts
|
||||
at the window border opposite to the OSC and the size controls how much
|
||||
of the window it will span. Values between 0 and 1, where 0 means the
|
||||
OSC will always popup with mouse movement in the window, and 1 means the
|
||||
OSC will only show up when the mouse hovers it.
|
||||
of the window it will span. Values between 0 and 1.
|
||||
|
||||
``minmousemove``
|
||||
| Default: 0
|
||||
| Default: 3
|
||||
| Minimum amount of pixels the mouse has to move between ticks to make
|
||||
the OSC show up
|
||||
|
||||
``layout``
|
||||
| Default: bottombar
|
||||
| The layout for the OSC. Currently available are: box, slimbox,
|
||||
bottombar and topbar.
|
||||
|
||||
``seekbarstyle``
|
||||
| Default: bar
|
||||
| Sets the style of the seekbar, slider (diamond marker) or bar (fill)
|
||||
|
||||
``tooltipborder``
|
||||
| Default: 1
|
||||
| Size of the tooltip outline when using bottombar or topbar layouts
|
||||
|
||||
``timetotal``
|
||||
| Default: no
|
||||
| Show total time instead of time remaining
|
||||
|
||||
``timems``
|
||||
| Default: no
|
||||
| Display timecodes with milliseconds
|
||||
|
||||
``visibility``
|
||||
| Default: auto (auto hide/show on mouse move)
|
||||
| Also supports ``never`` and ``always``
|
||||
``seektooltip``
|
||||
| Default: yes
|
||||
| Display a tooltip over the seekbar indicating time at mouse position.
|
||||
|
||||
Script Commands
|
||||
~~~~~~~~~~~~~~~
|
||||
@@ -243,19 +235,18 @@ Script Commands
|
||||
The OSC script listens to certain script commands. These commands can bound
|
||||
in ``input.conf``, or sent by other scripts.
|
||||
|
||||
``osc-message``
|
||||
Show a message on screen using the OSC. First argument is the message,
|
||||
second the duration in seconds.
|
||||
``enable-osc``
|
||||
Undoes ``disable-osc`` or the effect of the ``del`` key.
|
||||
|
||||
``disable-osc``
|
||||
Hide the OSC permanently. This is also what the ``del`` key does.
|
||||
|
||||
``osc-visibility``
|
||||
Controls visibility mode ``never`` / ``auto`` (on mouse move) / ``always``
|
||||
and also ``cycle`` to cycle between the modes
|
||||
|
||||
Example
|
||||
|
||||
You could put this into ``input.conf`` to hide the OSC with the ``a`` key and
|
||||
to set auto mode (the default) with ``b``::
|
||||
to unhide it with ``b``::
|
||||
|
||||
a script-message osc-visibility never
|
||||
b script-message osc-visibility auto
|
||||
a script_message disable-osc
|
||||
b script_message enable-osc
|
||||
|
||||
+402
-266
@@ -17,10 +17,6 @@ normal filter parameters.
|
||||
|
||||
To get a full list of available video filters, see ``--vf=help``.
|
||||
|
||||
Also, keep in mind that most actual filters are available via the ``lavfi``
|
||||
wrapper, which gives you access to most of libavfilter's filters. This
|
||||
includes all filters that have been ported from MPlayer to libavfilter.
|
||||
|
||||
Video filters are managed in lists. There are a few commands to manage the
|
||||
filter list.
|
||||
|
||||
@@ -51,7 +47,7 @@ Available filters are:
|
||||
|
||||
``crop[=w:h:x:y]``
|
||||
Crops the given part of the image and discards the rest. Useful to remove
|
||||
black bands from widescreen videos.
|
||||
black bands from widescreen movies.
|
||||
|
||||
``<w>,<h>``
|
||||
Cropped width and height, defaults to original width and height.
|
||||
@@ -59,7 +55,7 @@ Available filters are:
|
||||
Position of the cropped picture, defaults to center.
|
||||
|
||||
``expand[=w:h:x:y:aspect:round]``
|
||||
Expands (not scales) video resolution to the given value and places the
|
||||
Expands (not scales) movie resolution to the given value and places the
|
||||
unscaled original at coordinates x, y.
|
||||
|
||||
``<w>,<h>``
|
||||
@@ -97,11 +93,11 @@ Available filters are:
|
||||
|
||||
``scale[=w:h:param:param2:chr-drop:noup:arnd``
|
||||
Scales the image with the software scaler (slow) and performs a YUV<->RGB
|
||||
color space conversion (see also ``--sws``).
|
||||
colorspace conversion (see also ``--sws``).
|
||||
|
||||
All parameters are optional.
|
||||
|
||||
``<w>:<h>``
|
||||
``<w>,<h>``
|
||||
scaled width/height (default: original width/height)
|
||||
|
||||
:0: scaled d_width/d_height
|
||||
@@ -124,9 +120,9 @@ Available filters are:
|
||||
0.33:0.33 Mitchell-Netravali spline
|
||||
1.00:0.00 cubic B-spline
|
||||
|
||||
--sws=7 (Gaussian): sharpness (0 (soft) - 100 (sharp))
|
||||
--sws=7 (gaussian): sharpness (0 (soft) - 100 (sharp))
|
||||
|
||||
--sws=9 (Lanczos): filter length (1-10)
|
||||
--sws=9 (lanczos): filter length (1-10)
|
||||
|
||||
``<chr-drop>``
|
||||
chroma skipping
|
||||
@@ -147,19 +143,19 @@ Available filters are:
|
||||
Accurate rounding for the vertical scaler, which may be faster or
|
||||
slower than the default rounding.
|
||||
|
||||
:no: Disable accurate rounding (default).
|
||||
:yes: Enable accurate rounding.
|
||||
:0: Disable accurate rounding (default).
|
||||
:1: Enable accurate rounding.
|
||||
|
||||
``dsize[=w:h:aspect-method:r:aspect]``
|
||||
Changes the intended display aspect at an arbitrary point in the
|
||||
Changes the intended display size/aspect at an arbitrary point in the
|
||||
filter chain. Aspect can be given as a fraction (4/3) or floating point
|
||||
number (1.33). Note that this filter does *not* do any scaling itself; it
|
||||
number (1.33). Alternatively, you may specify the exact display width and
|
||||
height desired. Note that this filter does *not* do any scaling itself; it
|
||||
just affects what later scalers (software or hardware) will do when
|
||||
auto-scaling to the correct aspect.
|
||||
auto-scaling to correct aspect.
|
||||
|
||||
``<w>,<h>``
|
||||
New aspect ratio given by a display width and height. Unlike older mpv
|
||||
versions or MPlayer, this does not set the display size.
|
||||
New display width and height.
|
||||
|
||||
Can also be these special values:
|
||||
|
||||
@@ -202,7 +198,7 @@ Available filters are:
|
||||
``<aspect>``
|
||||
Force an aspect ratio.
|
||||
|
||||
``format=fmt=<value>:colormatrix=<value>:...``
|
||||
``format[=fmt[:outfmt]]``
|
||||
Restricts the color space for the next filter without doing any conversion.
|
||||
Use together with the scale filter for a real conversion.
|
||||
|
||||
@@ -211,145 +207,23 @@ Available filters are:
|
||||
For a list of available formats, see ``format=fmt=help``.
|
||||
|
||||
``<fmt>``
|
||||
Format name, e.g. rgb15, bgr24, 420p, etc. (default: don't change).
|
||||
Format name, e.g. rgb15, bgr24, 420p, etc. (default: yuyv).
|
||||
``<outfmt>``
|
||||
Format name that should be substituted for the output. If they do not
|
||||
have the same bytes per pixel and chroma subsampling, it will fail.
|
||||
``<colormatrix>``
|
||||
Controls the YUV to RGB color space conversion when playing video. There
|
||||
are various standards. Normally, BT.601 should be used for SD video, and
|
||||
BT.709 for HD video. (This is done by default.) Using incorrect color space
|
||||
results in slightly under or over saturated and shifted colors.
|
||||
Format name that should be substituted for the output. If this is not
|
||||
100% compatible with the ``<fmt>`` value, it will crash.
|
||||
|
||||
These options are not always supported. Different video outputs provide
|
||||
varying degrees of support. The ``opengl`` and ``vdpau`` video output
|
||||
drivers usually offer full support. The ``xv`` output can set the color
|
||||
space if the system video driver supports it, but not input and output
|
||||
levels. The ``scale`` video filter can configure color space and input
|
||||
levels, but only if the output format is RGB (if the video output driver
|
||||
supports RGB output, you can force this with ``-vf scale,format=rgba``).
|
||||
|
||||
If this option is set to ``auto`` (which is the default), the video's
|
||||
color space flag will be used. If that flag is unset, the color space
|
||||
will be selected automatically. This is done using a simple heuristic that
|
||||
attempts to distinguish SD and HD video. If the video is larger than
|
||||
1279x576 pixels, BT.709 (HD) will be used; otherwise BT.601 (SD) is
|
||||
selected.
|
||||
|
||||
Available color spaces are:
|
||||
|
||||
:auto: automatic selection (default)
|
||||
:bt.601: ITU-R BT.601 (SD)
|
||||
:bt.709: ITU-R BT.709 (HD)
|
||||
:bt.2020-ncl: ITU-R BT.2020 non-constant luminance system
|
||||
:bt.2020-cl: ITU-R BT.2020 constant luminance system
|
||||
:smpte-240m: SMPTE-240M
|
||||
|
||||
``<colorlevels>``
|
||||
YUV color levels used with YUV to RGB conversion. This option is only
|
||||
necessary when playing broken files which do not follow standard color
|
||||
levels or which are flagged wrong. If the video does not specify its
|
||||
color range, it is assumed to be limited range.
|
||||
|
||||
The same limitations as with ``<colormatrix>`` apply.
|
||||
|
||||
Available color ranges are:
|
||||
|
||||
:auto: automatic selection (normally limited range) (default)
|
||||
:limited: limited range (16-235 for luma, 16-240 for chroma)
|
||||
:full: full range (0-255 for both luma and chroma)
|
||||
|
||||
``<primaries>``
|
||||
RGB primaries the source file was encoded with. Normally this should be set
|
||||
in the file header, but when playing broken or mistagged files this can be
|
||||
used to override the setting.
|
||||
|
||||
This option only affects video output drivers that perform color
|
||||
management, for example ``opengl`` with the ``target-prim`` or
|
||||
``icc-profile`` suboptions set.
|
||||
|
||||
If this option is set to ``auto`` (which is the default), the video's
|
||||
primaries flag will be used. If that flag is unset, the color space will
|
||||
be selected automatically, using the following heuristics: If the
|
||||
``<colormatrix>`` is set or determined as BT.2020 or BT.709, the
|
||||
corresponding primaries are used. Otherwise, if the video height is
|
||||
exactly 576 (PAL), BT.601-625 is used. If it's exactly 480 or 486 (NTSC),
|
||||
BT.601-525 is used. If the video resolution is anything else, BT.709 is
|
||||
used.
|
||||
|
||||
Available primaries are:
|
||||
|
||||
:auto: automatic selection (default)
|
||||
:bt.601-525: ITU-R BT.601 (SD) 525-line systems (NTSC, SMPTE-C)
|
||||
:bt.601-625: ITU-R BT.601 (SD) 625-line systems (PAL, SECAM)
|
||||
:bt.709: ITU-R BT.709 (HD) (same primaries as sRGB)
|
||||
:bt.2020: ITU-R BT.2020 (UHD)
|
||||
:apple: Apple RGB
|
||||
:adobe: Adobe RGB (1998)
|
||||
:prophoto: ProPhoto RGB (ROMM)
|
||||
:cie1931: CIE 1931 RGB
|
||||
:dci-p3: DCI-P3 (Digital Cinema)
|
||||
:v-gamut: Panasonic V-Gamut primaries
|
||||
|
||||
``<gamma>``
|
||||
Gamma function the source file was encoded with. Normally this should be set
|
||||
in the file header, but when playing broken or mistagged files this can be
|
||||
used to override the setting.
|
||||
|
||||
This option only affects video output drivers that perform color management.
|
||||
|
||||
If this option is set to ``auto`` (which is the default), the gamma will
|
||||
be set to BT.1886 for YCbCr content, sRGB for RGB content and Linear for
|
||||
XYZ content.
|
||||
|
||||
Available gamma functions are:
|
||||
|
||||
:auto: automatic selection (default)
|
||||
:bt.1886: ITU-R BT.1886 (EOTF corresponding to BT.601/BT.709/BT.2020)
|
||||
:srgb: IEC 61966-2-4 (sRGB)
|
||||
:linear: Linear light
|
||||
:gamma1.8: Pure power curve (gamma 1.8)
|
||||
:gamma2.2: Pure power curve (gamma 2.2)
|
||||
:gamma2.8: Pure power curve (gamma 2.8)
|
||||
:prophoto: ProPhoto RGB (ROMM) curve
|
||||
:st2084: SMPTE ST2084 (HDR) curve
|
||||
:std-b67: ARIB STD-B67 (Hybrid Log-gamma) curve
|
||||
:v-log: Panasonic V-Log transfer curve
|
||||
|
||||
``<peak>``
|
||||
Reference peak illumination for the video file. This is mostly
|
||||
interesting for HDR, but it can also be used tone map SDR content
|
||||
to a darker or brighter exposure.
|
||||
|
||||
The default of 0.0 will default to the display's reference brightness
|
||||
for SDR and the source's reference brightness for HDR.
|
||||
|
||||
``<stereo-in>``
|
||||
Set the stereo mode the video is assumed to be encoded in. Takes the
|
||||
same values as the ``--video-stereo-mode`` option.
|
||||
|
||||
``<stereo-out>``
|
||||
Set the stereo mode the video should be displayed as. Takes the
|
||||
same values as the ``--video-stereo-mode`` option.
|
||||
|
||||
``<rotate>``
|
||||
Set the rotation the video is assumed to be encoded with in degrees.
|
||||
The special value ``-1`` uses the input format.
|
||||
|
||||
``<dw>``, ``<dh>``
|
||||
Set the display size. Note that setting the display size such that
|
||||
the video is scaled in both directions instead of just changing the
|
||||
aspect ratio is an implementation detail, and might change later.
|
||||
|
||||
``<dar>``
|
||||
Set the display aspect ratio of the video frame. This is a float,
|
||||
but values such as ``[16:9]`` can be passed too (``[...]`` for quoting
|
||||
to prevent the option parser from interpreting the ``:`` character).
|
||||
.. admonition:: Examples
|
||||
|
||||
====================== =====================
|
||||
Valid Invalid (will crash)
|
||||
====================== =====================
|
||||
``format=rgb24:bgr24`` ``format=rgb24:420p``
|
||||
``format=yuyv:uyvy``
|
||||
====================== =====================
|
||||
|
||||
``noformat[=fmt]``
|
||||
Restricts the color space for the next filter without doing any conversion.
|
||||
Unlike the format filter, this will allow any color space except the one
|
||||
Restricts the colorspace for the next filter without doing any conversion.
|
||||
Unlike the format filter, this will allow any colorspace except the one
|
||||
you specify.
|
||||
|
||||
.. note:: For a list of available formats, see ``noformat=fmt=help``.
|
||||
@@ -357,6 +231,150 @@ Available filters are:
|
||||
``<fmt>``
|
||||
Format name, e.g. rgb15, bgr24, 420p, etc. (default: 420p).
|
||||
|
||||
``pp[=[filter1[:option1[:option2...]]/[-]filter2...]]``
|
||||
Enables the specified chain of postprocessing subfilters. Subfilters must
|
||||
be separated by '/' and can be disabled by prepending a '-'. Each
|
||||
subfilter and some options have a short and a long name that can be used
|
||||
interchangeably, i.e. ``dr``/``dering`` are the same. All subfilters share
|
||||
common options to determine their scope:
|
||||
|
||||
``a/autoq``
|
||||
Automatically switch the subfilter off if the CPU is too slow.
|
||||
``c/chrom``
|
||||
Do chrominance filtering, too (default).
|
||||
``y/nochrom``
|
||||
Do luminance filtering only (no chrominance).
|
||||
``n/noluma``
|
||||
Do chrominance filtering only (no luminance).
|
||||
|
||||
.. note::
|
||||
|
||||
``--vf=pp:help`` shows a list of available subfilters.
|
||||
|
||||
.. note::
|
||||
|
||||
Unlike in MPlayer or in earlier versions, you must quote the pp string
|
||||
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
|
||||
|
||||
Available subfilters are:
|
||||
|
||||
``hb/hdeblock[:difference[:flatness]]``
|
||||
horizontal deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
``vb/vdeblock[:difference[:flatness]]``
|
||||
vertical deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
``ha/hadeblock[:difference[:flatness]]``
|
||||
accurate horizontal deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
``va/vadeblock[:difference[:flatness]]``
|
||||
accurate vertical deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
The horizontal and vertical deblocking filters share the difference and
|
||||
flatness values so you cannot set different horizontal and vertical
|
||||
thresholds.
|
||||
|
||||
``h1/x1hdeblock``
|
||||
experimental horizontal deblocking filter
|
||||
|
||||
``v1/x1vdeblock``
|
||||
experimental vertical deblocking filter
|
||||
|
||||
``dr/dering``
|
||||
deringing filter
|
||||
|
||||
``tn/tmpnoise[:threshold1[:threshold2[:threshold3]]]``
|
||||
temporal noise reducer
|
||||
|
||||
:<threshold1>: larger -> stronger filtering
|
||||
:<threshold2>: larger -> stronger filtering
|
||||
:<threshold3>: larger -> stronger filtering
|
||||
|
||||
``al/autolevels[:f/fullyrange]``
|
||||
automatic brightness / contrast correction
|
||||
|
||||
:f/fullyrange: Stretch luminance to (0-255).
|
||||
|
||||
``lb/linblenddeint``
|
||||
Linear blend deinterlacing filter that deinterlaces the given block by
|
||||
filtering all lines with a (1 2 1) filter.
|
||||
|
||||
``li/linipoldeint``
|
||||
Linear interpolating deinterlacing filter that deinterlaces the given
|
||||
block by linearly interpolating every second line.
|
||||
|
||||
``ci/cubicipoldeint``
|
||||
Cubic interpolating deinterlacing filter deinterlaces the given block
|
||||
by cubically interpolating every second line.
|
||||
|
||||
``md/mediandeint``
|
||||
Median deinterlacing filter that deinterlaces the given block by
|
||||
applying a median filter to every second line.
|
||||
|
||||
``fd/ffmpegdeint``
|
||||
FFmpeg deinterlacing filter that deinterlaces the given block by
|
||||
filtering every second line with a (-1 4 2 4 -1) filter.
|
||||
|
||||
``l5/lowpass5``
|
||||
Vertically applied FIR lowpass deinterlacing filter that deinterlaces
|
||||
the given block by filtering all lines with a (-1 2 6 2 -1) filter.
|
||||
|
||||
``fq/forceQuant[:quantizer]``
|
||||
Overrides the quantizer table from the input with the constant
|
||||
quantizer you specify.
|
||||
|
||||
:<quantizer>: quantizer to use
|
||||
|
||||
``de/default``
|
||||
default pp filter combination (hb:a,vb:a,dr:a)
|
||||
|
||||
``fa/fast``
|
||||
fast pp filter combination (h1:a,v1:a,dr:a)
|
||||
|
||||
``ac``
|
||||
high quality pp filter combination (ha:a:128:7,va:a,dr:a)
|
||||
|
||||
.. note::
|
||||
|
||||
This filter is only available if FFmpeg/libav has been compiled
|
||||
with libpostproc enabled.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``--vf=pp=hb/vb/dr/al``
|
||||
horizontal and vertical deblocking, deringing and automatic
|
||||
brightness/contrast
|
||||
|
||||
``--vf=pp=de/-al``
|
||||
default filters without brightness/contrast correction
|
||||
|
||||
``--vf=pp=[default/tmpnoise:1:2:3]``
|
||||
Enable default filters & temporal denoiser.
|
||||
|
||||
``--vf=pp=[hb:y/vb:a]``
|
||||
Horizontal deblocking on luminance only, and switch vertical
|
||||
deblocking on or off automatically depending on available CPU time.
|
||||
|
||||
``lavfi=graph[:sws-flags[:o=opts]]``
|
||||
Filter video using FFmpeg's libavfilter.
|
||||
|
||||
@@ -406,6 +424,45 @@ Available filters are:
|
||||
``'--vf=lavfi=yadif:o="threads=2,thread_type=slice"'``
|
||||
forces a specific threading configuration.
|
||||
|
||||
``noise[=<strength>[:averaged][:pattern][:temporal][:uniform][:hq]``
|
||||
Adds noise.
|
||||
|
||||
``strength``
|
||||
Set the noise for all components. If you want different strength
|
||||
values for luma and chroma, use libavfilter's noise filter directly
|
||||
(using ``--vf=lavfi=[noise=...]``), or tell the libavfilter developers
|
||||
to stop being stupid.
|
||||
|
||||
``averaged``
|
||||
averaged temporal noise (smoother, but a lot slower)
|
||||
|
||||
``pattern``
|
||||
mix random noise with a (semi)regular pattern
|
||||
|
||||
``temporal``
|
||||
temporal noise (noise pattern changes between frames)
|
||||
|
||||
``uniform``
|
||||
uniform noise (gaussian otherwise)
|
||||
|
||||
``hq``
|
||||
high quality (slightly better looking, slightly slower) - not available
|
||||
when using libavfilter
|
||||
|
||||
``hqdn3d[=luma_spatial:chroma_spatial:luma_tmp:chroma_tmp]``
|
||||
This filter aims to reduce image noise producing smooth images and making
|
||||
still images really still (This should enhance compressibility.).
|
||||
|
||||
``<luma_spatial>``
|
||||
spatial luma strength (default: 4)
|
||||
``<chroma_spatial>``
|
||||
spatial chroma strength (default: 3)
|
||||
``<luma_tmp>``
|
||||
luma temporal strength (default: 6)
|
||||
``<chroma_tmp>``
|
||||
chroma temporal strength (default:
|
||||
``luma_tmp*chroma_spatial/luma_spatial``)
|
||||
|
||||
``eq[=gamma:contrast:brightness:saturation:rg:gg:bg:weight]``
|
||||
Software equalizer that uses lookup tables (slow), allowing gamma correction
|
||||
in addition to simple brightness and contrast adjustment. The parameters are
|
||||
@@ -432,6 +489,39 @@ Available filters are:
|
||||
and just plain white. A value of 0.0 turns the gamma correction all
|
||||
the way down while 1.0 leaves it at its full strength (default: 1.0).
|
||||
|
||||
``ilpack[=mode]``
|
||||
When interlaced video is stored in YUV 4:2:0 formats, chroma interlacing
|
||||
does not line up properly due to vertical downsampling of the chroma
|
||||
channels. This filter packs the planar 4:2:0 data into YUY2 (4:2:2) format
|
||||
with the chroma lines in their proper locations, so that in any given
|
||||
scanline, the luma and chroma data both come from the same field.
|
||||
|
||||
``<mode>``
|
||||
Select the sampling mode.
|
||||
|
||||
:0: nearest-neighbor sampling, fast but incorrect
|
||||
:1: linear interpolation (default)
|
||||
|
||||
``unsharp[=lx:ly:la:cx:cy:ca]``
|
||||
unsharp mask / gaussian blur
|
||||
|
||||
``l`` is for the luma component, ``c`` for the chroma component. ``x``/``y``
|
||||
is the filter size. ``a`` is the amount.
|
||||
|
||||
``lx``, ``ly``, ``cx``, ``cy``
|
||||
width and height of the matrix, odd sized in both directions (min =
|
||||
3:3, max = 13:11 or 11:13, usually something between 3:3 and 7:7)
|
||||
|
||||
``la``, ``ca``
|
||||
Relative amount of sharpness/blur to add to the image (a sane range
|
||||
should be -1.5-1.5).
|
||||
|
||||
:<0: blur
|
||||
:>0: sharpen
|
||||
|
||||
``swapuv``
|
||||
Swap U & V plane.
|
||||
|
||||
``pullup[=jl:jr:jt:jb:sb:mp]``
|
||||
Pulldown reversal (inverse telecine) filter, capable of handling mixed
|
||||
hard-telecine, 24000/1001 fps progressive, and 30000/1001 fps progressive
|
||||
@@ -451,8 +541,9 @@ Available filters are:
|
||||
generating an occasional mismatched frame, but it may also cause an
|
||||
excessive number of frames to be dropped during high motion sequences.
|
||||
Conversely, setting it to -1 will make ``pullup`` match fields more
|
||||
easily. This may help process video with slight blurring between the
|
||||
fields, but may also cause interlaced frames in the output.
|
||||
easily. This may help processing of video where there is slight
|
||||
blurring between the fields, but may also cause there to be interlaced
|
||||
frames in the output.
|
||||
|
||||
``mp`` (metric plane)
|
||||
This option may be set to ``u`` or ``v`` to use a chroma plane instead of the
|
||||
@@ -462,32 +553,169 @@ Available filters are:
|
||||
video. The main purpose of setting ``mp`` to a chroma plane is to reduce
|
||||
CPU load and make pullup usable in realtime on slow machines.
|
||||
|
||||
``yadif=[mode:interlaced-only]``
|
||||
``divtc[=options]``
|
||||
Inverse telecine for deinterlaced video. If 3:2-pulldown telecined video
|
||||
has lost one of the fields or is deinterlaced using a method that keeps
|
||||
one field and interpolates the other, the result is a juddering video that
|
||||
has every fourth frame duplicated. This filter is intended to find and
|
||||
drop those duplicates and restore the original film framerate. Two
|
||||
different modes are available: One-pass mode is the default and is
|
||||
straightforward to use, but has the disadvantage that any changes in the
|
||||
telecine phase (lost frames or bad edits) cause momentary judder until the
|
||||
filter can resync again. Two-pass mode avoids this by analyzing the entire
|
||||
video beforehand so it will have forward knowledge about the phase changes
|
||||
and can resync at the exact spot. These passes do *not* correspond to pass
|
||||
one and two of the encoding process. You must run an extra pass using
|
||||
``divtc`` pass one before the actual encoding throwing the resulting video
|
||||
away. Then use ``divtc`` pass two for the actual encoding. If you use
|
||||
multiple encoder passes, use ``divtc`` pass two for all of them.
|
||||
|
||||
The options are:
|
||||
|
||||
``pass=1|2``
|
||||
Use two pass mode.
|
||||
|
||||
``file=<filename>``
|
||||
Set the two pass log filename (default: ``framediff.log``).
|
||||
|
||||
``threshold=<value>``
|
||||
Set the minimum strength the telecine pattern must have for the filter
|
||||
to believe in it (default: 0.5). This is used to avoid recognizing
|
||||
false pattern from the parts of the video that are very dark or very
|
||||
still.
|
||||
|
||||
``window=<numframes>``
|
||||
Set the number of past frames to look at when searching for pattern
|
||||
(default: 30). Longer window improves the reliability of the pattern
|
||||
search, but shorter window improves the reaction time to the changes
|
||||
in the telecine phase. This only affects the one-pass mode. The
|
||||
two-pass mode currently uses fixed window that extends to both future
|
||||
and past.
|
||||
|
||||
``phase=0|1|2|3|4``
|
||||
Sets the initial telecine phase for one pass mode (default: 0). The
|
||||
two-pass mode can see the future, so it is able to use the correct
|
||||
phase from the beginning, but one-pass mode can only guess. It catches
|
||||
the correct phase when it finds it, but this option can be used to fix
|
||||
the possible juddering at the beginning. The first pass of the two
|
||||
pass mode also uses this, so if you save the output from the first
|
||||
pass, you get constant phase result.
|
||||
|
||||
``deghost=<value>``
|
||||
Set the deghosting threshold (0-255 for one-pass mode, -255-255 for
|
||||
two-pass mode, default 0). If nonzero, deghosting mode is used. This
|
||||
is for video that has been deinterlaced by blending the fields
|
||||
together instead of dropping one of the fields. Deghosting amplifies
|
||||
any compression artifacts in the blended frames, so the parameter
|
||||
value is used as a threshold to exclude those pixels from deghosting
|
||||
that differ from the previous frame less than specified value. If two
|
||||
pass mode is used, then negative value can be used to make the filter
|
||||
analyze the whole video in the beginning of pass-2 to determine
|
||||
whether it needs deghosting or not and then select either zero or the
|
||||
absolute value of the parameter. Specify this option for pass 2, it
|
||||
makes no difference on pass 1.
|
||||
|
||||
``phase[=t|b|p|a|u|T|B|A|U][:v]``
|
||||
Delay interlaced video by one field time so that the field order changes.
|
||||
The intended use is to fix PAL movies that have been captured with the
|
||||
opposite field order to the film-to-video transfer. The options are:
|
||||
|
||||
``t``
|
||||
Capture field order top-first, transfer bottom-first. Filter will
|
||||
delay the bottom field.
|
||||
|
||||
``b``
|
||||
Capture bottom-first, transfer top-first. Filter will delay the top
|
||||
field.
|
||||
|
||||
``p``
|
||||
Capture and transfer with the same field order. This mode only exists
|
||||
for the documentation of the other options to refer to, but if you
|
||||
actually select it, the filter will faithfully do nothing ;-)
|
||||
|
||||
``a``
|
||||
Capture field order determined automatically by field flags, transfer
|
||||
opposite. Filter selects among ``t`` and ``b`` modes on a frame by frame
|
||||
basis using field flags. If no field information is available, then this
|
||||
works just like ``u``.
|
||||
|
||||
``u``
|
||||
Capture unknown or varying, transfer opposite. Filter selects among
|
||||
``t`` and ``b`` on a frame by frame basis by analyzing the images and
|
||||
selecting the alternative that produces best match between the fields.
|
||||
|
||||
``T``
|
||||
Capture top-first, transfer unknown or varying. Filter selects among
|
||||
``t`` and ``p`` using image analysis.
|
||||
|
||||
``B``
|
||||
Capture bottom-first, transfer unknown or varying. Filter selects
|
||||
among ``b`` and ``p`` using image analysis.
|
||||
|
||||
``A``
|
||||
Capture determined by field flags, transfer unknown or varying. Filter
|
||||
selects among ``t``, ``b`` and ``p`` using field flags and image
|
||||
analysis. If no field information is available, then this works just
|
||||
like ``U``. This is the default mode.
|
||||
|
||||
``U``
|
||||
Both capture and transfer unknown or varying. Filter selects among
|
||||
``t``, ``b`` and ``p`` using image analysis only.
|
||||
|
||||
``v``
|
||||
Verbose operation. Prints the selected mode for each frame and the
|
||||
average squared difference between fields for ``t``, ``b``, and ``p``
|
||||
alternatives. (Ignored when libavfilter is used.)
|
||||
|
||||
``yadif=[mode[:enabled=yes|no]]``
|
||||
Yet another deinterlacing filter
|
||||
|
||||
``<mode>``
|
||||
:frame: Output 1 frame for each frame.
|
||||
:field: Output 1 frame for each field (default).
|
||||
:field: Output 1 frame for each field.
|
||||
:frame-nospatial: Like ``frame`` but skips spatial interlacing check.
|
||||
:field-nospatial: Like ``field`` but skips spatial interlacing check.
|
||||
|
||||
``<interlaced-only>``
|
||||
:no: Deinterlace all frames.
|
||||
:yes: Only deinterlace frames marked as interlaced (default).
|
||||
``<enabled>``
|
||||
:yes: Filter is active (default).
|
||||
:no: Filter is not active, but can be activated with the ``D`` key
|
||||
(or any other key that toggles the ``deinterlace`` property).
|
||||
|
||||
This filter is automatically inserted when using the ``d`` key (or any
|
||||
This filter, is automatically inserted when using the ``D`` key (or any
|
||||
other key that toggles the ``deinterlace`` property or when using the
|
||||
``--deinterlace`` switch), assuming the video output does not have native
|
||||
deinterlacing support.
|
||||
|
||||
If you just want to set the default mode, put this filter and its options
|
||||
into ``--vf-defaults`` instead, and enable deinterlacing with ``d`` or
|
||||
into ``--vf-defaults`` instead, and enable deinterlacing with ``D`` or
|
||||
``--deinterlace``.
|
||||
|
||||
Also, note that the ``d`` key is stupid enough to insert a deinterlacer twice
|
||||
Also note that the ``D`` key is stupid enough to insert an interlacer twice
|
||||
when inserting yadif with ``--vf``, so using the above methods is
|
||||
recommended.
|
||||
|
||||
``delogo[=x:y:w:h:t:show]``
|
||||
Suppresses a TV station logo by a simple interpolation of the surrounding
|
||||
pixels. Just set a rectangle covering the logo and watch it disappear (and
|
||||
sometimes something even uglier appear - your mileage may vary).
|
||||
|
||||
``<x>,<y>``
|
||||
top left corner of the logo
|
||||
``<w>,<h>``
|
||||
width and height of the cleared rectangle
|
||||
``<t>``
|
||||
Thickness of the fuzzy edge of the rectangle (added to ``w`` and
|
||||
``h``). When set to -1, a green rectangle is drawn on the screen to
|
||||
simplify finding the right ``x``,``y``,``w``,``h`` parameters.
|
||||
``show``
|
||||
Draw a rectangle showing the area defined by x/y/w/h.
|
||||
|
||||
``screenshot``
|
||||
Optional filter for screenshot support. This is only needed if the video
|
||||
output does not provide working direct screenshot support. Note that it is
|
||||
not always safe to insert this filter by default. See `TAKING SCREENSHOTS`_
|
||||
for details.
|
||||
|
||||
``sub=[=bottom-margin:top-margin]``
|
||||
Moves subtitle rendering to an arbitrary point in the filter chain, or force
|
||||
subtitle rendering in the video filter as opposed to using video output OSD
|
||||
@@ -495,9 +723,9 @@ Available filters are:
|
||||
|
||||
``<bottom-margin>``
|
||||
Adds a black band at the bottom of the frame. The SSA/ASS renderer can
|
||||
place subtitles there (with ``--sub-use-margins``).
|
||||
place subtitles there (with ``--ass-use-margins``).
|
||||
``<top-margin>``
|
||||
Black band on the top for toptitles (with ``--sub-use-margins``).
|
||||
Black band on the top for toptitles (with ``--ass-use-margins``).
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
@@ -541,8 +769,8 @@ Available filters are:
|
||||
anaglyph red/cyan color (red filter on left eye, cyan filter on
|
||||
right eye)
|
||||
``arcd`` or ``anaglyph_red_cyan_dubois``
|
||||
anaglyph red/cyan color optimized with the least-squares
|
||||
projection of Dubois (red filter on left eye, cyan filter on right
|
||||
anaglyph red/cyan color optimized with the least squares
|
||||
projection of dubois (red filter on left eye, cyan filter on right
|
||||
eye)
|
||||
``agmg`` or ``anaglyph_green_magenta_gray``
|
||||
anaglyph green/magenta gray (green filter on left eye, magenta
|
||||
@@ -575,7 +803,7 @@ Available filters are:
|
||||
|
||||
``gradfun[=strength[:radius|:size=<size>]]``
|
||||
Fix the banding artifacts that are sometimes introduced into nearly flat
|
||||
regions by truncation to 8-bit color depth. Interpolates the gradients that
|
||||
regions by truncation to 8bit color depth. Interpolates the gradients that
|
||||
should go where the bands are, and dithers them.
|
||||
|
||||
``<strength>``
|
||||
@@ -596,8 +824,6 @@ Available filters are:
|
||||
Loads an external library to filter the image. The library interface
|
||||
is the ``vf_dlopen`` interface specified using ``libmpcodecs/vf_dlopen.h``.
|
||||
|
||||
.. warning:: This filter is deprecated.
|
||||
|
||||
``dll=<library>``
|
||||
Specify the library to load. This may require a full file system path
|
||||
in some cases. This argument is required.
|
||||
@@ -656,11 +882,10 @@ Available filters are:
|
||||
``buffered-frames``
|
||||
Maximum number of decoded video frames that should be buffered before
|
||||
the filter (default: 4). This specifies the maximum number of frames
|
||||
the script can request in reverse direction.
|
||||
E.g. if ``buffered-frames=5``, and the script just requested frame 15,
|
||||
it can still request frame 10, but frame 9 is not available anymore.
|
||||
If it requests frame 30, mpv will decode 15 more frames, and keep only
|
||||
frames 25-30.
|
||||
the script can requests backwards. E.g. if ``buffered-frames=5``, and
|
||||
the script just requested frame 15, it can still request frame 10, but
|
||||
frame 9 is not available anymore. If it requests frame 30, mpv will
|
||||
decode 15 more frames, and keep only frames 25-30.
|
||||
|
||||
The actual number of buffered frames also depends on the value of the
|
||||
``concurrent-frames`` option. Currently, both option values are
|
||||
@@ -672,68 +897,17 @@ Available filters are:
|
||||
filters work anyway.)
|
||||
|
||||
``concurrent-frames``
|
||||
Number of frames that should be requested in parallel. The
|
||||
Number of frames that should be requested in parallel (default: 2). The
|
||||
level of concurrency depends on the filter and how quickly mpv can
|
||||
decode video to feed the filter. This value should probably be
|
||||
proportional to the number of cores on your machine. Most time,
|
||||
making it higher than the number of cores can actually make it
|
||||
slower.
|
||||
|
||||
By default, this uses the special value ``auto``, which sets the option
|
||||
to the number of detected logical CPU cores.
|
||||
|
||||
The following variables are defined by mpv:
|
||||
|
||||
``video_in``
|
||||
The mpv video source as vapoursynth clip. Note that this has no length
|
||||
set, which confuses many filters. Using ``Trim`` on the clip with a
|
||||
high dummy length can turn it into a finite clip.
|
||||
|
||||
``video_in_dw``, ``video_in_dh``
|
||||
Display size of the video. Can be different from video size if the
|
||||
video does not use square pixels (e.g. DVD).
|
||||
|
||||
``container_fps``
|
||||
FPS value as reported by file headers. This value can be wrong or
|
||||
completely broken (e.g. 0 or NaN). Even if the value is correct,
|
||||
if another filter changes the real FPS (by dropping or inserting
|
||||
frames), the value of this variable might not be useful. Note that
|
||||
the ``--fps`` command line option overrides this value.
|
||||
|
||||
Useful for some filters which insist on having a FPS.
|
||||
|
||||
``display_fps``
|
||||
Refresh rate of the current display. Note that this value can be 0.
|
||||
|
||||
``vapoursynth-lazy``
|
||||
The same as ``vapoursynth``, but doesn't load Python scripts. Instead, a
|
||||
custom backend using Lua and the raw VapourSynth API is used. The syntax
|
||||
is completely different, and absolutely no convenience features are
|
||||
provided. There's no type checking either, and you can trigger crashes.
|
||||
|
||||
.. admonition:: Example:
|
||||
|
||||
::
|
||||
|
||||
video_out = invoke("morpho", "Open", {clip = video_in})
|
||||
|
||||
The special variable ``video_in`` is the mpv video source, while the
|
||||
special variable ``video_out`` is used to read video from. The 1st argument
|
||||
is the plugin (queried with ``getPluginByNs``), the 2nd is the filter name,
|
||||
and the 3rd argument is a table with the arguments. Positional arguments
|
||||
are not supported. The types must match exactly. Since Lua is terrible and
|
||||
can't distinguish integers and floats, integer arguments must be prefixed
|
||||
with ``i_``, in which case the prefix is removed and the argument is cast
|
||||
to an integer. Should the argument's name start with ``i_``, you're out of
|
||||
luck.
|
||||
|
||||
Clips (VSNodeRef) are passed as light userdata, so trying to pass any
|
||||
other userdata type will result in hard crashes.
|
||||
|
||||
``vavpp``
|
||||
VA-AP-API video post processing. Works with ``--vo=vaapi`` and ``--vo=opengl``
|
||||
only. Currently deinterlaces. This filter is automatically inserted if
|
||||
deinterlacing is requested (either using the ``d`` key, by default mapped to
|
||||
deinterlacing is requested (either using the ``D`` key, by default mapped to
|
||||
the command ``cycle deinterlace``, or the ``--deinterlace`` option).
|
||||
|
||||
``deint=<method>``
|
||||
@@ -745,19 +919,11 @@ Available filters are:
|
||||
Show only first field (going by ``--field-dominance``).
|
||||
bob
|
||||
bob deinterlacing (default).
|
||||
weave, motion-adaptive, motion-compensated
|
||||
Advanced deinterlacing algorithms. Whether these actually work
|
||||
depends on the GPU hardware, the GPU drivers, driver bugs, and
|
||||
mpv bugs.
|
||||
|
||||
``<interlaced-only>``
|
||||
:no: Deinterlace all frames.
|
||||
:yes: Only deinterlace frames marked as interlaced (default).
|
||||
|
||||
``vdpaupp``
|
||||
VDPAU video post processing. Works with ``--vo=vdpau`` and ``--vo=opengl``
|
||||
only. This filter is automatically inserted if deinterlacing is requested
|
||||
(either using the ``d`` key, by default mapped to the command
|
||||
(either using the ``D`` key, by default mapped to the command
|
||||
``cycle deinterlace``, or the ``--deinterlace`` option). When enabling
|
||||
deinterlacing, it is always preferred over software deinterlacer filters
|
||||
if the ``vdpau`` VO is used, and also if ``opengl`` is used and hardware
|
||||
@@ -798,38 +964,8 @@ Available filters are:
|
||||
``pullup``
|
||||
Try to apply inverse telecine, needs motion adaptive temporal
|
||||
deinterlacing.
|
||||
``interlaced-only=<yes|no>``
|
||||
If ``yes`` (default), only deinterlace frames marked as interlaced.
|
||||
``hqscaling=<0-9>``
|
||||
0
|
||||
Use default VDPAU scaling (default).
|
||||
1-9
|
||||
Apply high quality VDPAU scaling (needs capable hardware).
|
||||
|
||||
``vdpaurb``
|
||||
VDPAU video read back. Works with ``--vo=vdpau`` and ``--vo=opengl`` only.
|
||||
This filter will read back frames decoded by VDPAU so that other filters,
|
||||
which are not normally compatible with VDPAU, can be used like normal.
|
||||
This filter must be specified before ``vdpaupp`` in the filter chain if
|
||||
``vdpaupp`` is used.
|
||||
|
||||
``d3d11vpp``
|
||||
Direct3D 11 video post processing. Currently requires D3D11 hardware
|
||||
decoding for use.
|
||||
|
||||
``deint=<yes|no>``
|
||||
Whether deinterlacing is enabled (default: no).
|
||||
``interlaced-only=<yes|no>``
|
||||
If ``yes`` (default), only deinterlace frames marked as interlaced.
|
||||
``mode=<blend|bob|adaptive|mocomp|ivctc|none>``
|
||||
Tries to select a video processor with the given processing capability.
|
||||
If a video processor supports multiple capabilities, it is not clear
|
||||
which algorithm is actually selected. ``none`` always falls back. On
|
||||
most if not all hardware, this option will probably do nothing, because
|
||||
a video processor usually supports all modes or none.
|
||||
|
||||
``buffer=<num>``
|
||||
Buffer ``<num>`` frames in the filter chain. This filter is probably pretty
|
||||
useless, except for debugging. (Note that this won't help to smooth out
|
||||
latencies with decoding, because the filter will never output a frame if
|
||||
the buffer isn't full, except on EOF.)
|
||||
+574
-201
@@ -4,25 +4,29 @@ VIDEO OUTPUT DRIVERS
|
||||
Video output drivers are interfaces to different video output facilities. The
|
||||
syntax is:
|
||||
|
||||
``--vo=<driver1,driver2,...[,]>``
|
||||
``--vo=<driver1[:suboption1[=value]:...],driver2,...[,]>``
|
||||
Specify a priority list of video output drivers to be used.
|
||||
|
||||
If the list has a trailing ``,``, mpv will fall back on drivers not contained
|
||||
in the list.
|
||||
If the list has a trailing ',', mpv will fall back on drivers not contained
|
||||
in the list. Suboptions are optional and can mostly be omitted.
|
||||
|
||||
You can also set defaults for each driver. The defaults are applied before the
|
||||
normal driver parameters.
|
||||
|
||||
``--vo-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
|
||||
Set defaults for each driver.
|
||||
|
||||
Deprecated. No replacement.
|
||||
|
||||
.. note::
|
||||
|
||||
See ``--vo=help`` for a list of compiled-in video output drivers.
|
||||
|
||||
The recommended output driver is ``--vo=opengl``, which is the default. All
|
||||
other drivers are for compatibility or special purposes. If the default
|
||||
does not work, it will fallback to other drivers (in the same order as
|
||||
listed by ``--vo=help``).
|
||||
The recommended output drivers are ``--vo=vdpau`` and ``--vo=opengl-hq``.
|
||||
All other drivers are just for compatibility or special purposes.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``--vo=opengl,xv,``
|
||||
Try the ``opengl`` driver, then the ``xv`` driver, then others.
|
||||
|
||||
Available video output drivers are:
|
||||
|
||||
@@ -33,44 +37,37 @@ Available video output drivers are:
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--xv-adaptor=<number>``
|
||||
Select a specific XVideo adapter (check xvinfo results).
|
||||
``--xv-port=<number>``
|
||||
``adaptor=<number>``
|
||||
Select a specific XVideo adaptor (check xvinfo results).
|
||||
``port=<number>``
|
||||
Select a specific XVideo port.
|
||||
``--xv-ck=<cur|use|set>``
|
||||
Select the source from which the color key is taken (default: cur).
|
||||
``ck=<cur|use|set>``
|
||||
Select the source from which the colorkey is taken (default: cur).
|
||||
|
||||
cur
|
||||
The default takes the color key currently set in Xv.
|
||||
The default takes the colorkey currently set in Xv.
|
||||
use
|
||||
Use but do not set the color key from mpv (use the ``--colorkey``
|
||||
Use but do not set the colorkey from mpv (use the ``--colorkey``
|
||||
option to change it).
|
||||
set
|
||||
Same as use but also sets the supplied color key.
|
||||
Same as use but also sets the supplied colorkey.
|
||||
|
||||
``--xv-ck-method=<none|man|bg|auto>``
|
||||
Sets the color key drawing method (default: man).
|
||||
``ck-method=<man|bg|auto>``
|
||||
Sets the colorkey drawing method (default: man).
|
||||
|
||||
none
|
||||
Disables color-keying.
|
||||
man
|
||||
Draw the color key manually (reduces flicker in some cases).
|
||||
Draw the colorkey manually (reduces flicker in some cases).
|
||||
bg
|
||||
Set the color key as window background.
|
||||
Set the colorkey as window background.
|
||||
auto
|
||||
Let Xv draw the color key.
|
||||
Let Xv draw the colorkey.
|
||||
|
||||
``--xv-colorkey=<number>``
|
||||
Changes the color key to an RGB value of your choice. ``0x000000`` is
|
||||
``colorkey=<number>``
|
||||
Changes the colorkey to an RGB value of your choice. ``0x000000`` is
|
||||
black and ``0xffffff`` is white.
|
||||
|
||||
``--xv-buffers=<number>``
|
||||
Number of image buffers to use for the internal ringbuffer (default: 2).
|
||||
Increasing this will use more memory, but might help with the X server
|
||||
not responding quickly enough if video FPS is close to or higher than
|
||||
the display refresh rate.
|
||||
``no-colorkey``
|
||||
Disables colorkeying.
|
||||
|
||||
``x11`` (X11 only)
|
||||
Shared memory video output driver without hardware acceleration that works
|
||||
@@ -85,29 +82,27 @@ Available video output drivers are:
|
||||
.. note::
|
||||
|
||||
Earlier versions of mpv (and MPlayer, mplayer2) provided sub-options
|
||||
to tune vdpau post-processing, like ``deint``, ``sharpen``, ``denoise``,
|
||||
to tune vdpau postprocessing, like ``deint``, ``sharpen``, ``denoise``,
|
||||
``chroma-deint``, ``pullup``, ``hqscaling``. These sub-options are
|
||||
deprecated, and you should use the ``vdpaupp`` video filter instead.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--vo-vdpau-sharpen=<-1-1>``
|
||||
``sharpen=<-1-1>``
|
||||
(Deprecated. See note about ``vdpaupp``.)
|
||||
|
||||
For positive values, apply a sharpening algorithm to the video, for
|
||||
negative values a blurring algorithm (default: 0).
|
||||
``--vo-vdpau-denoise=<0-1>``
|
||||
``denoise=<0-1>``
|
||||
(Deprecated. See note about ``vdpaupp``.)
|
||||
|
||||
Apply a noise reduction algorithm to the video (default: 0; no noise
|
||||
reduction).
|
||||
``--vo-vdpau-deint=<-4-4>``
|
||||
``deint=<-4-4>``
|
||||
(Deprecated. See note about ``vdpaupp``.)
|
||||
|
||||
Select deinterlacing mode (default: 0). In older versions (as well as
|
||||
MPlayer/mplayer2) you could use this option to enable deinterlacing.
|
||||
This doesn't work anymore, and deinterlacing is enabled with either
|
||||
the ``d`` key (by default mapped to the command ``cycle deinterlace``),
|
||||
the ``D`` key (by default mapped to the command ``cycle deinterlace``),
|
||||
or the ``--deinterlace`` option. Also, to select the default deint mode,
|
||||
you should use something like ``--vf-defaults=vdpaupp:deint-mode=temporal``
|
||||
instead of this sub-option.
|
||||
@@ -124,32 +119,32 @@ Available video output drivers are:
|
||||
4
|
||||
Motion-adaptive temporal deinterlacing with edge-guided spatial
|
||||
interpolation. Needs fast video hardware.
|
||||
``--vo-vdpau-chroma-deint``
|
||||
``chroma-deint``
|
||||
(Deprecated. See note about ``vdpaupp``.)
|
||||
|
||||
Makes temporal deinterlacers operate both on luma and chroma (default).
|
||||
Use no-chroma-deint to solely use luma and speed up advanced
|
||||
deinterlacing. Useful with slow video memory.
|
||||
``--vo-vdpau-pullup``
|
||||
``pullup``
|
||||
(Deprecated. See note about ``vdpaupp``.)
|
||||
|
||||
Try to apply inverse telecine, needs motion adaptive temporal
|
||||
deinterlacing.
|
||||
``--vo-vdpau-hqscaling=<0-9>``
|
||||
``hqscaling=<0-9>``
|
||||
(Deprecated. See note about ``vdpaupp``.)
|
||||
|
||||
0
|
||||
Use default VDPAU scaling (default).
|
||||
1-9
|
||||
Apply high quality VDPAU scaling (needs capable hardware).
|
||||
``--vo-vdpau-fps=<number>``
|
||||
``fps=<number>``
|
||||
Override autodetected display refresh rate value (the value is needed
|
||||
for framedrop to allow video playback rates higher than display
|
||||
refresh rate, and for vsync-aware frame timing adjustments). Default 0
|
||||
means use autodetected value. A positive value is interpreted as a
|
||||
refresh rate in Hz and overrides the autodetected value. A negative
|
||||
value disables all timing adjustment and framedrop logic.
|
||||
``--vo-vdpau-composite-detect``
|
||||
``composite-detect``
|
||||
NVIDIA's current VDPAU implementation behaves somewhat differently
|
||||
under a compositing window manager and does not give accurate frame
|
||||
timing information. With this option enabled, the player tries to
|
||||
@@ -160,25 +155,25 @@ Available video output drivers are:
|
||||
with the composited mode behavior of the NVIDIA driver, there is no
|
||||
hard playback speed limit even without the disabled logic. Enabled by
|
||||
default, use ``no-composite-detect`` to disable.
|
||||
``--vo-vdpau-queuetime-windowed=<number>`` and ``queuetime-fs=<number>``
|
||||
``queuetime_windowed=<number>`` and ``queuetime_fs=<number>``
|
||||
Use VDPAU's presentation queue functionality to queue future video
|
||||
frame changes at most this many milliseconds in advance (default: 50).
|
||||
See below for additional information.
|
||||
``--vo-vdpau-output-surfaces=<2-15>``
|
||||
``output_surfaces=<2-15>``
|
||||
Allocate this many output surfaces to display video frames (default:
|
||||
3). See below for additional information.
|
||||
``--vo-vdpau-colorkey=<#RRGGBB|#AARRGGBB>``
|
||||
``colorkey=<#RRGGBB|#AARRGGBB>``
|
||||
Set the VDPAU presentation queue background color, which in practice
|
||||
is the colorkey used if VDPAU operates in overlay mode (default:
|
||||
``#020507``, some shade of black). If the alpha component of this value
|
||||
is 0, the default VDPAU colorkey will be used instead (which is usually
|
||||
green).
|
||||
``--vo-vdpau-force-yuv``
|
||||
``force-yuv``
|
||||
Never accept RGBA input. This means mpv will insert a filter to convert
|
||||
to a YUV format before the VO. Sometimes useful to force availability
|
||||
of certain YUV-only features, like video equalizer or deinterlacing.
|
||||
|
||||
Using the VDPAU frame queuing functionality controlled by the queuetime
|
||||
Using the VDPAU frame queueing functionality controlled by the queuetime
|
||||
options makes mpv's frame flip timing less sensitive to system CPU load and
|
||||
allows mpv to start decoding the next frame(s) slightly earlier, which can
|
||||
reduce jitter caused by individual slow-to-decode frames. However, the
|
||||
@@ -200,40 +195,31 @@ Available video output drivers are:
|
||||
driver implementation may also have limits on the length of maximum
|
||||
queuing time or number of queued surfaces that work well or at all.
|
||||
|
||||
``direct3d`` (Windows only)
|
||||
``direct3d_shaders`` (Windows only)
|
||||
Video output driver that uses the Direct3D interface.
|
||||
|
||||
.. note:: This driver is for compatibility with systems that don't provide
|
||||
proper OpenGL drivers, and where ANGLE does not perform well.
|
||||
proper OpenGL drivers.
|
||||
|
||||
.. note:: Before to 0.21.0, ``direct3d_shaders`` and ``direct3d`` were
|
||||
different, with ``direct3d`` not using shader by default. Now
|
||||
both use shaders by default, and ``direct3d_shaders`` is a
|
||||
deprecated alias. Use the ``--vo-direct3d-prefer-stretchrect``
|
||||
or the ``--vo-direct3d-disable-shaders`` options to get the old
|
||||
behavior of ``direct3d``.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--vo-direct3d-prefer-stretchrect``
|
||||
``prefer-stretchrect``
|
||||
Use ``IDirect3DDevice9::StretchRect`` over other methods if possible.
|
||||
|
||||
``--vo-direct3d-disable-stretchrect``
|
||||
``disable-stretchrect``
|
||||
Never render the video using ``IDirect3DDevice9::StretchRect``.
|
||||
|
||||
``--vo-direct3d-disable-textures``
|
||||
``disable-textures``
|
||||
Never render the video using D3D texture rendering. Rendering with
|
||||
textures + shader will still be allowed. Add ``disable-shaders`` to
|
||||
completely disable video rendering with textures.
|
||||
|
||||
``--vo-direct3d-disable-shaders``
|
||||
``disable-shaders``
|
||||
Never use shaders when rendering video.
|
||||
|
||||
``--vo-direct3d-only-8bit``
|
||||
``only-8bit``
|
||||
Never render YUV video with more than 8 bits per component.
|
||||
Using this flag will force software conversion to 8-bit.
|
||||
|
||||
``--vo-direct3d-disable-texture-align``
|
||||
``disable-texture-align``
|
||||
Normally texture sizes are always aligned to 16. With this option
|
||||
enabled, the video texture will always have exactly the same size as
|
||||
the video itself.
|
||||
@@ -243,72 +229,532 @@ Available video output drivers are:
|
||||
might crash, might cause slow downs, etc. Contact the developers if you
|
||||
actually need any of these for performance or proper operation.
|
||||
|
||||
``--vo-direct3d-force-power-of-2``
|
||||
``force-power-of-2``
|
||||
Always force textures to power of 2, even if the device reports
|
||||
non-power-of-2 texture sizes as supported.
|
||||
|
||||
``--vo-direct3d-texture-memory=<mode>``
|
||||
``texture-memory=N``
|
||||
Only affects operation with shaders/texturing enabled, and (E)OSD.
|
||||
Possible values:
|
||||
Values for N:
|
||||
|
||||
``default`` (default)
|
||||
Use ``D3DPOOL_DEFAULT``, with a ``D3DPOOL_SYSTEMMEM`` texture for
|
||||
locking. If the driver supports ``D3DDEVCAPS_TEXTURESYSTEMMEMORY``,
|
||||
``D3DPOOL_SYSTEMMEM`` is used directly.
|
||||
0
|
||||
default, will often use an additional shadow texture + copy
|
||||
1
|
||||
use ``D3DPOOL_MANAGED``
|
||||
2
|
||||
use ``D3DPOOL_DEFAULT``
|
||||
3
|
||||
use ``D3DPOOL_SYSTEMMEM``, but without shadow texture
|
||||
|
||||
``default-pool``
|
||||
Use ``D3DPOOL_DEFAULT``. (Like ``default``, but never use a
|
||||
shadow-texture.)
|
||||
|
||||
``default-pool-shadow``
|
||||
Use ``D3DPOOL_DEFAULT``, with a ``D3DPOOL_SYSTEMMEM`` texture for
|
||||
locking. (Like ``default``, but always force the shadow-texture.)
|
||||
|
||||
``managed``
|
||||
Use ``D3DPOOL_MANAGED``.
|
||||
|
||||
``scratch``
|
||||
Use ``D3DPOOL_SCRATCH``, with a ``D3DPOOL_SYSTEMMEM`` texture for
|
||||
locking.
|
||||
|
||||
``--vo-direct3d-swap-discard``
|
||||
``swap-discard``
|
||||
Use ``D3DSWAPEFFECT_DISCARD``, which might be faster.
|
||||
Might be slower too, as it must(?) clear every frame.
|
||||
|
||||
``--vo-direct3d-exact-backbuffer``
|
||||
``exact-backbuffer``
|
||||
Always resize the backbuffer to window size.
|
||||
|
||||
``direct3d`` (Windows only)
|
||||
Same as ``direct3d_shaders``, but with the options ``disable-textures``
|
||||
and ``disable-shaders`` forced.
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``corevideo`` (Mac OS X 10.6 and later)
|
||||
Mac OS X CoreVideo video output driver. Uses the CoreVideo APIs to fill
|
||||
PixelBuffers and generate OpenGL textures from them (useful as a fallback
|
||||
for ``opengl``).
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``opengl``
|
||||
OpenGL video output driver. It supports extended scaling methods, dithering
|
||||
and color management.
|
||||
|
||||
See `OpenGL renderer options`_ for options specific to this VO.
|
||||
By default, it tries to use fast and fail-safe settings. Use the alias
|
||||
``opengl-hq`` to use this driver with defaults set to high quality
|
||||
rendering.
|
||||
|
||||
By default, it tries to use fast and fail-safe settings. Use the
|
||||
``opengl-hq`` profile to use this driver with defaults set to high
|
||||
quality rendering. (This profile is also the replacement for
|
||||
``--vo=opengl-hq``.) The profile can be applied with ``--profile=opengl-hq``
|
||||
and its contents can be viewed with ``--show-profile=opengl-hq``.
|
||||
|
||||
Requires at least OpenGL 2.1.
|
||||
Requires at least OpenGL 2.1 and the ``GL_ARB_texture_rg`` extension. For
|
||||
older drivers, ``opengl-old`` may work.
|
||||
|
||||
Some features are available with OpenGL 3 capable graphics drivers only
|
||||
(or if the necessary extensions are available).
|
||||
|
||||
OpenGL ES 2.0 and 3.0 are supported as well.
|
||||
|
||||
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
|
||||
colorspace conversion and chroma upsampling is generally in the hand of
|
||||
the hardware decoder APIs.
|
||||
|
||||
``opengl`` makes use of FBOs by default. Sometimes you can achieve better
|
||||
quality or performance by changing the ``--opengl-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 OS X setups being very slow with ``rgb16`` but fast
|
||||
with ``rgb32f``. If you have problems, you can also try enabling the
|
||||
``--opengl-dumb-mode=yes`` option.
|
||||
``lscale=<filter>``
|
||||
|
||||
``bilinear``
|
||||
Bilinear hardware texture filtering (fastest, mid-quality).
|
||||
This is the default.
|
||||
|
||||
``lanczos2``
|
||||
Lanczos scaling with radius=2. Provides good quality and speed.
|
||||
|
||||
``lanczos3``
|
||||
Lanczos with radius=3.
|
||||
|
||||
``spline36``
|
||||
This is the default when using ``opengl-hq``.
|
||||
|
||||
``bicubic_fast``
|
||||
Bicubic filter. Has a blurring effect on the image, even if no
|
||||
scaling is done.
|
||||
|
||||
``sharpen3``
|
||||
Unsharp masking (sharpening) with radius=3 and a default strength
|
||||
of 0.5 (see ``lparam1``).
|
||||
|
||||
``sharpen5``
|
||||
Unsharp masking (sharpening) with radius=5 and a default strength
|
||||
of 0.5 (see ``lparam1``).
|
||||
|
||||
``mitchell``
|
||||
Mitchell-Netravali. The ``b`` and ``c`` parameters can be set with
|
||||
``lparam1`` and ``lparam2``. Both are set to 1/3 by default.
|
||||
|
||||
|
||||
There are some more filters. For a complete list, pass ``help`` as
|
||||
value, e.g.::
|
||||
|
||||
mpv --vo=opengl:lscale=help
|
||||
|
||||
``lparam1=<value>``
|
||||
Set filter parameters. Ignored if the filter is not tunable. These are
|
||||
unset by default, and use the filter specific default if applicable.
|
||||
|
||||
``lparam2=<value>``
|
||||
See ``lparam1``.
|
||||
|
||||
``scaler-resizes-only``
|
||||
Disable the scaler if the video image is not resized. In that case,
|
||||
``bilinear`` is used instead whatever is set with ``lscale``. Bilinear
|
||||
will reproduce the source image perfectly if no scaling is performed.
|
||||
Note that this option never affects ``cscale``, although the different
|
||||
processing chain might do chroma scaling differently if ``lscale`` is
|
||||
disabled.
|
||||
|
||||
``stereo=<value>``
|
||||
Select a method for stereo display. You may have to use
|
||||
``--video-aspect`` to fix the aspect value. Experimental, do not expect
|
||||
too much from it.
|
||||
|
||||
no
|
||||
Normal 2D display
|
||||
red-cyan
|
||||
Convert side by side input to full-color red-cyan stereo.
|
||||
green-magenta
|
||||
Convert side by side input to full-color green-magenta stereo.
|
||||
quadbuffer
|
||||
Convert side by side input to quadbuffered stereo. Only supported
|
||||
by very few OpenGL cards.
|
||||
|
||||
``srgb``
|
||||
Convert and color correct the output to sRGB before displaying it on
|
||||
the screen. This option enables linear light scaling. It also forces
|
||||
the options ``indirect`` and ``gamma``.
|
||||
|
||||
This option is equivalent to using ``icc-profile`` with an sRGB ICC
|
||||
profile, but it is implemented without a 3DLUT and does not require
|
||||
LittleCMS 2. If both ``srgb`` and ``icc-profile`` are present, the
|
||||
latter takes precedence, as they are somewhat redundant.
|
||||
|
||||
Note: When playing back BT.2020 content with this option enabled, out
|
||||
of gamut colors will be numerically clipped, which can potentially
|
||||
change the hue and/or luminance. If this is not desired, it is
|
||||
recommended to use ``icc-profile`` with an sRGB ICC profile instead,
|
||||
when playing back wide-gamut BT.2020 content.
|
||||
|
||||
``pbo``
|
||||
Enable use of PBOs. This is slightly faster, but can sometimes lead to
|
||||
sporadic and temporary image corruption (in theory, because reupload
|
||||
is not retried when it fails), and perhaps actually triggers slower
|
||||
paths with drivers that don't support PBOs properly.
|
||||
|
||||
``dither-depth=<N|no|auto>``
|
||||
Set dither target depth to N. Default: no.
|
||||
|
||||
no
|
||||
Disable any dithering done by mpv.
|
||||
auto
|
||||
Automatic selection. If output bit depth cannot be detected,
|
||||
8 bits per component are assumed.
|
||||
8
|
||||
Dither to 8 bit output.
|
||||
|
||||
Note that the depth of the connected video display device can not be
|
||||
detected. Often, LCD panels will do dithering on their own, which
|
||||
conflicts with ``opengl``'s dithering and leads to ugly output.
|
||||
|
||||
``dither-size-fruit=<2-8>``
|
||||
Set the size of the dither matrix (default: 6). The actual size of
|
||||
the matrix is ``(2^N) x (2^N)`` for an option value of ``N``, so a
|
||||
value of 6 gives a size of 64x64. The matrix is generated at startup
|
||||
time, and a large matrix can take rather long to compute (seconds).
|
||||
|
||||
Used in ``dither=fruit`` mode only.
|
||||
|
||||
``dither=<fruit|ordered|no>``
|
||||
Select dithering algorithm (default: fruit).
|
||||
|
||||
``temporal-dither``
|
||||
Enable temporal dithering. (Only active if dithering is enabled in
|
||||
general.) This changes between 8 different dithering pattern on each
|
||||
frame by changing the orientation of the tiled dithering matrix.
|
||||
Unfortunately, this can lead to flicker on LCD displays, since these
|
||||
have a high reaction time.
|
||||
|
||||
``debug``
|
||||
Check for OpenGL errors, i.e. call ``glGetError()``. Also request a
|
||||
debug OpenGL context (which does nothing with current graphics drivers
|
||||
as of this writing).
|
||||
|
||||
``swapinterval=<n>``
|
||||
Interval in displayed frames between two buffer swaps.
|
||||
1 is equivalent to enable VSYNC, 0 to disable VSYNC.
|
||||
|
||||
``no-scale-sep``
|
||||
When using a separable scale filter for luma, usually two filter
|
||||
passes are done. This is often faster. However, it forces
|
||||
conversion to RGB in an extra pass, so it can actually be slower
|
||||
if used with fast filters on small screen resolutions. Using
|
||||
this options will make rendering a single operation.
|
||||
Note that chroma scalers are always done as 1-pass filters.
|
||||
|
||||
``cscale=<n>``
|
||||
As ``lscale``, but for chroma (2x slower with little visible effect).
|
||||
Note that with some scaling filters, upscaling is always done in
|
||||
RGB. If chroma is not subsampled, this option is ignored, and the
|
||||
luma scaler is used instead. Setting this option is often useless.
|
||||
|
||||
``fancy-downscaling``
|
||||
When using convolution based filters, extend the filter size
|
||||
when downscaling. Trades quality for reduced downscaling performance.
|
||||
|
||||
``no-npot``
|
||||
Force use of power-of-2 texture sizes. For debugging only.
|
||||
Borders will be distorted due to filtering.
|
||||
|
||||
``glfinish``
|
||||
Call ``glFinish()`` before swapping buffers
|
||||
|
||||
``sw``
|
||||
Continue even if a software renderer is detected.
|
||||
|
||||
``backend=<sys>``
|
||||
The value ``auto`` (the default) selects the windowing backend. You
|
||||
can also pass ``help`` to get a complete list of compiled in backends
|
||||
(sorted by autoprobe order).
|
||||
|
||||
auto
|
||||
auto-select (default)
|
||||
cocoa
|
||||
Cocoa/OSX
|
||||
win
|
||||
Win32/WGL
|
||||
x11
|
||||
X11/GLX
|
||||
wayland
|
||||
Wayland/EGL
|
||||
|
||||
``indirect``
|
||||
Do YUV conversion and scaling as separate passes. This will first render
|
||||
the video into a video-sized RGB texture, and draw the result on screen.
|
||||
The luma scaler is used to scale the RGB image when rendering to screen.
|
||||
The chroma scaler is used only on YUV conversion, and only if the video
|
||||
is chroma-subsampled (usually the case).
|
||||
This mechanism is disabled on RGB input.
|
||||
Specifying this option directly is generally useful for debugging only.
|
||||
|
||||
``fbo-format=<fmt>``
|
||||
Selects the internal format of textures used for FBOs. The format can
|
||||
influence performance and quality of the video output. (FBOs are not
|
||||
always used, and typically only when using extended scalers.)
|
||||
``fmt`` can be one of: rgb, rgba, rgb8, rgb10, rgb10_a2, rgb16, rgb16f,
|
||||
rgb32f, rgba12, rgba16, rgba16f, rgba32f.
|
||||
Default: rgb.
|
||||
|
||||
``gamma=<0.0..10.0>``
|
||||
Set a gamma value. If gamma is adjusted in other ways (like with
|
||||
the ``--gamma`` option or keybindings and the ``gamma`` property), the
|
||||
value is multiplied with the other gamma value.
|
||||
|
||||
Setting this value to 1.0 can be used to always enable gamma control.
|
||||
(Disables delayed enabling.)
|
||||
|
||||
``icc-profile=<file>``
|
||||
Load an ICC profile and use it to transform linear RGB to screen output.
|
||||
Needs LittleCMS2 support compiled in. This option overrides the ``srgb``
|
||||
property, as using both is somewhat redundant. It also enables linear
|
||||
light scaling.
|
||||
|
||||
|
||||
``icc-profile-auto``
|
||||
Automatically select the ICC display profile currently specified by
|
||||
the display settings of the operating system.
|
||||
|
||||
NOTE: Only implemented on OS X with Cocoa.
|
||||
|
||||
``icc-cache=<file>``
|
||||
Store and load the 3D LUT created from the ICC profile in this file.
|
||||
This can be used to speed up loading, since LittleCMS2 can take a while
|
||||
to create the 3D LUT. Note that this file contains an uncompressed LUT.
|
||||
Its size depends on the ``3dlut-size``, and can be very big.
|
||||
|
||||
``icc-intent=<value>``
|
||||
Specifies the ICC Intent used for transformations between colorspaces.
|
||||
This affects the rendering when using ``icc-profile`` or ``srgb`` and
|
||||
also affects the way DCP XYZ content gets converted to RGB.
|
||||
|
||||
0
|
||||
perceptual
|
||||
1
|
||||
relative colorimetric (default)
|
||||
2
|
||||
saturation
|
||||
3
|
||||
absolute colorimetric
|
||||
|
||||
``approx-gamma``
|
||||
Approximate the actual gamma function as a pure power curve of
|
||||
1.95. A number of video editing programs and studios apparently use this
|
||||
for mastering instead of the true curve. Most notably, anything in the
|
||||
Apple ecosystem uses this approximation - including all programs
|
||||
compatible with it. It's a sound idea to try enabling this flag first
|
||||
when watching movies and shows to see if things look better that way.
|
||||
|
||||
This only affects the output when using either ``icc-profile`` or ``srgb``.
|
||||
|
||||
``3dlut-size=<r>x<g>x<b>``
|
||||
Size of the 3D LUT generated from the ICC profile in each dimension.
|
||||
Default is 128x256x64.
|
||||
Sizes must be a power of two, and 512 at most.
|
||||
|
||||
``alpha=<blend|yes|no>``
|
||||
Decides what to do if the input has an alpha component (default: blend).
|
||||
|
||||
blend
|
||||
Blend the frame against a black background.
|
||||
yes
|
||||
Try to create a framebuffer with alpha component. This only makes sense
|
||||
if the video contains alpha information (which is extremely rare). May
|
||||
not be supported on all platforms. If alpha framebuffers are
|
||||
unavailable, it silently falls back on a normal framebuffer. Note
|
||||
that when using FBO indirections (such as with ``opengl-hq``), an FBO
|
||||
format with alpha must be specified with the ``fbo-format`` option.
|
||||
no
|
||||
Ignore alpha component.
|
||||
|
||||
``chroma-location=<auto|center|left>``
|
||||
Set the YUV chroma sample location. auto means use the bitstream
|
||||
flags (default: auto).
|
||||
|
||||
``rectangle-textures``
|
||||
Force use of rectangle textures (default: no). Normally this shouldn't
|
||||
have any advantages over normal textures. Note that hardware decoding
|
||||
overrides this flag.
|
||||
|
||||
``opengl-hq``
|
||||
Same as ``opengl``, but with default settings for high quality rendering.
|
||||
|
||||
This is equivalent to::
|
||||
|
||||
--vo=opengl:lscale=spline36:dither-depth=auto:fbo-format=rgb16
|
||||
|
||||
Note that some cheaper LCDs do dithering that gravely interferes with
|
||||
``opengl``'s dithering. Disabling dithering with ``dither-depth=no`` helps.
|
||||
|
||||
Unlike ``opengl``, ``opengl-hq`` makes use of FBOs by default. Sometimes you
|
||||
can achieve better quality or performance by changing the ``fbo-format``
|
||||
suboption to ``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include
|
||||
Mesa/Intel not accepting ``rgb16``, Mesa sometimes not being compiled with
|
||||
float texture support, and some OSX setups being very slow with ``rgb16``
|
||||
but fast with ``rgb32f``.
|
||||
|
||||
``opengl-old``
|
||||
OpenGL video output driver, old version. Video size must be smaller
|
||||
than the maximum texture size of your OpenGL implementation. Intended to
|
||||
work even with the most basic OpenGL implementations, but also makes use
|
||||
of newer extensions which allow support for more color spaces.
|
||||
|
||||
The code performs very few checks, so if a feature does not work, this
|
||||
might be because it is not supported by your card and/or OpenGL
|
||||
implementation, even if you do not get any error message. Use ``glxinfo``
|
||||
or a similar tool to display the supported OpenGL extensions.
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``(no-)ati-hack``
|
||||
ATI drivers may give a corrupted image when PBOs are used (when using
|
||||
``force-pbo``). This option fixes this, at the expense of using a bit
|
||||
more memory.
|
||||
``(no-)force-pbo``
|
||||
Always uses PBOs to transfer textures even if this involves an extra
|
||||
copy. Currently this gives a little extra speed with NVIDIA drivers
|
||||
and a lot more speed with ATI drivers. May need the ``ati-hack``
|
||||
suboption to work correctly.
|
||||
``(no-)scaled-osd``
|
||||
Scales the OSD and subtitles instead of rendering them at display size
|
||||
(default: disabled).
|
||||
``rectangle=<0,1,2>``
|
||||
Select usage of rectangular textures, which saves video RAM, but often
|
||||
is slower (default: 0).
|
||||
|
||||
0
|
||||
Use power-of-two textures (default).
|
||||
1
|
||||
Use the ``GL_ARB_texture_rectangle`` extension.
|
||||
2
|
||||
Use the ``GL_ARB_texture_non_power_of_two`` extension. In some
|
||||
cases only supported in software and thus very slow.
|
||||
|
||||
``swapinterval=<n>``
|
||||
Minimum interval between two buffer swaps, counted in displayed frames
|
||||
(default: 1). 1 is equivalent to enabling VSYNC, 0 to disabling VSYNC.
|
||||
Values below 0 will leave it at the system default. This limits the
|
||||
framerate to (horizontal refresh rate / n). Requires
|
||||
``GLX_SGI_swap_control`` support to work. With some (most/all?)
|
||||
implementations this only works in fullscreen mode.
|
||||
``ycbcr``
|
||||
Use the ``GL_MESA_ycbcr_texture`` extension to convert YUV to RGB. In
|
||||
most cases this is probably slower than doing software conversion to
|
||||
RGB.
|
||||
``yuv=<n>``
|
||||
Select the type of YUV to RGB conversion. The default is
|
||||
auto-detection deciding between values 0 and 2.
|
||||
|
||||
0
|
||||
Use software conversion. Compatible with all OpenGL versions.
|
||||
Provides brightness, contrast and saturation control.
|
||||
1
|
||||
Same as 2. This used to use NVIDIA-specific extensions, which
|
||||
did not provide any advantages over using fragment programs, except
|
||||
possibly on very ancient graphics cards. It produced a gray-ish
|
||||
output, which is why it has been removed.
|
||||
2
|
||||
Use a fragment program. Needs the ``GL_ARB_fragment_program``
|
||||
extension and at least three texture units. Provides brightness,
|
||||
contrast, saturation and hue control.
|
||||
3
|
||||
Use a fragment program using the ``POW`` instruction. Needs the
|
||||
``GL_ARB_fragment_program`` extension and at least three texture
|
||||
units. Provides brightness, contrast, saturation, hue and gamma
|
||||
control. Gamma can also be set independently for red, green and
|
||||
blue. Method 4 is usually faster.
|
||||
4
|
||||
Use a fragment program with additional lookup. Needs the
|
||||
``GL_ARB_fragment_program`` extension and at least four texture
|
||||
units. Provides brightness, contrast, saturation, hue and gamma
|
||||
control. Gamma can also be set independently for red, green and
|
||||
blue.
|
||||
5
|
||||
Use ATI-specific method (for older cards). This uses an
|
||||
ATI-specific extension (``GL_ATI_fragment_shader`` - not
|
||||
``GL_ARB_fragment_shader``!). At least three texture units are
|
||||
needed. Provides saturation and hue control. This method is fast
|
||||
but inexact.
|
||||
6
|
||||
Use a 3D texture to do conversion via lookup. Needs the
|
||||
``GL_ARB_fragment_program extension`` and at least four texture
|
||||
units. Extremely slow (software emulation) on some (all?) ATI
|
||||
cards since it uses a texture with border pixels. Provides
|
||||
brightness, contrast, saturation, hue and gamma control. Gamma can
|
||||
also be set independently for red, green and blue. Speed depends
|
||||
more on GPU memory bandwidth than other methods.
|
||||
|
||||
``lscale=<n>``
|
||||
Select the scaling function to use for luminance scaling. Only valid
|
||||
for yuv modes 2, 3, 4 and 6.
|
||||
|
||||
0
|
||||
Use simple linear filtering (default).
|
||||
1
|
||||
Use bicubic B-spline filtering (better quality). Needs one
|
||||
additional texture unit. Older cards will not be able to handle
|
||||
this for chroma at least in fullscreen mode.
|
||||
2
|
||||
Use cubic filtering in horizontal, linear filtering in vertical
|
||||
direction. Works on a few more cards than method 1.
|
||||
3
|
||||
Same as 1 but does not use a lookup texture. Might be faster on
|
||||
some cards.
|
||||
4
|
||||
Use experimental unsharp masking with 3x3 support and a default
|
||||
strength of 0.5 (see ``filter-strength``).
|
||||
5
|
||||
Use experimental unsharp masking with 5x5 support and a default
|
||||
strength of 0.5 (see ``filter-strength``).
|
||||
|
||||
``cscale=<n>``
|
||||
Select the scaling function to use for chrominance scaling. For
|
||||
details see ``lscale``.
|
||||
``filter-strength=<value>``
|
||||
Set the effect strength for the ``lscale``/``cscale`` filters that
|
||||
support it.
|
||||
``stereo=<value>``
|
||||
Select a method for stereo display. You may have to use
|
||||
``--video-aspect`` to fix the aspect value. Experimental, do not expect
|
||||
too much from it.
|
||||
|
||||
0
|
||||
Normal 2D display
|
||||
1
|
||||
Convert side by side input to full-color red-cyan stereo.
|
||||
2
|
||||
Convert side by side input to full-color green-magenta stereo.
|
||||
3
|
||||
Convert side by side input to quadbuffered stereo. Only supported
|
||||
by very few OpenGL cards.
|
||||
|
||||
The following options are only useful if writing your own fragment programs.
|
||||
|
||||
``customprog=<filename>``
|
||||
Load a custom fragment program from ``<filename>``.
|
||||
``customtex=<filename>``
|
||||
Load a custom "gamma ramp" texture from ``<filename>``. This can be used
|
||||
in combination with ``yuv=4`` or with the ``customprog`` option.
|
||||
``(no-)customtlin``
|
||||
If enabled (default) use ``GL_LINEAR`` interpolation, otherwise use
|
||||
``GL_NEAREST`` for customtex texture.
|
||||
``(no-)customtrect``
|
||||
If enabled, use ``texture_rectangle`` for the ``customtex`` texture.
|
||||
Default is disabled.
|
||||
``(no-)mipmapgen``
|
||||
If enabled, mipmaps for the video are automatically generated. This
|
||||
should be useful together with the ``customprog`` and the ``TXB``
|
||||
instruction to implement blur filters with a large radius. For most
|
||||
OpenGL implementations, this is very slow for any non-RGB formats.
|
||||
Default is disabled.
|
||||
|
||||
Normally there is no reason to use the following options; they mostly
|
||||
exist for testing purposes.
|
||||
|
||||
``(no-)glfinish``
|
||||
Call ``glFinish()`` before swapping buffers. Slower but in some cases
|
||||
more correct output (default: disabled).
|
||||
``(no-)manyfmts``
|
||||
Enables support for more (RGB and BGR) color formats (default: enabled).
|
||||
Needs OpenGL version >= 1.2.
|
||||
``slice-height=<0-...>``
|
||||
Number of lines copied to texture in one piece (default: 0). 0 for
|
||||
whole image.
|
||||
``sw``
|
||||
Continue even if a software renderer is detected.
|
||||
|
||||
``backend=<sys>``
|
||||
auto
|
||||
auto-select (default)
|
||||
cocoa
|
||||
Cocoa/OSX
|
||||
win
|
||||
Win32/WGL
|
||||
x11
|
||||
X11/GLX
|
||||
wayland
|
||||
Wayland/EGL
|
||||
|
||||
``sdl``
|
||||
SDL 2.0+ Render video output driver, depending on system with or without
|
||||
@@ -318,12 +764,10 @@ Available video output drivers are:
|
||||
.. note:: This driver is for compatibility with systems that don't provide
|
||||
proper graphics drivers, or which support GLES only.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--sdl-sw``
|
||||
``sw``
|
||||
Continue even if a software renderer is detected.
|
||||
|
||||
``--sdl-switch-mode``
|
||||
``switch-mode``
|
||||
Instruct SDL to switch the monitor video mode when going fullscreen.
|
||||
|
||||
``vaapi``
|
||||
@@ -335,9 +779,7 @@ Available video output drivers are:
|
||||
.. note:: This driver is for compatibility with crappy systems. You can
|
||||
use vaapi hardware decoding with ``--vo=opengl`` too.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--vo-vaapi-scaling=<algorithm>``
|
||||
``scaling=<algorithm>``
|
||||
default
|
||||
Driver default (mpv default as well).
|
||||
fast
|
||||
@@ -347,9 +789,9 @@ Available video output drivers are:
|
||||
nla
|
||||
``non-linear anamorphic scaling``
|
||||
|
||||
``--vo-vaapi-deint-mode=<mode>``
|
||||
``deint-mode=<mode>``
|
||||
Select deinterlacing algorithm. Note that by default deinterlacing is
|
||||
initially always off, and needs to be enabled with the ``d`` key
|
||||
initially always off, and needs to be enabled with the ``D`` key
|
||||
(default key binding for ``cycle deinterlace``).
|
||||
|
||||
This option doesn't apply if libva supports video post processing (vpp).
|
||||
@@ -366,7 +808,7 @@ Available video output drivers are:
|
||||
bob
|
||||
bob deinterlacing (default for older libva).
|
||||
|
||||
``--vo-vaapi-scaled-osd=<yes|no>``
|
||||
``scaled-osd=<yes|no>``
|
||||
If enabled, then the OSD is rendered at video resolution and scaled to
|
||||
display resolution. By default, this is disabled, and the OSD is
|
||||
rendered at display resolution if the driver supports it.
|
||||
@@ -374,14 +816,6 @@ Available video output drivers are:
|
||||
``null``
|
||||
Produces no video output. Useful for benchmarking.
|
||||
|
||||
Usually, it's better to disable video with ``--no-video`` instead.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--vo-null-fps=<value>``
|
||||
Simulate display FPS. This artificially limits how many frames the
|
||||
VO accepts per second.
|
||||
|
||||
``caca``
|
||||
Color ASCII art video output driver that works on a text console.
|
||||
|
||||
@@ -391,9 +825,7 @@ Available video output drivers are:
|
||||
Output each frame into an image file in the current directory. Each file
|
||||
takes the frame number padded with leading zeros as name.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--vo-image-format=<format>``
|
||||
``format=<format>``
|
||||
Select the image file format.
|
||||
|
||||
jpg
|
||||
@@ -411,24 +843,24 @@ Available video output drivers are:
|
||||
tga
|
||||
Truevision TGA.
|
||||
|
||||
``--vo-image-png-compression=<0-9>``
|
||||
``png-compression=<0-9>``
|
||||
PNG compression factor (speed vs. file size tradeoff) (default: 7)
|
||||
``--vo-image-png-filter=<0-5>``
|
||||
``png-filter=<0-5>``
|
||||
Filter applied prior to PNG compression (0 = none; 1 = sub; 2 = up;
|
||||
3 = average; 4 = Paeth; 5 = mixed) (default: 5)
|
||||
``--vo-image-jpeg-quality=<0-100>``
|
||||
``jpeg-quality=<0-100>``
|
||||
JPEG quality factor (default: 90)
|
||||
``--vo-image-jpeg-progressive=<yes|no>``
|
||||
``(no-)jpeg-progressive``
|
||||
Specify standard or progressive JPEG (default: no).
|
||||
``--vo-image-jpeg-baseline=<yes|no>``
|
||||
``(no-)jpeg-baseline``
|
||||
Specify use of JPEG baseline or not (default: yes).
|
||||
``--vo-image-jpeg-optimize=<0-100>``
|
||||
``jpeg-optimize=<0-100>``
|
||||
JPEG optimization factor (default: 100)
|
||||
``--vo-image-jpeg-smooth=<0-100>``
|
||||
``jpeg-smooth=<0-100>``
|
||||
smooth factor (default: 0)
|
||||
``--vo-image-jpeg-dpi=<1->``
|
||||
``jpeg-dpi=<1->``
|
||||
JPEG DPI (default: 72)
|
||||
``--vo-image-outdir=<dirname>``
|
||||
``outdir=<dirname>``
|
||||
Specify the directory to save the image files to (default: ``./``).
|
||||
|
||||
``wayland`` (Wayland only)
|
||||
@@ -437,73 +869,14 @@ Available video output drivers are:
|
||||
.. note:: This driver is for compatibility with systems that don't provide
|
||||
working OpenGL drivers.
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--vo-wayland-alpha``
|
||||
``alpha``
|
||||
Use a buffer format that supports videos and images with alpha
|
||||
information
|
||||
``--vo-wayland-rgb565``
|
||||
``rgb565``
|
||||
Use RGB565 as buffer format. This format is implemented on most
|
||||
platforms, especially on embedded where it is far more efficient then
|
||||
RGB8888.
|
||||
``--vo-wayland-triple-buffering``
|
||||
``triple-buffering``
|
||||
Use 3 buffers instead of 2. This can lead to more fluid playback, but
|
||||
uses more memory.
|
||||
|
||||
``opengl-cb``
|
||||
For use with libmpv direct OpenGL embedding; useless in any other contexts.
|
||||
(See ``<mpv/opengl_cb.h>``.)
|
||||
|
||||
This also supports many of the options the ``opengl`` VO has.
|
||||
|
||||
``rpi`` (Raspberry Pi)
|
||||
Native video output on the Raspberry Pi using the MMAL API.
|
||||
|
||||
This is deprecated. Use ``--vo=opengl`` instead, which is the default and
|
||||
provides the same functionality. The ``rpi`` VO will be removed in
|
||||
mpv 0.22.0. Its functionality was folded into --vo=opengl, which now uses
|
||||
RPI hardware decoding by treating it as a hardware overlay (without applying
|
||||
GL filtering). Also to be changed in 0.22.0: the --fs flag will be reset to
|
||||
"no" by default (like on the other platforms).
|
||||
|
||||
The following deprecated global options are supported by this video output:
|
||||
|
||||
``--rpi-display=<number>``
|
||||
Select the display number on which the video overlay should be shown
|
||||
(default: 0).
|
||||
|
||||
``--rpi-layer=<number>``
|
||||
Select the dispmanx layer on which the video overlay should be shown
|
||||
(default: -10). Note that mpv will also use the 2 layers above the
|
||||
selected layer, to handle the window background and OSD. Actual video
|
||||
rendering will happen on the layer above the selected layer.
|
||||
|
||||
``--rpi-background=<yes|no>``
|
||||
Whether to render a black background behind the video (default: no).
|
||||
Normally it's better to kill the console framebuffer instead, which
|
||||
gives better performance.
|
||||
|
||||
``--rpi-osd=<yes|no>``
|
||||
Enabled by default. If disabled with ``no``, no OSD layer is created.
|
||||
This also means there will be no subtitles rendered.
|
||||
|
||||
``drm`` (Direct Rendering Manager)
|
||||
Video output driver using Kernel Mode Setting / Direct Rendering Manager.
|
||||
Should be used when one doesn't want to install full-blown graphical
|
||||
environment (e.g. no X). Does not support hardware acceleration (if you
|
||||
need this, check the ``drm-egl`` backend for ``opengl`` VO).
|
||||
|
||||
The following global options are supported by this video output:
|
||||
|
||||
``--drm-connector=[<gpu_number>.]<name>``
|
||||
Select the connector to use (usually this is a monitor.) If ``<name>``
|
||||
is empty or ``auto``, mpv renders the output on the first available
|
||||
connector. Use ``--drm-connector=help`` to get list of available
|
||||
connectors. When using multiple graphic cards, use the ``<gpu_number>``
|
||||
argument to disambiguate.
|
||||
(default: empty)
|
||||
|
||||
``--drm-mode=<number>``
|
||||
Mode ID to use (resolution, bit depth and frame rate).
|
||||
(default: 0)
|
||||
|
||||
@@ -1,453 +0,0 @@
|
||||
CHANGES FROM OTHER VERSIONS OF MPLAYER
|
||||
======================================
|
||||
|
||||
**mpv** is based on mplayer2, which in turn is based on the original MPlayer
|
||||
(also called mplayer, mplayer-svn, mplayer1). Many changes have been made, a
|
||||
large part of which is incompatible or completely changes how the player
|
||||
behaves. Although there are still many similarities to its ancestors, **mpv**
|
||||
should generally be treated as a completely different program.
|
||||
|
||||
.. admonition:: Warning
|
||||
This document is not updated anymore, and is incomplete and outdated.
|
||||
|
||||
General Changes from MPlayer to mpv
|
||||
-----------------------------------
|
||||
|
||||
This listing is about changes introduced by mplayer2 and mpv relatively to
|
||||
MPlayer.
|
||||
|
||||
Player
|
||||
~~~~~~
|
||||
|
||||
* New name for the binary (``mpv``). New location for config files (either
|
||||
``~/.config/mpv/mpv.conf``, or if you want, ``~/.mpv/config``).
|
||||
* Encoding functionality (replacement for MEncoder, see the `ENCODING`_ section).
|
||||
* Support for Lua scripting (see the `LUA SCRIPTING`_ section).
|
||||
* Better pause handling (e.g. do not unpause on a command).
|
||||
* Precise seeking support.
|
||||
* Improvements in audio/video sync handling.
|
||||
* Do not lose settings when playing a new file in the same player instance.
|
||||
* Slave mode compatibility broken (see below).
|
||||
* Re-enable screensaver while the player is paused.
|
||||
* Allow resuming playback at a later point with ``Shift+q``, also see the
|
||||
``quit-watch-later`` input command.
|
||||
* ``--keep-open`` option to stop the player from closing the window and
|
||||
exiting after playback ends.
|
||||
* A client API, that allows embedding **mpv** into applications
|
||||
(see ``libmpv/client.h`` in the sources).
|
||||
|
||||
Input
|
||||
~~~~~
|
||||
|
||||
* Improved default keybindings. MPlayer bindings are also available (see
|
||||
``etc/mplayer-input.conf`` in the source tree).
|
||||
* Improved responsiveness on user input.
|
||||
* Support for modifier keys (alt, shift, ctrl) in input.conf.
|
||||
* Allow customizing whether a key binding for seeking shows the video time, the
|
||||
OSD bar, or nothing (see the `Input Command Prefixes`_ section).
|
||||
* Support mapping multiple commands to one key.
|
||||
* Classic LIRC support was removed. Install remotes as input devices instead.
|
||||
This way they will send X11 key events to the mpv window, which can be bound
|
||||
using the normal ``input.conf``.
|
||||
Also see: http://github.com/mpv-player/mpv/wiki/IR-remotes
|
||||
* Joystick support was removed. It was considered useless and was the cause
|
||||
of some problems (e.g. a laptop's accelerator being recognized as joystick).
|
||||
* Support for relative seeking by percentage.
|
||||
|
||||
Audio
|
||||
~~~~~
|
||||
|
||||
* Support for gapless audio (see the ``--gapless-audio`` option).
|
||||
* Support for OSS4 volume control.
|
||||
* Improved support for PulseAudio.
|
||||
* Make ``--softvol`` default (**mpv** is not a mixer control panel).
|
||||
* By default, do pitch correction if playback speed is increased.
|
||||
* Improved downmixing and output of surround audio:
|
||||
|
||||
- Instead of using hardcoded pan filters to do remixing, libavresample is used
|
||||
- Channel maps are used to identify the channel layout, so e.g. ``3.0`` and
|
||||
``2.1`` audio can be distinguished.
|
||||
|
||||
Video
|
||||
~~~~~
|
||||
|
||||
* Wayland support.
|
||||
* Native support for VAAPI and VDA. Improved VDPAU video output.
|
||||
* Improved OpenGL output (see the ``opengl-hq`` video output).
|
||||
* Make hardware decoding work with the ``opengl`` video output.
|
||||
* Support for libavfilter (for video->video and audio->audio). This allows
|
||||
using most of FFmpeg's filters, which improve greatly on the old MPlayer
|
||||
filters in features, performance, and correctness.
|
||||
* More correct color reproduction (color matrix generation), including support
|
||||
for BT.2020 (Ultra HD). linear XYZ (Digital Cinema) and SMPTE ST2084 (HDR)
|
||||
inputs.
|
||||
* Support for color managed displays, via ICC profiles.
|
||||
* High-quality image resamplers (see the ``opengl`` ``scale`` suboption).
|
||||
* Support for scaling in (sigmoidized) linear light.
|
||||
* Better subtitle rendering using libass by default.
|
||||
* Improvements when playing multiple files (``-fixed-vo`` is default, do not
|
||||
reset settings by default when playing a new file).
|
||||
* Replace image video outputs (``--vo=jpeg`` etc.) with ``--vo=image``.
|
||||
* Removal of ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding
|
||||
can handle these use cases. For yuv4mpeg, for example, use::
|
||||
|
||||
mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop
|
||||
|
||||
* Image subtitles (DVDs etc.) are rendered in color and use more correct
|
||||
positioning (color for image subs can be disabled with ``--sub-gray``).
|
||||
* Support for the X11 video output is removed, since it was considered
|
||||
deprecated. SDL video output can still be used as a fallback.
|
||||
|
||||
OSD and terminal
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* Cleaned up terminal output: nicer status line, less useless noise.
|
||||
* Improved OSD rendering using libass, with full Unicode support.
|
||||
* New OSD bar with chapter marks. Not positioned in the middle of the video
|
||||
(this can be customized with the ``--osd-bar-align-y`` option).
|
||||
* Display list of chapters and audio/subtitle tracks on OSD (see the
|
||||
`Properties`_ section).
|
||||
|
||||
Screenshots
|
||||
~~~~~~~~~~~
|
||||
|
||||
* Instant screenshots without 1-frame delay.
|
||||
* Support for taking screenshots even with hardware decoding.
|
||||
* Support for saving screenshots as JPEG or PNG.
|
||||
* Support for configurable file names.
|
||||
* Support for taking screenshots with or without subtitles.
|
||||
|
||||
Note that the ``screenshot`` video filter is not needed anymore, and should not
|
||||
be put into the mpv config file.
|
||||
|
||||
Miscellaneous
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* Better MKV support (e.g. ordered chapters, 3D metadata).
|
||||
* Matroska edition switching at runtime.
|
||||
* Support for playing URLs of popular streaming sites directly.
|
||||
(e.g. ``mpv https://www.youtube.com/watch?v=...``).
|
||||
Requires a recent version of ``youtube-dl`` to be installed. Can be
|
||||
disabled with ``ytdl=no`` in the mpv config file.
|
||||
* Support for precise scrolling which scales the parameter of commands. If the
|
||||
input doesn't support precise scrolling the scale factor stays 1.
|
||||
* Allow changing/adjusting video filters at runtime. (This is also used to make
|
||||
the ``D`` key insert vf_yadif if deinterlacing is not supported otherwise).
|
||||
* Improved support for .cue files.
|
||||
|
||||
Mac OS X
|
||||
~~~~~~~~
|
||||
|
||||
* Native OpenGL backend.
|
||||
* Cocoa event loop is independent from MPlayer's event loop, so user
|
||||
actions like accessing menus and live resizing do not block the playback.
|
||||
* Apple Remote support.
|
||||
* Media Keys support.
|
||||
* VDA support using libavcodec hwaccel API instead of FFmpeg's decoder with up
|
||||
to 2-2.5x reduction in CPU usage.
|
||||
|
||||
Windows
|
||||
~~~~~~~
|
||||
|
||||
* Improved support for Unicode file names.
|
||||
* Improved window handling.
|
||||
* Do not block playback when moving the window.
|
||||
* Improved Direct3D video output.
|
||||
* Added WASAPI audio output.
|
||||
|
||||
Internal changes
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* Switch to GPLv2+ (see ``Copyright`` file for details).
|
||||
* Removal of lots of cruft:
|
||||
|
||||
- Internal GUI (replaced by the OSC, see the `ON SCREEN CONTROLLER`_ section).
|
||||
- MEncoder (replaced by native encoding, see the `ENCODING`_ section).
|
||||
- OSD menu.
|
||||
- Kernel video drivers for Linux 2.4 (including VIDIX).
|
||||
- Teletext support.
|
||||
- Support for dead platforms.
|
||||
- Most built-in demuxers have been replaced by their libavformat counterparts.
|
||||
- Built-in network support has been replaced by libavformat's (which also
|
||||
supports https URLs).
|
||||
- Embedded copies of libraries (such as FFmpeg).
|
||||
|
||||
* General code cleanups (including refactoring or rewrites of many parts).
|
||||
* New build system.
|
||||
* Many bug fixes and removal of long-standing issues.
|
||||
* Generally preferring FFmpeg/Libav over internal demuxers, decoders, and
|
||||
filters.
|
||||
|
||||
Detailed Listing of User-visible Changes
|
||||
----------------------------------------
|
||||
|
||||
This listing is about changed command line switches, slave commands, and similar
|
||||
things. Completely removed features are not listed.
|
||||
|
||||
Command Line Switches
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* There is a new command line syntax, which is generally preferred over the old
|
||||
syntax. ``-optname optvalue`` becomes ``--optname=optvalue``.
|
||||
|
||||
The old syntax will not be removed. However, the new syntax is mentioned in
|
||||
all documentation and so on, and unlike the old syntax is not ambiguous,
|
||||
so it is a good thing to know about this change.
|
||||
* In general, negating switches like ``-noopt`` now have to be written as
|
||||
``-no-opt`` or ``--no-opt``.
|
||||
* Per-file options are not the default anymore. You can explicitly specify
|
||||
file-local options. See ``Usage`` section.
|
||||
* Many options have been renamed, removed or changed semantics. Some options
|
||||
that are required for a good playback experience with MPlayer are now
|
||||
superfluous or even worse than the defaults, so make sure to read the manual
|
||||
before trying to use your existing configuration with **mpv**.
|
||||
* Table of renamed/replaced switches:
|
||||
|
||||
=========================== ========================================
|
||||
Old New
|
||||
=========================== ========================================
|
||||
``-no<opt>`` ``--no-<opt>`` (add a dash)
|
||||
``-a52drc level`` ``--ad-lavc-ac3drc=level``
|
||||
``-ac spdifac3`` ``--ad=spdif:ac3`` (see ``--ad=help``)
|
||||
``-af volnorm`` ``--af=drc`` (renamed)
|
||||
``-afm hwac3`` ``--ad=spdif:ac3,spdif:dts``
|
||||
``-ao alsa:device=hw=0.3`` ``--ao=alsa:device=[hw:0,3]``
|
||||
``-aspect`` ``--video-aspect``
|
||||
``-ass-bottom-margin`` ``--vf=sub=bottom:top``
|
||||
``-ass`` ``--sub-ass``
|
||||
``-audiofile-cache`` (removed; the main cache settings are used)
|
||||
``-audiofile`` ``--audio-file``
|
||||
``-benchmark`` ``--untimed`` (no stats)
|
||||
``-capture`` ``--stream-capture=<filename>``
|
||||
``-channels`` ``--audio-channels`` (changed semantics)
|
||||
``-cursor-autohide-delay`` ``--cursor-autohide``
|
||||
``-delay`` ``--audio-delay``
|
||||
``-dumpstream`` ``--stream-dump=<filename>``
|
||||
``-dvdangle`` ``--dvd-angle``
|
||||
``-endpos`` ``--length``
|
||||
``-fixed-vo`` (removed; always the default)
|
||||
``-font`` ``--osd-font``
|
||||
``-forcedsubsonly`` ``--sub-forced-only``
|
||||
``-forceidx`` ``--index``
|
||||
``-format`` ``--audio-format``
|
||||
``-fsmode-dontuse`` (removed)
|
||||
``-fstype`` ``--x11-netwm`` (changed semantics)
|
||||
``-hardframedrop`` ``--framedrop=hard``
|
||||
``-identify`` (removed; use TOOLS/mpv_identify.sh)
|
||||
``-idx`` ``--index``
|
||||
``-lavdopts ...`` ``--vd-lavc-...``
|
||||
``-lavfdopts`` ``--demuxer-lavf-...``
|
||||
``-loop 0`` ``--loop=inf``
|
||||
``-mixer-channel`` AO suboptions (``alsa``, ``oss``)
|
||||
``-mixer`` AO suboptions (``alsa``, ``oss``)
|
||||
``-mouse-movements`` ``--input-cursor``
|
||||
``-msgcolor`` ``--msg-color``
|
||||
``-msglevel`` ``--msg-level`` (changed semantics)
|
||||
``-msgmodule`` ``--msg-module``
|
||||
``-name`` ``--x11-name``
|
||||
``-noar`` ``--no-input-appleremote``
|
||||
``-noautosub`` ``--no-sub-auto``
|
||||
``-noconsolecontrols`` ``--no-input-terminal``
|
||||
``-nosound`` ``--no-audio``
|
||||
``-osdlevel`` ``--osd-level``
|
||||
``-panscanrange`` ``--video-zoom``, ``--video-pan-x/y``
|
||||
``-playing-msg`` ``--term-playing-msg``
|
||||
``-pp ...`` ``'--vf=lavfi=[pp=...]'``
|
||||
``-pphelp`` (See FFmpeg libavfilter documentation.)
|
||||
``-rawaudio ...`` ``--demuxer-rawaudio-...``
|
||||
``-rawvideo ...`` ``--demuxer-rawvideo-...``
|
||||
``-spugauss`` ``--sub-gauss``
|
||||
``-srate`` ``--audio-samplerate``
|
||||
``-ss`` ``--start``
|
||||
``-ssf <sub>`` ``--sws-...``
|
||||
``-stop-xscreensaver`` ``--stop-screensaver``
|
||||
``-sub-fuzziness`` ``--sub-auto``
|
||||
``-sub-text-*`` ``--sub-*``
|
||||
``-sub`` ``--sub-file``
|
||||
``-subcp`` ``--sub-codepage``
|
||||
``-subdelay`` ``--sub-delay``
|
||||
``-subfile`` ``--sub-file``
|
||||
``-subfont-*`` ``--sub-*``, ``--osd-*``
|
||||
``-subfont-text-scale`` ``--sub-scale``
|
||||
``-subfont`` ``--sub-font``
|
||||
``-subfps`` ``--sub-fps``
|
||||
``-subpos`` ``--sub-pos``
|
||||
``-sws`` ``--sws-scaler``
|
||||
``-tvscan`` ``--tv-scan``
|
||||
``-use-filename-title`` ``--title='${filename}'``
|
||||
``-vc ffh264vdpau`` (etc.) ``--hwdec=vdpau``
|
||||
``-vobsub`` ``--sub-file`` (pass the .idx file)
|
||||
``-x W``, ``-y H`` ``--geometry=WxH`` + ``--no-keepaspect``
|
||||
``-xineramascreen`` ``--screen`` (different values)
|
||||
``-xy W`` ``--autofit=W``
|
||||
``-zoom`` Inverse available as ``--video-unscaled``
|
||||
``dvdnav://`` Removed.
|
||||
``dvd://1`` ``dvd://0`` (0-based offset)
|
||||
=========================== ========================================
|
||||
|
||||
.. note::
|
||||
|
||||
``-opt val`` becomes ``--opt=val``.
|
||||
|
||||
.. note::
|
||||
|
||||
Quite some video filters, video outputs, audio filters, audio outputs, had
|
||||
changes in their option parsing. These aren't mentioned in the table above.
|
||||
|
||||
Also, some video and audio filters have been removed, and you have to use
|
||||
libavfilter (using ``--vf=lavfi=[...]`` or ``--af=lavfi=[...]``) to get
|
||||
them back.
|
||||
|
||||
input.conf and Slave Commands
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Table of renamed input commands:
|
||||
|
||||
This lists only commands that are not always gracefully handled by the
|
||||
internal legacy translation layer. If an input.conf contains any legacy
|
||||
commands, a warning will be printed when starting the player. The warnings
|
||||
also show the replacement commands.
|
||||
|
||||
Properties containing ``_`` to separate words use ``-`` instead.
|
||||
|
||||
+--------------------------------+----------------------------------------+
|
||||
| Old | New |
|
||||
+================================+========================================+
|
||||
| ``pt_step 1 [0|1]`` | ``playlist-next [weak|force]`` |
|
||||
| | (translation layer cannot deal with |
|
||||
| | whitespace) |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``pt_step -1 [0|1]`` | ``playlist-prev [weak|force] (same)`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``switch_ratio [<ratio>]`` | ``set video-aspect <ratio>`` |
|
||||
| | |
|
||||
| | ``set video-aspect 0`` (reset aspect) |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``step_property_osd <prop>`` | ``cycle <prop> <step>`` (wraps), |
|
||||
| ``<step> <dir>`` | ``add <prop> <step>`` (clamps). |
|
||||
| | ``<dir>`` parameter unsupported. Use |
|
||||
| | a negative ``<step>`` instead. |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``step_property <prop>`` | Prefix ``cycle`` or ``add`` with |
|
||||
| ``<step> <dir>`` | ``no-osd``: ``no-osd cycle <prop>`` |
|
||||
| | ``<step>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``osd_show_property_text`` | ``show-text <text>`` |
|
||||
| ``<text>`` | The property expansion format string |
|
||||
| | syntax slightly changed. |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``osd_show_text`` | Now does the same as |
|
||||
| | ``osd_show_property_text``. Use the |
|
||||
| | ``raw`` prefix to disable property |
|
||||
| | expansion. |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``show_tracks`` | ``show-text ${track-list}`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``show_chapters`` | ``show-text ${chapter-list}`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``af_switch``, ``af_add``, ... | ``af set|add|...`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_start_scan`` | ``set tv-scan yes`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_set_channel <val>`` | ``set tv-channel <val>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_step_channel`` | ``cycle tv-channel`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``dvb_set_channel <v1> <v2>`` | ``set dvb-channel <v1>-<v2>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``dvb_step_channel`` | ``cycle dvb-channel`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_set_freq <val>`` | ``set tv-freq <val>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_step_freq`` | ``cycle tv-freq`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_set_norm <norm>`` | ``set tv-norm <norm>`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``tv_step_norm`` | ``cycle tv-norm`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
|
||||
.. note::
|
||||
|
||||
Due to lack of hardware and users using the TV/DVB/PVR features, and
|
||||
due to the need to cleanup the related command code, it's possible
|
||||
that the new commands are buggy or behave worse. This can be improved
|
||||
if testers are available. Otherwise, some of the TV code will be
|
||||
removed at some point.
|
||||
|
||||
Slave mode
|
||||
~~~~~~~~~~
|
||||
|
||||
* Slave mode was removed. A proper slave mode application needed tons of code
|
||||
and hacks to get
|
||||
it right. The main problem is that slave mode is a bad and incomplete
|
||||
interface, and to get around that, applications parsed output messages
|
||||
intended for users. It is hard to know which messages exactly are parsed by
|
||||
slave mode applications. This makes it virtually impossible to improve
|
||||
terminal output intended for users without possibly breaking something.
|
||||
|
||||
This is absolutely insane, and since initial improvements to **mpv** quickly
|
||||
made slave mode incompatible to most applications, it was removed as useless
|
||||
cruft. The client API (see below) is provided instead.
|
||||
|
||||
``--identify`` was replaced by the ``TOOLS/mpv_identify.sh`` wrapper script.
|
||||
|
||||
* For some time (until including release 0.4.x), mpv supported a
|
||||
``--slave-broken`` option. The following options are equivalent:
|
||||
|
||||
::
|
||||
|
||||
--input-file=/dev/stdin --input-terminal=no
|
||||
|
||||
|
||||
Assuming the system supports ``/dev/stdin``.
|
||||
|
||||
(The option was added back in 0.5.1 and sets exactly these options. It was
|
||||
removed in 0.10.x again.)
|
||||
|
||||
* A JSON RPC protocol giving access to the client API is also supported. See
|
||||
`JSON IPC`_ for more information.
|
||||
|
||||
* **mpv** also provides a client API, which can be used to embed the player
|
||||
by loading it as shared library. (See ``libmpv/client.h`` in the sources.)
|
||||
It might also be possible to implement a custom slave mode-like protocol
|
||||
using Lua scripting.
|
||||
|
||||
Policy for Removed Features
|
||||
---------------------------
|
||||
|
||||
**mpv** is in active development. If something is in the way of more important
|
||||
development (such as fixing bugs or implementing new features), we sometimes
|
||||
remove features. Usually this happens only with old features that either seem
|
||||
to be useless, or are not used by anyone. Often these are obscure, or
|
||||
"inherited", or were marked experimental, but never received any particular
|
||||
praise by any users.
|
||||
|
||||
Sometimes, features are replaced by something new. The new code will be either
|
||||
simpler or more powerful, but doesn't necessarily provide everything the old
|
||||
feature did.
|
||||
|
||||
We can not exclude that we accidentally remove features that are actually
|
||||
popular. Generally, we do not know how much a specific functionality is used.
|
||||
If you miss a feature and think it should be re-added, please open an issue
|
||||
on the mpv bug tracker. Hopefully, a solution can be found. Often, it turns
|
||||
out that re-adding something is not much of a problem, or that there are
|
||||
better alternatives.
|
||||
|
||||
Why this Fork?
|
||||
--------------
|
||||
|
||||
mplayer2 is practically dead, and mpv started out as a branch containing
|
||||
new/experimental development. (Some of it was merged right *after* the fork
|
||||
was made public, seemingly as an acknowledgment that development, or at
|
||||
least merging, should have been more active.)
|
||||
|
||||
MPlayer is focused on not breaking anything, but is stuck with a horrible
|
||||
codebase resistant to cleanup. (Unless you do what mpv did - merciless and
|
||||
consequent pruning of bad, old code.) Cleanup and keeping broken things
|
||||
conflict, so the kind of development mpv strives for can't be done within
|
||||
MPlayer due to clashing development policies.
|
||||
|
||||
Additionally, mplayer2 already had lots of changes over MPlayer, which would
|
||||
have needed to be backported to the MPlayer codebase. This would not only
|
||||
have been hard (several years of diverging development), but also would have
|
||||
been impossible due to the aforementioned MPlayer development policy.
|
||||
+24
-81
@@ -1,114 +1,57 @@
|
||||
Release Policy
|
||||
==============
|
||||
|
||||
Once or twice a month, a new release is cut off of the master branch and is
|
||||
assigned a 0.X.Y version number, where X is incremented each time a release
|
||||
contains breaking changes, such as changed options or added/removed features,
|
||||
and Y is incremented if a release contains only bugfixes and other minor
|
||||
changes.
|
||||
Every few months, a new release is cut off of the master branch and is assigned
|
||||
a 0.X.0 version number.
|
||||
|
||||
There is only one release branch that keeps track of the latest version and
|
||||
will not be maintained separately.
|
||||
As part of the maintenance process, minor releases are made, which are assigned
|
||||
0.X.Y version numbers. Minor releases contain bug fixes only. They never merge
|
||||
the master branch, and no features are added to it. Only the latest release is
|
||||
maintained.
|
||||
|
||||
The goal of releases is to provide Linux distributions with something to
|
||||
package. If you want the newest features, just use the master branch.
|
||||
We try our best to keep it deployable at all times.
|
||||
The goal of releases is to provide stability and an unchanged base for the sake
|
||||
of Linux distributions. If you want the newest features, just use the master
|
||||
branch, which is stable most of the time, except sometimes, when it's not.
|
||||
|
||||
Releases other than the latest release are unsupported and unmaintained.
|
||||
|
||||
Release procedure
|
||||
-----------------
|
||||
|
||||
- Merge master into branch release/current.
|
||||
- Create branch release/0.X or cherry-pick commits to the relevant branch.
|
||||
|
||||
- Create and/or update the `RELEASE_NOTES` file.
|
||||
- Create and/or update the ``RELEASE_NOTES`` file.
|
||||
|
||||
- Create and/or update the `VERSION` file.
|
||||
|
||||
- Update `DOCS/client-api-changes.rst` and `DOCS/interface-changes.rst`
|
||||
(in particular, update the last version numbers if necessary)
|
||||
- Create and/or update the ``VERSION`` file.
|
||||
|
||||
- Create tag v0.X.Y.
|
||||
|
||||
- Push branch and tag to GitHub.
|
||||
|
||||
- Create a new GitHub release using the content of `RELEASE_NOTES` related to
|
||||
the new version.
|
||||
- Create a new GitHub release using the content of ``RELEASE_NOTES``.
|
||||
|
||||
Release notes template
|
||||
----------------------
|
||||
|
||||
Here is a template that can be used for writing the `RELEASE_NOTES` file.
|
||||
Here is a template that can be used for writing the ``RELEASE_NOTES`` file.
|
||||
|
||||
```markdown
|
||||
Release 0.X.Y
|
||||
=============
|
||||
Changes
|
||||
-------
|
||||
|
||||
Features
|
||||
--------
|
||||
- List of changes.
|
||||
|
||||
New
|
||||
~~~
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- List of new features
|
||||
- List of bug fixes.
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
New features
|
||||
------------
|
||||
|
||||
- List of removed features
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
||||
- List of deprecated features
|
||||
|
||||
Behavior
|
||||
--------
|
||||
|
||||
- List of user-visible changes in behavior
|
||||
|
||||
Options and Commands
|
||||
--------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- List of added options and commands
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- List of changed options and commands
|
||||
|
||||
Renamed
|
||||
~~~~~~~
|
||||
|
||||
- List of renamed options and commands
|
||||
|
||||
Deprecated
|
||||
~~~~~~~~~~
|
||||
|
||||
- List of deprecated options and commands
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
||||
- List of removed options and commands
|
||||
|
||||
Fixes and Minor Enhancements
|
||||
----------------------------
|
||||
|
||||
- List of fixes and minor enhancements
|
||||
- List of new features.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running `git log <start>..<end>` in
|
||||
complete change log can be viewed by running ``git log <start>..<end>`` in
|
||||
the git repository.
|
||||
```
|
||||
|
||||
Note that the "Release 0.X.Y" title should be removed when creating a new GitHub
|
||||
release.
|
||||
|
||||
When creating a new point release its changes should be added on top of the
|
||||
`RELEASE_NOTES` file (with the appropriate title) so that all the changes in
|
||||
the current 0.X branch will be included. This way the `RELEASE_NOTES` file
|
||||
can be used by distributors as changelog for point releases too.
|
||||
+31
-48
@@ -1,4 +1,4 @@
|
||||
This file intends to give a big picture overview of how mpv is structured.
|
||||
This file intends to give a big picture of how mpv is structured.
|
||||
|
||||
player/*.c:
|
||||
Essentially makes up the player applications, including the main() function
|
||||
@@ -17,12 +17,12 @@ player/*.c:
|
||||
* check help options etc. (call handle_help_options()), possibly exit
|
||||
* call play_files() function that works down the playlist:
|
||||
* run idle loop (idle_loop()), until there are files in the
|
||||
playlist or an exit command was given (only if --idle it set)
|
||||
playlist or an exit command was given (slave mode only)
|
||||
* actually load and play a file in play_current_file():
|
||||
* run all the dozens of functions to load the file and
|
||||
initialize playback
|
||||
* run a small loop that does normal playback, until the file is
|
||||
done or a command terminates playback
|
||||
done or a slave command terminates playback
|
||||
(on each iteration, run_playloop() is called, which is rather
|
||||
big and complicated - it decodes some audio and video on
|
||||
each frame, waits for input, etc.)
|
||||
@@ -31,28 +31,15 @@ player/*.c:
|
||||
* loop, or exit if no next file or quit is requested
|
||||
(see enum stop_play_reason)
|
||||
* call exit_player_with_rc()
|
||||
* run_playloop():
|
||||
* calls fill_audio_out_buffers()
|
||||
This checks whether new audio needs to be decoded, and pushes it
|
||||
to the AO.
|
||||
* calls write_video()
|
||||
Decode new video, and push it to the VO.
|
||||
* determines whether playback of the current file has ended
|
||||
* determines when to start playback after seeks
|
||||
* and calls a whole lot of other stuff
|
||||
(Really, this function does everything.)
|
||||
|
||||
Things worth saying about the playback core:
|
||||
- most state is in MPContext (core.h), which is not available to the
|
||||
subsystems
|
||||
- the currently played tracks are in mpctx->current_tracks, and decoder
|
||||
state in d_video/d_audio/d_sub
|
||||
- the currently played tracks are in sh_video and sh_audio
|
||||
- the timeline stuff is used only with MKV ordered chapters (and some other
|
||||
minor features: cue, edl)
|
||||
- most state is in MPContext (mp_core.h), which is not available to the
|
||||
subsystems
|
||||
- the other subsystems rarely call back into the frontend, and the frontend
|
||||
polls them instead (probably a good thing)
|
||||
- one exceptions are wakeup callbacks, which notify a "higher" component
|
||||
of a changed situation in a subsystem
|
||||
|
||||
I like to call the player/*.c files the "frontend".
|
||||
|
||||
@@ -75,7 +62,8 @@ talloc.h & talloc.c:
|
||||
allocation call will never return NULL.
|
||||
|
||||
One very useful feature of talloc is fast tracking of memory leaks. ("Fast"
|
||||
as in it doesn't require valgrind.) You can enable it by setting the
|
||||
as in it doesn't require valgrind.) You can enable it by passing the option
|
||||
--leak-report as first parameter, or better, setting the
|
||||
MPV_LEAK_REPORT environment variable to "1":
|
||||
export MPV_LEAK_REPORT=1
|
||||
This will list all unfree'd allocations on exit.
|
||||
@@ -94,7 +82,7 @@ talloc.h & talloc.c:
|
||||
(See ta/README for details.)
|
||||
|
||||
player/command.c:
|
||||
This contains the implementation for client API commands and properties.
|
||||
This contains the implementation for slave commands and properties.
|
||||
Properties are essentially dynamic variables changed by certain commands.
|
||||
This is basically responsible for all user commands, like initiating
|
||||
seeking, switching tracks, etc. It calls into other player/*.c files,
|
||||
@@ -104,10 +92,9 @@ player/core.h:
|
||||
Data structures and function prototypes for most of player/*.c. They are
|
||||
usually not accessed by other parts of mpv for the sake of modularization.
|
||||
|
||||
player/client.c:
|
||||
This implements the client API (libmpv/client.h). For the most part, this
|
||||
just calls into other parts of the player. This also manages a ringbuffer
|
||||
of events from player to clients.
|
||||
Note that there are lots of global variables floating around everywhere
|
||||
else. This is an ongoing transition, and eventually there should be no
|
||||
global variables anymore.
|
||||
|
||||
options/options.h, options/options.c
|
||||
options.h contains the global option struct MPOpts. The option declarations
|
||||
@@ -115,7 +102,7 @@ options/options.h, options/options.c
|
||||
options.c. Most default values for options and MPOpts are in
|
||||
mp_default_opts at the end of options.c.
|
||||
|
||||
MPOpts is unfortunately quite monolithic, and virtually accessed by
|
||||
MPOpts is unfortunarely quite monolithic, and virtually accessed by
|
||||
everything.But some components (like video outputs and video filters) have
|
||||
their own sub-option tables separate from MPOpts.
|
||||
|
||||
@@ -123,18 +110,19 @@ options/options.h, options/options.c
|
||||
parser-mpcmd.c, and uses the option table in options.c.
|
||||
|
||||
input/input.c:
|
||||
This translates keyboard input coming from VOs and other sources (such
|
||||
as remote control devices like Apple IR or client API commands) to the
|
||||
This translates keyboard input comming from libvo and other sources (such
|
||||
as remote control devices like Apple IR or slave mode commands) to the
|
||||
key bindings listed in the user's (or the builtin) input.conf and turns
|
||||
them into items of type struct mp_cmd. These commands are queued, and read
|
||||
by playloop.c. They get pushed with run_command() to command.c.
|
||||
|
||||
Note that keyboard input and commands used by the client API are the same.
|
||||
The client API only uses the command parser though, and has its own queue
|
||||
of input commands somewhere else.
|
||||
Note that keyboard input and slave mode input are essentially the same
|
||||
things. Just looking at input.conf should make this clear. (The other
|
||||
direction of slave mode communication, mpv to application, consists of
|
||||
random mp_msg() calls all over the code in all parts of the player.)
|
||||
|
||||
common/msg.h:
|
||||
All terminal output must go through mp_msg().
|
||||
All terminal output should go through mp_msg().
|
||||
|
||||
stream/*:
|
||||
File input is implemented here. stream.h/.c provides a simple stream based
|
||||
@@ -193,7 +181,7 @@ video/out/:
|
||||
vo_opengl can pick a windowing system at runtime, e.g. the same binary can
|
||||
provide both X11 and Cocoa support on OSX.
|
||||
|
||||
VOs can be reconfigured at runtime. A vo_config() call can change the video
|
||||
VOs can be reconfigured at runtime. A config() call can change the video
|
||||
resolution and format, without destroying the window.
|
||||
|
||||
vo_vdpau and vo_opengl should be taken as reference.
|
||||
@@ -215,12 +203,9 @@ audio/filter/:
|
||||
audio/out/:
|
||||
Audio outputs.
|
||||
|
||||
Unlike VOs, AOs can't be reconfigured on a format change. On audio format
|
||||
changes, the AO will simply be closed and re-opened.
|
||||
|
||||
There are wrappers to support for two types of audio APIs: push.c and
|
||||
pull.c. ao.c calls into one of these. They contain generic code to deal
|
||||
with the data flow these APIs impose.
|
||||
Unlike VOs, AOs can't be reconfigured on a format change. Without
|
||||
--gapless-audio, even playing a new file will close and re-open the audio
|
||||
device.
|
||||
|
||||
Note that mpv synchronizes the video to the audio. That's the reason
|
||||
why buggy audio drivers can have a bad influence on playback quality.
|
||||
@@ -228,19 +213,17 @@ audio/out/:
|
||||
sub/:
|
||||
Contains subtitle and OSD rendering.
|
||||
|
||||
osd.c/.h is actually the OSD code. It queries dec_sub.c to retrieve
|
||||
sub.c/.h is actually the OSD code. It queries dec_sub.c to retrieve
|
||||
decoded/rendered subtitles. osd_libass.c is the actual implementation of
|
||||
the OSD text renderer (which uses libass, and takes care of all the tricky
|
||||
fontconfig/freetype API usage and text layouting).
|
||||
|
||||
The VOs call osd.c to render OSD and subtitle (via e.g. osd_draw()). osd.c
|
||||
in turn asks dec_sub.c for subtitle overlay bitmaps, which relays the
|
||||
request to one of the sd_*.c subtitle decoders/renderers.
|
||||
|
||||
Subtitle loading is in demux/. The MPlayer subreader.c is mostly gone - parts
|
||||
of it survive in demux_subreader.c. It's used as last fallback, or to handle
|
||||
some text subtitle types on Libav. It should go away eventually. Normally,
|
||||
subtitles are loaded via demux_lavf.c.
|
||||
Subtitle loading is now in demux/ instead. demux_libass.c wraps loading
|
||||
.ass subtitles via libass. demux_lavf.c loads most subtitle types via
|
||||
FFmpeg. demux_subreader.c is the old MPlayer code. It's used as last
|
||||
fallback, or to handle some text subtitle types on Libav. (It also can
|
||||
load UTF-16 encoded subtitles without requiring the use of -sub-codepage.)
|
||||
demux_subreader.c should eventually go away (maybe).
|
||||
|
||||
The subtitles are passed to dec_sub.c and the subtitle decoders in sd_*.c
|
||||
as they are demuxed. All text subtitles are rendered by sd_ass.c. If text
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
waf build system overview
|
||||
=========================
|
||||
|
||||
mpv's new build system is based on waf and it should completely replace the
|
||||
mpv's new build system is based on waf and it should completly replace the
|
||||
custom ./configure + Makefile based system inherited from MPlayer.
|
||||
|
||||
Goals and the choice of waf
|
||||
@@ -20,9 +20,8 @@ shortcomings:
|
||||
part is this pieces are spread apart in the configure and copy pasted for
|
||||
any single case. That brings us to..
|
||||
|
||||
2) --enable-feature has to be overridden by the user and helps them understand that
|
||||
they have libraries missing and should install them for the feature to be
|
||||
enabled.
|
||||
2) --enable-feature has to override the user and help him understand that he
|
||||
has libraries missing and should install them for the feature to be enabled.
|
||||
|
||||
3) Must be customizable, hackable, pleasant to the developer eyes and to work
|
||||
with in general.
|
||||
@@ -65,7 +64,7 @@ This defines a feature called ``vdpau`` which can be enabled or disabled by
|
||||
the users with configure flags (that's the meaning of ``--``). This feature
|
||||
depends on another feature whose name is ``x11``, and the autodetection check
|
||||
consists of running ``pkg-config`` and looking for ``vdpau`` with version
|
||||
``>= 0.2``. If the check succeeds a ``#define HAVE_VDPAU 1`` will be added to
|
||||
``>= 0.2``. If the check succeds a ``#define HAVE_VDPAU 1`` will be added to
|
||||
``config.h``, if not ``#define HAVE_VDPAU 0`` will be added.
|
||||
|
||||
The defines names are automatically prepended with ``HAVE_``, capitalized and
|
||||
|
||||
@@ -1,54 +1,19 @@
|
||||

|
||||
mpv
|
||||
===
|
||||
|
||||
## mpv
|
||||
[](https://travis-ci.org/mpv-player/mpv)
|
||||
|
||||
--------------
|
||||
Overview
|
||||
--------
|
||||
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Downloads](#downloads)
|
||||
* [Compilation](#compilation)
|
||||
* [FFmpeg vs. Libav](#ffmpeg-vs-libav)
|
||||
* [Release cycle](#release-cycle)
|
||||
* [Bug reports](#bug-reports)
|
||||
* [Contributing](#contributing)
|
||||
* [Relation to MPlayer and mplayer2](#relation-to-mplayer-and-mplayer2)
|
||||
* [Wiki](https://github.com/mpv-player/mpv/wiki)
|
||||
* [Man pages](http://mpv.io/manual/master/)
|
||||
* [Contact](#contact)
|
||||
* [License](#license)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
**mpv** is a media player based on MPlayer and mplayer2. It supports a wide
|
||||
**mpv** is a movie player based on MPlayer and mplayer2. It supports a wide
|
||||
variety of video file formats, audio and video codecs, and subtitle types.
|
||||
|
||||
Releases can be found on the [release list][releases].
|
||||
|
||||
## System requirements
|
||||
|
||||
- A not too ancient Linux, or Windows Vista or later, or OSX 10.8 or later.
|
||||
- A somewhat capable CPU. Hardware decoding might sometimes help if the CPU
|
||||
is too slow to decode video realtime, but must be explicitly enabled with
|
||||
the `--hwdec` option. On Windows, a CPU with SSE4 instruction set is required
|
||||
to get decent hardware decoding performance.
|
||||
- A not too crappy GPU. mpv is not intended to be used with bad GPUs. There are
|
||||
many caveats with drivers or system compositors causing tearing, stutter,
|
||||
etc. On Windows, you might want to make sure the graphics drivers are
|
||||
current, especially OpenGL. In some cases, ancient fallback video output
|
||||
methods can help (such as `--vo=xv` on Linux), but this use is not
|
||||
recommended or supported.
|
||||
|
||||
|
||||
## Downloads
|
||||
|
||||
|
||||
For semi-official builds and third-party packages please see
|
||||
[mpv.io](http://mpv.io/installation/).
|
||||
|
||||
## Compilation
|
||||
If you are wondering what's different from mplayer2 and MPlayer you can read
|
||||
more about the [changes][changes].
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
Compiling with full features requires development files for several
|
||||
external libraries. Below is a list of some important requirements.
|
||||
@@ -72,29 +37,23 @@ To build the software you can use `./waf build`: the result of the compilation
|
||||
will be located in `build/mpv`. You can use `./waf install` to install mpv
|
||||
to the *prefix* after it is compiled.
|
||||
|
||||
NOTE: Using the old build system (with `./old-configure`) should still work,
|
||||
but will be removed in a future version of mpv.
|
||||
|
||||
Essential dependencies (incomplete list):
|
||||
|
||||
- gcc or clang
|
||||
- X development headers (xlib, X extensions, libvdpau, libGL, libXv, ...)
|
||||
- Audio output development headers (libasound/ALSA, pulseaudio)
|
||||
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavfilter
|
||||
and either libswresample or libavresample)
|
||||
At least FFmpeg 2.4.0 or Libav 11 is required.
|
||||
- zlib
|
||||
- iconv (normally provided by the system libc)
|
||||
- libass (OSD, OSC, text subtitles)
|
||||
- Lua (optional, required for the OSC pseudo-GUI and youtube-dl integration)
|
||||
- libjpeg (optional, used for screenshots only)
|
||||
- uchardet (optional, for subtitle charset detection)
|
||||
- vdpau and vaapi libraries for hardware decoding on Linux (optional)
|
||||
- Audio output development headers (libasound, pulseaudio)
|
||||
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavresample)
|
||||
At least FFmpeg 2.1.4 or Libav 10 is required.
|
||||
- libjpeg (for screenshots)
|
||||
- libquvi if you want to play Youtube videos directly
|
||||
|
||||
Libass dependencies:
|
||||
|
||||
- gcc or clang, yasm on x86 and x86_64
|
||||
- fribidi, freetype, fontconfig development headers (for libass)
|
||||
- harfbuzz (optional, required for correct rendering of combining characters,
|
||||
particularly for correct rendering of non-English text on OSX, and
|
||||
Arabic/Indic scripts on any platform)
|
||||
|
||||
FFmpeg dependencies:
|
||||
|
||||
@@ -111,117 +70,70 @@ the separately available build wrapper ([mpv-build][mpv-build]) that first compi
|
||||
libraries and libass, and then compiles the player statically linked against
|
||||
those.
|
||||
|
||||
If you want to build a Windows binary, you either have to use MSYS2 and MinGW,
|
||||
or cross-compile from Linux with MinGW. See [Windows compilation][windows_compilation].
|
||||
|
||||
|
||||
## FFmpeg vs. Libav
|
||||
If you are running Mac OSX and using homebrew we provide [homebrew-mpv][homebrew-mpv], an up
|
||||
to date formula that compiles mpv with sensible dependencies and defaults for
|
||||
OSX.
|
||||
|
||||
FFmpeg vs. Libav
|
||||
----------------
|
||||
|
||||
Generally, mpv should work with the latest release as well as the git version
|
||||
of both FFmpeg and Libav. But FFmpeg is preferred, and some mpv features work
|
||||
with FFmpeg only (subtitle formats in particular).
|
||||
with FFmpeg only. See the [wiki article][ffmpeg_vs_libav] about the issue.
|
||||
|
||||
|
||||
## Preferred FFmpeg version
|
||||
Release cycle
|
||||
-------------
|
||||
|
||||
Every few months, a new release is cut off of the master branch and is assigned
|
||||
a 0.X.0 version number.
|
||||
|
||||
Using the latest FFmpeg release (or FFmpeg git master) is strongly recommended.
|
||||
Older versions are unsupported, even if the build system still happens to
|
||||
accept them. The main reason mpv still builds with older FFmpeg versions is to
|
||||
evade arguing with people (users, distros) who insist on using older FFmpeg
|
||||
versions for no rational reason.
|
||||
As part of the maintenance process, minor releases are made, which are assigned
|
||||
0.X.Y version numbers. Minor releases contain bug fixes only. They never merge
|
||||
the master branch, and no features are added to it. Only the latest release is
|
||||
maintained.
|
||||
|
||||
If you want to use a stable FFmpeg release, use the latest release, which has
|
||||
most likely the best maintenance out of all stable releases. Older releases
|
||||
are for distros, and at best receive basic changes like fixing critical security
|
||||
issues or build fixes, and at worst are completely abandoned.
|
||||
|
||||
## FFmpeg ABI compatibility
|
||||
|
||||
mpv does not support linking against FFmpeg versions it was not built with, even
|
||||
if the linked version is supposedly ABI-compatible with the version it was
|
||||
compiled against. Expect malfunctions, crashes, and security issues if you
|
||||
do it anyway.
|
||||
|
||||
The reason for not supporting this is because it creates far too much complexity
|
||||
with little to no benefit, coupled with absurd and unusable FFmpeg API
|
||||
artifacts.
|
||||
|
||||
Newer mpv versions will refuse to start if runtime and compile time FFmpeg
|
||||
library versions mismatch.
|
||||
|
||||
## Release cycle
|
||||
|
||||
Every other month, an arbitrary git snapshot is made, and is assigned
|
||||
a 0.X.0 version number. No further maintenance is done.
|
||||
|
||||
The goal of releases is to make Linux distributions happy. Linux distributions
|
||||
are also expected to apply their own patches in case of bugs and security
|
||||
issues.
|
||||
The goal of releases is to provide stability and an unchanged base for the sake
|
||||
of Linux distributions. If you want the newest features, just use the master
|
||||
branch, which is stable most of the time, except sometimes, when it's not.
|
||||
|
||||
Releases other than the latest release are unsupported and unmaintained.
|
||||
|
||||
See the [release policy document][release-policy] for more information.
|
||||
|
||||
## Bug reports
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
|
||||
Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug
|
||||
reports or feature requests.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
For small changes you can just send us pull requests through GitHub. For bigger
|
||||
changes come and talk to us on IRC before you start working on them. It will
|
||||
make code review easier for both parties later on.
|
||||
|
||||
## Relation to MPlayer and mplayer2
|
||||
Contact
|
||||
-------
|
||||
|
||||
These forms of contact are meant to ask questions about mpv usage, give
|
||||
feedback on mpv and discuss it's development.
|
||||
|
||||
mpv is based on mplayer2, which in turn is based on the original MPlayer
|
||||
(also called mplayer, mplayer-svn, mplayer1). Many changes have been made, a
|
||||
large part of which is incompatible or completely changes how the player
|
||||
behaves. Although there are still many similarities to its ancestors, mpv
|
||||
should generally be treated as a completely different program.
|
||||
If possible, please avoid posting bugs here and use the [issue tracker][issue-tracker]
|
||||
instead.
|
||||
|
||||
mpv was forked because we wanted to modernize MPlayer. This includes
|
||||
removing cruft (including features which stopped making sense 10 years ago),
|
||||
and of course adding modern features. Such huge and intrusive changes made it
|
||||
infeasible to work directly with MPlayer, which is mostly focused on
|
||||
preservation, so a fork had to be made. (Actually, mpv is based on mplayer2,
|
||||
which already started this process of removing cruft.)
|
||||
- **Users IRC Channel**: `#mpv-player` on `irc.freenode.net`
|
||||
- **Users Mailing List**: `mpv-users@googlegroups.com` ([Archive / Subscribe][mpv-users]).
|
||||
- **Devel Mailing List**: `mpv-devel@googlegroups.com` ([Archive / Subscribe][mpv-devel])
|
||||
|
||||
In general, mpv should be considered a completely new program, rather than a
|
||||
MPlayer drop-in replacement.
|
||||
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`.
|
||||
|
||||
If you are wondering what's different from mplayer2 and MPlayer, an incomplete
|
||||
list of changes is located [here][mplayer-changes].
|
||||
|
||||
## Contact
|
||||
|
||||
|
||||
Most activity happens on the IRC channel and the github issue tracker. The
|
||||
mailing lists are mostly unused.
|
||||
|
||||
- **GitHub issue tracker**: [issue tracker][issue-tracker] (report bugs here)
|
||||
- **User IRC Channel**: `#mpv` on `irc.freenode.net`
|
||||
- **Developer IRC Channel**: `#mpv-devel` on `irc.freenode.net`
|
||||
|
||||
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`. Use
|
||||
only if discretion is required.
|
||||
|
||||
[releases]: https://github.com/mpv-player/mpv/releases
|
||||
[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/changes.rst
|
||||
[mpv-build]: https://github.com/mpv-player/mpv-build
|
||||
[homebrew-mpv]: https://github.com/mpv-player/homebrew-mpv
|
||||
[issue-tracker]: https://github.com/mpv-player/mpv/issues
|
||||
[mpv-users]: https://groups.google.com/forum/?hl=en#!forum/mpv-users
|
||||
[mpv-devel]: https://groups.google.com/forum/?hl=en#!forum/mpv-devel
|
||||
[ffmpeg_vs_libav]: https://github.com/mpv-player/mpv/wiki/FFmpeg-versus-Libav
|
||||
[release-policy]: https://github.com/mpv-player/mpv/blob/master/DOCS/release-policy.md
|
||||
[windows_compilation]: https://github.com/mpv-player/mpv/blob/master/DOCS/compile-windows.md
|
||||
[mplayer-changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/mplayer-changes.rst
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Mostly GPLv2 or later. See [details.](https://github.com/mpv-player/mpv/blob/master/Copyright)
|
||||
+151
-2118
File diff suppressed because it is too large.
Load diff
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/bash
|
||||
set -e
|
||||
|
||||
export DEST_OS=win32
|
||||
export CC=gcc
|
||||
export PKG_CONFIG=/usr/bin/pkg-config
|
||||
export PERL=/usr/bin/perl
|
||||
export PYTHON=/usr/bin/python3
|
||||
|
||||
"$PYTHON" bootstrap.py
|
||||
"$PYTHON" waf configure \
|
||||
--check-c-compiler=gcc \
|
||||
--disable-cdda \
|
||||
--enable-egl-angle \
|
||||
--enable-jpeg \
|
||||
--enable-lcms2 \
|
||||
--enable-libarchive \
|
||||
--enable-libass \
|
||||
--enable-lua \
|
||||
--enable-rubberband \
|
||||
--enable-uchardet
|
||||
"$PYTHON" waf build
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/bash
|
||||
set -e
|
||||
|
||||
case $MSYSTEM in
|
||||
MINGW32)
|
||||
export MINGW_PACKAGE_PREFIX=mingw-w64-i686
|
||||
;;
|
||||
MINGW64)
|
||||
export MINGW_PACKAGE_PREFIX=mingw-w64-x86_64
|
||||
;;
|
||||
esac
|
||||
|
||||
# Write an empty fonts.conf to speed up fc-cache
|
||||
export FONTCONFIG_FILE=/dummy-fonts.conf
|
||||
cat >"$FONTCONFIG_FILE" <<EOF
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig></fontconfig>
|
||||
EOF
|
||||
|
||||
# Install build dependencies for mpv
|
||||
pacman -S --noconfirm --needed \
|
||||
$MINGW_PACKAGE_PREFIX-gcc \
|
||||
$MINGW_PACKAGE_PREFIX-angleproject-git \
|
||||
$MINGW_PACKAGE_PREFIX-ffmpeg \
|
||||
$MINGW_PACKAGE_PREFIX-lcms2 \
|
||||
$MINGW_PACKAGE_PREFIX-libarchive \
|
||||
$MINGW_PACKAGE_PREFIX-libass \
|
||||
$MINGW_PACKAGE_PREFIX-libjpeg-turbo \
|
||||
$MINGW_PACKAGE_PREFIX-lua51 \
|
||||
$MINGW_PACKAGE_PREFIX-rubberband \
|
||||
$MINGW_PACKAGE_PREFIX-uchardet-git
|
||||
|
||||
# Delete unused packages to reduce space used in the Appveyor cache
|
||||
pacman -Sc --noconfirm
|
||||
@@ -15,11 +15,10 @@ def is_user_lib(objfile, libname):
|
||||
return not sys_re.match(libname) and \
|
||||
not usr_re.match(libname) and \
|
||||
not exe_re.match(libname) and \
|
||||
not "libobjc." in libname and \
|
||||
not "libSystem." in libname and \
|
||||
not "libc." in libname and \
|
||||
not "libgcc." in libname and \
|
||||
not os.path.basename(libname) == 'Python' and \
|
||||
not "libobjc" in libname and \
|
||||
not "libSystem" in libname and \
|
||||
not "libc" in libname and \
|
||||
not "libgcc" in libname and \
|
||||
not os.path.basename(objfile) in libname
|
||||
|
||||
def otool(objfile):
|
||||
|
||||
@@ -9,8 +9,8 @@ use warnings;
|
||||
# the exact contents of the original file.
|
||||
# FIXME: why not a char array?
|
||||
|
||||
# treat only alphanumeric and punctuations (excluding " and ?) as safe
|
||||
my $unsafe_chars = qr{[^][A-Za-z0-9!#%&'()*+,./:;<=>^_{|}~ -]};
|
||||
# treat only alphanumeric and not-" punctuation as safe
|
||||
my $unsafe_chars = qr{[^][A-Za-z0-9!#%&'()*+,./:;<=>?^_{|}~ -]};
|
||||
|
||||
for my $file (@ARGV) {
|
||||
open my $fh, '<:raw', $file or next;
|
||||
|
||||
Executable → Regular
+2
-2
@@ -5,8 +5,8 @@
|
||||
|
||||
conv() {
|
||||
echo
|
||||
echo `identify -format "icon: %w %h" "$1"`
|
||||
convert "$1" -depth 8 rgba:-
|
||||
identify -format "icon: %w %h" $1
|
||||
convert $1 -depth 8 rgba:-
|
||||
}
|
||||
|
||||
(echo "# File generated by gen-x11-icon.sh" ;
|
||||
|
||||
+62
-59
@@ -1,15 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
: "${MPV:=mpv}"
|
||||
: "${ILDETECT_MPV:=$MPV}"
|
||||
: "${ILDETECT_MPVFLAGS:=--start=35% --length=35}"
|
||||
: "${ILDETECT_DRY_RUN:=}"
|
||||
: "${ILDETECT_QUIET:=}"
|
||||
: "${ILDETECT_RUN_INTERLACED_ONLY:=}"
|
||||
: "${ILDETECT_FORCE_RUN:=}"
|
||||
case "$0" in
|
||||
*/*)
|
||||
MYDIR=${0%/*}
|
||||
;;
|
||||
*)
|
||||
MYDIR=.
|
||||
;;
|
||||
esac
|
||||
|
||||
# This script uses ffmpeg's "idet" filter for interlace detection. In the
|
||||
# long run this should replace ildetect.sh+ildetect.so.
|
||||
: ${MPV:=mpv}
|
||||
: ${ILDETECT_MPV:=$MPV}
|
||||
: ${ILDETECT_MPV:=$MPV}
|
||||
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
|
||||
: ${ILDETECT_DRY_RUN:=}
|
||||
: ${ILDETECT_QUIET:=}
|
||||
: ${ILDETECT_RUN_INTERLACED_ONLY:=}
|
||||
: ${ILDETECT_FORCE_RUN:=}
|
||||
: ${MAKE:=make}
|
||||
|
||||
# exit status:
|
||||
# 0 progressive
|
||||
@@ -22,131 +30,126 @@
|
||||
testfun()
|
||||
{
|
||||
$ILDETECT_MPV "$@" \
|
||||
--vf-add=lavfi="[idet]" --msg-level ffmpeg=v \
|
||||
--vf=lavfi="[idet]" --msg-level ffmpeg=v \
|
||||
--o= --vo=null --no-audio --untimed \
|
||||
$ILDETECT_MPVFLAGS \
|
||||
| { if [ -n "$ILDETECT_QUIET" ]; then cat; else tee /dev/stderr; fi } \
|
||||
| grep "Parsed_idet_0: Multi frame detection: "
|
||||
| grep "Parsed_idet_0: Multi frame detection: " | tail -n 1
|
||||
}
|
||||
|
||||
judge()
|
||||
{
|
||||
tff=0
|
||||
bff=0
|
||||
progressive=0
|
||||
undetermined=0
|
||||
while read -r _ _ _ _ _ _ tff1 _ bff1 _ progressive1 _ undetermined1 _; do
|
||||
case "$tff1$bff1$progressive1$undetermined1" in
|
||||
*[!0-9]*)
|
||||
printf >&2 'ERROR: Unrecognized idet output: %s\n' "$out"
|
||||
exit 16
|
||||
;;
|
||||
esac
|
||||
tff=$((tff + tff1))
|
||||
bff=$((bff + bff1))
|
||||
progressive=$((progressive + progressive1))
|
||||
undetermined=$((undetermined + undetermined1))
|
||||
done <<EOF
|
||||
$(testfun "$@" | sed 's/:/: /g')
|
||||
EOF
|
||||
out=`testfun "$@"`
|
||||
|
||||
tff=${out##* TFF:}; tff=${tff%% *}
|
||||
bff=${out##* BFF:}; bff=${bff%% *}
|
||||
progressive=${out##* Progressive:}; progressive=${progressive%% *}
|
||||
undetermined=${out##* Undetermined:}; undetermined=${undetermined%% *}
|
||||
|
||||
case "$tff$bff$progressive$undetermined" in
|
||||
*[!0-9]*)
|
||||
echo >&2 "ERROR: Unrecognized idet output: $out"
|
||||
exit 16
|
||||
;;
|
||||
esac
|
||||
|
||||
interlaced=$((bff + tff))
|
||||
determined=$((interlaced + progressive))
|
||||
|
||||
if [ "$undetermined" -gt "$determined" ] || [ "$determined" -lt 250 ]; then
|
||||
if [ $undetermined -gt $determined ] || [ $determined -lt 250 ]; then
|
||||
echo >&2 "ERROR: Less than 50% or 250 frames are determined."
|
||||
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
|
||||
echo >&2 "Assuming interlacing."
|
||||
if [ "$tff" -gt $((bff * 10)) ]; then
|
||||
verdict="interlaced-tff"
|
||||
elif [ "$bff" -gt $((tff * 10)) ]; then
|
||||
verdict="interlaced-bff"
|
||||
if [ $tff -gt $((bff * 10)) ]; then
|
||||
verdict=interlaced-tff
|
||||
elif [ $bff -gt $((tff * 10)) ]; then
|
||||
verdict=interlaced-bff
|
||||
else
|
||||
verdict="interlaced"
|
||||
verdict=interlaced
|
||||
fi
|
||||
elif [ $((interlaced * 20)) -gt "$progressive" ]; then
|
||||
elif [ $((interlaced * 20)) -gt $progressive ]; then
|
||||
# At least 5% of the frames are interlaced!
|
||||
if [ "$tff" -gt $((bff * 10)) ]; then
|
||||
verdict="interlaced-tff"
|
||||
elif [ "$bff" -gt $((tff * 10)) ]; then
|
||||
verdict="interlaced-bff"
|
||||
if [ $tff -gt $((bff * 10)) ]; then
|
||||
verdict=interlaced-tff
|
||||
elif [ $bff -gt $((tff * 10)) ]; then
|
||||
verdict=interlaced-bff
|
||||
else
|
||||
echo >&2 "ERROR: Content is interlaced, but can't determine field order."
|
||||
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
|
||||
echo >&2 "Assuming interlacing with default field order."
|
||||
verdict="interlaced"
|
||||
verdict=interlaced
|
||||
fi
|
||||
else
|
||||
# Likely progressive
|
||||
verdict="progressive"
|
||||
# Likely progrssive.
|
||||
verdict=progressive
|
||||
fi
|
||||
|
||||
printf '%s\n' "$verdict"
|
||||
echo "$verdict"
|
||||
}
|
||||
|
||||
judge "$@" --vf-clr
|
||||
judge "$@"
|
||||
case "$verdict" in
|
||||
progressive)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
[ -n "$ILDETECT_RUN_INTERLACED_ONLY" ] || \
|
||||
$ILDETECT_MPV "$@"
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 0
|
||||
;;
|
||||
interlaced-tff)
|
||||
judge "$@" --vf-clr --vf-pre=lavfi=\[setfield=tff\],pullup
|
||||
judge "$@" --vf-pre=pullup --field-dominance=top
|
||||
case "$verdict" in
|
||||
progressive)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=tff\],pullup
|
||||
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=top
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=tff\],yadif
|
||||
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=top
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
interlaced-bff)
|
||||
judge "$@" --vf-clr --vf-pre=lavfi=\[setfield=bff\],pullup
|
||||
judge "$@" --vf-pre=pullup --field-dominance=bottom
|
||||
case "$verdict" in
|
||||
progressive)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=bff\],pullup
|
||||
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=bottom
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=bff\],yadif
|
||||
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=bottom
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
interlaced)
|
||||
judge "$@" --vf-clr --vf-pre=pullup
|
||||
judge "$@" --vf-pre=pullup
|
||||
case "$verdict" in
|
||||
progressive)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" --vf-pre=pullup
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" --vf-pre=yadif
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $((r | 16))
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -84,7 +84,7 @@ sub elem_by_hexid {
|
||||
# used by elem when setting the 'valname' key
|
||||
use constant TYPE_MAP => {
|
||||
uint => 'uint64_t',
|
||||
str => 'char *',
|
||||
str => 'struct bstr',
|
||||
binary => 'struct bstr',
|
||||
ebml_id => 'uint32_t',
|
||||
float => 'double',
|
||||
@@ -232,7 +232,6 @@ sub define_matroska {
|
||||
elem('Block', 'a1', 'binary'),
|
||||
elem('BlockDuration', '9b', 'uint'),
|
||||
elem('ReferenceBlock*', 'fb', 'sint'),
|
||||
elem('DiscardPadding', '75A2', 'sint'),
|
||||
}),
|
||||
elem('SimpleBlock*', 'a3', 'binary'),
|
||||
}),
|
||||
@@ -257,8 +256,6 @@ sub define_matroska {
|
||||
elem('CodecPrivate', '63a2', 'binary'),
|
||||
elem('CodecName', '258688', 'str'),
|
||||
elem('CodecDecodeAll', 'aa', 'uint'),
|
||||
elem('CodecDelay', '56AA', 'uint'),
|
||||
elem('SeekPreRoll', '56BB', 'uint'),
|
||||
elem('Video', 'e0', {
|
||||
elem('FlagInterlaced', '9a', 'uint'),
|
||||
elem('PixelWidth', 'b0', 'uint'),
|
||||
@@ -268,7 +265,6 @@ sub define_matroska {
|
||||
elem('DisplayUnit', '54b2', 'uint'),
|
||||
elem('FrameRate', '2383e3', 'float'),
|
||||
elem('ColourSpace', '2eb524', 'binary'),
|
||||
elem('StereoMode', '53b8', 'uint'),
|
||||
}),
|
||||
elem('Audio', 'e1', {
|
||||
elem('SamplingFrequency', 'b5', 'float'),
|
||||
@@ -296,8 +292,6 @@ sub define_matroska {
|
||||
elem('CueTrackPositions*', 'b7', {
|
||||
elem('CueTrack', 'f7', 'uint'),
|
||||
elem('CueClusterPosition', 'f1', 'uint'),
|
||||
elem('CueRelativePosition','f0', 'uint'),
|
||||
elem('CueDuration', 'b2', 'uint'),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
|
||||
+10
-11
@@ -4,17 +4,16 @@ mpv lua scripts
|
||||
The lua scripts in this folder can be loaded on a one-time basis by
|
||||
adding the option
|
||||
|
||||
--script=/path/to/script.lua
|
||||
--lua=/path/to/script.lua
|
||||
|
||||
to mpv's command line.
|
||||
|
||||
Where appropriate, they may also be placed in ~/.config/mpv/scripts/ from
|
||||
where they will be automatically loaded when mpv starts.
|
||||
|
||||
This is only a small selection of internally maintained scripts. Some of them
|
||||
are just for testing mpv internals, or serve as examples. An extensive
|
||||
user-edited list of 3rd party scripts is available here:
|
||||
|
||||
https://github.com/mpv-player/mpv/wiki/User-Scripts
|
||||
|
||||
(Anyone can add their own scripts to that list.)
|
||||
Unless otherwise specified, they are also suitable for inclusion in
|
||||
the `~/.mpv/lua` directory where they will be loaded every time mpv
|
||||
starts, obviating the need to load them with the above `--lua=...`
|
||||
argument. This is acceptable as they do only basic argument parsing
|
||||
and key-binding registration, until those bound keys are actually
|
||||
pressed. They should therefore not interfere with normal playback
|
||||
(unless you have a conflicting user-defined key-binding, in which
|
||||
case, you may want to modify either the `mp.add_key_binding()` calls
|
||||
in the scripts, or your keybinding).
|
||||
@@ -1,20 +0,0 @@
|
||||
-- Handles the edge case where previous attempts to init audio have failed, but
|
||||
-- might start working due to a newly added device. This is required in
|
||||
-- particular for ao=wasapi, since the internal IMMNotificationClient code that
|
||||
-- normally triggers ao-reload will not be running in this case.
|
||||
|
||||
function do_reload()
|
||||
mp.command("ao-reload")
|
||||
reloading = nil
|
||||
end
|
||||
|
||||
function on_audio_device_list_change()
|
||||
if mp.get_property("current-ao") == "null" and not reloading then
|
||||
mp.msg.verbose("audio-device-list changed: reloading audio")
|
||||
-- avoid calling ao-reload too often
|
||||
reloading = mp.add_timeout(0.5, do_reload)
|
||||
end
|
||||
end
|
||||
|
||||
mp.set_property("options/audio-fallback-to-null", "yes")
|
||||
mp.observe_property("audio-device-list", "native", on_audio_device_list_change)
|
||||
@@ -1,13 +0,0 @@
|
||||
local utils = require("mp.utils")
|
||||
|
||||
mp.observe_property("audio-device-list", "native", function(name, val)
|
||||
print("Audio device list changed:")
|
||||
for index, e in ipairs(val) do
|
||||
print(" - '" .. e.name .. "' (" .. e.description .. ")")
|
||||
end
|
||||
end)
|
||||
|
||||
mp.observe_property("audio-out-detected-device", "native", function(name, val)
|
||||
print("Detected audio device changed:")
|
||||
print(" - '" .. val)
|
||||
end)
|
||||
+19
-19
@@ -21,7 +21,7 @@
|
||||
-- The default delay between insertion of the cropdetect and
|
||||
-- crop filters may be overridden by adding
|
||||
--
|
||||
-- --script-opts=autocrop.detect_seconds=<number of seconds>
|
||||
-- --lua-opts=autocrop.detect_seconds=<number of seconds>
|
||||
--
|
||||
-- to mpv's arguments. This may be desirable to allow cropdetect more
|
||||
-- time to collect data.
|
||||
@@ -42,11 +42,11 @@ function del_filter_if_present(label)
|
||||
-- error if the filter doesn't exist
|
||||
local vfs = mp.get_property_native("vf")
|
||||
for i,vf in pairs(vfs) do
|
||||
if vf["label"] == label then
|
||||
table.remove(vfs, i)
|
||||
mp.set_property_native("vf", vfs)
|
||||
return true
|
||||
end
|
||||
if vf["label"] == label then
|
||||
table.remove(vfs, i)
|
||||
mp.set_property_native("vf", vfs)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -65,10 +65,10 @@ function autocrop_start()
|
||||
|
||||
-- insert the cropdetect filter
|
||||
ret=mp.command(
|
||||
string.format(
|
||||
'vf add @%s:lavfi=graph="cropdetect=limit=24:round=2:reset=0"',
|
||||
cropdetect_label
|
||||
)
|
||||
string.format(
|
||||
'vf add @%s:lavfi=graph="cropdetect=limit=24:round=2:reset=0"',
|
||||
cropdetect_label
|
||||
)
|
||||
)
|
||||
-- wait to gather data
|
||||
timer=mp.add_timeout(detect_seconds, do_crop)
|
||||
@@ -77,15 +77,15 @@ end
|
||||
function do_crop()
|
||||
-- get the metadata
|
||||
local cropdetect_metadata = mp.get_property_native(
|
||||
string.format("vf-metadata/%s", cropdetect_label)
|
||||
string.format("vf-metadata/%s", cropdetect_label)
|
||||
)
|
||||
-- use it to crop if its valid
|
||||
if cropdetect_metadata then
|
||||
if cropdetect_metadata["lavfi.cropdetect.w"]
|
||||
and cropdetect_metadata["lavfi.cropdetect.h"]
|
||||
and cropdetect_metadata["lavfi.cropdetect.x"]
|
||||
and cropdetect_metadata["lavfi.cropdetect.y"]
|
||||
then
|
||||
if cropdetect_metadata["lavfi.cropdetect.w"]
|
||||
and cropdetect_metadata["lavfi.cropdetect.h"]
|
||||
and cropdetect_metadata["lavfi.cropdetect.x"]
|
||||
and cropdetect_metadata["lavfi.cropdetect.y"]
|
||||
then
|
||||
mp.command(string.format("vf add @%s:crop=%s:%s:%s:%s",
|
||||
crop_label,
|
||||
cropdetect_metadata["lavfi.cropdetect.w"],
|
||||
@@ -94,9 +94,9 @@ function do_crop()
|
||||
cropdetect_metadata["lavfi.cropdetect.y"]))
|
||||
else
|
||||
mp.msg.error(
|
||||
"Got empty crop data. You might need to increase detect_seconds."
|
||||
)
|
||||
end
|
||||
"Got empty crop data. You might need to increase detect_seconds."
|
||||
)
|
||||
end
|
||||
else
|
||||
mp.msg.error(
|
||||
"No crop data. Was the cropdetect filter successfully inserted?"
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
-- This script uses the lavfi idet filter to automatically insert the
|
||||
-- appropriate deinterlacing filter based on a short section of the
|
||||
-- currently playing video.
|
||||
--
|
||||
-- It registers the key-binding ctrl+d, which when pressed, inserts the filters
|
||||
-- ``vf=lavfi=idet,pullup,vf=lavfi=idet``. After 4 seconds, it removes these
|
||||
-- filters and decides whether the content is progressive, interlaced, or
|
||||
-- telecined and the interlacing field dominance.
|
||||
--
|
||||
-- Based on this information, it may set mpv's ``deinterlace`` property (which
|
||||
-- usually inserts the yadif filter), or insert the ``pullup`` filter if the
|
||||
-- content is telecined. It also sets mpv's ``field-dominance`` property.
|
||||
--
|
||||
-- OPTIONS:
|
||||
-- The default detection time may be overridden by adding
|
||||
--
|
||||
-- --script-opts=autodeint.detect_seconds=<number of seconds>
|
||||
--
|
||||
-- to mpv's arguments. This may be desirable to allow idet more
|
||||
-- time to collect data.
|
||||
--
|
||||
-- To see counts of the various types of frames for each detection phase,
|
||||
-- the verbosity can be increased with
|
||||
--
|
||||
-- --msg-level autodeint=v
|
||||
--
|
||||
-- This script requires a recent version of ffmpeg for which the idet
|
||||
-- filter adds the required metadata.
|
||||
|
||||
require "mp.msg"
|
||||
|
||||
script_name = mp.get_script_name()
|
||||
detect_label = string.format("%s-detect", script_name)
|
||||
pullup_label = string.format("%s", script_name)
|
||||
ivtc_detect_label = string.format("%s-ivtc-detect", script_name)
|
||||
|
||||
-- number of seconds to gather cropdetect data
|
||||
detect_seconds = tonumber(mp.get_opt(string.format("%s.detect_seconds", script_name)))
|
||||
if not detect_seconds then
|
||||
detect_seconds = 4
|
||||
end
|
||||
|
||||
function del_filter_if_present(label)
|
||||
-- necessary because mp.command('vf del @label:filter') raises an
|
||||
-- error if the filter doesn't exist
|
||||
local vfs = mp.get_property_native("vf")
|
||||
|
||||
for i,vf in pairs(vfs) do
|
||||
if vf["label"] == label then
|
||||
table.remove(vfs, i)
|
||||
mp.set_property_native("vf", vfs)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function start_detect()
|
||||
-- exit if detection is already in progress
|
||||
if timer then
|
||||
mp.msg.warn("already detecting!")
|
||||
return
|
||||
end
|
||||
|
||||
mp.set_property("deinterlace","no")
|
||||
del_filter_if_present(pullup_label)
|
||||
|
||||
-- insert the detection filter
|
||||
local cmd = string.format('vf add @%s:lavfi=graph="idet",@%s:pullup,@%s:lavfi=graph="idet"',
|
||||
detect_label, pullup_label, ivtc_detect_label)
|
||||
if not mp.command(cmd) then
|
||||
mp.msg.error("failed to insert detection filters")
|
||||
return
|
||||
end
|
||||
|
||||
-- wait to gather data
|
||||
timer = mp.add_timeout(detect_seconds, select_filter)
|
||||
end
|
||||
|
||||
function stop_detect()
|
||||
del_filter_if_present(detect_label)
|
||||
del_filter_if_present(ivtc_detect_label)
|
||||
timer = nil
|
||||
end
|
||||
|
||||
progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3, 4
|
||||
|
||||
function judge(label)
|
||||
-- get the metadata
|
||||
local result = mp.get_property_native(string.format("vf-metadata/%s", label))
|
||||
num_tff = tonumber(result["lavfi.idet.multiple.tff"])
|
||||
num_bff = tonumber(result["lavfi.idet.multiple.bff"])
|
||||
num_progressive = tonumber(result["lavfi.idet.multiple.progressive"])
|
||||
num_undetermined = tonumber(result["lavfi.idet.multiple.undetermined"])
|
||||
num_interlaced = num_tff + num_bff
|
||||
num_determined = num_interlaced + num_progressive
|
||||
|
||||
mp.msg.verbose(label.." progressive = "..num_progressive)
|
||||
mp.msg.verbose(label.." interlaced-tff = "..num_tff)
|
||||
mp.msg.verbose(label.." interlaced-bff = "..num_bff)
|
||||
mp.msg.verbose(label.." undetermined = "..num_undetermined)
|
||||
|
||||
if num_determined < num_undetermined then
|
||||
mp.msg.warn("majority undetermined frames")
|
||||
end
|
||||
if num_progressive > 20*num_interlaced then
|
||||
return progressive
|
||||
elseif num_tff > 10*num_bff then
|
||||
return interlaced_tff
|
||||
elseif num_bff > 10*num_tff then
|
||||
return interlaced_bff
|
||||
else
|
||||
return interlaced
|
||||
end
|
||||
end
|
||||
|
||||
function select_filter()
|
||||
-- handle the first detection filter results
|
||||
verdict = judge(detect_label)
|
||||
if verdict == progressive then
|
||||
mp.msg.info("progressive: doing nothing")
|
||||
stop_detect()
|
||||
return
|
||||
elseif verdict == interlaced_tff then
|
||||
mp.set_property("field-dominance", "top")
|
||||
elseif verdict == interlaced_bff then
|
||||
mp.set_property("field-dominance", "bottom")
|
||||
elseif verdict == interlaced then
|
||||
mp.set_property("field-dominance", "auto")
|
||||
end
|
||||
|
||||
-- handle the ivtc detection filter results
|
||||
verdict = judge(ivtc_detect_label)
|
||||
if verdict == progressive then
|
||||
mp.msg.info(string.format("telecinied with %s field dominance: using pullup", mp.get_property("field-dominance")))
|
||||
stop_detect()
|
||||
else
|
||||
mp.msg.info(string.format("interlaced with %s field dominance: setting deinterlace property", mp.get_property("field-dominance")))
|
||||
del_filter_if_present(pullup_label)
|
||||
mp.set_property("deinterlace","yes")
|
||||
stop_detect()
|
||||
end
|
||||
end
|
||||
|
||||
mp.add_key_binding("ctrl+d", script_name, start_detect)
|
||||
+11
-74
@@ -4,19 +4,8 @@
|
||||
-- alphabetically, and adds entries before and after the current file to
|
||||
-- the internal playlist. (It stops if the it would add an already existing
|
||||
-- playlist entry at the same position - this makes it "stable".)
|
||||
-- Add at most 5000 * 2 files when starting a file (before + after).
|
||||
MAXENTRIES = 5000
|
||||
|
||||
function Set (t)
|
||||
local set = {}
|
||||
for _, v in pairs(t) do set[v] = true end
|
||||
return set
|
||||
end
|
||||
|
||||
EXTENSIONS = Set {
|
||||
'mkv', 'avi', 'mp4', 'ogv', 'webm', 'rmvb', 'flv', 'wmv', 'mpeg', 'mpg', 'm4v', '3gp',
|
||||
'mp3', 'wav', 'ogv', 'flac', 'm4a', 'wma',
|
||||
}
|
||||
-- Add at most 5 * 2 files when starting a file (before + after).
|
||||
MAXENTRIES = 5
|
||||
|
||||
mputils = require 'mp.utils'
|
||||
|
||||
@@ -25,24 +14,7 @@ function add_files_at(index, files)
|
||||
local oldcount = mp.get_property_number("playlist-count", 1)
|
||||
for i = 1, #files do
|
||||
mp.commandv("loadfile", files[i], "append")
|
||||
mp.commandv("playlist-move", oldcount + i - 1, index + i - 1)
|
||||
end
|
||||
end
|
||||
|
||||
function get_extension(path)
|
||||
match = string.match(path, "%.([^%.]+)$" )
|
||||
if match == nil then
|
||||
return "nomatch"
|
||||
else
|
||||
return match
|
||||
end
|
||||
end
|
||||
|
||||
table.filter = function(t, iter)
|
||||
for i = #t, 1, -1 do
|
||||
if not iter(t[i]) then
|
||||
table.remove(t, i)
|
||||
end
|
||||
mp.commandv("playlist_move", oldcount + i - 1, index + i - 1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,38 +24,8 @@ function find_and_add_entries()
|
||||
if #dir == 0 then
|
||||
return
|
||||
end
|
||||
local pl_count = mp.get_property_number("playlist-count", 1)
|
||||
if (pl_count > 1 and autoload == nil) or
|
||||
(pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil) then
|
||||
return
|
||||
else
|
||||
autoload = true
|
||||
end
|
||||
|
||||
local files = mputils.readdir(dir, "files")
|
||||
if files == nil then
|
||||
return
|
||||
end
|
||||
table.filter(files, function (v, k)
|
||||
local ext = get_extension(v)
|
||||
if ext == nil then
|
||||
return false
|
||||
end
|
||||
return EXTENSIONS[string.lower(ext)]
|
||||
end)
|
||||
table.sort(files, function (a, b)
|
||||
local len = string.len(a) - string.len(b)
|
||||
if len ~= 0 then -- case for ordering filename ending with such as X.Y.Z
|
||||
local ext = string.len(get_extension(a)) + 1
|
||||
return string.sub(a, 1, -ext) < string.sub(b, 1, -ext)
|
||||
end
|
||||
return string.lower(a) < string.lower(b)
|
||||
end)
|
||||
|
||||
if dir == "." then
|
||||
dir = ""
|
||||
end
|
||||
|
||||
table.sort(files)
|
||||
local pl = mp.get_property_native("playlist", {})
|
||||
local pl_current = mp.get_property_number("playlist-pos", 0) + 1
|
||||
-- Find the current pl entry (dir+"/"+filename) in the sorted dir list
|
||||
@@ -97,36 +39,31 @@ function find_and_add_entries()
|
||||
if current == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local append = {[-1] = {}, [1] = {}}
|
||||
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
|
||||
for dir = -1, 1, 2 do -- 2 iterations, with dir = -1 and +1
|
||||
for i = 1, MAXENTRIES do
|
||||
local file = files[current + i * direction]
|
||||
local pl_e = pl[pl_current + i * direction]
|
||||
local file = files[current + i * dir]
|
||||
local pl_e = pl[pl_current + i * dir]
|
||||
if file == nil or file[1] == "." then
|
||||
break
|
||||
end
|
||||
|
||||
local filepath = dir .. file
|
||||
if pl_e then
|
||||
-- If there's a playlist entry, and it's the same file, stop.
|
||||
if pl_e.filename == filepath then
|
||||
if pl_e.filename == file then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if direction == -1 then
|
||||
if dir == -1 then
|
||||
if pl_current == 1 then -- never add additional entries in the middle
|
||||
mp.msg.info("Prepending " .. file)
|
||||
table.insert(append[-1], 1, filepath)
|
||||
table.insert(append[-1], 1, file)
|
||||
end
|
||||
else
|
||||
mp.msg.info("Adding " .. file)
|
||||
table.insert(append[1], filepath)
|
||||
table.insert(append[1], file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
add_files_at(pl_current + 1, append[1])
|
||||
add_files_at(pl_current, append[-1])
|
||||
end
|
||||
|
||||
@@ -20,9 +20,9 @@ pullup_label = string.format("%s-pullup", script_name)
|
||||
|
||||
function pullup_on()
|
||||
for i,vf in pairs(mp.get_property_native('vf')) do
|
||||
if vf['label'] == pullup_label then
|
||||
return "yes"
|
||||
end
|
||||
if vf['label'] == pullup_label then
|
||||
return "yes"
|
||||
end
|
||||
end
|
||||
return "no"
|
||||
end
|
||||
|
||||
+31
-31
@@ -4,7 +4,7 @@
|
||||
-- parameters. See the entry for "drc" under the "AUDIO FILTERS"
|
||||
-- section of the man page for a complete description of the filter.
|
||||
--
|
||||
-- This script registers the key-binding "\" to toggle the filter between
|
||||
-- This script registers the key-binding "\" to toggle the filter between
|
||||
--
|
||||
-- * off
|
||||
-- * method=1 (single-sample smoothing)
|
||||
@@ -21,30 +21,30 @@ script_name = mp.get_script_name()
|
||||
|
||||
function print_state(params)
|
||||
if params then
|
||||
mp.osd_message(script_name..":\n"
|
||||
.."method = "..params["method"].."\n"
|
||||
.."target = "..params["target"])
|
||||
mp.osd_message(script_name..":\n"
|
||||
.."method = "..params["method"].."\n"
|
||||
.."target = "..params["target"])
|
||||
else
|
||||
mp.osd_message(script_name..":\noff")
|
||||
mp.osd_message(script_name..":\noff")
|
||||
end
|
||||
end
|
||||
|
||||
function get_index_of_drc(afs)
|
||||
for i,af in pairs(afs) do
|
||||
if af["label"] == script_name then
|
||||
return i
|
||||
end
|
||||
if af["label"] == script_name then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function append_drc(afs)
|
||||
afs[#afs+1] = {
|
||||
name = "drc",
|
||||
label = script_name,
|
||||
params = {
|
||||
method = "1",
|
||||
target = "0.25"
|
||||
}
|
||||
name = "drc",
|
||||
label = script_name,
|
||||
params = {
|
||||
method = "1",
|
||||
target = "0.25"
|
||||
}
|
||||
}
|
||||
print_state(afs[#afs]["params"])
|
||||
end
|
||||
@@ -53,34 +53,34 @@ function modify_or_create_af(fun)
|
||||
afs = mp.get_property_native("af")
|
||||
i = get_index_of_drc(afs)
|
||||
if not i then
|
||||
append_drc(afs)
|
||||
append_drc(afs)
|
||||
else
|
||||
fun(afs, i)
|
||||
fun(afs, i)
|
||||
end
|
||||
mp.set_property_native("af", afs)
|
||||
end
|
||||
|
||||
function drc_toggle_method_handler()
|
||||
modify_or_create_af(
|
||||
function (afs, i)
|
||||
new_method=(afs[i]["params"]["method"]+1)%3
|
||||
if new_method == 0 then
|
||||
table.remove(afs, i)
|
||||
print_state(nil)
|
||||
else
|
||||
afs[i]["params"]["method"] = tostring((afs[i]["params"]["method"])%2+1)
|
||||
print_state(afs[i]["params"])
|
||||
end
|
||||
end
|
||||
function (afs, i)
|
||||
new_method=(afs[i]["params"]["method"]+1)%3
|
||||
if new_method == 0 then
|
||||
table.remove(afs, i)
|
||||
print_state(nil)
|
||||
else
|
||||
afs[i]["params"]["method"] = tostring((afs[i]["params"]["method"])%2+1)
|
||||
print_state(afs[i]["params"])
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function drc_scale_target(factor)
|
||||
modify_or_create_af(
|
||||
function (afs)
|
||||
afs[i]["params"]["target"] = tostring(afs[i]["params"]["target"]*factor)
|
||||
print_state(afs[i]["params"])
|
||||
end
|
||||
function (afs)
|
||||
afs[i]["params"]["target"] = tostring(afs[i]["params"]["target"]*factor)
|
||||
print_state(afs[i]["params"])
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
@@ -92,7 +92,7 @@ function drc_quieter_handler()
|
||||
drc_scale_target(0.5)
|
||||
end
|
||||
|
||||
-- toggle between off, method 1 and method 2
|
||||
-- toggle between off, method 1 and method 2
|
||||
mp.add_key_binding("\\", "drc_toggle_method", drc_toggle_method_handler)
|
||||
-- increase or decrease target volume
|
||||
mp.add_key_binding("ctrl+9", "drc_quieter", drc_quieter_handler)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
-- Test script for property change notification mechanism.
|
||||
-- Note that watching/reading some properties can be very expensive, or
|
||||
-- require the player to synchronously wait on network (when playing
|
||||
-- remote files), so you should in general only watch properties you
|
||||
-- are interested in.
|
||||
|
||||
local utils = require("mp.utils")
|
||||
|
||||
function observe(name)
|
||||
mp.observe_property(name, "native", function(name, val)
|
||||
print("property '" .. name .. "' changed to '" ..
|
||||
utils.to_string(val) .. "'")
|
||||
end)
|
||||
end
|
||||
|
||||
for i,name in ipairs(mp.get_property_native("property-list")) do
|
||||
observe(name)
|
||||
end
|
||||
|
||||
for i,name in ipairs(mp.get_property_native("options")) do
|
||||
observe("options/" .. name)
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
--makes mpv disable ontop when pausing and re-enable it again when resuming playback
|
||||
--please note that this won't do anything if ontop was not enabled before pausing
|
||||
|
||||
local was_ontop = false
|
||||
|
||||
mp.observe_property("pause", "bool", function(name, value)
|
||||
local ontop = mp.get_property_native("ontop")
|
||||
if value then
|
||||
if ontop then
|
||||
mp.set_property_native("ontop", false)
|
||||
was_ontop = true
|
||||
end
|
||||
else
|
||||
if was_ontop and not ontop then
|
||||
mp.set_property_native("ontop", true)
|
||||
end
|
||||
was_ontop = false
|
||||
end
|
||||
end)
|
||||
@@ -1,20 +0,0 @@
|
||||
-- This script pauses playback when minimizing the window, and resumes playback
|
||||
-- if it's brought back again. If the player was already paused when minimizing,
|
||||
-- then try not to mess with the pause state.
|
||||
|
||||
local did_minimize = false
|
||||
|
||||
mp.observe_property("window-minimized", "bool", function(name, value)
|
||||
local pause = mp.get_property_native("pause")
|
||||
if value == true then
|
||||
if pause == false then
|
||||
mp.set_property_native("pause", true)
|
||||
did_minimize = true
|
||||
end
|
||||
elseif value == false then
|
||||
if did_minimize and (pause == true) then
|
||||
mp.set_property_native("pause", false)
|
||||
end
|
||||
did_minimize = false
|
||||
end
|
||||
end)
|
||||
+1
-1
@@ -64,7 +64,7 @@ sub generate_c_header {
|
||||
|
||||
# Output a counter variable for each element
|
||||
# (presence/absence for scalars, item count for arrays)
|
||||
for my $subel (sort values %{$el->{subelements}}) {
|
||||
for my $subel (values %{$el->{subelements}}) {
|
||||
print " int n_$subel->{fieldname};\n"
|
||||
}
|
||||
print "};\n";
|
||||
|
||||
+150
-127
@@ -17,134 +17,157 @@
|
||||
# When multiple files were specified, their info will be put into FOO_* for the
|
||||
# first file, FOO_1_* for the second file, FOO_2_* for the third file, etc.
|
||||
|
||||
__midentify__main() {
|
||||
|
||||
case "$0" in
|
||||
mpv_identify.sh|*/mpv_identify.sh)
|
||||
# we are NOT being sourced
|
||||
[ -n "$1" ] && set -- '' "$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
cat >&2 <<EOF
|
||||
Usage 1 (for humans only): $0 filename.mkv
|
||||
will print all property values.
|
||||
Note that this output really shouldn't be parsed, as the
|
||||
format is subject to change.
|
||||
|
||||
Usage 2 (for use by scripts): see top of this file
|
||||
|
||||
NOTE: for mkv with ordered chapters, this may
|
||||
not always identify the specified file, but the
|
||||
file providing the first chapter. Specify
|
||||
--no-ordered-chapters to prevent this.
|
||||
EOF
|
||||
return 2
|
||||
fi
|
||||
|
||||
local LF="
|
||||
"
|
||||
|
||||
local nextprefix="$1"
|
||||
shift
|
||||
|
||||
if [ -n "$nextprefix" ]; then
|
||||
# in case of error, we always want this unset
|
||||
unset "${nextprefix}path"
|
||||
fi
|
||||
|
||||
local allprops="
|
||||
filename
|
||||
path
|
||||
stream-start
|
||||
stream-end
|
||||
stream-length
|
||||
|
||||
demuxer
|
||||
|
||||
length
|
||||
chapters
|
||||
editions
|
||||
titles
|
||||
|
||||
audio
|
||||
audio-bitrate
|
||||
audio-codec
|
||||
audio-format
|
||||
channels
|
||||
samplerate
|
||||
|
||||
video
|
||||
angle
|
||||
video-bitrate
|
||||
video-codec
|
||||
video-format
|
||||
video-aspect
|
||||
fps
|
||||
width
|
||||
height
|
||||
dwidth
|
||||
dheight
|
||||
|
||||
sub
|
||||
"
|
||||
# TODO add metadata support once mpv can do it
|
||||
|
||||
local propstr="X-MIDENTIFY-START:$LF"
|
||||
local key
|
||||
for key in $allprops; do
|
||||
propstr="${propstr}X-MIDENTIFY: $key \${=$key}$LF"
|
||||
key="$(printf '%s\n' "$key" | tr - _)"
|
||||
unset "$nextprefix$key"
|
||||
done
|
||||
|
||||
local fileindex=0
|
||||
local prefix=
|
||||
local line
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
X-MIDENTIFY-START:)
|
||||
if [ -n "$nextprefix" ]; then
|
||||
prefix="$nextprefix"
|
||||
if [ "$fileindex" -gt 0 ]; then
|
||||
nextprefix="${prefix%${fileindex}_}"
|
||||
fi
|
||||
fileindex="$((fileindex+1))"
|
||||
nextprefix="${nextprefix}${fileindex}_"
|
||||
for key in $allprops; do
|
||||
key="$(printf '%s\n' "$key" | tr - _)"
|
||||
unset "$nextprefix$key"
|
||||
done
|
||||
else
|
||||
if [ "$fileindex" -gt 0 ]; then
|
||||
printf '\n'
|
||||
fi
|
||||
fileindex="$((fileindex+1))"
|
||||
fi
|
||||
case "$0" in
|
||||
mpv_identify.sh|*/mpv_identify.sh)
|
||||
# we are NOT being sourced
|
||||
case "$1" in
|
||||
'')
|
||||
;;
|
||||
X-MIDENTIFY:\ *)
|
||||
local key="${line#X-MIDENTIFY: }"
|
||||
local value="${key#* }"
|
||||
key="${key%% *}"
|
||||
key="$(printf '%s\n' "$key" | tr - _)"
|
||||
if [ -n "$nextprefix" ]; then
|
||||
if [ -z "$prefix" ]; then
|
||||
echo >&2 "Got X-MIDENTIFY: without X-MIDENTIFY-START:"
|
||||
elif [ -n "$value" ]; then
|
||||
eval "$prefix$key"='"$value"'
|
||||
fi
|
||||
else
|
||||
if [ -n "$value" ]; then
|
||||
printf '%s=%s\n' "$key" "$value"
|
||||
fi
|
||||
fi
|
||||
*)
|
||||
set -- '' "$@"
|
||||
;;
|
||||
esac
|
||||
done <<EOF
|
||||
$(${MPV:-mpv} --term-playing-msg="$propstr" --vo=null --ao=null \
|
||||
--frames=1 --quiet --no-cache --no-config -- "$@")
|
||||
EOF
|
||||
}
|
||||
;;
|
||||
esac
|
||||
|
||||
__midentify__main "$@"
|
||||
if [ $# -lt 2 ]; then
|
||||
echo >&2 "Usage 1 (for humans only): $0 filename.mkv"
|
||||
echo >&2 "will print all property values."
|
||||
echo >&2 "Note that this output really shouldn't be parsed, as the"
|
||||
echo >&2 "format is subject to change."
|
||||
echo >&2
|
||||
echo >&2 "Usage 2 (for use by scripts): see top of this file"
|
||||
echo >&2
|
||||
echo >&2 "NOTE: for mkv with ordered chapters, this may"
|
||||
echo >&2 "not always identify the specified file, but the"
|
||||
echo >&2 "file providing the first chapter. Specify"
|
||||
echo >&2 "--no-ordered-chapters to prevent this."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MPV" ]; then
|
||||
MPV="mpv"
|
||||
fi
|
||||
|
||||
__midentify__LF="
|
||||
"
|
||||
|
||||
__midentify__nextprefix=$1
|
||||
shift
|
||||
|
||||
if [ -n "$__midentify__nextprefix" ]; then
|
||||
# in case of error, we always want this unset
|
||||
eval unset $__midentify__nextprefix'path'
|
||||
fi
|
||||
|
||||
__midentify__allprops="
|
||||
filename
|
||||
path
|
||||
stream-start
|
||||
stream-end
|
||||
stream-length
|
||||
|
||||
demuxer
|
||||
|
||||
length
|
||||
chapters
|
||||
editions
|
||||
titles
|
||||
|
||||
audio
|
||||
audio-bitrate
|
||||
audio-codec
|
||||
audio-format
|
||||
channels
|
||||
samplerate
|
||||
|
||||
video
|
||||
angle
|
||||
video-bitrate
|
||||
video-codec
|
||||
video-format
|
||||
video-aspect
|
||||
fps
|
||||
width
|
||||
height
|
||||
dwidth
|
||||
dheight
|
||||
|
||||
sub
|
||||
"
|
||||
# TODO add metadata support once mpv can do it
|
||||
|
||||
__midentify__propstr="X-MIDENTIFY-START:$__midentify__LF"
|
||||
for __midentify__key in $__midentify__allprops; do
|
||||
__midentify__propstr=$__midentify__propstr"X-MIDENTIFY: $__midentify__key \${=$__midentify__key}$__midentify__LF"
|
||||
__midentify__key=`echo "$__midentify__key" | tr - _`
|
||||
eval unset $__midentify__nextprefix$__midentify__key
|
||||
done
|
||||
|
||||
__midentify__output=`$MPV --term-playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet --no-cache --no-config "$@"`
|
||||
__midentify__fileindex=0
|
||||
__midentify__prefix=
|
||||
while :; do
|
||||
case "$__midentify__output" in
|
||||
'')
|
||||
break
|
||||
;;
|
||||
*$__midentify__LF*)
|
||||
__midentify__line=${__midentify__output%%$__midentify__LF*}
|
||||
__midentify__output=${__midentify__output#*$__midentify__LF}
|
||||
;;
|
||||
*)
|
||||
__midentify__line=$__midentify__output
|
||||
__midentify__output=
|
||||
;;
|
||||
esac
|
||||
case "$__midentify__line" in
|
||||
X-MIDENTIFY-START:)
|
||||
if [ -n "$__midentify__nextprefix" ]; then
|
||||
__midentify__prefix=$__midentify__nextprefix
|
||||
if [ $__midentify__fileindex -gt 0 ]; then
|
||||
__midentify__nextprefix=${__midentify__prefix%$__midentify__fileindex\_}
|
||||
fi
|
||||
__midentify__fileindex=$(($__midentify__fileindex+1))
|
||||
__midentify__nextprefix=$__midentify__nextprefix$__midentify__fileindex\_
|
||||
for __midentify__key in $__midentify__allprops; do
|
||||
__midentify__key=`echo "$__midentify__key" | tr - _`
|
||||
eval unset $__midentify__nextprefix$__midentify__key
|
||||
done
|
||||
else
|
||||
if [ $__midentify__fileindex -gt 0 ]; then
|
||||
echo
|
||||
fi
|
||||
__midentify__fileindex=$(($__midentify__fileindex+1))
|
||||
fi
|
||||
;;
|
||||
X-MIDENTIFY:\ *)
|
||||
__midentify__key=${__midentify__line#X-MIDENTIFY:\ }
|
||||
__midentify__value=${__midentify__key#* }
|
||||
__midentify__key=${__midentify__key%% *}
|
||||
__midentify__key=`echo "$__midentify__key" | tr - _`
|
||||
if [ -n "$__midentify__nextprefix" ]; then
|
||||
if [ -z "$__midentify__prefix" ]; then
|
||||
echo >&2 "Got X-MIDENTIFY: without X-MIDENTIFY-START:"
|
||||
elif [ -n "$__midentify__value" ]; then
|
||||
eval $__midentify__prefix$__midentify__key=\$__midentify__value
|
||||
fi
|
||||
else
|
||||
if [ -n "$__midentify__value" ]; then
|
||||
echo "$__midentify__key=$__midentify__value"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
unset __midentify__fileindex
|
||||
unset __midentify__allprops
|
||||
unset __midentify__key
|
||||
unset __midentify__LF
|
||||
unset __midentify__line
|
||||
unset __midentify__output
|
||||
unset __midentify__nextprefix
|
||||
unset __midentify__prefix
|
||||
unset __midentify__propstr
|
||||
unset __midentify__value
|
||||
+2
-13
@@ -3,7 +3,6 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import fileinput
|
||||
from optparse import OptionParser
|
||||
|
||||
def sh(command):
|
||||
@@ -36,20 +35,10 @@ def copy_binary(binary_name):
|
||||
shutil.copy(binary_name, target_binary(binary_name))
|
||||
|
||||
def apply_plist_template(plist_file, version):
|
||||
for line in fileinput.input(plist_file, inplace=1):
|
||||
print (line.rstrip().replace('${VERSION}', version))
|
||||
|
||||
def bundle_version():
|
||||
if os.path.exists('VERSION'):
|
||||
x = open('VERSION')
|
||||
version = x.read()
|
||||
x.close()
|
||||
else:
|
||||
version = sh("./version.sh").strip()
|
||||
return version
|
||||
sh("sed -i -e 's/${VERSION}/%s/g' %s" % (version, plist_file))
|
||||
|
||||
def main():
|
||||
version = bundle_version().rstrip()
|
||||
version = sh("./version.sh --print").strip()
|
||||
|
||||
usage = "usage: %prog [options] arg"
|
||||
parser = OptionParser(usage)
|
||||
|
||||
@@ -88,7 +88,6 @@
|
||||
<string>VOB</string>
|
||||
<string>WEBM</string>
|
||||
<string>WMV</string>
|
||||
<string>MK3D</string>
|
||||
<string>asf</string>
|
||||
<string>avi</string>
|
||||
<string>cpk</string>
|
||||
@@ -123,7 +122,6 @@
|
||||
<string>vob</string>
|
||||
<string>webm</string>
|
||||
<string>wmv</string>
|
||||
<string>mk3d</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
@@ -210,7 +208,6 @@
|
||||
<string>mms</string>
|
||||
<string>mmst</string>
|
||||
<string>http</string>
|
||||
<string>https</string>
|
||||
<string>httpproxy</string>
|
||||
<string>rtp</string>
|
||||
<string>rtsp</string>
|
||||
@@ -516,47 +513,6 @@
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mkv</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Matroska stereoscopic/3D video</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.mk3d</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://www.matroska.org</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mk3d</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>WebM Video</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.webm</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://www.webmproject.org</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>webm</string>
|
||||
</array>
|
||||
</dict>
|
||||
@@ -668,90 +624,6 @@
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>AVC raw stream</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.h264</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://www.itu.int/rec/T-REC-H.264</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>264</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>HEVC raw stream</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.hevc</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://hevc.info</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>hevc</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>YUV stream</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.yuv</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://en.wikipedia.org/wiki/YUV</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>yuv</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>YUV4MPEG2 stream</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.y4m</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://wiki.multimedia.cx/index.php?title=YUV4MPEG2</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>y4m</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
player-operation-mode=pseudo-gui
|
||||
+38
-108
@@ -1,16 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
import pyqtgraph as pg
|
||||
import matplotlib.pyplot as plot
|
||||
import sys
|
||||
import re
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
events = ".*"
|
||||
if len(sys.argv) > 2:
|
||||
events = sys.argv[2]
|
||||
event_regex = re.compile(events)
|
||||
|
||||
"""
|
||||
This script is meant to display stats written by mpv --dump-stats=filename.
|
||||
In general, each line in that file is an event of the form:
|
||||
@@ -25,142 +18,79 @@ e.g.:
|
||||
|
||||
Currently, the following event types are supported:
|
||||
|
||||
'signal' <name> singular event
|
||||
'start' <name> start of the named event
|
||||
'end' <name> end of the named event
|
||||
'value' <float> <name> a normal value (as opposed to event)
|
||||
'event-timed' <ts> <name> singular event at the given timestamp
|
||||
'value-timed' <ts> <float> <name> a value for an event at the given timestamp
|
||||
'range-timed' <ts1> <ts2> <name> like start/end, but explicit times
|
||||
<name> singular event (same as 'signal')
|
||||
'start' <name> start of the named event
|
||||
'end' <name> end of the named event
|
||||
'value' <float> <name> a normal value (as opposed to event)
|
||||
<event> singular event
|
||||
|
||||
"""
|
||||
|
||||
class G:
|
||||
events = {}
|
||||
sevents = [] # events, deterministically sorted
|
||||
start = None
|
||||
markers = ["o", "s", "t", "d"]
|
||||
curveno = {}
|
||||
|
||||
def find_marker():
|
||||
if len(G.markers) == 0:
|
||||
return "o"
|
||||
m = G.markers[0]
|
||||
G.markers = G.markers[1:]
|
||||
return m
|
||||
|
||||
class Event:
|
||||
pass
|
||||
|
||||
def get_event(event, evtype):
|
||||
def get_event(event):
|
||||
if event not in G.events:
|
||||
e = Event()
|
||||
G.events[event] = e
|
||||
e.name = event
|
||||
e.vals = []
|
||||
e.type = evtype
|
||||
e.marker = "o"
|
||||
if e.type == "event-signal":
|
||||
e.marker = find_marker()
|
||||
if not event_regex.match(e.name):
|
||||
return e
|
||||
G.events[event] = e
|
||||
e.type = "unknown"
|
||||
G.sevents = list(G.events.values())
|
||||
G.sevents.sort(key=lambda x: x.name)
|
||||
return G.events[event]
|
||||
|
||||
colors = [(0.0, 0.5, 0.0), (0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (1.0, 0.0, 0.0), (0.75, 0.75, 0), (0.0, 0.75, 0.75), (0.75, 0, 0.75)]
|
||||
def mkColor(t):
|
||||
return pg.mkColor(int(t[0] * 255), int(t[1] * 255), int(t[2] * 255))
|
||||
|
||||
SCALE = 1e6 # microseconds to seconds
|
||||
|
||||
for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
ts, event = line.split(" ", 1)
|
||||
ts = int(ts) / SCALE
|
||||
ts = int(ts) / 1000 # milliseconds
|
||||
if G.start is None:
|
||||
G.start = ts
|
||||
ts = ts - G.start
|
||||
if event.startswith("start "):
|
||||
e = get_event(event[6:], "event")
|
||||
e = get_event(event[6:])
|
||||
e.type = "event"
|
||||
e.vals.append((ts, 0))
|
||||
e.vals.append((ts, 1))
|
||||
elif event.startswith("end "):
|
||||
e = get_event(event[4:], "event")
|
||||
e = get_event(event[4:])
|
||||
e.type = "event"
|
||||
e.vals.append((ts, 1))
|
||||
e.vals.append((ts, 0))
|
||||
elif event.startswith("value "):
|
||||
_, val, name = event.split(" ", 2)
|
||||
val = float(val)
|
||||
e = get_event(name, "value")
|
||||
e = get_event(name)
|
||||
e.type = "value"
|
||||
e.vals.append((ts, val))
|
||||
elif event.startswith("event-timed "):
|
||||
_, val, name = event.split(" ", 2)
|
||||
val = int(val) / SCALE - G.start
|
||||
e = get_event(name, "event-signal")
|
||||
e.vals.append((val, 1))
|
||||
elif event.startswith("range-timed "):
|
||||
_, ts1, ts2, name = event.split(" ", 3)
|
||||
ts1 = int(ts1) / SCALE - G.start
|
||||
ts2 = int(ts2) / SCALE - G.start
|
||||
e = get_event(name, "event")
|
||||
e.vals.append((ts1, 0))
|
||||
e.vals.append((ts1, 1))
|
||||
e.vals.append((ts2, 1))
|
||||
e.vals.append((ts2, 0))
|
||||
elif event.startswith("value-timed "):
|
||||
_, tsval, val, name = event.split(" ", 3)
|
||||
tsval = int(tsval) / SCALE - G.start
|
||||
val = float(val)
|
||||
e = get_event(name, "value")
|
||||
e.vals.append((tsval, val))
|
||||
elif event.startswith("signal "):
|
||||
name = event.split(" ", 2)[1]
|
||||
e = get_event(name, "event-signal")
|
||||
e.vals.append((ts, 1))
|
||||
else:
|
||||
e = get_event(event, "event-signal")
|
||||
e = get_event(event)
|
||||
e.type = "event-signal"
|
||||
e.vals.append((ts, 1))
|
||||
|
||||
# deterministically sort them; make sure the legend is sorted too
|
||||
G.sevents = list(G.events.values())
|
||||
G.sevents.sort(key=lambda x: x.name)
|
||||
hasval = False
|
||||
for e, index in zip(G.sevents, range(len(G.sevents))):
|
||||
m = len(G.sevents)
|
||||
if e.type == "value":
|
||||
hasval = True
|
||||
else:
|
||||
e.vals = [(x, y * (m - index) / m) for (x, y) in e.vals]
|
||||
|
||||
pg.setConfigOption('background', 'w')
|
||||
pg.setConfigOption('foreground', 'k')
|
||||
app = QtGui.QApplication([])
|
||||
win = pg.GraphicsWindow()
|
||||
#win.resize(1500, 900)
|
||||
|
||||
ax = [None, None]
|
||||
plots = 2 if hasval else 1
|
||||
ax[0] = win.addPlot()
|
||||
if hasval:
|
||||
win.nextRow()
|
||||
ax[1] = win.addPlot()
|
||||
ax[1].setXLink(ax[0])
|
||||
for cur in ax:
|
||||
if cur is not None:
|
||||
cur.addLegend(offset = (-1, 1))
|
||||
ao_events = ["ao fill", "audio wait"]
|
||||
for e in G.sevents:
|
||||
cur = ax[1 if e.type == "value" else 0]
|
||||
if not cur in G.curveno:
|
||||
G.curveno[cur] = 0
|
||||
args = {'name': e.name,'antialias':True}
|
||||
color = mkColor(colors[G.curveno[cur] % len(colors)])
|
||||
if e.type == "event-signal":
|
||||
args['symbol'] = e.marker
|
||||
args['symbolBrush'] = pg.mkBrush(color, width=0)
|
||||
else:
|
||||
args['pen'] = pg.mkPen(color, width=0)
|
||||
G.curveno[cur] += 1
|
||||
n = cur.plot([x for x,y in e.vals], [y for x,y in e.vals], **args)
|
||||
if e.name in ao_events:
|
||||
e.vals = [(x, y * 0.5) for (x, y) in e.vals]
|
||||
|
||||
QtGui.QApplication.instance().exec_()
|
||||
plot.hold(True)
|
||||
mainpl = plot.subplot(2, 1, 1)
|
||||
legend = []
|
||||
for e in G.sevents:
|
||||
if e.type == "value":
|
||||
plot.subplot(2, 1, 2, sharex=mainpl)
|
||||
else:
|
||||
plot.subplot(2, 1, 1)
|
||||
pl, = plot.plot([x for x,y in e.vals], [y for x,y in e.vals], label=e.name)
|
||||
if e.type == "event-signal":
|
||||
plot.setp(pl, marker = "o", linestyle = "None")
|
||||
legend.append(pl)
|
||||
plot.subplot(2, 1, 1)
|
||||
plot.legend(legend, [pl.get_label() for pl in legend])
|
||||
plot.show()
|
||||
@@ -1,147 +0,0 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
class TravisDepsBuilder
|
||||
def self.make(name)
|
||||
instance = klass.new(name)
|
||||
instance.fill_data
|
||||
instance.deps
|
||||
instance.build
|
||||
end
|
||||
|
||||
def self.klass
|
||||
Module.const_get([self.name, self.os.capitalize].join)
|
||||
rescue NameError
|
||||
self
|
||||
end
|
||||
|
||||
def self.os
|
||||
ENV['TRAVIS_OS_NAME']
|
||||
end
|
||||
|
||||
attr_reader :name, :url, :action, :os
|
||||
|
||||
def initialize(name)
|
||||
@name, @os = name, self.class.os
|
||||
end
|
||||
|
||||
def fill_data
|
||||
data = build_map.fetch(name)
|
||||
@url, @action = data[:url], data[:action]
|
||||
end
|
||||
|
||||
def build
|
||||
send(action)
|
||||
end
|
||||
|
||||
def deps; end
|
||||
|
||||
private
|
||||
def package_manager_update
|
||||
# yes class variable, you wanna update only once across all instances
|
||||
@@updated ||= false
|
||||
return if @@updated
|
||||
sh({'linux' => 'sudo apt-get update -y', 'osx' => 'brew update'}[os])
|
||||
@@updated = true
|
||||
end
|
||||
|
||||
def package_install(*packages)
|
||||
cmd = {
|
||||
'linux' => 'sudo apt-get install %s -y',
|
||||
'osx' => 'brew install %s'
|
||||
}[os] % [packages.join(" ")]
|
||||
|
||||
sh cmd
|
||||
end
|
||||
|
||||
def git
|
||||
sh "git clone --depth=1 #{url} #{name}"
|
||||
compile name
|
||||
end
|
||||
|
||||
def stable
|
||||
filename = File.basename(url)
|
||||
sh "wget #{url}"
|
||||
sh "tar -xzvf #{filename}"
|
||||
dirname = File.basename(url, ".tar.gz" )
|
||||
compile dirname
|
||||
end
|
||||
|
||||
def package
|
||||
package_install(url)
|
||||
end
|
||||
|
||||
def compile(dirname)
|
||||
sh "cd #{dirname} && #{configure} && make && sudo make install"
|
||||
sh "cd $TRAVIS_BUILD_DIR"
|
||||
end
|
||||
|
||||
def configure
|
||||
"./configure"
|
||||
end
|
||||
|
||||
def sh(command)
|
||||
`#{command}`
|
||||
end
|
||||
end
|
||||
|
||||
class Libav < TravisDepsBuilder
|
||||
def build_map
|
||||
{
|
||||
"libav-stable" => {
|
||||
:action => :stable,
|
||||
:url => 'http://libav.org/releases/libav-11.tar.gz'
|
||||
},
|
||||
"libav-git" => {
|
||||
:action => :git,
|
||||
:url => "git://git.libav.org/libav.git"
|
||||
},
|
||||
"ffmpeg-stable" => {
|
||||
:action => :stable,
|
||||
:url => 'http://www.ffmpeg.org/releases/ffmpeg-2.4.tar.gz'
|
||||
},
|
||||
"ffmpeg-git" => {
|
||||
:action => :git,
|
||||
:url => "git://github.com/FFmpeg/FFmpeg.git"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def configure
|
||||
[super, "--cc=#{ENV['CC']}"].join(" ")
|
||||
end
|
||||
end
|
||||
|
||||
class LibavOsx < Libav
|
||||
def build_map
|
||||
{
|
||||
"ffmpeg-stable" => { :action => :package, :url => 'ffmpeg' },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Libass < TravisDepsBuilder
|
||||
def build_map
|
||||
{
|
||||
"libass-stable" => {
|
||||
:action => :stable,
|
||||
:url => 'https://github.com/libass/libass/releases/download/0.12.1/libass-0.12.1.tar.gz'
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Dependencies < TravisDepsBuilder
|
||||
def deps
|
||||
packages = {
|
||||
'linux' => 'pkg-config fontconfig libfribidi-dev yasm',
|
||||
'osx' => 'pkg-config fontconfig freetype fribidi yasm'
|
||||
}
|
||||
package_manager_update
|
||||
package_install(packages.fetch(os))
|
||||
end
|
||||
end
|
||||
|
||||
Dependencies.new(:deps).deps
|
||||
|
||||
Libass.make(ARGV[0])
|
||||
Libav.make(ARGV[1])
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "x$LIBAV" != "xffmpeg-git" ] || [ "x$TRAVIS_OS_NAME" != "xlinux" ]; then
|
||||
# trigger build only on one of the matrix nodes
|
||||
exit;
|
||||
fi
|
||||
|
||||
if [ "x$TRAVIS_BRANCH" != "xmaster" ]; then
|
||||
# only rebuild website with pushes to master
|
||||
exit;
|
||||
fi
|
||||
|
||||
TRAVIS_COMMIT_RANGE=${TRAVIS_COMMIT_RANGE:-HEAD^..}
|
||||
if git diff --quiet --name-only --exit-code "$TRAVIS_COMMIT_RANGE" DOCS/; then
|
||||
exit;
|
||||
fi
|
||||
|
||||
body='{
|
||||
"request": {
|
||||
"branch":"master"
|
||||
}}'
|
||||
|
||||
curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Travis-API-Version: 3" \
|
||||
-H "Authorization: token $WEBSITE_TRAVIS_TOKEN" \
|
||||
-d "$body" \
|
||||
https://api.travis-ci.org/repo/mpv-player%2Fmpv.io/requests
|
||||
+41
-16
@@ -21,13 +21,20 @@ script after that will start a new mpv instance.
|
||||
|
||||
Note that you can control the mpv instance by writing to the command fifo:
|
||||
|
||||
echo "cycle fullscreen" > ~/.umpv_fifo
|
||||
echo "cycle fullscreen" > /tmp/umpv-fifo-*
|
||||
|
||||
Note: you can supply custom mpv path and options with the MPV environment
|
||||
variable. The environment variable will be split on whitespace, and the
|
||||
first item is used as path to mpv binary and the rest is passed as options
|
||||
_if_ the script starts mpv. If mpv is not started by the script (i.e. mpv
|
||||
is already running), this will be ignored.
|
||||
Note: you can supply custom options with the UMPV_OPTIONS environment variable.
|
||||
The environment variable will be split on whitespace, and each item is
|
||||
passed as option to mpv _if_ the script starts mpv. If mpv is not started
|
||||
by the script (i.e. mpv is already running), the options will be ignored.
|
||||
|
||||
Warning:
|
||||
|
||||
The script attempts to make sure the FIFO is safely created (i.e. not world-
|
||||
writable), and checks that it's really a FIFO. This is important for security,
|
||||
because the FIFO allows anyone with write access to run arbitrary commands
|
||||
in mpv's context using the "run" input command. If you are worried about
|
||||
security, you should verify that the code handles these concerns correctly.
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -38,17 +45,21 @@ import fcntl
|
||||
import stat
|
||||
import string
|
||||
|
||||
if len(sys.argv) < 1:
|
||||
sys.exit(1)
|
||||
files = sys.argv[1:]
|
||||
|
||||
# this is the same method mpv uses to decide this
|
||||
# this is about the same method mpv uses to decide this
|
||||
def is_url(filename):
|
||||
parts = filename.split("://", 1)
|
||||
parts = filename.split(":", 1)
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
# protocol prefix has no special characters => it's an URL
|
||||
allowed_symbols = string.ascii_letters + string.digits + '_'
|
||||
prefix = parts[0]
|
||||
return all(map(lambda c: c in allowed_symbols, prefix))
|
||||
for c in prefix:
|
||||
if string.ascii_letters.find(c) < 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
# make them absolute; also makes them safe against interpretation as options
|
||||
def make_abs(filename):
|
||||
@@ -57,7 +68,10 @@ def make_abs(filename):
|
||||
return filename
|
||||
files = [make_abs(f) for f in files]
|
||||
|
||||
FIFO = os.path.join(os.getenv("HOME"), ".umpv_fifo")
|
||||
opts_env = os.getenv("UMPV_OPTIONS")
|
||||
opts_env = opts_env.split() if opts_env else []
|
||||
|
||||
FIFO = "/tmp/umpv-fifo-" + os.getenv("USER")
|
||||
|
||||
fifo_fd = -1
|
||||
try:
|
||||
@@ -70,6 +84,14 @@ except OSError as e:
|
||||
else:
|
||||
raise e
|
||||
|
||||
if fifo_fd >= 0:
|
||||
st = os.fstat(fifo_fd)
|
||||
if (((st.st_mode & (stat.S_IRWXG | stat.S_IRWXO)) != 0) or
|
||||
(not stat.S_ISFIFO(st.st_mode)) or
|
||||
(st.st_uid != os.getuid())):
|
||||
print("error: command FIFO is not a FIFO or has bogus permissions")
|
||||
sys.exit(1)
|
||||
|
||||
if fifo_fd >= 0:
|
||||
# Unhandled race condition: what if mpv is terminating right now?
|
||||
fcntl.fcntl(fifo_fd, fcntl.F_SETFL, 0) # set blocking mode
|
||||
@@ -86,12 +108,15 @@ else:
|
||||
try:
|
||||
os.unlink(FIFO)
|
||||
except OSError as e:
|
||||
pass
|
||||
os.mkfifo(FIFO, 0o600)
|
||||
if e.errno == errno.ENOENT:
|
||||
pass
|
||||
else:
|
||||
raise e
|
||||
os.mkfifo(FIFO, int("0600", 8))
|
||||
|
||||
opts = (os.getenv("MPV") or "mpv").split()
|
||||
opts.extend(["--no-terminal", "--force-window", "--input-file=" + FIFO,
|
||||
"--"])
|
||||
opts = ["mpv", "--no-terminal", "--force-window", "--input-file=" + FIFO]
|
||||
opts.extend(opts_env)
|
||||
opts.append("--")
|
||||
opts.extend(files)
|
||||
|
||||
subprocess.check_call(opts)
|
||||
@@ -19,7 +19,7 @@
|
||||
# 02110-1301 USA
|
||||
#
|
||||
|
||||
FILTERS = telecine tile rectangle framestep ildetect
|
||||
FILTERS = showqscale telecine tile rectangle framestep ildetect
|
||||
COMMON = filterutils.o
|
||||
|
||||
OBJECTS = $(patsubst %,%.o,$(FILTERS)) $(COMMON)
|
||||
|
||||
@@ -90,7 +90,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
|
||||
if (argc != 1 && argc != 2)
|
||||
return -1;
|
||||
|
||||
framestep_data_t *framestep = calloc(1,sizeof(framestep_data_t));
|
||||
framestep_data_t *framestep = malloc(sizeof(framestep_data_t));
|
||||
memset(framestep, 0, sizeof(*framestep));
|
||||
|
||||
framestep->step = atoi(argv[0]);
|
||||
framestep->pos = (argc >= 2) ? atoi(argv[1]) : 0;
|
||||
|
||||
@@ -267,7 +267,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
ildetect_data_t *il = calloc(1,sizeof(ildetect_data_t));
|
||||
ildetect_data_t *il = malloc(sizeof(ildetect_data_t));
|
||||
memset(il, 0, sizeof(*il));
|
||||
|
||||
#define A(i,d) ((argc>(i) && *argv[i]) ? atof(argv[i]) : (d))
|
||||
il->method = A(0, 0);
|
||||
|
||||
@@ -11,6 +11,7 @@ esac
|
||||
|
||||
: ${MPV:=mpv}
|
||||
: ${ILDETECT_MPV:=$MPV}
|
||||
: ${ILDETECT_MPV:=$MPV}
|
||||
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
|
||||
: ${ILDETECT_DRY_RUN:=}
|
||||
: ${ILDETECT_QUIET:=}
|
||||
|
||||
@@ -348,7 +348,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
|
||||
{ "yuv420p", "yuv420p" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
privdata *priv = calloc(1,sizeof(privdata));
|
||||
privdata *priv = malloc(sizeof(privdata));
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
priv->step = 8;
|
||||
if(argc >= 1)
|
||||
priv->w = atoi(argv[0]);
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
|
||||
*
|
||||
* This file is part of mpv's vf_dlopen examples.
|
||||
*
|
||||
* mpv's vf_dlopen examples are free software; you can redistribute them and/or
|
||||
* modify them 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's vf_dlopen examples are distributed in the hope that they 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's vf_dlopen examples; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vf_dlopen.h"
|
||||
|
||||
/*
|
||||
* qscale visualizer
|
||||
*
|
||||
* usage: --vf=dlopen=/path/to/showqscale.so
|
||||
*
|
||||
* uses reddish colors for high QPs, and greenish colors for low QPs
|
||||
*/
|
||||
|
||||
#define PLANE_Y 0
|
||||
#define PLANE_U 1
|
||||
#define PLANE_V 2
|
||||
|
||||
static int qs_put_image(struct vf_dlopen_context *ctx)
|
||||
{
|
||||
unsigned int x, y, p;
|
||||
|
||||
assert(ctx->inpic.planes == ctx->outpic[0].planes);
|
||||
|
||||
for (p = 0; p < ctx->outpic[0].planes; ++p) {
|
||||
assert(ctx->inpic.planewidth[p] == ctx->outpic[0].planewidth[p]);
|
||||
assert(ctx->inpic.planeheight[p] == ctx->outpic[0].planeheight[p]);
|
||||
if ((p == PLANE_U || p == PLANE_V) && ctx->inpic_qscale)
|
||||
continue;
|
||||
#if 0
|
||||
// copy as is
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
memcpy(
|
||||
&ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y],
|
||||
&inpic[ctx->outpic[0].planeofs[p] + ctx->inpic.planestride[p] * y],
|
||||
ctx->outpic[0].planewidth[p]
|
||||
);
|
||||
#else
|
||||
// reduce contrast
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
for (x = 0; x < ctx->outpic[0].planewidth[p]; ++x)
|
||||
ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y + x] =
|
||||
0x20 + ((ctx->inpic.plane[p][ctx->inpic.planestride[p] * y + x] * 3) >> 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ctx->inpic_qscale) {
|
||||
int qmin = 255;
|
||||
int qmax = -255;
|
||||
|
||||
// clear U plane
|
||||
p = PLANE_U;
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
memset(
|
||||
&ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y],
|
||||
0x80,
|
||||
ctx->outpic[0].planewidth[p]
|
||||
);
|
||||
|
||||
// replace V by the qp (0 = green, 12 = red)
|
||||
p = PLANE_V;
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
for (x = 0; x < ctx->outpic[0].planewidth[p]; ++x) {
|
||||
int q = ctx->inpic_qscale[
|
||||
(x >> (ctx->inpic_qscaleshift - ctx->inpic.planexshift[p])) +
|
||||
(y >> (ctx->inpic_qscaleshift - ctx->inpic.planeyshift[p])) * ctx->inpic_qscalestride];
|
||||
if (q < qmin)
|
||||
qmin = q;
|
||||
if (q > qmax)
|
||||
qmax = q;
|
||||
int v = 128 + 21 * (q - 6); // range: 0 = green, 12 = red
|
||||
if (v < 0)
|
||||
v = 0;
|
||||
if (v > 255)
|
||||
v = 255;
|
||||
ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y + x] = v;
|
||||
}
|
||||
|
||||
// printf("qscale range: %d .. %d\n", qmin, qmax);
|
||||
}
|
||||
|
||||
ctx->outpic[0].pts = ctx->inpic.pts;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **argv)
|
||||
{
|
||||
VF_DLOPEN_CHECK_VERSION(ctx);
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
static struct vf_dlopen_formatpair map[] = {
|
||||
{ "yuv420p", "yuv420p" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ctx->format_mapping = map;
|
||||
ctx->put_image = qs_put_image;
|
||||
return 1;
|
||||
}
|
||||
@@ -237,7 +237,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
|
||||
if (!a0[0] || a0[1] || !a1[0] || argc > 2)
|
||||
return -1;
|
||||
|
||||
tc_data_t *tc = calloc(1,sizeof(tc_data_t));
|
||||
tc_data_t *tc = malloc(sizeof(tc_data_t));
|
||||
memset(tc, 0, sizeof(*tc));
|
||||
|
||||
if (a0[0] == 't')
|
||||
tc->firstfield = 0;
|
||||
|
||||
@@ -150,7 +150,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
|
||||
if (argc != 2)
|
||||
return -1;
|
||||
|
||||
tile_data_t *tile = calloc(1,sizeof(tile_data_t));
|
||||
tile_data_t *tile = malloc(sizeof(tile_data_t));
|
||||
memset(tile, 0, sizeof(*tile));
|
||||
|
||||
tile->cols = atoi(argv[0]);
|
||||
tile->rows = atoi(argv[1]);
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
# Example of script for using mpv with youtube-dl
|
||||
set -e
|
||||
|
||||
cookies_dir="$(mktemp -d /tmp/youtube-dl_mpv.XXXX)"
|
||||
cookies_file="${cookies_dir}/cookies"
|
||||
user_agent="$(youtube-dl --dump-user-agent)" # or set whatever you want
|
||||
|
||||
video_url="$(youtube-dl \
|
||||
--user-agent="$user_agent" \
|
||||
--cookies="$cookies_file" \
|
||||
--get-url \
|
||||
"$1")"
|
||||
|
||||
shift
|
||||
|
||||
mpv \
|
||||
--cookies \
|
||||
--cookies-file="$cookies_file" \
|
||||
--user-agent="$user_agent" \
|
||||
"$@" -- $video_url
|
||||
|
||||
rm -rf "$cookies_dir"
|
||||
+72
-189
@@ -4,23 +4,18 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use warnings FATAL => 'uninitialized';
|
||||
|
||||
my $mpv = $ARGV[0] || 'mpv';
|
||||
|
||||
my @opts = parse_main_opts('--list-options', '^ (\-\-[^\s\*]*)\*?\s*(.*)');
|
||||
my @opts = parse_opts("$mpv --list-options", '^ (\-\-[^\s\*]*)\*?\s*(.*)', 1);
|
||||
|
||||
die "Couldn't find any options" unless (@opts);
|
||||
my @ao = parse_opts("$mpv --ao=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @vo = parse_opts("$mpv --vo=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
|
||||
my @ao = parse_opts('--ao=help', '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @vo = parse_opts('--vo=help', '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @af = parse_opts("$mpv --af=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @vf = parse_opts("$mpv --vf=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
|
||||
my @af = parse_opts('--af=help', '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @vf = parse_opts('--vf=help', '^ ([^\s\:]*)\s*: (.*)');
|
||||
|
||||
my @protos = parse_opts('--list-protocols', '^ ([^\s]*)');
|
||||
|
||||
my ($opts_str, $ao_str, $vo_str, $af_str, $vf_str, $protos_str);
|
||||
my ($opts_str, $ao_str, $vo_str, $af_str, $vf_str);
|
||||
|
||||
$opts_str .= qq{ '$_' \\\n} foreach (@opts);
|
||||
chomp $opts_str;
|
||||
@@ -37,227 +32,115 @@ chomp $af_str;
|
||||
$vf_str .= qq{ '$_' \\\n} foreach (@vf);
|
||||
chomp $vf_str;
|
||||
|
||||
$protos_str = join(' ', @protos);
|
||||
|
||||
my $runtime_completions = <<'EOS';
|
||||
profile|show-profile)
|
||||
local -a profiles
|
||||
local current
|
||||
for current in "${(@f)$($words[1] --profile=help)}"; do
|
||||
current=${current//\*/\\\*}
|
||||
current=${current//\:/\\\:}
|
||||
current=${current//\[/\\\[}
|
||||
current=${current//\]/\\\]}
|
||||
if [[ $current =~ $'\t'([^$'\t']*)$'\t'(.*) ]]; then
|
||||
if [[ -n $match[2] ]]; then
|
||||
current="$match[1][$match[2]]"
|
||||
else
|
||||
current="$match[1]"
|
||||
fi
|
||||
profiles=($profiles $current)
|
||||
fi
|
||||
done
|
||||
if [[ $state == show-profile ]]; then
|
||||
# For --show-profile, only one allowed
|
||||
if (( ${#profiles} > 0 )); then
|
||||
_values 'profile' $profiles && rc=0
|
||||
fi
|
||||
else
|
||||
# For --profile, multiple allowed
|
||||
profiles=($profiles 'help[list profiles]')
|
||||
_values -s , 'profile(s)' $profiles && rc=0
|
||||
fi
|
||||
;;
|
||||
|
||||
audio-device)
|
||||
local -a audio_devices
|
||||
local current
|
||||
for current in "${(@f)$($words[1] --audio-device=help)}"; do
|
||||
current=${current//\*/\\\*}
|
||||
current=${current//\:/\\\:}
|
||||
current=${current//\[/\\\[}
|
||||
current=${current//\]/\\\]}
|
||||
if [[ $current =~ ' '\'([^\']*)\'' \('(.*)'\)' ]]; then
|
||||
audio_devices=($audio_devices "$match[1][$match[2]]")
|
||||
fi
|
||||
done
|
||||
audio_devices=($audio_devices 'help[list audio devices]')
|
||||
_values 'audio device' $audio_devices && rc=0
|
||||
;;
|
||||
EOS
|
||||
chomp $runtime_completions;
|
||||
|
||||
my $tmpl = <<"EOS";
|
||||
#compdef mpv
|
||||
|
||||
# For customization, see:
|
||||
# https://github.com/mpv-player/mpv/wiki/Zsh-completion-customization
|
||||
# mpv zsh completion
|
||||
|
||||
local curcontext="\$curcontext" state state_descr line
|
||||
typeset -A opt_args
|
||||
|
||||
# By default, don't complete URLs unless no files match
|
||||
local -a tag_order
|
||||
zstyle -a ":completion:*:*:\$service:*" tag-order tag_order || \
|
||||
zstyle ":completion:*:*:\$service:*" tag-order '!urls'
|
||||
|
||||
local rc=1
|
||||
|
||||
_arguments -C -S \\
|
||||
_x_arguments -C -s \\
|
||||
$opts_str
|
||||
'*:files:->mfiles' && rc=0
|
||||
'*:files:->mfiles'
|
||||
|
||||
case \$state in
|
||||
ao)
|
||||
_values -s , 'audio outputs' \\
|
||||
local -a values
|
||||
values=(
|
||||
$ao_str
|
||||
&& rc=0
|
||||
)
|
||||
|
||||
_describe -t values 'audio outputs' values
|
||||
;;
|
||||
|
||||
vo)
|
||||
_values -s , 'video outputs' \\
|
||||
local -a values
|
||||
values=(
|
||||
$vo_str
|
||||
&& rc=0
|
||||
)
|
||||
|
||||
_describe -t values 'video outputs' values
|
||||
;;
|
||||
|
||||
af)
|
||||
_values -s , 'audio filters' \\
|
||||
local -a values
|
||||
values=(
|
||||
$af_str
|
||||
&& rc=0
|
||||
)
|
||||
|
||||
_describe -t values 'audio filters' values
|
||||
;;
|
||||
|
||||
vf)
|
||||
_values -s , 'video filters' \\
|
||||
local -a values
|
||||
values=(
|
||||
$vf_str
|
||||
&& rc=0
|
||||
;;
|
||||
)
|
||||
|
||||
$runtime_completions
|
||||
|
||||
files)
|
||||
compset -P '*,'
|
||||
compset -S ',*'
|
||||
_files -r ',/ \\t\\n\\-' && rc=0
|
||||
_describe -t values 'video filters' values
|
||||
;;
|
||||
|
||||
mfiles)
|
||||
local expl
|
||||
_tags files urls
|
||||
while _tags; do
|
||||
_requested files expl 'media file' _files && rc=0
|
||||
_requested files expl 'media file' _files -g \\
|
||||
"*.(#i)(asf|asx|avi|flac|flv|m1v|m2p|m2v|m4v|mjpg|mka|mkv|mov|mp3|mp4|mpe|mpeg|mpg|ogg|ogm|ogv|qt|rm|ts|vob|wav|webm|wma|wmv)(-.)" && ret=0
|
||||
if _requested urls; then
|
||||
while _next_label urls expl URL; do
|
||||
_urls "\$expl[@]" && rc=0
|
||||
compadd -S '' "\$expl[@]" $protos_str && rc=0
|
||||
_urls "\$expl[@]" && ret=0
|
||||
compadd -S '' "\$expl[@]" \{dvd,vcd,cdda,cddb,tv\}:// && ret=0
|
||||
done
|
||||
fi
|
||||
(( rc )) || return 0
|
||||
(( ret )) || return 0
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
return rc
|
||||
EOS
|
||||
|
||||
print $tmpl;
|
||||
|
||||
sub parse_main_opts {
|
||||
my ($cmd, $regex) = @_;
|
||||
|
||||
my @list;
|
||||
my @lines = call_mpv($cmd);
|
||||
|
||||
foreach my $line (@lines) {
|
||||
my ($name, $desc) = ($line =~ /^$regex/) or next;
|
||||
|
||||
next if ($desc eq 'removed' || $desc eq 'alias');
|
||||
|
||||
if ($desc =~ /^Flag/) {
|
||||
|
||||
push @list, $name;
|
||||
|
||||
$name =~ /^--(.*)/;
|
||||
if ($1 !~ /^(\{|\}|v|list-options|really-quiet|no-.*)$/) {
|
||||
push @list, "--no-$1";
|
||||
}
|
||||
|
||||
} elsif ($desc =~ /^Print/) {
|
||||
|
||||
push @list, $name;
|
||||
|
||||
} else {
|
||||
|
||||
# Option takes argument
|
||||
|
||||
my $entry = $name;
|
||||
|
||||
$desc =~ s/\:/\\:/g;
|
||||
$entry .= "=-:$desc:";
|
||||
|
||||
if ($desc =~ /^Choices\\: ([^(]*)/) {
|
||||
my $choices = $1;
|
||||
$choices =~ s/ +$//; # strip trailing space
|
||||
$entry .= "($choices)";
|
||||
|
||||
# If "no" is one of the choices, it can also be
|
||||
# negated like a flag (--no-whatever).
|
||||
if ($choices =~ /\bno\b/) {
|
||||
$name =~ s/^--/--no-/;
|
||||
push @list, $name;
|
||||
}
|
||||
} elsif ($line =~ /\[file\]/) {
|
||||
$entry .= '->files';
|
||||
} elsif ($name =~ /^--(ao|vo|af|vf|profile|show-profile|audio-device)$/) {
|
||||
$entry .= "->$1";
|
||||
}
|
||||
push @list, $entry;
|
||||
}
|
||||
}
|
||||
|
||||
# Sort longest first, because zsh won't complete an option listed
|
||||
# after one that's a prefix of it.
|
||||
@list = sort {
|
||||
$a =~ /([^=]*)/; my $ma = $1;
|
||||
$b =~ /([^=]*)/; my $mb = $1;
|
||||
|
||||
length($mb) <=> length($ma)
|
||||
} @list;
|
||||
|
||||
return @list;
|
||||
}
|
||||
|
||||
sub parse_opts {
|
||||
my ($cmd, $regex) = @_;
|
||||
my ($cmd, $regex, $parsing_main_options) = @_;
|
||||
|
||||
my @list;
|
||||
my @lines = call_mpv($cmd);
|
||||
my @list;
|
||||
my @lines = split /\n/, `$cmd`;
|
||||
|
||||
foreach my $line (@lines) {
|
||||
if ($line !~ /^$regex/) {
|
||||
next;
|
||||
}
|
||||
foreach my $line (@lines) {
|
||||
if ($line !~ /^$regex/) {
|
||||
next;
|
||||
}
|
||||
|
||||
my $entry = $1;
|
||||
my $entry = $1;
|
||||
|
||||
if (defined $2) {
|
||||
my $desc = $2;
|
||||
$desc =~ s/\:/\\:/g;
|
||||
$entry .= "[$desc]";
|
||||
}
|
||||
if ($parsing_main_options) {
|
||||
$entry .= '=-';
|
||||
}
|
||||
|
||||
push @list, $entry
|
||||
}
|
||||
if (defined $2) {
|
||||
my $desc = $2;
|
||||
$desc =~ s/\:/\\:/g;
|
||||
|
||||
return @list;
|
||||
}
|
||||
|
||||
sub call_mpv {
|
||||
my ($cmd) = @_;
|
||||
my $output = `"$mpv" --no-config $cmd`;
|
||||
if ($? == -1) {
|
||||
die "Could not run mpv: $!";
|
||||
} elsif ((my $exit_code = $? >> 8) != 0) {
|
||||
die "mpv returned $exit_code with output:\n$output";
|
||||
}
|
||||
return split /\n/, $output;
|
||||
$entry .= ':' . $desc;
|
||||
}
|
||||
|
||||
if ($parsing_main_options) {
|
||||
$entry .= ':';
|
||||
|
||||
$entry .= '->ao' if ($1 eq '--ao');
|
||||
$entry .= '->vo' if ($1 eq '--vo');
|
||||
$entry .= '->af' if ($1 eq '--af');
|
||||
$entry .= '->vf' if ($1 eq '--vf');
|
||||
}
|
||||
|
||||
push @list, $entry
|
||||
}
|
||||
|
||||
if ($parsing_main_options) {
|
||||
@list = sort {
|
||||
$a =~ /(.*?)\:/; my $ma = $1;
|
||||
$b =~ /(.*?)\:/; my $mb = $1;
|
||||
|
||||
length($mb) <=> length($ma)
|
||||
} @list;
|
||||
}
|
||||
|
||||
return @list;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- appveyor
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- MSYSTEM: MINGW64
|
||||
- MSYSTEM: MINGW32
|
||||
|
||||
shallow_clone: true
|
||||
test: off
|
||||
|
||||
install:
|
||||
# Update core packages
|
||||
- C:\msys64\usr\bin\pacman -Syyuu --noconfirm
|
||||
# Update non-core packages
|
||||
- C:\msys64\usr\bin\pacman -Suu --noconfirm
|
||||
# Install required MSYS2 packages
|
||||
- C:\msys64\usr\bin\pacman -S --noconfirm --needed 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 \"$APPVEYOR_BUILD_FOLDER\" && exec ./TOOLS/appveyor-install.sh"
|
||||
build_script:
|
||||
- C:\msys64\usr\bin\bash -lc "cd \"$APPVEYOR_BUILD_FOLDER\" && exec ./TOOLS/appveyor-build.sh"
|
||||
on_failure:
|
||||
- type "%APPVEYOR_BUILD_FOLDER%\build\config.log"
|
||||
|
||||
cache:
|
||||
- C:\msys64\var\cache\pacman\pkg
|
||||
+45
-372
@@ -20,14 +20,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/buffer.h>
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/mem.h>
|
||||
#include <libavutil/version.h>
|
||||
|
||||
#include "mpv_talloc.h"
|
||||
#include "talloc.h"
|
||||
#include "common/common.h"
|
||||
#include "fmt-conversion.h"
|
||||
#include "audio.h"
|
||||
|
||||
static void update_redundant_info(struct mp_audio *mpa)
|
||||
@@ -35,7 +31,7 @@ static void update_redundant_info(struct mp_audio *mpa)
|
||||
assert(mp_chmap_is_empty(&mpa->channels) ||
|
||||
mp_chmap_is_valid(&mpa->channels));
|
||||
mpa->nch = mpa->channels.num;
|
||||
mpa->bps = af_fmt_to_bytes(mpa->format);
|
||||
mpa->bps = af_fmt2bps(mpa->format);
|
||||
if (af_fmt_is_planar(mpa->format)) {
|
||||
mpa->spf = 1;
|
||||
mpa->num_planes = mpa->nch;
|
||||
@@ -59,6 +55,13 @@ void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels)
|
||||
update_redundant_info(mpa);
|
||||
}
|
||||
|
||||
// Use old MPlayer/ALSA channel layout.
|
||||
void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels)
|
||||
{
|
||||
mp_chmap_from_channels_alsa(&mpa->channels, num_channels);
|
||||
update_redundant_info(mpa);
|
||||
}
|
||||
|
||||
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap)
|
||||
{
|
||||
mpa->channels = *chmap;
|
||||
@@ -85,16 +88,18 @@ bool mp_audio_config_valid(const struct mp_audio *mpa)
|
||||
&& mpa->rate >= 1 && mpa->rate < 10000000;
|
||||
}
|
||||
|
||||
char *mp_audio_config_to_str_buf(char *buf, size_t buf_sz, struct mp_audio *mpa)
|
||||
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format)
|
||||
{
|
||||
char ch[128];
|
||||
mp_chmap_to_str_buf(ch, sizeof(ch), &mpa->channels);
|
||||
char *hr_ch = mp_chmap_to_str_hr(&mpa->channels);
|
||||
if (strcmp(hr_ch, ch) != 0)
|
||||
mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch);
|
||||
snprintf(buf, buf_sz, "%dHz %s %dch %s", mpa->rate,
|
||||
ch, mpa->channels.num, af_fmt_to_str(mpa->format));
|
||||
return buf;
|
||||
char *chstr = mp_chmap_to_str(chmap);
|
||||
char *res = talloc_asprintf(NULL, "%dHz %s %dch %s", srate, chstr,
|
||||
chmap->num, af_fmt_to_str(format));
|
||||
talloc_free(chstr);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *mp_audio_config_to_str(struct mp_audio *mpa)
|
||||
{
|
||||
return mp_audio_fmt_to_str(mpa->rate, &mpa->channels, mpa->format);
|
||||
}
|
||||
|
||||
void mp_audio_force_interleaved_format(struct mp_audio *mpa)
|
||||
@@ -111,36 +116,25 @@ int mp_audio_psize(struct mp_audio *mpa)
|
||||
|
||||
void mp_audio_set_null_data(struct mp_audio *mpa)
|
||||
{
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
mpa->planes[n] = NULL;
|
||||
mpa->allocated[n] = NULL;
|
||||
}
|
||||
mpa->samples = 0;
|
||||
}
|
||||
|
||||
static int get_plane_size(const struct mp_audio *mpa, int samples)
|
||||
{
|
||||
if (samples < 0 || !mp_audio_config_valid(mpa))
|
||||
return -1;
|
||||
if (samples >= INT_MAX / mpa->sstride)
|
||||
return -1;
|
||||
return MPMAX(samples * mpa->sstride, 1);
|
||||
}
|
||||
|
||||
static void mp_audio_destructor(void *ptr)
|
||||
{
|
||||
struct mp_audio *mpa = ptr;
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
av_buffer_unref(&mpa->allocated[n]);
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
// Note: don't free if not allocated by mp_audio_realloc
|
||||
if (mpa->allocated[n])
|
||||
av_free(mpa->planes[n]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reallocate the data stored in mpa->planes[n] so that enough samples are
|
||||
* available on every plane. The previous data is kept (for the smallest
|
||||
* common number of samples before/after resize).
|
||||
*
|
||||
* This also makes sure the resulting buffer is writable (even in the case
|
||||
* the buffer has the correct size).
|
||||
*
|
||||
* mpa->samples is not set or used.
|
||||
*
|
||||
* This function is flexible enough to handle format and channel layout
|
||||
@@ -153,25 +147,27 @@ static void mp_audio_destructor(void *ptr)
|
||||
*/
|
||||
void mp_audio_realloc(struct mp_audio *mpa, int samples)
|
||||
{
|
||||
int size = get_plane_size(mpa, samples);
|
||||
if (size < 0)
|
||||
abort(); // oom or invalid parameters
|
||||
if (!mp_audio_is_writeable(mpa)) {
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
av_buffer_unref(&mpa->allocated[n]);
|
||||
mpa->planes[n] = NULL;
|
||||
}
|
||||
}
|
||||
assert(samples >= 0);
|
||||
if (samples >= INT_MAX / mpa->sstride)
|
||||
abort(); // oom
|
||||
int size = MPMAX(samples * mpa->sstride, 1);
|
||||
for (int n = 0; n < mpa->num_planes; n++) {
|
||||
if (!mpa->allocated[n] || size != mpa->allocated[n]->size) {
|
||||
if (av_buffer_realloc(&mpa->allocated[n], size) < 0)
|
||||
abort(); // OOM
|
||||
if (size != mpa->allocated[n]) {
|
||||
// Note: av_realloc() can't be used (see libavutil doxygen)
|
||||
void *new = av_malloc(size);
|
||||
if (!new)
|
||||
abort();
|
||||
if (mpa->allocated[n])
|
||||
memcpy(new, mpa->planes[n], MPMIN(mpa->allocated[n], size));
|
||||
av_free(mpa->planes[n]);
|
||||
mpa->planes[n] = new;
|
||||
mpa->allocated[n] = size;
|
||||
}
|
||||
mpa->planes[n] = mpa->allocated[n]->data;
|
||||
}
|
||||
for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) {
|
||||
av_buffer_unref(&mpa->allocated[n]);
|
||||
av_free(mpa->planes[n]);
|
||||
mpa->planes[n] = NULL;
|
||||
mpa->allocated[n] = 0;
|
||||
}
|
||||
talloc_set_destructor(mpa, mp_audio_destructor);
|
||||
}
|
||||
@@ -180,7 +176,7 @@ void mp_audio_realloc(struct mp_audio *mpa, int samples)
|
||||
// If the buffer is reallocated, also preallocate.
|
||||
void mp_audio_realloc_min(struct mp_audio *mpa, int samples)
|
||||
{
|
||||
if (samples > mp_audio_get_allocated_size(mpa) || !mp_audio_is_writeable(mpa)) {
|
||||
if (samples > mp_audio_get_allocated_size(mpa)) {
|
||||
size_t alloc = ta_calc_prealloc_elems(samples);
|
||||
if (alloc > INT_MAX)
|
||||
abort(); // oom
|
||||
@@ -198,18 +194,8 @@ int mp_audio_get_allocated_size(struct mp_audio *mpa)
|
||||
{
|
||||
int size = 0;
|
||||
for (int n = 0; n < mpa->num_planes; n++) {
|
||||
for (int i = 0; i < MP_NUM_CHANNELS && mpa->allocated[i]; i++) {
|
||||
uint8_t *start = mpa->allocated[i]->data;
|
||||
uint8_t *end = start + mpa->allocated[i]->size;
|
||||
uint8_t *plane = mpa->planes[n];
|
||||
if (plane >= start && plane < end) {
|
||||
int s = MPMIN((end - plane) / mpa->sstride, INT_MAX);
|
||||
size = n == 0 ? s : MPMIN(size, s);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
return 0; // plane is not covered by any buffer
|
||||
next: ;
|
||||
int s = mpa->allocated[n] / mpa->sstride;
|
||||
size = n == 0 ? s : MPMIN(size, s);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -244,14 +230,6 @@ void mp_audio_copy(struct mp_audio *dst, int dst_offset,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy fields that describe characteristics of the audio frame, but which are
|
||||
// not part of the core format (format/channels/rate), and not part of the
|
||||
// data (samples).
|
||||
void mp_audio_copy_attributes(struct mp_audio *dst, struct mp_audio *src)
|
||||
{
|
||||
// nothing yet
|
||||
}
|
||||
|
||||
// Set data to the audio after the given number of samples (i.e. slice it).
|
||||
void mp_audio_skip_samples(struct mp_audio *data, int samples)
|
||||
{
|
||||
@@ -261,309 +239,4 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
|
||||
data->planes[n] = (uint8_t *)data->planes[n] + samples * data->sstride;
|
||||
|
||||
data->samples -= samples;
|
||||
|
||||
if (data->pts != MP_NOPTS_VALUE)
|
||||
data->pts += samples / (double)data->rate;
|
||||
}
|
||||
|
||||
// Return the timestamp of the sample just after the end of this frame.
|
||||
double mp_audio_end_pts(struct mp_audio *f)
|
||||
{
|
||||
if (f->pts == MP_NOPTS_VALUE || f->rate < 1)
|
||||
return MP_NOPTS_VALUE;
|
||||
return f->pts + f->samples / (double)f->rate;
|
||||
}
|
||||
|
||||
// Clip the given frame to the given timestamp range. Adjusts the frame size
|
||||
// and timestamp.
|
||||
void mp_audio_clip_timestamps(struct mp_audio *f, double start, double end)
|
||||
{
|
||||
double f_end = mp_audio_end_pts(f);
|
||||
if (f_end == MP_NOPTS_VALUE)
|
||||
return;
|
||||
if (end != MP_NOPTS_VALUE) {
|
||||
if (f_end >= end) {
|
||||
if (f->pts >= end) {
|
||||
f->samples = 0;
|
||||
} else {
|
||||
int new = (end - f->pts) * f->rate;
|
||||
f->samples = MPCLAMP(new, 0, f->samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (start != MP_NOPTS_VALUE) {
|
||||
if (f->pts < start) {
|
||||
if (f_end <= start) {
|
||||
f->samples = 0;
|
||||
f->pts = f_end;
|
||||
} else {
|
||||
int skip = (start - f->pts) * f->rate;
|
||||
skip = MPCLAMP(skip, 0, f->samples);
|
||||
mp_audio_skip_samples(f, skip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return false if the frame data is shared, true otherwise.
|
||||
// Will return true for non-refcounted frames.
|
||||
bool mp_audio_is_writeable(struct mp_audio *data)
|
||||
{
|
||||
bool ok = true;
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
if (data->allocated[n])
|
||||
ok &= av_buffer_is_writable(data->allocated[n]);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void mp_audio_steal_data(struct mp_audio *dst, struct mp_audio *src)
|
||||
{
|
||||
talloc_set_destructor(dst, mp_audio_destructor);
|
||||
mp_audio_destructor(dst);
|
||||
*dst = *src;
|
||||
talloc_set_destructor(src, NULL);
|
||||
talloc_free(src);
|
||||
}
|
||||
|
||||
// Make sure the frame owns the audio data, and if not, copy the data.
|
||||
// Return negative value on failure (which means it can't be made writeable).
|
||||
// Non-refcounted frames are always considered writeable.
|
||||
int mp_audio_make_writeable(struct mp_audio *data)
|
||||
{
|
||||
if (!mp_audio_is_writeable(data)) {
|
||||
struct mp_audio *new = talloc(NULL, struct mp_audio);
|
||||
*new = *data;
|
||||
mp_audio_set_null_data(new); // use format only
|
||||
mp_audio_realloc(new, data->samples);
|
||||
new->samples = data->samples;
|
||||
mp_audio_copy(new, 0, data, 0, data->samples);
|
||||
mp_audio_steal_data(data, new);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe)
|
||||
{
|
||||
AVFrame *tmp = NULL;
|
||||
struct mp_audio *new = talloc_zero(NULL, struct mp_audio);
|
||||
talloc_set_destructor(new, mp_audio_destructor);
|
||||
|
||||
mp_audio_set_format(new, af_from_avformat(avframe->format));
|
||||
|
||||
struct mp_chmap lavc_chmap;
|
||||
mp_chmap_from_lavc(&lavc_chmap, avframe->channel_layout);
|
||||
|
||||
#if LIBAVUTIL_VERSION_MICRO >= 100
|
||||
// FFmpeg being stupid POS again
|
||||
if (lavc_chmap.num != av_frame_get_channels(avframe))
|
||||
mp_chmap_from_channels(&lavc_chmap, av_frame_get_channels(avframe));
|
||||
#endif
|
||||
|
||||
new->rate = avframe->sample_rate;
|
||||
|
||||
mp_audio_set_channels(new, &lavc_chmap);
|
||||
|
||||
// Force refcounted frame.
|
||||
if (!avframe->buf[0]) {
|
||||
tmp = av_frame_alloc();
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
if (av_frame_ref(tmp, avframe) < 0)
|
||||
goto fail;
|
||||
avframe = tmp;
|
||||
}
|
||||
|
||||
// If we can't handle the format (e.g. too many channels), bail out.
|
||||
if (!mp_audio_config_valid(new))
|
||||
goto fail;
|
||||
|
||||
for (int n = 0; n < AV_NUM_DATA_POINTERS + avframe->nb_extended_buf; n++) {
|
||||
AVBufferRef *buf = n < AV_NUM_DATA_POINTERS ? avframe->buf[n]
|
||||
: avframe->extended_buf[n - AV_NUM_DATA_POINTERS];
|
||||
if (!buf)
|
||||
break;
|
||||
if (n >= MP_NUM_CHANNELS)
|
||||
goto fail;
|
||||
new->allocated[n] = av_buffer_ref(buf);
|
||||
if (!new->allocated[n])
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (int n = 0; n < new->num_planes; n++)
|
||||
new->planes[n] = avframe->extended_data[n];
|
||||
new->samples = avframe->nb_samples;
|
||||
|
||||
return new;
|
||||
|
||||
fail:
|
||||
talloc_free(new);
|
||||
av_frame_free(&tmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mp_audio_to_avframe(struct mp_audio *frame, struct AVFrame *avframe)
|
||||
{
|
||||
av_frame_unref(avframe);
|
||||
|
||||
avframe->nb_samples = frame->samples;
|
||||
avframe->format = af_to_avformat(frame->format);
|
||||
if (avframe->format == AV_SAMPLE_FMT_NONE)
|
||||
goto fail;
|
||||
|
||||
avframe->channel_layout = mp_chmap_to_lavc(&frame->channels);
|
||||
if (!avframe->channel_layout)
|
||||
goto fail;
|
||||
#if LIBAVUTIL_VERSION_MICRO >= 100
|
||||
// FFmpeg being a stupid POS again
|
||||
av_frame_set_channels(avframe, frame->channels.num);
|
||||
#endif
|
||||
avframe->sample_rate = frame->rate;
|
||||
|
||||
if (frame->num_planes > AV_NUM_DATA_POINTERS) {
|
||||
avframe->extended_data =
|
||||
av_mallocz_array(frame->num_planes, sizeof(avframe->extended_data[0]));
|
||||
int extbufs = frame->num_planes - AV_NUM_DATA_POINTERS;
|
||||
avframe->extended_buf =
|
||||
av_mallocz_array(extbufs, sizeof(avframe->extended_buf[0]));
|
||||
if (!avframe->extended_data || !avframe->extended_buf)
|
||||
goto fail;
|
||||
avframe->nb_extended_buf = extbufs;
|
||||
}
|
||||
|
||||
for (int p = 0; p < frame->num_planes; p++)
|
||||
avframe->extended_data[p] = frame->planes[p];
|
||||
avframe->linesize[0] = frame->samples * frame->sstride;
|
||||
|
||||
for (int p = 0; p < AV_NUM_DATA_POINTERS; p++)
|
||||
avframe->data[p] = avframe->extended_data[p];
|
||||
|
||||
for (int p = 0; p < frame->num_planes; p++) {
|
||||
if (!frame->allocated[p])
|
||||
break;
|
||||
AVBufferRef *nref = av_buffer_ref(frame->allocated[p]);
|
||||
if (!nref)
|
||||
goto fail;
|
||||
if (p < AV_NUM_DATA_POINTERS) {
|
||||
avframe->buf[p] = nref;
|
||||
} else {
|
||||
avframe->extended_buf[p - AV_NUM_DATA_POINTERS] = nref;
|
||||
}
|
||||
}
|
||||
|
||||
// Force refcounted frame.
|
||||
if (!avframe->buf[0]) {
|
||||
AVFrame *tmp = av_frame_alloc();
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
if (av_frame_ref(tmp, avframe) < 0)
|
||||
goto fail;
|
||||
av_frame_free(&avframe);
|
||||
avframe = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
av_frame_unref(avframe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns NULL on failure. The input is always unreffed.
|
||||
struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame)
|
||||
{
|
||||
struct AVFrame *avframe = av_frame_alloc();
|
||||
if (!avframe)
|
||||
goto fail;
|
||||
|
||||
if (mp_audio_to_avframe(frame, avframe) < 0)
|
||||
goto fail;
|
||||
|
||||
talloc_free(frame);
|
||||
return avframe;
|
||||
|
||||
fail:
|
||||
av_frame_free(&avframe);
|
||||
talloc_free(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mp_audio_pool {
|
||||
AVBufferPool *avpool;
|
||||
int element_size;
|
||||
};
|
||||
|
||||
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent)
|
||||
{
|
||||
return talloc_zero(ta_parent, struct mp_audio_pool);
|
||||
}
|
||||
|
||||
static void mp_audio_pool_destructor(void *p)
|
||||
{
|
||||
struct mp_audio_pool *pool = p;
|
||||
av_buffer_pool_uninit(&pool->avpool);
|
||||
}
|
||||
|
||||
// Allocate data using the given format and number of samples.
|
||||
// Returns NULL on error.
|
||||
struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
|
||||
const struct mp_audio *fmt, int samples)
|
||||
{
|
||||
int size = get_plane_size(fmt, samples);
|
||||
if (size < 0)
|
||||
return NULL;
|
||||
if (!pool->avpool || size > pool->element_size) {
|
||||
size_t alloc = ta_calc_prealloc_elems(size);
|
||||
if (alloc >= INT_MAX)
|
||||
return NULL;
|
||||
av_buffer_pool_uninit(&pool->avpool);
|
||||
pool->element_size = alloc;
|
||||
pool->avpool = av_buffer_pool_init(pool->element_size, NULL);
|
||||
if (!pool->avpool)
|
||||
return NULL;
|
||||
talloc_set_destructor(pool, mp_audio_pool_destructor);
|
||||
}
|
||||
struct mp_audio *new = talloc_ptrtype(NULL, new);
|
||||
talloc_set_destructor(new, mp_audio_destructor);
|
||||
*new = *fmt;
|
||||
mp_audio_set_null_data(new);
|
||||
new->samples = samples;
|
||||
for (int n = 0; n < new->num_planes; n++) {
|
||||
new->allocated[n] = av_buffer_pool_get(pool->avpool);
|
||||
if (!new->allocated[n]) {
|
||||
talloc_free(new);
|
||||
return NULL;
|
||||
}
|
||||
new->planes[n] = new->allocated[n]->data;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
// Return a copy of the given frame.
|
||||
// Returns NULL on error.
|
||||
struct mp_audio *mp_audio_pool_new_copy(struct mp_audio_pool *pool,
|
||||
struct mp_audio *frame)
|
||||
{
|
||||
struct mp_audio *new = mp_audio_pool_get(pool, frame, frame->samples);
|
||||
if (new) {
|
||||
mp_audio_copy(new, 0, frame, 0, new->samples);
|
||||
mp_audio_copy_attributes(new, frame);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
// Exactly like mp_audio_make_writeable(), but get the data from the pool.
|
||||
int mp_audio_pool_make_writeable(struct mp_audio_pool *pool,
|
||||
struct mp_audio *data)
|
||||
{
|
||||
if (mp_audio_is_writeable(data))
|
||||
return 0;
|
||||
struct mp_audio *new = mp_audio_pool_get(pool, data, data->samples);
|
||||
if (!new)
|
||||
return -1;
|
||||
mp_audio_copy(new, 0, data, 0, data->samples);
|
||||
mp_audio_copy_attributes(new, data);
|
||||
mp_audio_steal_data(data, new);
|
||||
return 0;
|
||||
}
|
||||
+6
-30
@@ -35,26 +35,22 @@ struct mp_audio {
|
||||
int nch; // number of channels (redundant with chmap)
|
||||
int spf; // sub-samples per sample on each plane
|
||||
int num_planes; // number of planes
|
||||
int bps; // size of sub-samples (af_fmt_to_bytes(format))
|
||||
int bps; // size of sub-samples (af_fmt2bps(format))
|
||||
|
||||
double pts; // currently invalid within the filter chain
|
||||
|
||||
// --- private
|
||||
// These do not necessarily map directly to planes[]. They can have
|
||||
// different order or count. There shouldn't be more buffers than planes.
|
||||
// If allocated[n] is NULL, allocated[n+1] must also be NULL.
|
||||
struct AVBufferRef *allocated[MP_NUM_CHANNELS];
|
||||
// private
|
||||
int allocated[MP_NUM_CHANNELS]; // use mp_audio_get_allocated_size()
|
||||
};
|
||||
|
||||
void mp_audio_set_format(struct mp_audio *mpa, int format);
|
||||
void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels);
|
||||
void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels);
|
||||
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap);
|
||||
void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src);
|
||||
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b);
|
||||
bool mp_audio_config_valid(const struct mp_audio *mpa);
|
||||
|
||||
char *mp_audio_config_to_str_buf(char *buf, size_t buf_sz, struct mp_audio *mpa);
|
||||
#define mp_audio_config_to_str(m) mp_audio_config_to_str_buf((char[64]){0}, 64, (m))
|
||||
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format);
|
||||
char *mp_audio_config_to_str(struct mp_audio *mpa);
|
||||
|
||||
void mp_audio_force_interleaved_format(struct mp_audio *mpa);
|
||||
|
||||
@@ -70,26 +66,6 @@ void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length);
|
||||
|
||||
void mp_audio_copy(struct mp_audio *dst, int dst_offset,
|
||||
struct mp_audio *src, int src_offset, int length);
|
||||
void mp_audio_copy_attributes(struct mp_audio *dst, struct mp_audio *src);
|
||||
void mp_audio_skip_samples(struct mp_audio *data, int samples);
|
||||
void mp_audio_clip_timestamps(struct mp_audio *f, double start, double end);
|
||||
double mp_audio_end_pts(struct mp_audio *data);
|
||||
|
||||
bool mp_audio_is_writeable(struct mp_audio *data);
|
||||
int mp_audio_make_writeable(struct mp_audio *data);
|
||||
|
||||
struct AVFrame;
|
||||
struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe);
|
||||
struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame);
|
||||
int mp_audio_to_avframe(struct mp_audio *frame, struct AVFrame *avframe);
|
||||
|
||||
struct mp_audio_pool;
|
||||
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent);
|
||||
struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
|
||||
const struct mp_audio *fmt, int samples);
|
||||
struct mp_audio *mp_audio_pool_new_copy(struct mp_audio_pool *pool,
|
||||
struct mp_audio *frame);
|
||||
int mp_audio_pool_make_writeable(struct mp_audio_pool *pool,
|
||||
struct mp_audio *frame);
|
||||
|
||||
#endif
|
||||
+7
-16
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU 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 free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* GNU 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/>.
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -119,15 +119,6 @@ void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples)
|
||||
mp_audio_fill_silence(ab->buffer, 0, samples);
|
||||
}
|
||||
|
||||
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= ab->buffer->samples);
|
||||
int oldlen = ab->buffer->samples;
|
||||
ab->buffer->samples += samples;
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, oldlen, ab->buffer, oldlen - samples, samples);
|
||||
}
|
||||
|
||||
// Get the start of the current readable buffer.
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa)
|
||||
{
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU 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 free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* GNU 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/>.
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MP_AUDIO_BUFFER_H
|
||||
@@ -35,7 +35,6 @@ void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples
|
||||
void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa);
|
||||
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa);
|
||||
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_clear(struct mp_audio_buffer *ab);
|
||||
|
||||
+126
-126
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* 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 free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* GNU 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/>.
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/msg.h"
|
||||
#include "chmap.h"
|
||||
|
||||
@@ -52,7 +49,6 @@ static const char *const speaker_names[MP_SPEAKER_ID_COUNT][2] = {
|
||||
[MP_SPEAKER_ID_SDL] = {"sdl", "surround direct left"},
|
||||
[MP_SPEAKER_ID_SDR] = {"sdr", "surround direct right"},
|
||||
[MP_SPEAKER_ID_LFE2] = {"lfe2", "low frequency 2"},
|
||||
[MP_SPEAKER_ID_NA] = {"na", "not available"},
|
||||
};
|
||||
|
||||
// Names taken from libavutil/channel_layout.c (Not accessible by API.)
|
||||
@@ -60,9 +56,7 @@ static const char *const speaker_names[MP_SPEAKER_ID_COUNT][2] = {
|
||||
static const char *const std_layout_names[][2] = {
|
||||
{"empty", ""}, // not in lavc
|
||||
{"mono", "fc"},
|
||||
{"1.0", "fc"}, // not in lavc
|
||||
{"stereo", "fl-fr"},
|
||||
{"2.0", "fl-fr"}, // not in lavc
|
||||
{"2.1", "fl-fr-lfe"},
|
||||
{"3.0", "fl-fr-fc"},
|
||||
{"3.0(back)", "fl-fr-bc"},
|
||||
@@ -70,7 +64,6 @@ static const char *const std_layout_names[][2] = {
|
||||
{"quad", "fl-fr-bl-br"},
|
||||
{"quad(side)", "fl-fr-sl-sr"},
|
||||
{"3.1", "fl-fr-fc-lfe"},
|
||||
{"3.1(back)", "fl-fr-lfe-bc"}, // not in lavc
|
||||
{"5.0", "fl-fr-fc-bl-br"},
|
||||
{"5.0(alsa)", "fl-fr-bl-br-fc"}, // not in lavc
|
||||
{"5.0(side)", "fl-fr-fc-sl-sr"},
|
||||
@@ -84,23 +77,19 @@ static const char *const std_layout_names[][2] = {
|
||||
{"hexagonal", "fl-fr-fc-bl-br-bc"},
|
||||
{"6.1", "fl-fr-fc-lfe-bc-sl-sr"},
|
||||
{"6.1(back)", "fl-fr-fc-lfe-bl-br-bc"}, // lavc calls this "6.1" too
|
||||
{"6.1(top)", "fl-fr-fc-lfe-bl-br-tc"}, // not in lavc
|
||||
{"6.1(front)", "fl-fr-lfe-flc-frc-sl-sr"},
|
||||
{"7.0", "fl-fr-fc-bl-br-sl-sr"},
|
||||
{"7.0(front)", "fl-fr-fc-flc-frc-sl-sr"},
|
||||
{"7.0(rear)", "fl-fr-fc-bl-br-sdl-sdr"}, // not in lavc
|
||||
{"7.1", "fl-fr-fc-lfe-bl-br-sl-sr"},
|
||||
{"7.1(alsa)", "fl-fr-bl-br-fc-lfe-sl-sr"}, // not in lavc
|
||||
{"7.1(wide)", "fl-fr-fc-lfe-bl-br-flc-frc"},
|
||||
{"7.1(wide-side)", "fl-fr-fc-lfe-flc-frc-sl-sr"},
|
||||
{"7.1(rear)", "fl-fr-fc-lfe-bl-br-sdl-sdr"}, // not in lavc
|
||||
{"octagonal", "fl-fr-fc-bl-br-bc-sl-sr"},
|
||||
{"downmix", "dl-dr"},
|
||||
{"auto", ""}, // not in lavc
|
||||
{0}
|
||||
};
|
||||
|
||||
static const struct mp_chmap default_layouts[] = {
|
||||
static const struct mp_chmap default_layouts[MP_NUM_CHANNELS + 1] = {
|
||||
{0}, // empty
|
||||
MP_CHMAP_INIT_MONO, // mono
|
||||
MP_CHMAP2(FL, FR), // stereo
|
||||
@@ -112,6 +101,19 @@ static const struct mp_chmap default_layouts[] = {
|
||||
MP_CHMAP8(FL, FR, FC, LFE, BL, BR, SL, SR), // 7.1
|
||||
};
|
||||
|
||||
// The channel order was lavc/waveex, but differs from lavc for 5, 6 and 8
|
||||
// channels. 3 and 7 channels were likely undefined (no ALSA support).
|
||||
// I'm not sure about the 4 channel case: ALSA uses "quad", while the ffmpeg
|
||||
// default layout is "4.0".
|
||||
static const char *const mplayer_layouts[MP_NUM_CHANNELS + 1] = {
|
||||
[1] = "mono",
|
||||
[2] = "stereo",
|
||||
[4] = "quad",
|
||||
[5] = "5.0(alsa)",
|
||||
[6] = "5.1(alsa)",
|
||||
[8] = "7.1(alsa)",
|
||||
};
|
||||
|
||||
// Returns true if speakers are mapped uniquely, and there's at least 1 channel.
|
||||
bool mp_chmap_is_valid(const struct mp_chmap *src)
|
||||
{
|
||||
@@ -120,8 +122,7 @@ bool mp_chmap_is_valid(const struct mp_chmap *src)
|
||||
int sp = src->speaker[n];
|
||||
if (sp >= MP_SPEAKER_ID_COUNT || mapped[sp])
|
||||
return false;
|
||||
if (sp != MP_SPEAKER_ID_NA)
|
||||
mapped[sp] = true;
|
||||
mapped[sp] = true;
|
||||
}
|
||||
return src->num > 0;
|
||||
}
|
||||
@@ -136,10 +137,12 @@ bool mp_chmap_is_empty(const struct mp_chmap *src)
|
||||
bool mp_chmap_is_unknown(const struct mp_chmap *src)
|
||||
{
|
||||
for (int n = 0; n < src->num; n++) {
|
||||
if (src->speaker[n] != MP_SPEAKER_ID_NA)
|
||||
return false;
|
||||
int speaker = src->speaker[n];
|
||||
if (speaker >= MP_SPEAKER_ID_UNKNOWN0 &&
|
||||
speaker <= MP_SPEAKER_ID_UNKNOWN_LAST)
|
||||
return true;
|
||||
}
|
||||
return mp_chmap_is_valid(src);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: empty channel maps compare as equal. Invalid ones can equal too.
|
||||
@@ -163,6 +166,15 @@ bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *
|
||||
return mp_chmap_equals(&t1, &t2);
|
||||
}
|
||||
|
||||
bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b)
|
||||
{
|
||||
if (mp_chmap_equals(a, b))
|
||||
return true;
|
||||
if (a->num == b->num && (mp_chmap_is_unknown(a) || mp_chmap_is_unknown(b)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mp_chmap_is_stereo(const struct mp_chmap *src)
|
||||
{
|
||||
static const struct mp_chmap stereo = MP_CHMAP_INIT_STEREO;
|
||||
@@ -182,43 +194,34 @@ void mp_chmap_reorder_norm(struct mp_chmap *map)
|
||||
qsort(arr, map->num, 1, comp_uint8);
|
||||
}
|
||||
|
||||
// Remove silent (NA) channels, if any.
|
||||
void mp_chmap_remove_na(struct mp_chmap *map)
|
||||
{
|
||||
struct mp_chmap new = {0};
|
||||
for (int n = 0; n < map->num; n++) {
|
||||
int sp = map->speaker[n];
|
||||
if (sp != MP_SPEAKER_ID_NA)
|
||||
new.speaker[new.num++] = map->speaker[n];
|
||||
}
|
||||
*map = new;
|
||||
}
|
||||
|
||||
// Add silent (NA) channels to map until map->num >= num.
|
||||
void mp_chmap_fill_na(struct mp_chmap *map, int num)
|
||||
{
|
||||
assert(num <= MP_NUM_CHANNELS);
|
||||
while (map->num < num)
|
||||
map->speaker[map->num++] = MP_SPEAKER_ID_NA;
|
||||
}
|
||||
|
||||
// Set *dst to a standard layout with the given number of channels.
|
||||
// If the number of channels is invalid, an invalid map is set, and
|
||||
// mp_chmap_is_valid(dst) will return false.
|
||||
void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels)
|
||||
{
|
||||
*dst = (struct mp_chmap) {0};
|
||||
if (num_channels >= 0 && num_channels < MP_ARRAY_SIZE(default_layouts))
|
||||
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
|
||||
*dst = (struct mp_chmap) {0};
|
||||
} else {
|
||||
*dst = default_layouts[num_channels];
|
||||
if (!dst->num)
|
||||
mp_chmap_set_unknown(dst, num_channels);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to do what mplayer/mplayer2/mpv did before channel layouts were
|
||||
// introduced, i.e. get the old default channel order.
|
||||
void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels)
|
||||
{
|
||||
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
|
||||
*dst = (struct mp_chmap) {0};
|
||||
} else {
|
||||
mp_chmap_from_str(dst, bstr0(mplayer_layouts[num_channels]));
|
||||
if (!dst->num)
|
||||
mp_chmap_from_channels(dst, num_channels);
|
||||
}
|
||||
}
|
||||
|
||||
// Set *dst to an unknown layout for the given numbers of channels.
|
||||
// If the number of channels is invalid, an invalid map is set, and
|
||||
// mp_chmap_is_valid(dst) will return false.
|
||||
// A mp_chmap with all entries set to NA is treated specially in some
|
||||
// contexts (watch out for mp_chmap_is_unknown()).
|
||||
void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels)
|
||||
{
|
||||
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
|
||||
@@ -226,31 +229,60 @@ void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels)
|
||||
} else {
|
||||
dst->num = num_channels;
|
||||
for (int n = 0; n < dst->num; n++)
|
||||
dst->speaker[n] = MP_SPEAKER_ID_NA;
|
||||
dst->speaker[n] = MP_SPEAKER_ID_UNKNOWN0 + n;
|
||||
}
|
||||
}
|
||||
|
||||
// Return channel index of the given speaker, or -1.
|
||||
static int mp_chmap_find_speaker(const struct mp_chmap *map, int speaker)
|
||||
{
|
||||
for (int n = 0; n < map->num; n++) {
|
||||
if (map->speaker[n] == speaker)
|
||||
return n;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void mp_chmap_remove_speaker(struct mp_chmap *map, int speaker)
|
||||
{
|
||||
int index = mp_chmap_find_speaker(map, speaker);
|
||||
if (index >= 0) {
|
||||
for (int n = index; n < map->num - 1; n++)
|
||||
map->speaker[n] = map->speaker[n + 1];
|
||||
map->num--;
|
||||
}
|
||||
}
|
||||
|
||||
// Some decoders output additional, redundant channels, which are usually
|
||||
// useless and will mess up proper audio output channel handling.
|
||||
// map: channel map from which the channels should be removed
|
||||
// requested: if not NULL, and if it contains any of the "useless" channels,
|
||||
// don't remove them (this is for convenience)
|
||||
void mp_chmap_remove_useless_channels(struct mp_chmap *map,
|
||||
const struct mp_chmap *requested)
|
||||
{
|
||||
if (requested &&
|
||||
mp_chmap_find_speaker(requested, MP_SPEAKER_ID_DL) >= 0)
|
||||
return;
|
||||
|
||||
if (map->num > 2) {
|
||||
mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DL);
|
||||
mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DR);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>.
|
||||
// Speakers not representable by ffmpeg/libav are dropped.
|
||||
// Warning: this ignores the order of the channels, and will return a channel
|
||||
// mask even if the order is different from libavcodec's.
|
||||
// Also, "unknown" channel maps are translated to non-sense channel
|
||||
// maps with the same number of channels.
|
||||
uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src)
|
||||
{
|
||||
// lavc has no concept for unknown layouts yet, so pick a default
|
||||
struct mp_chmap t = *src;
|
||||
if (t.num > 64)
|
||||
return 0;
|
||||
// lavc has no concept for unknown layouts yet, so pick something that does
|
||||
// the job of signaling the number of channels, even if it makes no sense
|
||||
// as a proper layout.
|
||||
if (mp_chmap_is_unknown(&t))
|
||||
return t.num == 64 ? (uint64_t)-1 : (1ULL << t.num) - 1;
|
||||
mp_chmap_from_channels(&t, t.num);
|
||||
uint64_t mask = 0;
|
||||
for (int n = 0; n < t.num; n++) {
|
||||
if (t.speaker[n] < 64) // ignore MP_SPEAKER_ID_NA etc.
|
||||
mask |= 1ULL << t.speaker[n];
|
||||
}
|
||||
for (int n = 0; n < t.num; n++)
|
||||
mask |= 1ULL << t.speaker[n];
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -301,8 +333,6 @@ bool mp_chmap_is_lavc(const struct mp_chmap *src)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Warning: for "unknown" channel maps, this returns something that may not
|
||||
// make sense. Invalid channel maps are not changed.
|
||||
void mp_chmap_reorder_to_lavc(struct mp_chmap *map)
|
||||
{
|
||||
if (!mp_chmap_is_valid(map))
|
||||
@@ -313,77 +343,66 @@ void mp_chmap_reorder_to_lavc(struct mp_chmap *map)
|
||||
|
||||
// Get reordering array for from->to reordering. from->to must have the same set
|
||||
// of speakers (i.e. same number and speaker IDs, just different order). Then,
|
||||
// for each speaker n, src[n] will be set such that:
|
||||
// to->speaker[n] = from->speaker[src[n]]
|
||||
// (src[n] gives the source channel for destination channel n)
|
||||
// If *from and *to don't contain the same set of speakers, then the above
|
||||
// invariant is not guaranteed. Instead, src[n] can be set to -1 if the channel
|
||||
// at to->speaker[n] is unmapped.
|
||||
void mp_chmap_get_reorder(int src[MP_NUM_CHANNELS], const struct mp_chmap *from,
|
||||
// for each speaker n, dst[n] will be set such that:
|
||||
// to->speaker[dst[n]] = from->speaker[n]
|
||||
// (dst[n] gives the source channel for destination channel n)
|
||||
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
|
||||
const struct mp_chmap *to)
|
||||
{
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
src[n] = -1;
|
||||
|
||||
assert(from->num == to->num);
|
||||
if (mp_chmap_is_unknown(from) || mp_chmap_is_unknown(to)) {
|
||||
for (int n = 0; n < to->num; n++)
|
||||
src[n] = n < from->num ? n : -1;
|
||||
for (int n = 0; n < from->num; n++)
|
||||
dst[n] = n;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int n = 0; n < to->num; n++) {
|
||||
for (int i = 0; i < from->num; i++) {
|
||||
if (to->speaker[n] == from->speaker[i]) {
|
||||
src[n] = i;
|
||||
// Same set of speakers required
|
||||
assert(mp_chmap_equals_reordered(from, to));
|
||||
for (int n = 0; n < from->num; n++) {
|
||||
int src = from->speaker[n];
|
||||
dst[n] = -1;
|
||||
for (int i = 0; i < to->num; i++) {
|
||||
if (src == to->speaker[i]) {
|
||||
dst[n] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(dst[n] != -1);
|
||||
}
|
||||
|
||||
for (int n = 0; n < to->num; n++)
|
||||
assert(src[n] < 0 || (to->speaker[n] == from->speaker[src[n]]));
|
||||
}
|
||||
|
||||
// Return the number of channels only in a.
|
||||
int mp_chmap_diffn(const struct mp_chmap *a, const struct mp_chmap *b)
|
||||
{
|
||||
uint64_t a_mask = mp_chmap_to_lavc_unchecked(a);
|
||||
uint64_t b_mask = mp_chmap_to_lavc_unchecked(b);
|
||||
return av_popcount64((a_mask ^ b_mask) & a_mask);
|
||||
for (int n = 0; n < from->num; n++)
|
||||
assert(to->speaker[dst[n]] == from->speaker[n]);
|
||||
}
|
||||
|
||||
// Returns something like "fl-fr-fc". If there's a standard layout in lavc
|
||||
// order, return that, e.g. "3.0" instead of "fl-fr-fc".
|
||||
// Unassigned but valid speakers get names like "sp28".
|
||||
char *mp_chmap_to_str_buf(char *buf, size_t buf_size, const struct mp_chmap *src)
|
||||
char *mp_chmap_to_str(const struct mp_chmap *src)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
char *res = talloc_strdup(NULL, "");
|
||||
|
||||
if (mp_chmap_is_unknown(src)) {
|
||||
snprintf(buf, buf_size, "unknown%d", src->num);
|
||||
return buf;
|
||||
}
|
||||
if (mp_chmap_is_unknown(src))
|
||||
return talloc_asprintf_append_buffer(res, "unknown%d", src->num);
|
||||
|
||||
for (int n = 0; n < src->num; n++) {
|
||||
int sp = src->speaker[n];
|
||||
const char *s = sp < MP_SPEAKER_ID_COUNT ? speaker_names[sp][0] : NULL;
|
||||
char sp_buf[10];
|
||||
char buf[10];
|
||||
if (!s) {
|
||||
snprintf(sp_buf, sizeof(sp_buf), "sp%d", sp);
|
||||
s = sp_buf;
|
||||
snprintf(buf, sizeof(buf), "sp%d", sp);
|
||||
s = buf;
|
||||
}
|
||||
mp_snprintf_cat(buf, buf_size, "%s%s", n > 0 ? "-" : "", s);
|
||||
res = talloc_asprintf_append_buffer(res, "%s%s", n > 0 ? "-" : "", s);
|
||||
}
|
||||
|
||||
// To standard layout name
|
||||
for (int n = 0; std_layout_names[n][0]; n++) {
|
||||
if (strcmp(buf, std_layout_names[n][1]) == 0) {
|
||||
snprintf(buf, buf_size, "%s", std_layout_names[n][0]);
|
||||
if (res && strcmp(res, std_layout_names[n][1]) == 0) {
|
||||
talloc_free(res);
|
||||
res = talloc_strdup(NULL, std_layout_names[n][0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
return res;
|
||||
}
|
||||
|
||||
// If src can be parsed as channel map (as produced by mp_chmap_to_str()),
|
||||
@@ -452,25 +471,6 @@ bool mp_chmap_from_str(struct mp_chmap *dst, bstr src)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Output a human readable "canonical" channel map string. Converting this from
|
||||
// a string back to a channel map can yield a different map, but the string
|
||||
// looks nicer. E.g. "fc-fl-fr-na" becomes "3.0".
|
||||
char *mp_chmap_to_str_hr_buf(char *buf, size_t buf_size, const struct mp_chmap *src)
|
||||
{
|
||||
struct mp_chmap map = *src;
|
||||
mp_chmap_remove_na(&map);
|
||||
for (int n = 0; std_layout_names[n][0]; n++) {
|
||||
struct mp_chmap s;
|
||||
if (mp_chmap_from_str(&s, bstr0(std_layout_names[n][0])) &&
|
||||
mp_chmap_equals_reordered(&s, &map))
|
||||
{
|
||||
map = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mp_chmap_to_str_buf(buf, buf_size, &map);
|
||||
}
|
||||
|
||||
void mp_chmap_print_help(struct mp_log *log)
|
||||
{
|
||||
mp_info(log, "Speakers:\n");
|
||||
|
||||
+22
-29
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU 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 free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* GNU 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/>.
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MP_CHMAP_H
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include "misc/bstr.h"
|
||||
#include "bstr/bstr.h"
|
||||
|
||||
#define MP_NUM_CHANNELS 16
|
||||
#define MP_NUM_CHANNELS 8
|
||||
|
||||
// Speaker a channel can be assigned to.
|
||||
// This corresponds to WAVEFORMATEXTENSIBLE channel mask bit indexes.
|
||||
@@ -47,7 +47,7 @@ enum mp_speaker_id {
|
||||
MP_SPEAKER_ID_TBL, // TOP_BACK_LEFT
|
||||
MP_SPEAKER_ID_TBC, // TOP_BACK_CENTER
|
||||
MP_SPEAKER_ID_TBR, // TOP_BACK_RIGHT
|
||||
// Unofficial/libav* extensions
|
||||
// Inofficial/libav* extensions
|
||||
MP_SPEAKER_ID_DL = 29, // STEREO_LEFT (stereo downmix special speakers)
|
||||
MP_SPEAKER_ID_DR, // STEREO_RIGHT
|
||||
MP_SPEAKER_ID_WL, // WIDE_LEFT
|
||||
@@ -56,15 +56,12 @@ enum mp_speaker_id {
|
||||
MP_SPEAKER_ID_SDR, // SURROUND_DIRECT_RIGHT
|
||||
MP_SPEAKER_ID_LFE2, // LOW_FREQUENCY_2
|
||||
|
||||
// Speaker IDs >= 64 are not representable in WAVEFORMATEXTENSIBLE or libav*.
|
||||
// Special mpv-specific speaker entries reserved for channels which have no
|
||||
// known meaning.
|
||||
MP_SPEAKER_ID_UNKNOWN0 = 64,
|
||||
MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1,
|
||||
|
||||
// "Silent" channels. These are sometimes used to insert padding for
|
||||
// unused channels. Unlike other speaker types, multiple of these can
|
||||
// occur in a single mp_chmap.
|
||||
MP_SPEAKER_ID_NA = 64,
|
||||
|
||||
// Including the unassigned IDs in between. This is not a valid ID anymore,
|
||||
// but is still within uint8_t.
|
||||
// Including the unassigned IDs in between. This is not a valid ID anymore.
|
||||
MP_SPEAKER_ID_COUNT,
|
||||
};
|
||||
|
||||
@@ -100,14 +97,17 @@ bool mp_chmap_is_empty(const struct mp_chmap *src);
|
||||
bool mp_chmap_is_unknown(const struct mp_chmap *src);
|
||||
bool mp_chmap_equals(const struct mp_chmap *a, const struct mp_chmap *b);
|
||||
bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *b);
|
||||
bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b);
|
||||
bool mp_chmap_is_stereo(const struct mp_chmap *src);
|
||||
|
||||
void mp_chmap_reorder_norm(struct mp_chmap *map);
|
||||
void mp_chmap_remove_na(struct mp_chmap *map);
|
||||
void mp_chmap_fill_na(struct mp_chmap *map, int num);
|
||||
|
||||
void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels);
|
||||
void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels);
|
||||
void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels);
|
||||
|
||||
void mp_chmap_remove_useless_channels(struct mp_chmap *map,
|
||||
const struct mp_chmap *requested);
|
||||
|
||||
uint64_t mp_chmap_to_lavc(const struct mp_chmap *src);
|
||||
uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src);
|
||||
@@ -116,17 +116,10 @@ void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src);
|
||||
bool mp_chmap_is_lavc(const struct mp_chmap *src);
|
||||
void mp_chmap_reorder_to_lavc(struct mp_chmap *map);
|
||||
|
||||
void mp_chmap_get_reorder(int src[MP_NUM_CHANNELS], const struct mp_chmap *from,
|
||||
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
|
||||
const struct mp_chmap *to);
|
||||
|
||||
int mp_chmap_diffn(const struct mp_chmap *a, const struct mp_chmap *b);
|
||||
|
||||
char *mp_chmap_to_str_buf(char *buf, size_t buf_size, const struct mp_chmap *src);
|
||||
#define mp_chmap_to_str(m) mp_chmap_to_str_buf((char[64]){0}, 64, (m))
|
||||
|
||||
char *mp_chmap_to_str_hr_buf(char *buf, size_t buf_size, const struct mp_chmap *src);
|
||||
#define mp_chmap_to_str_hr(m) mp_chmap_to_str_hr_buf((char[128]){0}, 128, (m))
|
||||
|
||||
char *mp_chmap_to_str(const struct mp_chmap *src);
|
||||
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
|
||||
|
||||
struct mp_log;
|
||||
|
||||
+29
-202
@@ -1,26 +1,24 @@
|
||||
/*
|
||||
* 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 free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* GNU 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/>.
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/msg.h"
|
||||
#include "chmap_sel.h"
|
||||
|
||||
static const struct mp_chmap speaker_replacements[][2] = {
|
||||
@@ -59,29 +57,6 @@ static bool replace_speakers(struct mp_chmap *map, struct mp_chmap list[2])
|
||||
return false;
|
||||
}
|
||||
|
||||
// These go strictly from the first to the second entry and always use the
|
||||
// full layout (possibly reordered and/or padding channels added).
|
||||
static const struct mp_chmap preferred_remix[][2] = {
|
||||
// mono can be perfectly played as stereo
|
||||
{ MP_CHMAP_INIT_MONO, MP_CHMAP_INIT_STEREO },
|
||||
};
|
||||
|
||||
// Conversion from src to dst is explicitly encouraged and should be preferred
|
||||
// over "mathematical" upmixes or downmixes (which minimize lost channels).
|
||||
static bool test_preferred_remix(const struct mp_chmap *src,
|
||||
const struct mp_chmap *dst)
|
||||
{
|
||||
struct mp_chmap src_p = *src, dst_p = *dst;
|
||||
mp_chmap_remove_na(&src_p);
|
||||
mp_chmap_remove_na(&dst_p);
|
||||
for (int n = 0; n < MP_ARRAY_SIZE(preferred_remix); n++) {
|
||||
if (mp_chmap_equals_reordered(&src_p, &preferred_remix[n][0]) &&
|
||||
mp_chmap_equals_reordered(&dst_p, &preferred_remix[n][1]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow all channel layouts that can be expressed with mp_chmap.
|
||||
// (By default, all layouts are rejected.)
|
||||
void mp_chmap_sel_add_any(struct mp_chmap_sel *s)
|
||||
@@ -95,27 +70,31 @@ void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s)
|
||||
s->allow_waveext = true;
|
||||
}
|
||||
|
||||
// Classic ALSA-based MPlayer layouts.
|
||||
void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s)
|
||||
{
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
struct mp_chmap t;
|
||||
mp_chmap_from_channels_alsa(&t, n);
|
||||
if (t.num)
|
||||
mp_chmap_sel_add_map(s, &t);
|
||||
}
|
||||
}
|
||||
|
||||
#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
// Add a channel map that should be allowed.
|
||||
void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map)
|
||||
{
|
||||
if (!mp_chmap_is_valid(map))
|
||||
return;
|
||||
if (!s->chmaps)
|
||||
s->chmaps = s->chmaps_storage;
|
||||
if (s->num_chmaps == MP_ARRAY_SIZE(s->chmaps_storage)) {
|
||||
if (!s->tmp)
|
||||
return;
|
||||
s->chmaps = talloc_memdup(s->tmp, s->chmaps, sizeof(s->chmaps_storage));
|
||||
}
|
||||
if (s->chmaps != s->chmaps_storage)
|
||||
MP_TARRAY_GROW(s->tmp, s->chmaps, s->num_chmaps);
|
||||
s->chmaps[s->num_chmaps++] = *map;
|
||||
assert(s->num_chmaps < ARRAY_LEN(s->chmaps));
|
||||
if (mp_chmap_is_valid(map))
|
||||
s->chmaps[s->num_chmaps++] = *map;
|
||||
}
|
||||
|
||||
// Allow all waveext formats in default order.
|
||||
void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s)
|
||||
{
|
||||
for (int n = 1; n <= MP_NUM_CHANNELS; n++) {
|
||||
for (int n = 1; n < MP_NUM_CHANNELS; n++) {
|
||||
struct mp_chmap map;
|
||||
mp_chmap_from_channels(&map, n);
|
||||
mp_chmap_sel_add_map(s, &map);
|
||||
@@ -189,10 +168,6 @@ bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mp_chmap_sel_fallback(s, map))
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(speaker_replacements); i++) {
|
||||
struct mp_chmap t = *map;
|
||||
struct mp_chmap *r = (struct mp_chmap *)speaker_replacements[i];
|
||||
@@ -201,132 +176,18 @@ bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to mono/stereo as last resort
|
||||
*map = (struct mp_chmap) MP_CHMAP_INIT_STEREO;
|
||||
if (test_layout(s, map))
|
||||
return true;
|
||||
*map = (struct mp_chmap) MP_CHMAP_INIT_MONO;
|
||||
if (map->num == 1) {
|
||||
*map = (struct mp_chmap) MP_CHMAP_INIT_MONO;
|
||||
} else if (map->num >= 2) {
|
||||
*map = (struct mp_chmap) MP_CHMAP_INIT_STEREO;
|
||||
}
|
||||
if (test_layout(s, map))
|
||||
return true;
|
||||
*map = (struct mp_chmap) {0};
|
||||
return false;
|
||||
}
|
||||
|
||||
// Like mp_chmap_diffn(), but find the minimum difference with all possible
|
||||
// speaker replacements considered.
|
||||
static int mp_chmap_diffn_r(const struct mp_chmap *a, const struct mp_chmap *b)
|
||||
{
|
||||
int mindiff = INT_MAX;
|
||||
|
||||
for (int i = -1; i < (int)MP_ARRAY_SIZE(speaker_replacements); i++) {
|
||||
struct mp_chmap ar = *a;
|
||||
if (i >= 0) {
|
||||
struct mp_chmap *r = (struct mp_chmap *)speaker_replacements[i];
|
||||
if (!replace_speakers(&ar, r))
|
||||
continue;
|
||||
}
|
||||
int d = mp_chmap_diffn(&ar, b);
|
||||
if (d < mindiff)
|
||||
mindiff = d;
|
||||
}
|
||||
|
||||
// Special-case: we consider stereo a replacement for mono. (This is not
|
||||
// true in the other direction. Also, fl-fr is generally not a replacement
|
||||
// for fc. Thus it's not part of the speaker replacement list.)
|
||||
struct mp_chmap mono = MP_CHMAP_INIT_MONO;
|
||||
struct mp_chmap stereo = MP_CHMAP_INIT_STEREO;
|
||||
if (mp_chmap_equals(&mono, b) && mp_chmap_equals(&stereo, a))
|
||||
mindiff = 0;
|
||||
|
||||
return mindiff;
|
||||
}
|
||||
|
||||
// Decide whether we should prefer old or new for the requested layout.
|
||||
// Return true if new should be used, false if old should be used.
|
||||
// If old is empty, always return new (initial case).
|
||||
static bool mp_chmap_is_better(struct mp_chmap *req, struct mp_chmap *old,
|
||||
struct mp_chmap *new)
|
||||
{
|
||||
// Initial case
|
||||
if (!old->num)
|
||||
return true;
|
||||
|
||||
// Exact pick - this also ensures that the best layout is chosen if the
|
||||
// layouts are the same, but with different order of channels.
|
||||
if (mp_chmap_equals(req, old))
|
||||
return false;
|
||||
if (mp_chmap_equals(req, new))
|
||||
return true;
|
||||
|
||||
// If there's no exact match, strictly do a preferred conversion.
|
||||
bool old_pref = test_preferred_remix(req, old);
|
||||
bool new_pref = test_preferred_remix(req, new);
|
||||
if (old_pref && !new_pref)
|
||||
return false;
|
||||
if (!old_pref && new_pref)
|
||||
return true;
|
||||
|
||||
int old_lost_r = mp_chmap_diffn_r(req, old); // num. channels only in req
|
||||
int new_lost_r = mp_chmap_diffn_r(req, new);
|
||||
|
||||
// Imperfect upmix (no real superset) - minimize lost channels
|
||||
if (new_lost_r != old_lost_r)
|
||||
return new_lost_r < old_lost_r;
|
||||
|
||||
struct mp_chmap old_p = *old, new_p = *new;
|
||||
mp_chmap_remove_na(&old_p);
|
||||
mp_chmap_remove_na(&new_p);
|
||||
|
||||
// If the situation is equal with replaced speakers, but the replacement is
|
||||
// perfect for only one of them, let the better one win. This prefers
|
||||
// inexact equivalents over exact supersets.
|
||||
bool perfect_r_new = !new_lost_r && new_p.num <= old_p.num;
|
||||
bool perfect_r_old = !old_lost_r && old_p.num <= new_p.num;
|
||||
if (perfect_r_new != perfect_r_old)
|
||||
return perfect_r_new;
|
||||
|
||||
int old_lost = mp_chmap_diffn(req, old);
|
||||
int new_lost = mp_chmap_diffn(req, new);
|
||||
// If the situation is equal with replaced speakers, pick the better one,
|
||||
// even if it means an upmix.
|
||||
if (new_lost != old_lost)
|
||||
return new_lost < old_lost;
|
||||
|
||||
// Some kind of upmix. If it's perfect, prefer the smaller one. Even if not,
|
||||
// both have equal loss, so also prefer the smaller one.
|
||||
// Drop padding channels (NA) for the sake of this check, as the number of
|
||||
// padding channels isn't really meaningful.
|
||||
if (new_p.num != old_p.num)
|
||||
return new_p.num < old_p.num;
|
||||
|
||||
// Again, with physical channels (minimizes number of NA channels).
|
||||
return new->num < old->num;
|
||||
}
|
||||
|
||||
// Determine which channel map to fallback to given a source channel map.
|
||||
bool mp_chmap_sel_fallback(const struct mp_chmap_sel *s, struct mp_chmap *map)
|
||||
{
|
||||
struct mp_chmap best = {0};
|
||||
|
||||
for (int n = 0; n < s->num_chmaps; n++) {
|
||||
struct mp_chmap e = s->chmaps[n];
|
||||
|
||||
if (mp_chmap_is_unknown(&e))
|
||||
continue;
|
||||
|
||||
if (mp_chmap_is_better(map, &best, &e))
|
||||
best = e;
|
||||
}
|
||||
|
||||
if (best.num) {
|
||||
*map = best;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set map to a default layout with num channels. Used for audio APIs that
|
||||
// return a channel count as part of format negotiation, but give no
|
||||
// information about the channel layout.
|
||||
@@ -353,37 +214,3 @@ bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
|
||||
}
|
||||
return map->num > 0;
|
||||
}
|
||||
|
||||
// Print the set of allowed channel layouts.
|
||||
void mp_chmal_sel_log(const struct mp_chmap_sel *s, struct mp_log *log, int lev)
|
||||
{
|
||||
if (!mp_msg_test(log, lev))
|
||||
return;
|
||||
|
||||
for (int i = 0; i < s->num_chmaps; i++)
|
||||
mp_msg(log, lev, " - %s\n", mp_chmap_to_str(&s->chmaps[i]));
|
||||
for (int i = 0; i < MP_SPEAKER_ID_COUNT; i++) {
|
||||
if (!s->speakers[i])
|
||||
continue;
|
||||
struct mp_chmap l = {.num = 1, .speaker = { i }};
|
||||
mp_msg(log, lev, " - #%s\n",
|
||||
i == MP_SPEAKER_ID_FC ? "fc" : mp_chmap_to_str_hr(&l));
|
||||
}
|
||||
if (s->allow_waveext)
|
||||
mp_msg(log, lev, " - waveext\n");
|
||||
if (s->allow_any)
|
||||
mp_msg(log, lev, " - anything\n");
|
||||
}
|
||||
|
||||
// Select a channel map from the given list that fits best to c. Don't change
|
||||
// *c if there's no match, or the list is empty.
|
||||
void mp_chmap_sel_list(struct mp_chmap *c, struct mp_chmap *maps, int num_maps)
|
||||
{
|
||||
// This is a separate function to keep messing with mp_chmap_sel internals
|
||||
// within this source file.
|
||||
struct mp_chmap_sel sel = {
|
||||
.chmaps = maps,
|
||||
.num_chmaps = num_maps,
|
||||
};
|
||||
mp_chmap_sel_fallback(&sel, c);
|
||||
}
|
||||
+9
-18
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU 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 free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* GNU 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/>.
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MP_CHMAP_SEL_H
|
||||
@@ -26,27 +26,18 @@ struct mp_chmap_sel {
|
||||
// should be considered opaque
|
||||
bool allow_any, allow_waveext;
|
||||
bool speakers[MP_SPEAKER_ID_COUNT];
|
||||
struct mp_chmap *chmaps;
|
||||
struct mp_chmap chmaps[20];
|
||||
int num_chmaps;
|
||||
|
||||
struct mp_chmap chmaps_storage[20];
|
||||
|
||||
void *tmp; // set to any talloc context to allow more chmaps entries
|
||||
};
|
||||
|
||||
void mp_chmap_sel_add_any(struct mp_chmap_sel *s);
|
||||
void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s);
|
||||
void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s);
|
||||
void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s);
|
||||
void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map);
|
||||
void mp_chmap_sel_add_speaker(struct mp_chmap_sel *s, int id);
|
||||
bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map);
|
||||
bool mp_chmap_sel_fallback(const struct mp_chmap_sel *s, struct mp_chmap *map);
|
||||
bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
|
||||
int num);
|
||||
|
||||
struct mp_log;
|
||||
void mp_chmal_sel_log(const struct mp_chmap_sel *s, struct mp_log *log, int lev);
|
||||
|
||||
void mp_chmap_sel_list(struct mp_chmap *c, struct mp_chmap *maps, int num_maps);
|
||||
|
||||
#endif
|
||||
+6
-6
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_AD_H
|
||||
@@ -35,8 +36,7 @@ struct ad_functions {
|
||||
int (*init)(struct dec_audio *da, const char *decoder);
|
||||
void (*uninit)(struct dec_audio *da);
|
||||
int (*control)(struct dec_audio *da, int cmd, void *arg);
|
||||
int (*decode_packet)(struct dec_audio *da, struct demux_packet *pkt,
|
||||
struct mp_audio **out);
|
||||
int (*decode_audio)(struct dec_audio *da, struct mp_audio *buffer, int maxlen);
|
||||
};
|
||||
|
||||
enum ad_ctrl {
|
||||
|
||||
+240
-131
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -24,71 +25,190 @@
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "mpv_talloc.h"
|
||||
#include "talloc.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "common/av_common.h"
|
||||
#include "common/codecs.h"
|
||||
#include "common/msg.h"
|
||||
#include "options/options.h"
|
||||
#include "common/av_opts.h"
|
||||
|
||||
#include "ad.h"
|
||||
#include "audio/fmt-conversion.h"
|
||||
|
||||
#include "compat/libav.h"
|
||||
|
||||
struct priv {
|
||||
AVCodecContext *avctx;
|
||||
AVFrame *avframe;
|
||||
struct mp_audio frame;
|
||||
bool force_channel_map;
|
||||
uint32_t skip_samples, trim_samples;
|
||||
bool preroll_done;
|
||||
double next_pts;
|
||||
bool needs_reset;
|
||||
AVRational codec_timebase;
|
||||
struct demux_packet *packet;
|
||||
};
|
||||
|
||||
static void uninit(struct dec_audio *da);
|
||||
static int decode_new_packet(struct dec_audio *da);
|
||||
|
||||
#define OPT_BASE_STRUCT struct ad_lavc_params
|
||||
struct ad_lavc_params {
|
||||
float ac3drc;
|
||||
int downmix;
|
||||
int threads;
|
||||
char **avopts;
|
||||
char *avopt;
|
||||
};
|
||||
|
||||
const struct m_sub_options ad_lavc_conf = {
|
||||
.opts = (const m_option_t[]) {
|
||||
OPT_FLOATRANGE("ac3drc", ac3drc, 0, 0, 6),
|
||||
OPT_FLOATRANGE("ac3drc", ac3drc, 0, 0, 2),
|
||||
OPT_FLAG("downmix", downmix, 0),
|
||||
OPT_INTRANGE("threads", threads, 0, 0, 16),
|
||||
OPT_KEYVALUELIST("o", avopts, 0),
|
||||
OPT_INTRANGE("threads", threads, 0, 1, 16),
|
||||
OPT_STRING("o", avopt, 0),
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct ad_lavc_params),
|
||||
.defaults = &(const struct ad_lavc_params){
|
||||
.ac3drc = 0,
|
||||
.ac3drc = 1.,
|
||||
.downmix = 1,
|
||||
.threads = 1,
|
||||
},
|
||||
};
|
||||
|
||||
struct pcm_map
|
||||
{
|
||||
int tag;
|
||||
const char *codecs[6]; // {any, 1byte, 2bytes, 3bytes, 4bytes, 8bytes}
|
||||
};
|
||||
|
||||
// NOTE: these are needed to make rawaudio with demux_mkv work.
|
||||
static const struct pcm_map tag_map[] = {
|
||||
// Microsoft PCM
|
||||
{0x0, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
|
||||
{0x1, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
|
||||
// MS PCM, Extended
|
||||
{0xfffe, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
|
||||
// IEEE float
|
||||
{0x3, {"pcm_f32le", [5] = "pcm_f64le"}},
|
||||
// 'raw '
|
||||
{0x20776172, {"pcm_s16be", [1] = "pcm_u8"}},
|
||||
// 'twos', used by demux_mkv.c internally
|
||||
{MKTAG('t', 'w', 'o', 's'),
|
||||
{NULL, "pcm_s8", "pcm_s16be", "pcm_s24be", "pcm_s32be"}},
|
||||
{-1},
|
||||
};
|
||||
|
||||
// For demux_rawaudio.c; needed because ffmpeg doesn't have these sample
|
||||
// formats natively.
|
||||
static const struct pcm_map af_map[] = {
|
||||
{AF_FORMAT_U8, {"pcm_u8"}},
|
||||
{AF_FORMAT_S8, {"pcm_u8"}},
|
||||
{AF_FORMAT_U16_LE, {"pcm_u16le"}},
|
||||
{AF_FORMAT_U16_BE, {"pcm_u16be"}},
|
||||
{AF_FORMAT_S16_LE, {"pcm_s16le"}},
|
||||
{AF_FORMAT_S16_BE, {"pcm_s16be"}},
|
||||
{AF_FORMAT_U24_LE, {"pcm_u24le"}},
|
||||
{AF_FORMAT_U24_BE, {"pcm_u24be"}},
|
||||
{AF_FORMAT_S24_LE, {"pcm_s24le"}},
|
||||
{AF_FORMAT_S24_BE, {"pcm_s24be"}},
|
||||
{AF_FORMAT_U32_LE, {"pcm_u32le"}},
|
||||
{AF_FORMAT_U32_BE, {"pcm_u32be"}},
|
||||
{AF_FORMAT_S32_LE, {"pcm_s32le"}},
|
||||
{AF_FORMAT_S32_BE, {"pcm_s32be"}},
|
||||
{AF_FORMAT_FLOAT_LE, {"pcm_f32le"}},
|
||||
{AF_FORMAT_FLOAT_BE, {"pcm_f32be"}},
|
||||
{AF_FORMAT_DOUBLE_LE, {"pcm_f64le"}},
|
||||
{AF_FORMAT_DOUBLE_BE, {"pcm_f64be"}},
|
||||
{-1},
|
||||
};
|
||||
|
||||
static const char *find_pcm_decoder(const struct pcm_map *map, int format,
|
||||
int bits_per_sample)
|
||||
{
|
||||
int bytes = (bits_per_sample + 7) / 8;
|
||||
if (bytes == 8)
|
||||
bytes = 5; // 64 bit entry
|
||||
for (int n = 0; map[n].tag != -1; n++) {
|
||||
const struct pcm_map *entry = &map[n];
|
||||
if (entry->tag == format) {
|
||||
const char *dec = NULL;
|
||||
if (bytes >= 1 && bytes <= 5)
|
||||
dec = entry->codecs[bytes];
|
||||
if (!dec)
|
||||
dec = entry->codecs[0];
|
||||
if (dec)
|
||||
return dec;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int setup_format(struct dec_audio *da)
|
||||
{
|
||||
struct priv *priv = da->priv;
|
||||
AVCodecContext *lavc_context = priv->avctx;
|
||||
struct sh_audio *sh_audio = da->header->audio;
|
||||
|
||||
// Note: invalid parameters are rejected by dec_audio.c
|
||||
|
||||
int fmt = lavc_context->sample_fmt;
|
||||
mp_audio_set_format(&da->decoded, af_from_avformat(fmt));
|
||||
if (!da->decoded.format)
|
||||
MP_FATAL(da, "unsupported lavc format %s", av_get_sample_fmt_name(fmt));
|
||||
|
||||
da->decoded.rate = lavc_context->sample_rate;
|
||||
if (!da->decoded.rate && sh_audio->wf) {
|
||||
// If not set, try container samplerate.
|
||||
// (Maybe this can't happen, and it's an artifact from the past.)
|
||||
da->decoded.rate = sh_audio->wf->nSamplesPerSec;
|
||||
MP_WARN(da, "using container rate.\n");
|
||||
}
|
||||
|
||||
struct mp_chmap lavc_chmap;
|
||||
mp_chmap_from_lavc(&lavc_chmap, lavc_context->channel_layout);
|
||||
// No channel layout or layout disagrees with channel count
|
||||
if (lavc_chmap.num != lavc_context->channels)
|
||||
mp_chmap_from_channels(&lavc_chmap, lavc_context->channels);
|
||||
if (priv->force_channel_map) {
|
||||
if (lavc_chmap.num == sh_audio->channels.num)
|
||||
lavc_chmap = sh_audio->channels;
|
||||
}
|
||||
mp_audio_set_channels(&da->decoded, &lavc_chmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_from_wf(AVCodecContext *avctx, MP_WAVEFORMATEX *wf)
|
||||
{
|
||||
avctx->channels = wf->nChannels;
|
||||
avctx->sample_rate = wf->nSamplesPerSec;
|
||||
avctx->bit_rate = wf->nAvgBytesPerSec * 8;
|
||||
avctx->block_align = wf->nBlockAlign;
|
||||
avctx->bits_per_coded_sample = wf->wBitsPerSample;
|
||||
|
||||
if (wf->cbSize > 0)
|
||||
mp_lavc_set_extradata(avctx, wf + 1, wf->cbSize);
|
||||
}
|
||||
|
||||
static int init(struct dec_audio *da, const char *decoder)
|
||||
{
|
||||
struct MPOpts *mpopts = da->opts;
|
||||
struct ad_lavc_params *opts = mpopts->ad_lavc_params;
|
||||
AVCodecContext *lavc_context;
|
||||
AVCodec *lavc_codec;
|
||||
struct mp_codec_params *c = da->codec;
|
||||
struct sh_stream *sh = da->header;
|
||||
struct sh_audio *sh_audio = sh->audio;
|
||||
|
||||
struct priv *ctx = talloc_zero(NULL, struct priv);
|
||||
da->priv = ctx;
|
||||
|
||||
ctx->codec_timebase = mp_get_codec_timebase(da->codec);
|
||||
|
||||
ctx->force_channel_map = c->force_channels;
|
||||
if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
|
||||
decoder = find_pcm_decoder(tag_map, sh->format,
|
||||
sh_audio->wf->wBitsPerSample);
|
||||
} else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
|
||||
decoder = find_pcm_decoder(af_map, sh->format, 0);
|
||||
ctx->force_channel_map = true;
|
||||
}
|
||||
|
||||
lavc_codec = avcodec_find_decoder_by_name(decoder);
|
||||
if (!lavc_codec) {
|
||||
@@ -104,41 +224,42 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
lavc_context->codec_id = lavc_codec->id;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MICRO >= 100
|
||||
lavc_context->pkt_timebase = ctx->codec_timebase;
|
||||
#endif
|
||||
|
||||
if (opts->downmix && mpopts->audio_output_channels.num_chmaps == 1) {
|
||||
if (opts->downmix) {
|
||||
lavc_context->request_channel_layout =
|
||||
mp_chmap_to_lavc(&mpopts->audio_output_channels.chmaps[0]);
|
||||
mp_chmap_to_lavc(&mpopts->audio_output_channels);
|
||||
}
|
||||
|
||||
// Always try to set - option only exists for AC3 at the moment
|
||||
av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc,
|
||||
AV_OPT_SEARCH_CHILDREN);
|
||||
|
||||
#if HAVE_AVFRAME_SKIP_SAMPLES
|
||||
// Let decoder add AV_FRAME_DATA_SKIP_SAMPLES.
|
||||
av_opt_set(lavc_context, "flags2", "+skip_manual", AV_OPT_SEARCH_CHILDREN);
|
||||
#endif
|
||||
if (opts->avopt) {
|
||||
if (parse_avopts(lavc_context, opts->avopt) < 0) {
|
||||
MP_ERR(da, "setting AVOptions '%s' failed.\n", opts->avopt);
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mp_set_avopts(da->log, lavc_context, opts->avopts);
|
||||
lavc_context->codec_tag = sh->format;
|
||||
lavc_context->sample_rate = sh_audio->samplerate;
|
||||
lavc_context->bit_rate = sh_audio->bitrate;
|
||||
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
|
||||
|
||||
lavc_context->codec_tag = c->codec_tag;
|
||||
lavc_context->sample_rate = c->samplerate;
|
||||
lavc_context->bit_rate = c->bitrate;
|
||||
lavc_context->block_align = c->block_align;
|
||||
lavc_context->bits_per_coded_sample = c->bits_per_coded_sample;
|
||||
lavc_context->channels = c->channels.num;
|
||||
if (!mp_chmap_is_unknown(&c->channels))
|
||||
lavc_context->channel_layout = mp_chmap_to_lavc(&c->channels);
|
||||
if (sh_audio->wf)
|
||||
set_from_wf(lavc_context, sh_audio->wf);
|
||||
|
||||
// demux_mkv
|
||||
mp_lavc_set_extradata(lavc_context, c->extradata, c->extradata_size);
|
||||
// demux_mkv, demux_mpg
|
||||
if (sh_audio->codecdata_len && sh_audio->codecdata &&
|
||||
!lavc_context->extradata) {
|
||||
mp_lavc_set_extradata(lavc_context, sh_audio->codecdata,
|
||||
sh_audio->codecdata_len);
|
||||
}
|
||||
|
||||
mp_set_lav_codec_headers(lavc_context, c);
|
||||
if (sh->lav_headers)
|
||||
mp_copy_lav_codec_headers(lavc_context, sh->lav_headers);
|
||||
|
||||
mp_set_avcodec_threads(da->log, lavc_context, opts->threads);
|
||||
mp_set_avcodec_threads(lavc_context, opts->threads);
|
||||
|
||||
/* open it */
|
||||
if (avcodec_open2(lavc_context, lavc_codec, NULL) < 0) {
|
||||
@@ -146,8 +267,27 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
MP_VERBOSE(da, "INFO: libavcodec \"%s\" init OK!\n",
|
||||
lavc_codec->name);
|
||||
|
||||
ctx->next_pts = MP_NOPTS_VALUE;
|
||||
// Decode at least 1 sample: (to get header filled)
|
||||
for (int tries = 1; ; tries++) {
|
||||
int x = decode_new_packet(da);
|
||||
if (x >= 0 && ctx->frame.samples > 0) {
|
||||
MP_VERBOSE(da, "Initial decode succeeded after %d packets.\n", tries);
|
||||
break;
|
||||
}
|
||||
if (tries >= 50) {
|
||||
MP_ERR(da, "initial decode failed\n");
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lavc_context->bit_rate != 0)
|
||||
da->bitrate = lavc_context->bit_rate;
|
||||
else if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
|
||||
da->bitrate = sh_audio->wf->nAvgBytesPerSec * 8;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -174,53 +314,40 @@ static int control(struct dec_audio *da, int cmd, void *arg)
|
||||
switch (cmd) {
|
||||
case ADCTRL_RESET:
|
||||
avcodec_flush_buffers(ctx->avctx);
|
||||
ctx->skip_samples = 0;
|
||||
ctx->trim_samples = 0;
|
||||
ctx->preroll_done = false;
|
||||
ctx->next_pts = MP_NOPTS_VALUE;
|
||||
ctx->needs_reset = false;
|
||||
ctx->frame.samples = 0;
|
||||
talloc_free(ctx->packet);
|
||||
ctx->packet = NULL;
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
|
||||
struct mp_audio **out)
|
||||
static int decode_new_packet(struct dec_audio *da)
|
||||
{
|
||||
struct priv *priv = da->priv;
|
||||
AVCodecContext *avctx = priv->avctx;
|
||||
|
||||
// If the decoder discards the timestamp for some reason, we use the
|
||||
// interpolated PTS. Initialize it so that it works for the initial
|
||||
// packet as well.
|
||||
if (mpkt && priv->next_pts == MP_NOPTS_VALUE)
|
||||
priv->next_pts = mpkt->pts;
|
||||
priv->frame.samples = 0;
|
||||
|
||||
struct demux_packet *mpkt = priv->packet;
|
||||
if (!mpkt)
|
||||
mpkt = demux_read_packet(da->header);
|
||||
|
||||
priv->packet = talloc_steal(priv, mpkt);
|
||||
|
||||
int in_len = mpkt ? mpkt->len : 0;
|
||||
|
||||
AVPacket pkt;
|
||||
mp_set_av_packet(&pkt, mpkt, &priv->codec_timebase);
|
||||
mp_set_av_packet(&pkt, mpkt, NULL);
|
||||
|
||||
// If we don't have a PTS yet, use the first packet PTS we can get.
|
||||
if (da->pts == MP_NOPTS_VALUE && mpkt && mpkt->pts != MP_NOPTS_VALUE) {
|
||||
da->pts = mpkt->pts;
|
||||
da->pts_offset = 0;
|
||||
}
|
||||
|
||||
int got_frame = 0;
|
||||
av_frame_unref(priv->avframe);
|
||||
|
||||
if (priv->needs_reset)
|
||||
control(da, ADCTRL_RESET, NULL);
|
||||
|
||||
#if HAVE_AVCODEC_NEW_CODEC_API
|
||||
int ret = avcodec_send_packet(avctx, &pkt);
|
||||
if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
if (ret >= 0 && mpkt)
|
||||
mpkt->len = 0;
|
||||
ret = avcodec_receive_frame(avctx, priv->avframe);
|
||||
if (ret >= 0)
|
||||
got_frame = 1;
|
||||
if (ret == AVERROR_EOF)
|
||||
priv->needs_reset = true;
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||
ret = 0;
|
||||
}
|
||||
#else
|
||||
int ret = avcodec_decode_audio4(avctx, priv->avframe, &got_frame, &pkt);
|
||||
if (mpkt) {
|
||||
// At least "shorten" decodes sub-frames, instead of the whole packet.
|
||||
@@ -231,82 +358,64 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
|
||||
mpkt->len -= ret;
|
||||
mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time
|
||||
}
|
||||
// LATM may need many packets to find mux info
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
mpkt->len = 0;
|
||||
return 0;
|
||||
if (mpkt->len == 0 || ret < 0) {
|
||||
talloc_free(mpkt);
|
||||
priv->packet = NULL;
|
||||
}
|
||||
// LATM may need many packets to find mux info
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
MP_ERR(da, "Error decoding audio.\n");
|
||||
MP_VERBOSE(da, "lavc_audio: error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!got_frame)
|
||||
return 0;
|
||||
return mpkt ? 0 : -1; // -1: eof
|
||||
|
||||
double out_pts = mp_pts_from_av(MP_AVFRAME_DEC_PTS(priv->avframe),
|
||||
&priv->codec_timebase);
|
||||
|
||||
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
|
||||
if (!mpframe)
|
||||
if (setup_format(da) < 0)
|
||||
return -1;
|
||||
|
||||
struct mp_chmap lavc_chmap = mpframe->channels;
|
||||
if (lavc_chmap.num != avctx->channels)
|
||||
mp_chmap_from_channels(&lavc_chmap, avctx->channels);
|
||||
if (priv->force_channel_map) {
|
||||
if (lavc_chmap.num == da->codec->channels.num)
|
||||
lavc_chmap = da->codec->channels;
|
||||
}
|
||||
mp_audio_set_channels(mpframe, &lavc_chmap);
|
||||
priv->frame.samples = priv->avframe->nb_samples;
|
||||
mp_audio_copy_config(&priv->frame, &da->decoded);
|
||||
for (int n = 0; n < priv->frame.num_planes; n++)
|
||||
priv->frame.planes[n] = priv->avframe->data[n];
|
||||
|
||||
mpframe->pts = out_pts;
|
||||
|
||||
if (mpframe->pts == MP_NOPTS_VALUE)
|
||||
mpframe->pts = priv->next_pts;
|
||||
if (mpframe->pts != MP_NOPTS_VALUE)
|
||||
priv->next_pts = mpframe->pts + mpframe->samples / (double)mpframe->rate;
|
||||
|
||||
#if HAVE_AVFRAME_SKIP_SAMPLES
|
||||
AVFrameSideData *sd =
|
||||
av_frame_get_side_data(priv->avframe, AV_FRAME_DATA_SKIP_SAMPLES);
|
||||
if (sd && sd->size >= 10) {
|
||||
char *d = sd->data;
|
||||
priv->skip_samples += AV_RL32(d + 0);
|
||||
priv->trim_samples += AV_RL32(d + 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!priv->preroll_done) {
|
||||
// Skip only if this isn't already handled by AV_FRAME_DATA_SKIP_SAMPLES.
|
||||
if (!priv->skip_samples)
|
||||
priv->skip_samples = avctx->delay;
|
||||
priv->preroll_done = true;
|
||||
double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, NULL);
|
||||
if (out_pts != MP_NOPTS_VALUE) {
|
||||
da->pts = out_pts;
|
||||
da->pts_offset = 0;
|
||||
}
|
||||
|
||||
uint32_t skip = MPMIN(priv->skip_samples, mpframe->samples);
|
||||
if (skip) {
|
||||
mp_audio_skip_samples(mpframe, skip);
|
||||
priv->skip_samples -= skip;
|
||||
}
|
||||
uint32_t trim = MPMIN(priv->trim_samples, mpframe->samples);
|
||||
if (trim) {
|
||||
mpframe->samples -= trim;
|
||||
priv->trim_samples -= trim;
|
||||
MP_DBG(da, "Decoded %d -> %d samples\n", in_len,
|
||||
priv->frame.samples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
|
||||
{
|
||||
struct priv *priv = da->priv;
|
||||
|
||||
if (!priv->frame.samples) {
|
||||
if (decode_new_packet(da) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = mpframe;
|
||||
if (!mp_audio_config_equals(buffer, &priv->frame))
|
||||
return 0;
|
||||
|
||||
av_frame_unref(priv->avframe);
|
||||
|
||||
MP_DBG(da, "Decoded %d -> %d samples\n", in_len, mpframe->samples);
|
||||
buffer->samples = MPMIN(priv->frame.samples, maxlen);
|
||||
mp_audio_copy(buffer, 0, &priv->frame, 0, buffer->samples);
|
||||
mp_audio_skip_samples(&priv->frame, buffer->samples);
|
||||
da->pts_offset += buffer->samples;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_decoders(struct mp_decoder_list *list)
|
||||
{
|
||||
mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
|
||||
mp_add_decoder(list, "lavc", "pcm", "pcm", "Raw PCM");
|
||||
mp_add_decoder(list, "lavc", "mp-pcm", "mp-pcm", "Raw PCM");
|
||||
}
|
||||
|
||||
const struct ad_functions ad_lavc = {
|
||||
@@ -315,5 +424,5 @@ const struct ad_functions ad_lavc = {
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode_packet = decode_packet,
|
||||
.decode_audio = decode_audio,
|
||||
};
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* MPEG 1.0/2.0/2.5 audio layer I, II, III decoding with libmpg123
|
||||
*
|
||||
* Copyright (C) 2010-2013 Thomas Orgis <thomas@orgis.org>
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ad.h"
|
||||
#include "common/msg.h"
|
||||
|
||||
#include <mpg123.h>
|
||||
|
||||
#if (defined MPG123_API_VERSION) && (MPG123_API_VERSION < 33)
|
||||
#error "This should not happen"
|
||||
#endif
|
||||
|
||||
struct ad_mpg123_context {
|
||||
mpg123_handle *handle;
|
||||
bool new_format;
|
||||
int sample_size;
|
||||
bool need_data;
|
||||
/* Running mean for bit rate, stream length estimation. */
|
||||
float mean_rate;
|
||||
unsigned int mean_count;
|
||||
/* Time delay for updates. */
|
||||
short delay;
|
||||
/* If the stream is actually VBR. */
|
||||
char vbr;
|
||||
};
|
||||
|
||||
static void uninit(struct dec_audio *da)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
|
||||
mpg123_close(con->handle);
|
||||
mpg123_delete(con->handle);
|
||||
mpg123_exit();
|
||||
}
|
||||
|
||||
/* This initializes libmpg123 and prepares the handle, including funky
|
||||
* parameters. */
|
||||
static int preinit(struct dec_audio *da)
|
||||
{
|
||||
int err;
|
||||
struct ad_mpg123_context *con;
|
||||
/* Assumption: You always call preinit + init + uninit, on every file.
|
||||
* But you stop at preinit in case it fails.
|
||||
* If that is not true, one must ensure not to call mpg123_init / exit
|
||||
* twice in a row. */
|
||||
if (mpg123_init() != MPG123_OK)
|
||||
return 0;
|
||||
|
||||
da->priv = talloc_zero(NULL, struct ad_mpg123_context);
|
||||
con = da->priv;
|
||||
/* Auto-choice of optimized decoder (first argument NULL). */
|
||||
con->handle = mpg123_new(NULL, &err);
|
||||
if (!con->handle)
|
||||
goto bad_end;
|
||||
|
||||
/* Basic settings.
|
||||
* Don't spill messages, enable better resync with non-seekable streams.
|
||||
* Give both flags individually without error checking to keep going with
|
||||
* old libmpg123. Generally, it is not fatal if the flags are not
|
||||
* honored */
|
||||
mpg123_param(con->handle, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0);
|
||||
/* Do not bail out on malformed streams at all.
|
||||
* MPlayer does not handle a decoder throwing the towel on crappy input. */
|
||||
mpg123_param(con->handle, MPG123_RESYNC_LIMIT, -1, 0.0);
|
||||
|
||||
/* Open decisions: Configure libmpg123 to force encoding (or stay open about
|
||||
* library builds that support only float or int32 output), (de)configure
|
||||
* gapless decoding (won't work with seeking in MPlayer, though).
|
||||
* Don't forget to eventually enable ReplayGain/RVA support, too.
|
||||
* Let's try to run with the default for now. */
|
||||
|
||||
/* That would produce floating point output.
|
||||
* You can get 32 and 24 bit ints, even 8 bit via format matrix.
|
||||
* If wanting a specific encoding here, configure format matrix and
|
||||
* make sure it is in set_format(). */
|
||||
/* mpg123_param(con->handle, MPG123_ADD_FLAGS, MPG123_FORCE_FLOAT, 0.); */
|
||||
|
||||
/* Example for RVA choice (available since libmpg123 1.0.0):
|
||||
mpg123_param(con->handle, MPG123_RVA, MPG123_RVA_MIX, 0.0) */
|
||||
|
||||
/* Prevent funky automatic resampling.
|
||||
* This way, we can be sure that one frame will never produce
|
||||
* more than 1152 stereo samples.
|
||||
* Background:
|
||||
* Going to decode directly to the output buffer. It is important to have
|
||||
* MPG123_AUTO_RESAMPLE disabled for the buffer size being an all-time
|
||||
* limit.
|
||||
* We need at least 1152 samples. dec_audio.c normally guarantees this. */
|
||||
mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.);
|
||||
|
||||
return 1;
|
||||
|
||||
bad_end:
|
||||
if (!con->handle)
|
||||
MP_ERR(da, "mpg123 preinit error: %s\n",
|
||||
mpg123_plain_strerror(err));
|
||||
else
|
||||
MP_ERR(da, "mpg123 preinit error: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpg123_format_to_af(int mpg123_encoding)
|
||||
{
|
||||
/* Without external force, mpg123 will always choose signed encoding,
|
||||
* and non-16-bit only on builds that don't support it.
|
||||
* Be reminded that it doesn't matter to the MPEG file what encoding
|
||||
* is produced from it. */
|
||||
switch (mpg123_encoding) {
|
||||
case MPG123_ENC_SIGNED_8: return AF_FORMAT_S8;
|
||||
case MPG123_ENC_SIGNED_16: return AF_FORMAT_S16;
|
||||
case MPG123_ENC_SIGNED_32: return AF_FORMAT_S32;
|
||||
case MPG123_ENC_FLOAT_32: return AF_FORMAT_FLOAT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* libmpg123 has a new format ready; query and store, return return value
|
||||
of mpg123_getformat() */
|
||||
static int set_format(struct dec_audio *da)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
int ret;
|
||||
long rate;
|
||||
int channels;
|
||||
int encoding;
|
||||
ret = mpg123_getformat(con->handle, &rate, &channels, &encoding);
|
||||
if (ret == MPG123_OK) {
|
||||
mp_audio_set_num_channels(&da->decoded, channels);
|
||||
da->decoded.rate = rate;
|
||||
int af = mpg123_format_to_af(encoding);
|
||||
if (!af) {
|
||||
/* This means we got a funny custom build of libmpg123 that only supports an unknown format. */
|
||||
MP_ERR(da, "Bad encoding from mpg123: %i.\n", encoding);
|
||||
return MPG123_ERR;
|
||||
}
|
||||
mp_audio_set_format(&da->decoded, af);
|
||||
con->sample_size = channels * af_fmt2bps(af);
|
||||
con->new_format = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int feed_new_packet(struct dec_audio *da)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
int ret;
|
||||
|
||||
struct demux_packet *pkt = demux_read_packet(da->header);
|
||||
if (!pkt)
|
||||
return -1; /* EOF. */
|
||||
|
||||
/* Next bytes from that presentation time. */
|
||||
if (pkt->pts != MP_NOPTS_VALUE) {
|
||||
da->pts = pkt->pts;
|
||||
da->pts_offset = 0;
|
||||
}
|
||||
|
||||
/* Have to use mpg123_feed() to avoid decoding here. */
|
||||
ret = mpg123_feed(con->handle, pkt->buffer, pkt->len);
|
||||
talloc_free(pkt);
|
||||
|
||||
if (ret == MPG123_ERR)
|
||||
return -1;
|
||||
|
||||
if (ret == MPG123_NEW_FORMAT)
|
||||
con->new_format = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now we really start accessing some data and determining file format.
|
||||
* Format now is allowed to change on-the-fly. Here is the only point
|
||||
* that has MPlayer react to errors. We have to pray that exceptional
|
||||
* erros in other places simply cannot occur. */
|
||||
static int init(struct dec_audio *da, const char *decoder)
|
||||
{
|
||||
if (!preinit(da))
|
||||
return 0;
|
||||
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
int ret;
|
||||
|
||||
ret = mpg123_open_feed(con->handle);
|
||||
if (ret != MPG123_OK)
|
||||
goto fail;
|
||||
|
||||
for (int n = 0; ; n++) {
|
||||
if (feed_new_packet(da) < 0) {
|
||||
ret = MPG123_NEED_MORE;
|
||||
goto fail;
|
||||
}
|
||||
size_t got_now = 0;
|
||||
ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);
|
||||
if (ret == MPG123_OK || ret == MPG123_NEW_FORMAT) {
|
||||
ret = set_format(da);
|
||||
if (ret == MPG123_OK)
|
||||
break;
|
||||
}
|
||||
if (ret != MPG123_NEED_MORE)
|
||||
goto fail;
|
||||
// max. 16 retries (randomly chosen number)
|
||||
if (n > 16) {
|
||||
ret = MPG123_NEED_MORE;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (ret == MPG123_NEED_MORE) {
|
||||
MP_ERR(da, "Could not find mp3 stream.\n");
|
||||
} else {
|
||||
MP_ERR(da, "mpg123 init error: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
}
|
||||
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute bitrate from frame size. */
|
||||
static int compute_bitrate(struct mpg123_frameinfo *i)
|
||||
{
|
||||
static const int samples_per_frame[4][4] = {
|
||||
{-1, 384, 1152, 1152}, /* MPEG 1 */
|
||||
{-1, 384, 1152, 576}, /* MPEG 2 */
|
||||
{-1, 384, 1152, 576}, /* MPEG 2.5 */
|
||||
{-1, -1, -1, -1}, /* Unknown */
|
||||
};
|
||||
return (int) ((i->framesize + 4) * 8 * i->rate /
|
||||
samples_per_frame[i->version][i->layer] + 0.5);
|
||||
}
|
||||
|
||||
/* Update mean bitrate. This could be dropped if accurate time display
|
||||
* on audio file playback is not desired. */
|
||||
static void update_info(struct dec_audio *da)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
struct mpg123_frameinfo finfo;
|
||||
if (mpg123_info(con->handle, &finfo) != MPG123_OK)
|
||||
return;
|
||||
|
||||
/* finfo.bitrate is expressed in kilobits */
|
||||
const int bitrate = finfo.bitrate * 1000;
|
||||
|
||||
if (finfo.vbr != MPG123_CBR) {
|
||||
if (--con->delay < 1) {
|
||||
if (++con->mean_count > ((unsigned int) -1) / 2)
|
||||
con->mean_count = ((unsigned int) -1) / 4;
|
||||
|
||||
/* Might not be numerically optimal, but works fine enough. */
|
||||
con->mean_rate = ((con->mean_count - 1) * con->mean_rate +
|
||||
bitrate) / con->mean_count;
|
||||
da->bitrate = (int) (con->mean_rate + 0.5);
|
||||
|
||||
con->delay = 10;
|
||||
}
|
||||
} else {
|
||||
da->bitrate = bitrate ? bitrate : compute_bitrate(&finfo);
|
||||
con->delay = 1;
|
||||
con->mean_rate = 0.;
|
||||
con->mean_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
void *buf = buffer->planes[0];
|
||||
int ret;
|
||||
|
||||
if (con->new_format) {
|
||||
ret = set_format(da);
|
||||
if (ret == MPG123_OK) {
|
||||
return 0; // let caller handle format change
|
||||
} else if (ret == MPG123_NEED_MORE) {
|
||||
con->need_data = true;
|
||||
} else {
|
||||
goto mpg123_fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (con->need_data) {
|
||||
if (feed_new_packet(da) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mp_audio_config_equals(&da->decoded, buffer))
|
||||
return 0;
|
||||
|
||||
size_t got_now = 0;
|
||||
ret = mpg123_replace_buffer(con->handle, buf, maxlen * con->sample_size);
|
||||
if (ret != MPG123_OK)
|
||||
goto mpg123_fail;
|
||||
|
||||
ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);
|
||||
|
||||
int got_samples = got_now / con->sample_size;
|
||||
buffer->samples += got_samples;
|
||||
da->pts_offset += got_samples;
|
||||
|
||||
if (ret == MPG123_NEW_FORMAT) {
|
||||
con->new_format = true;
|
||||
} else if (ret == MPG123_NEED_MORE) {
|
||||
con->need_data = true;
|
||||
} else if (ret != MPG123_OK && ret != MPG123_DONE) {
|
||||
goto mpg123_fail;
|
||||
}
|
||||
|
||||
update_info(da);
|
||||
return 0;
|
||||
|
||||
mpg123_fail:
|
||||
MP_ERR(da, "mpg123 decoding error: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int control(struct dec_audio *da, int cmd, void *arg)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case ADCTRL_RESET:
|
||||
mpg123_close(con->handle);
|
||||
|
||||
if (mpg123_open_feed(con->handle) != MPG123_OK) {
|
||||
MP_ERR(da, "mpg123 failed to reopen stream: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
static void add_decoders(struct mp_decoder_list *list)
|
||||
{
|
||||
mp_add_decoder(list, "mpg123", "mp3", "mp3",
|
||||
"High-performance decoder using libmpg123");
|
||||
}
|
||||
|
||||
const struct ad_functions ad_mpg123 = {
|
||||
.name = "mpg123",
|
||||
.add_decoders = add_decoders,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode_audio = decode_audio,
|
||||
};
|
||||
+61
-132
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* Copyright (C) 2012 Naoya OYAMA
|
||||
*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -34,21 +35,19 @@
|
||||
|
||||
struct spdifContext {
|
||||
struct mp_log *log;
|
||||
enum AVCodecID codec_id;
|
||||
AVFormatContext *lavf_ctx;
|
||||
int iec61937_packet_size;
|
||||
int out_buffer_len;
|
||||
uint8_t out_buffer[OUTBUF_SIZE];
|
||||
int out_buffer_size;
|
||||
uint8_t *out_buffer;
|
||||
bool need_close;
|
||||
bool use_dts_hd;
|
||||
struct mp_audio fmt;
|
||||
struct mp_audio_pool *pool;
|
||||
};
|
||||
|
||||
static int write_packet(void *p, uint8_t *buf, int buf_size)
|
||||
{
|
||||
struct spdifContext *ctx = p;
|
||||
|
||||
int buffer_left = OUTBUF_SIZE - ctx->out_buffer_len;
|
||||
int buffer_left = ctx->out_buffer_size - ctx->out_buffer_len;
|
||||
if (buf_size > buffer_left) {
|
||||
MP_ERR(ctx, "spdif packet too large.\n");
|
||||
buf_size = buffer_left;
|
||||
@@ -79,86 +78,17 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
struct spdifContext *spdif_ctx = talloc_zero(NULL, struct spdifContext);
|
||||
da->priv = spdif_ctx;
|
||||
spdif_ctx->log = da->log;
|
||||
spdif_ctx->use_dts_hd = da->opts->dtshd;
|
||||
spdif_ctx->pool = mp_audio_pool_create(spdif_ctx);
|
||||
|
||||
if (strcmp(decoder, "dts-hd") == 0) {
|
||||
decoder = "dts";
|
||||
spdif_ctx->use_dts_hd = true;
|
||||
}
|
||||
|
||||
spdif_ctx->codec_id = mp_codec_to_av_codec_id(decoder);
|
||||
return spdif_ctx->codec_id != AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
static int determine_codec_profile(struct dec_audio *da, AVPacket *pkt)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = da->priv;
|
||||
int profile = FF_PROFILE_UNKNOWN;
|
||||
AVCodecContext *ctx = NULL;
|
||||
AVFrame *frame = NULL;
|
||||
|
||||
AVCodec *codec = avcodec_find_decoder(spdif_ctx->codec_id);
|
||||
if (!codec)
|
||||
goto done;
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
goto done;
|
||||
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
if (!ctx)
|
||||
goto done;
|
||||
|
||||
if (avcodec_open2(ctx, codec, NULL) < 0) {
|
||||
av_free(ctx); // don't attempt to avcodec_close() an unopened ctx
|
||||
ctx = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if HAVE_AVCODEC_NEW_CODEC_API
|
||||
if (avcodec_send_packet(ctx, pkt) < 0)
|
||||
goto done;
|
||||
if (avcodec_receive_frame(ctx, frame) < 0)
|
||||
goto done;
|
||||
#else
|
||||
int got_frame = 0;
|
||||
if (avcodec_decode_audio4(ctx, frame, &got_frame, pkt) < 1 || !got_frame)
|
||||
goto done;
|
||||
#endif
|
||||
|
||||
profile = ctx->profile;
|
||||
|
||||
done:
|
||||
av_frame_free(&frame);
|
||||
if (ctx)
|
||||
avcodec_close(ctx);
|
||||
avcodec_free_context(&ctx);
|
||||
|
||||
if (profile == FF_PROFILE_UNKNOWN)
|
||||
MP_WARN(da, "Failed to parse codec profile.\n");
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
static int init_filter(struct dec_audio *da, AVPacket *pkt)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = da->priv;
|
||||
|
||||
int profile = FF_PROFILE_UNKNOWN;
|
||||
if (spdif_ctx->codec_id == AV_CODEC_ID_DTS)
|
||||
profile = determine_codec_profile(da, pkt);
|
||||
|
||||
AVFormatContext *lavf_ctx = avformat_alloc_context();
|
||||
if (!lavf_ctx)
|
||||
goto fail;
|
||||
|
||||
spdif_ctx->lavf_ctx = lavf_ctx;
|
||||
|
||||
lavf_ctx->oformat = av_guess_format("spdif", NULL, NULL);
|
||||
if (!lavf_ctx->oformat)
|
||||
goto fail;
|
||||
|
||||
spdif_ctx->lavf_ctx = lavf_ctx;
|
||||
|
||||
void *buffer = av_mallocz(OUTBUF_SIZE);
|
||||
if (!buffer)
|
||||
abort();
|
||||
@@ -178,65 +108,64 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt)
|
||||
if (!stream)
|
||||
goto fail;
|
||||
|
||||
#if HAVE_AVCODEC_HAS_CODECPAR
|
||||
stream->codecpar->codec_id = spdif_ctx->codec_id;
|
||||
#else
|
||||
stream->codec->codec_id = spdif_ctx->codec_id;
|
||||
#endif
|
||||
stream->codec->codec_id = mp_codec_to_av_codec_id(decoder);
|
||||
|
||||
AVDictionary *format_opts = NULL;
|
||||
|
||||
int num_channels = 0;
|
||||
int sample_format = 0;
|
||||
int samplerate = 0;
|
||||
switch (spdif_ctx->codec_id) {
|
||||
switch (stream->codec->codec_id) {
|
||||
case AV_CODEC_ID_AAC:
|
||||
sample_format = AF_FORMAT_S_AAC;
|
||||
spdif_ctx->iec61937_packet_size = 16384;
|
||||
sample_format = AF_FORMAT_IEC61937_LE;
|
||||
samplerate = 48000;
|
||||
num_channels = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_AC3:
|
||||
sample_format = AF_FORMAT_S_AC3;
|
||||
spdif_ctx->iec61937_packet_size = 6144;
|
||||
sample_format = AF_FORMAT_AC3_LE;
|
||||
samplerate = 48000;
|
||||
num_channels = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_DTS: {
|
||||
bool is_hd = profile == FF_PROFILE_DTS_HD_HRA ||
|
||||
profile == FF_PROFILE_DTS_HD_MA ||
|
||||
profile == FF_PROFILE_UNKNOWN;
|
||||
if (spdif_ctx->use_dts_hd && is_hd) {
|
||||
case AV_CODEC_ID_DTS:
|
||||
if (da->opts->dtshd) {
|
||||
av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
|
||||
sample_format = AF_FORMAT_S_DTSHD;
|
||||
samplerate = 192000;
|
||||
num_channels = 2*4;
|
||||
spdif_ctx->iec61937_packet_size = 32768;
|
||||
sample_format = AF_FORMAT_IEC61937_LE;
|
||||
samplerate = 192000;
|
||||
num_channels = 2*4;
|
||||
} else {
|
||||
sample_format = AF_FORMAT_S_DTS;
|
||||
samplerate = 48000;
|
||||
num_channels = 2;
|
||||
spdif_ctx->iec61937_packet_size = 32768;
|
||||
sample_format = AF_FORMAT_AC3_LE;
|
||||
samplerate = 48000;
|
||||
num_channels = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AV_CODEC_ID_EAC3:
|
||||
sample_format = AF_FORMAT_S_EAC3;
|
||||
spdif_ctx->iec61937_packet_size = 24576;
|
||||
sample_format = AF_FORMAT_IEC61937_LE;
|
||||
samplerate = 192000;
|
||||
num_channels = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_MP3:
|
||||
sample_format = AF_FORMAT_S_MP3;
|
||||
spdif_ctx->iec61937_packet_size = 4608;
|
||||
sample_format = AF_FORMAT_MPEG2;
|
||||
samplerate = 48000;
|
||||
num_channels = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_TRUEHD:
|
||||
sample_format = AF_FORMAT_S_TRUEHD;
|
||||
spdif_ctx->iec61937_packet_size = 61440;
|
||||
sample_format = AF_FORMAT_IEC61937_LE;
|
||||
samplerate = 192000;
|
||||
num_channels = 8;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
mp_audio_set_num_channels(&spdif_ctx->fmt, num_channels);
|
||||
mp_audio_set_format(&spdif_ctx->fmt, sample_format);
|
||||
spdif_ctx->fmt.rate = samplerate;
|
||||
mp_audio_set_num_channels(&da->decoded, num_channels);
|
||||
mp_audio_set_format(&da->decoded, sample_format);
|
||||
da->decoded.rate = samplerate;
|
||||
|
||||
if (avformat_write_header(lavf_ctx, &format_opts) < 0) {
|
||||
MP_FATAL(da, "libavformat spdif initialization failed.\n");
|
||||
@@ -247,46 +176,48 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt)
|
||||
|
||||
spdif_ctx->need_close = true;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
uninit(da);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
|
||||
struct mp_audio **out)
|
||||
static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxlen)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = da->priv;
|
||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
||||
|
||||
spdif_ctx->out_buffer_len = 0;
|
||||
int sstride = 2 * da->decoded.channels.num;
|
||||
assert(sstride == buffer->sstride);
|
||||
|
||||
if (!mpkt)
|
||||
if (maxlen * sstride < spdif_ctx->iec61937_packet_size)
|
||||
return 0;
|
||||
|
||||
double pts = mpkt->pts;
|
||||
spdif_ctx->out_buffer_len = 0;
|
||||
spdif_ctx->out_buffer_size = maxlen * sstride;
|
||||
spdif_ctx->out_buffer = buffer->planes[0];
|
||||
|
||||
struct demux_packet *mpkt = demux_read_packet(da->header);
|
||||
if (!mpkt)
|
||||
return -1;
|
||||
|
||||
AVPacket pkt;
|
||||
mp_set_av_packet(&pkt, mpkt, NULL);
|
||||
mpkt->len = 0; // will be fully consumed
|
||||
pkt.pts = pkt.dts = 0;
|
||||
if (!spdif_ctx->lavf_ctx) {
|
||||
if (init_filter(da, &pkt) < 0)
|
||||
return -1;
|
||||
MP_VERBOSE(da, "spdif packet, size=%d\n", pkt.size);
|
||||
if (mpkt->pts != MP_NOPTS_VALUE) {
|
||||
da->pts = mpkt->pts;
|
||||
da->pts_offset = 0;
|
||||
}
|
||||
int ret = av_write_frame(spdif_ctx->lavf_ctx, &pkt);
|
||||
avio_flush(spdif_ctx->lavf_ctx->pb);
|
||||
int ret = av_write_frame(lavf_ctx, &pkt);
|
||||
avio_flush(lavf_ctx->pb);
|
||||
buffer->samples = spdif_ctx->out_buffer_len / sstride;
|
||||
da->pts_offset += buffer->samples;
|
||||
talloc_free(mpkt);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
int samples = spdif_ctx->out_buffer_len / spdif_ctx->fmt.sstride;
|
||||
*out = mp_audio_pool_get(spdif_ctx->pool, &spdif_ctx->fmt, samples);
|
||||
if (!*out)
|
||||
return -1;
|
||||
|
||||
memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
|
||||
(*out)->pts = pts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -314,8 +245,6 @@ static void add_decoders(struct mp_decoder_list *list)
|
||||
"libavformat/spdifenc audio pass-through decoder");
|
||||
}
|
||||
}
|
||||
mp_add_decoder(list, "spdif", "dts", "dts-hd",
|
||||
"libavformat/spdifenc audio pass-through decoder");
|
||||
}
|
||||
|
||||
const struct ad_functions ad_spdif = {
|
||||
@@ -324,5 +253,5 @@ const struct ad_functions ad_spdif = {
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode_packet = decode_packet,
|
||||
.decode_audio = decode_audio,
|
||||
};
|
||||
+217
-150
@@ -1,33 +1,34 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/mem.h>
|
||||
|
||||
#include "demux/codec_tags.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "common/codecs.h"
|
||||
#include "common/msg.h"
|
||||
#include "misc/bstr.h"
|
||||
#include "bstr/bstr.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demux/demux.h"
|
||||
@@ -42,18 +43,42 @@
|
||||
|
||||
#include "audio/filter/af.h"
|
||||
|
||||
extern const struct ad_functions ad_mpg123;
|
||||
extern const struct ad_functions ad_lavc;
|
||||
extern const struct ad_functions ad_spdif;
|
||||
|
||||
static const struct ad_functions * const ad_drivers[] = {
|
||||
#if HAVE_MPG123
|
||||
&ad_mpg123,
|
||||
#endif
|
||||
&ad_lavc,
|
||||
&ad_spdif,
|
||||
NULL
|
||||
};
|
||||
|
||||
// ad_mpg123 needs to be able to decode 1152 samples at once
|
||||
// ad_spdif needs up to 8192
|
||||
#define DECODE_MAX_UNIT MPMAX(8192, 1152)
|
||||
|
||||
// At least 8192 samples, plus hack for ad_mpg123 and ad_spdif
|
||||
#define DECODE_BUFFER_SAMPLES (8192 + DECODE_MAX_UNIT)
|
||||
|
||||
// Drop audio buffer and reinit it (after format change)
|
||||
// Returns whether the format was valid at all.
|
||||
static bool reinit_audio_buffer(struct dec_audio *da)
|
||||
{
|
||||
if (!mp_audio_config_valid(&da->decoded)) {
|
||||
MP_ERR(da, "Audio decoder did not specify audio "
|
||||
"format, or requested an unsupported configuration!\n");
|
||||
return false;
|
||||
}
|
||||
mp_audio_buffer_reinit(da->decode_buffer, &da->decoded);
|
||||
mp_audio_buffer_preallocate_min(da->decode_buffer, DECODE_BUFFER_SAMPLES);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void uninit_decoder(struct dec_audio *d_audio)
|
||||
{
|
||||
audio_reset_decoding(d_audio);
|
||||
if (d_audio->ad_driver) {
|
||||
MP_VERBOSE(d_audio, "Uninit audio decoder.\n");
|
||||
d_audio->ad_driver->uninit(d_audio);
|
||||
@@ -72,6 +97,12 @@ static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_audio->decode_buffer = mp_audio_buffer_create(NULL);
|
||||
if (!reinit_audio_buffer(d_audio)) {
|
||||
uninit_decoder(d_audio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -83,21 +114,11 @@ struct mp_decoder_list *audio_decoder_list(void)
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio)
|
||||
static struct mp_decoder_list *audio_select_decoders(const char *codec,
|
||||
char *selection)
|
||||
{
|
||||
struct MPOpts *opts = d_audio->opts;
|
||||
const char *codec = d_audio->codec->codec;
|
||||
|
||||
struct mp_decoder_list *list = audio_decoder_list();
|
||||
struct mp_decoder_list *new =
|
||||
mp_select_decoders(list, codec, opts->audio_decoders);
|
||||
if (d_audio->try_spdif) {
|
||||
struct mp_decoder_list *spdif =
|
||||
mp_select_decoder_list(list, codec, "spdif", opts->audio_spdif);
|
||||
mp_append_decoders(spdif, new);
|
||||
talloc_free(new);
|
||||
new = spdif;
|
||||
}
|
||||
struct mp_decoder_list *new = mp_select_decoders(list, codec, selection);
|
||||
talloc_free(list);
|
||||
return new;
|
||||
}
|
||||
@@ -111,13 +132,14 @@ static const struct ad_functions *find_driver(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int audio_init_best_codec(struct dec_audio *d_audio)
|
||||
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
|
||||
{
|
||||
uninit_decoder(d_audio);
|
||||
assert(!d_audio->ad_driver);
|
||||
audio_reset_decoding(d_audio);
|
||||
|
||||
struct mp_decoder_entry *decoder = NULL;
|
||||
struct mp_decoder_list *list = audio_select_decoders(d_audio);
|
||||
struct mp_decoder_list *list =
|
||||
audio_select_decoders(d_audio->header->codec, audio_decoders);
|
||||
|
||||
mp_print_decoders(d_audio->log, MSGL_V, "Codec list:", list);
|
||||
|
||||
@@ -142,9 +164,12 @@ int audio_init_best_codec(struct dec_audio *d_audio)
|
||||
talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
|
||||
decoder->decoder);
|
||||
MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
|
||||
MP_VERBOSE(d_audio, "AUDIO: %d Hz, %d ch, %s\n",
|
||||
d_audio->decoded.rate, d_audio->decoded.channels.num,
|
||||
af_fmt_to_str(d_audio->decoded.format));
|
||||
} else {
|
||||
MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
|
||||
d_audio->codec->codec);
|
||||
d_audio->header->codec ? d_audio->header->codec : "<unknown>");
|
||||
}
|
||||
|
||||
talloc_free(list);
|
||||
@@ -155,139 +180,181 @@ void audio_uninit(struct dec_audio *d_audio)
|
||||
{
|
||||
if (!d_audio)
|
||||
return;
|
||||
if (d_audio->afilter) {
|
||||
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
|
||||
af_destroy(d_audio->afilter);
|
||||
d_audio->afilter = NULL;
|
||||
}
|
||||
uninit_decoder(d_audio);
|
||||
talloc_free(d_audio->decode_buffer);
|
||||
talloc_free(d_audio);
|
||||
}
|
||||
|
||||
|
||||
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
|
||||
int *out_samplerate, struct mp_chmap *out_channels,
|
||||
int *out_format)
|
||||
{
|
||||
if (!d_audio->afilter)
|
||||
d_audio->afilter = af_new(d_audio->global);
|
||||
struct af_stream *afs = d_audio->afilter;
|
||||
|
||||
// input format: same as codec's output format:
|
||||
mp_audio_buffer_get_format(d_audio->decode_buffer, &afs->input);
|
||||
// Sample rate can be different when adjusting playback speed
|
||||
afs->input.rate = in_samplerate;
|
||||
|
||||
// output format: same as ao driver's input format (if missing, fallback to input)
|
||||
afs->output.rate = *out_samplerate;
|
||||
mp_audio_set_channels(&afs->output, out_channels);
|
||||
mp_audio_set_format(&afs->output, *out_format);
|
||||
|
||||
afs->metadata = d_audio->metadata;
|
||||
|
||||
afs->replaygain_data = d_audio->replaygain_data;
|
||||
|
||||
char *s_from = mp_audio_config_to_str(&afs->input);
|
||||
char *s_to = mp_audio_config_to_str(&afs->output);
|
||||
MP_VERBOSE(d_audio, "Building audio filter chain for %s -> %s...\n", s_from, s_to);
|
||||
talloc_free(s_from);
|
||||
talloc_free(s_to);
|
||||
|
||||
// let's autoprobe it!
|
||||
if (af_init(afs) != 0) {
|
||||
af_destroy(afs);
|
||||
d_audio->afilter = NULL;
|
||||
return 0; // failed :(
|
||||
}
|
||||
|
||||
*out_samplerate = afs->output.rate;
|
||||
*out_channels = afs->output.channels;
|
||||
*out_format = afs->output.format;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Filter len bytes of input, put result into outbuf.
|
||||
static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
|
||||
int len)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
struct mp_audio config;
|
||||
mp_audio_buffer_get_format(da->decode_buffer, &config);
|
||||
|
||||
while (mp_audio_buffer_samples(da->decode_buffer) < len) {
|
||||
int maxlen = mp_audio_buffer_get_write_available(da->decode_buffer);
|
||||
if (maxlen < DECODE_MAX_UNIT)
|
||||
break;
|
||||
struct mp_audio buffer;
|
||||
mp_audio_buffer_get_write_buffer(da->decode_buffer, maxlen, &buffer);
|
||||
buffer.samples = 0;
|
||||
error = da->ad_driver->decode_audio(da, &buffer, maxlen);
|
||||
if (error < 0)
|
||||
break;
|
||||
// Commit the data just read as valid data
|
||||
mp_audio_buffer_finish_write(da->decode_buffer, buffer.samples);
|
||||
// Format change
|
||||
if (!mp_audio_config_equals(&da->decoded, &config)) {
|
||||
// If there are still samples left in the buffer, let them drain
|
||||
// first, and don't signal a format change to the caller yet.
|
||||
if (mp_audio_buffer_samples(da->decode_buffer) > 0)
|
||||
break;
|
||||
error = -2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter
|
||||
struct mp_audio filter_data;
|
||||
mp_audio_buffer_peek(da->decode_buffer, &filter_data);
|
||||
filter_data.rate = da->afilter->input.rate; // due to playback speed change
|
||||
len = MPMIN(filter_data.samples, len);
|
||||
filter_data.samples = len;
|
||||
bool eof = filter_data.samples == 0 && error < 0;
|
||||
|
||||
if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0)
|
||||
return -1;
|
||||
|
||||
mp_audio_buffer_append(outbuf, &filter_data);
|
||||
if (eof && filter_data.samples > 0)
|
||||
error = 0; // don't end playback yet
|
||||
|
||||
// remove processed data from decoder buffer:
|
||||
mp_audio_buffer_skip(da->decode_buffer, len);
|
||||
|
||||
// Assume the filter chain is drained from old data at this point.
|
||||
// (If not, the remaining old data is discarded.)
|
||||
if (error == -2) {
|
||||
if (!reinit_audio_buffer(da))
|
||||
error = -1; // switch to invalid format
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Try to get at least minsamples decoded+filtered samples in outbuf
|
||||
* (total length including possible existing data).
|
||||
* Return 0 on success, -1 on error/EOF (not distinguidaed).
|
||||
* In the former case outbuf has at least minsamples buffered on return.
|
||||
* In case of EOF/error it might or might not be. */
|
||||
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
|
||||
int minsamples)
|
||||
{
|
||||
// Indicates that a filter seems to be buffering large amounts of data
|
||||
int huge_filter_buffer = 0;
|
||||
// Decoded audio must be cut at boundaries of this many samples
|
||||
// (Note: the reason for this is unknown, possibly a refactoring artifact)
|
||||
int unitsize = 16;
|
||||
|
||||
/* Filter output size will be about filter_multiplier times input size.
|
||||
* If some filter buffers audio in big blocks this might only hold
|
||||
* as average over time. */
|
||||
double filter_multiplier = af_calc_filter_multiplier(d_audio->afilter);
|
||||
|
||||
int prev_buffered = -1;
|
||||
int res = 0;
|
||||
MP_STATS(d_audio, "start audio");
|
||||
while (res >= 0 && minsamples >= 0) {
|
||||
int buffered = mp_audio_buffer_samples(outbuf);
|
||||
if (minsamples < buffered || buffered == prev_buffered)
|
||||
break;
|
||||
prev_buffered = buffered;
|
||||
|
||||
int decsamples = (minsamples - buffered) / filter_multiplier;
|
||||
// + some extra for possible filter buffering
|
||||
decsamples += unitsize << 5;
|
||||
|
||||
if (huge_filter_buffer) {
|
||||
/* Some filter must be doing significant buffering if the estimated
|
||||
* input length didn't produce enough output from filters.
|
||||
* Feed the filters 250 samples at a time until we have enough
|
||||
* output. Very small amounts could make filtering inefficient while
|
||||
* large amounts can make mpv demux the file unnecessarily far ahead
|
||||
* to get audio data and buffer video frames in memory while doing
|
||||
* so. However the performance impact of either is probably not too
|
||||
* significant as long as the value is not completely insane. */
|
||||
decsamples = 250;
|
||||
}
|
||||
|
||||
/* if this iteration does not fill buffer, we must have lots
|
||||
* of buffering in filters */
|
||||
huge_filter_buffer = 1;
|
||||
|
||||
res = filter_n_bytes(d_audio, outbuf, decsamples);
|
||||
}
|
||||
MP_STATS(d_audio, "end audio");
|
||||
return res;
|
||||
}
|
||||
|
||||
void audio_reset_decoding(struct dec_audio *d_audio)
|
||||
{
|
||||
if (d_audio->ad_driver)
|
||||
d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
|
||||
if (d_audio->afilter)
|
||||
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
|
||||
d_audio->pts = MP_NOPTS_VALUE;
|
||||
talloc_free(d_audio->current_frame);
|
||||
d_audio->current_frame = NULL;
|
||||
talloc_free(d_audio->packet);
|
||||
d_audio->packet = NULL;
|
||||
talloc_free(d_audio->new_segment);
|
||||
d_audio->new_segment = NULL;
|
||||
d_audio->start = d_audio->end = MP_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
static void fix_audio_pts(struct dec_audio *da)
|
||||
{
|
||||
if (!da->current_frame)
|
||||
return;
|
||||
|
||||
if (da->current_frame->pts != MP_NOPTS_VALUE) {
|
||||
double newpts = da->current_frame->pts;
|
||||
|
||||
if (da->pts != MP_NOPTS_VALUE)
|
||||
MP_STATS(da, "value %f audio-pts-err", da->pts - newpts);
|
||||
|
||||
// Keep the interpolated timestamp if it doesn't deviate more
|
||||
// than 1 ms from the real one. (MKV rounded timestamps.)
|
||||
if (da->pts == MP_NOPTS_VALUE || fabs(da->pts - newpts) > 0.001)
|
||||
da->pts = newpts;
|
||||
}
|
||||
|
||||
if (da->pts == MP_NOPTS_VALUE && da->header->missing_timestamps)
|
||||
da->pts = 0;
|
||||
|
||||
da->current_frame->pts = da->pts;
|
||||
|
||||
if (da->pts != MP_NOPTS_VALUE)
|
||||
da->pts += da->current_frame->samples / (double)da->current_frame->rate;
|
||||
}
|
||||
|
||||
void audio_work(struct dec_audio *da)
|
||||
{
|
||||
if (da->current_frame)
|
||||
return;
|
||||
|
||||
if (!da->packet && !da->new_segment &&
|
||||
demux_read_packet_async(da->header, &da->packet) == 0)
|
||||
{
|
||||
da->current_state = DATA_WAIT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (da->packet && da->packet->new_segment) {
|
||||
assert(!da->new_segment);
|
||||
da->new_segment = da->packet;
|
||||
da->packet = NULL;
|
||||
}
|
||||
|
||||
bool had_input_packet = !!da->packet;
|
||||
bool had_packet = da->packet || da->new_segment;
|
||||
|
||||
int ret = da->ad_driver->decode_packet(da, da->packet, &da->current_frame);
|
||||
if (ret < 0 || (da->packet && da->packet->len == 0)) {
|
||||
talloc_free(da->packet);
|
||||
da->packet = NULL;
|
||||
}
|
||||
|
||||
if (da->current_frame && !mp_audio_config_valid(da->current_frame)) {
|
||||
talloc_free(da->current_frame);
|
||||
da->current_frame = NULL;
|
||||
}
|
||||
|
||||
da->current_state = DATA_OK;
|
||||
if (!da->current_frame) {
|
||||
da->current_state = DATA_EOF;
|
||||
if (had_packet)
|
||||
da->current_state = DATA_AGAIN;
|
||||
}
|
||||
|
||||
fix_audio_pts(da);
|
||||
|
||||
bool segment_end = !da->current_frame && !had_input_packet;
|
||||
|
||||
if (da->current_frame) {
|
||||
mp_audio_clip_timestamps(da->current_frame, da->start, da->end);
|
||||
if (da->current_frame->pts != MP_NOPTS_VALUE && da->start != MP_NOPTS_VALUE)
|
||||
segment_end = da->current_frame->pts >= da->end;
|
||||
if (da->current_frame->samples == 0) {
|
||||
talloc_free(da->current_frame);
|
||||
da->current_frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a new segment, start it as soon as we're drained/finished.
|
||||
if (segment_end && da->new_segment) {
|
||||
struct demux_packet *new_segment = da->new_segment;
|
||||
da->new_segment = NULL;
|
||||
|
||||
// Could avoid decoder reinit; would still need flush.
|
||||
da->codec = new_segment->codec;
|
||||
if (da->ad_driver)
|
||||
da->ad_driver->uninit(da);
|
||||
da->ad_driver = NULL;
|
||||
audio_init_best_codec(da);
|
||||
|
||||
da->start = new_segment->start;
|
||||
da->end = new_segment->end;
|
||||
|
||||
new_segment->new_segment = false;
|
||||
|
||||
da->packet = new_segment;
|
||||
da->current_state = DATA_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch an audio frame decoded with audio_work(). Returns one of:
|
||||
// DATA_OK: *out_frame is set to a new image
|
||||
// DATA_WAIT: waiting for demuxer; will receive a wakeup signal
|
||||
// DATA_EOF: end of file, no more frames to be expected
|
||||
// DATA_AGAIN: dropped frame or something similar
|
||||
int audio_get_frame(struct dec_audio *da, struct mp_audio **out_frame)
|
||||
{
|
||||
*out_frame = NULL;
|
||||
if (da->current_frame) {
|
||||
*out_frame = da->current_frame;
|
||||
da->current_frame = NULL;
|
||||
return DATA_OK;
|
||||
}
|
||||
if (da->current_state == DATA_OK)
|
||||
return DATA_AGAIN;
|
||||
return da->current_state;
|
||||
d_audio->pts_offset = 0;
|
||||
if (d_audio->decode_buffer)
|
||||
mp_audio_buffer_clear(d_audio->decode_buffer);
|
||||
}
|
||||
+25
-22
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_DEC_AUDIO_H
|
||||
@@ -32,31 +33,33 @@ struct dec_audio {
|
||||
struct mpv_global *global;
|
||||
const struct ad_functions *ad_driver;
|
||||
struct sh_stream *header;
|
||||
struct mp_codec_params *codec;
|
||||
struct mp_audio_buffer *decode_buffer;
|
||||
struct af_stream *afilter;
|
||||
char *decoder_desc;
|
||||
|
||||
bool try_spdif;
|
||||
|
||||
struct mp_tags *metadata;
|
||||
struct replaygain_data *replaygain_data;
|
||||
// set by decoder
|
||||
struct mp_audio decoded; // format of decoded audio (no data, temporarily
|
||||
// different from decode_buffer during format
|
||||
// changes)
|
||||
int bitrate; // input bitrate, can change with VBR sources
|
||||
// last known pts value in output from decoder
|
||||
double pts;
|
||||
// number of samples output by decoder after last known pts
|
||||
int pts_offset;
|
||||
// For free use by the ad_driver
|
||||
void *priv;
|
||||
|
||||
// Strictly internal (dec_audio.c).
|
||||
|
||||
double pts; // endpts of previous frame
|
||||
double start, end;
|
||||
struct demux_packet *packet;
|
||||
struct demux_packet *new_segment;
|
||||
struct mp_audio *current_frame;
|
||||
int current_state;
|
||||
};
|
||||
|
||||
struct mp_decoder_list *audio_decoder_list(void);
|
||||
int audio_init_best_codec(struct dec_audio *d_audio);
|
||||
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders);
|
||||
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
|
||||
int minsamples);
|
||||
void audio_reset_decoding(struct dec_audio *d_audio);
|
||||
void audio_uninit(struct dec_audio *d_audio);
|
||||
|
||||
void audio_work(struct dec_audio *d_audio);
|
||||
int audio_get_frame(struct dec_audio *d_audio, struct mp_audio **out_frame);
|
||||
|
||||
void audio_reset_decoding(struct dec_audio *d_audio);
|
||||
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
|
||||
int *out_samplerate, struct mp_chmap *out_channels,
|
||||
int *out_format);
|
||||
|
||||
#endif /* MPLAYER_DEC_AUDIO_H */
|
||||
+350
-392
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@@ -27,37 +28,71 @@
|
||||
#include "options/m_option.h"
|
||||
#include "options/m_config.h"
|
||||
|
||||
#include "audio/audio_buffer.h"
|
||||
#include "af.h"
|
||||
|
||||
// Static list of filters
|
||||
extern const struct af_info af_info_dummy;
|
||||
extern const struct af_info af_info_delay;
|
||||
extern const struct af_info af_info_channels;
|
||||
extern const struct af_info af_info_format;
|
||||
extern const struct af_info af_info_force;
|
||||
extern const struct af_info af_info_volume;
|
||||
extern const struct af_info af_info_equalizer;
|
||||
extern const struct af_info af_info_pan;
|
||||
extern const struct af_info af_info_surround;
|
||||
extern const struct af_info af_info_sub;
|
||||
extern const struct af_info af_info_export;
|
||||
extern const struct af_info af_info_drc;
|
||||
extern const struct af_info af_info_extrastereo;
|
||||
extern const struct af_info af_info_lavcac3enc;
|
||||
extern const struct af_info af_info_lavrresample;
|
||||
extern const struct af_info af_info_sweep;
|
||||
extern const struct af_info af_info_hrtf;
|
||||
extern const struct af_info af_info_ladspa;
|
||||
extern const struct af_info af_info_center;
|
||||
extern const struct af_info af_info_sinesuppress;
|
||||
extern const struct af_info af_info_karaoke;
|
||||
extern const struct af_info af_info_scaletempo;
|
||||
extern const struct af_info af_info_bs2b;
|
||||
extern const struct af_info af_info_lavfi;
|
||||
extern const struct af_info af_info_rubberband;
|
||||
extern const struct af_info af_info_convert24;
|
||||
extern const struct af_info af_info_convertsignendian;
|
||||
|
||||
static const struct af_info *const filter_list[] = {
|
||||
&af_info_dummy,
|
||||
&af_info_delay,
|
||||
&af_info_channels,
|
||||
&af_info_format,
|
||||
&af_info_volume,
|
||||
&af_info_equalizer,
|
||||
&af_info_pan,
|
||||
&af_info_surround,
|
||||
&af_info_sub,
|
||||
#if HAVE_SYS_MMAN_H
|
||||
&af_info_export,
|
||||
#endif
|
||||
&af_info_drc,
|
||||
&af_info_extrastereo,
|
||||
&af_info_lavcac3enc,
|
||||
&af_info_lavrresample,
|
||||
#if HAVE_RUBBERBAND
|
||||
&af_info_rubberband,
|
||||
&af_info_sweep,
|
||||
&af_info_hrtf,
|
||||
#if HAVE_LADSPA
|
||||
&af_info_ladspa,
|
||||
#endif
|
||||
&af_info_center,
|
||||
&af_info_sinesuppress,
|
||||
&af_info_karaoke,
|
||||
&af_info_scaletempo,
|
||||
#if HAVE_LIBBS2B
|
||||
&af_info_bs2b,
|
||||
#endif
|
||||
#if HAVE_LIBAVFILTER
|
||||
&af_info_lavfi,
|
||||
#endif
|
||||
// Must come last, because they're fallback format conversion filter
|
||||
&af_info_convert24,
|
||||
&af_info_convertsignendian,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -86,17 +121,11 @@ const struct m_obj_list af_obj_list = {
|
||||
},
|
||||
};
|
||||
|
||||
static void af_forget_frames(struct af_instance *af)
|
||||
static bool af_config_equals(struct mp_audio *a, struct mp_audio *b)
|
||||
{
|
||||
for (int n = 0; n < af->num_out_queued; n++)
|
||||
talloc_free(af->out_queued[n]);
|
||||
af->num_out_queued = 0;
|
||||
}
|
||||
|
||||
static void af_chain_forget_frames(struct af_stream *s)
|
||||
{
|
||||
for (struct af_instance *cur = s->first; cur; cur = cur->next)
|
||||
af_forget_frames(cur);
|
||||
return a->format == b->format
|
||||
&& mp_chmap_equals(&a->channels, &b->channels)
|
||||
&& a->rate == b->rate;
|
||||
}
|
||||
|
||||
static void af_copy_unset_fields(struct mp_audio *dst, struct mp_audio *src)
|
||||
@@ -133,15 +162,14 @@ static int output_control(struct af_instance* af, int cmd, void* arg)
|
||||
*filter_output = *output;
|
||||
af_copy_unset_fields(filter_output, in);
|
||||
*in = *filter_output;
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
return af_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int dummy_filter(struct af_instance *af, struct mp_audio *frame)
|
||||
static int dummy_filter(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
af_add_output_frame(af, frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,21 +183,34 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
|
||||
MP_ERR(s, "Couldn't find audio filter '%s'.\n", name);
|
||||
return NULL;
|
||||
}
|
||||
const struct af_info *info = desc.p;
|
||||
/* Make sure that the filter is not already in the list if it is
|
||||
non-reentrant */
|
||||
if (info->flags & AF_FLAGS_NOT_REENTRANT) {
|
||||
for (struct af_instance *cur = s->first; cur; cur = cur->next) {
|
||||
if (cur->info == info) {
|
||||
MP_ERR(s, "There can only be one "
|
||||
"instance of the filter '%s' in each stream\n", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP_VERBOSE(s, "Adding filter %s \n", name);
|
||||
|
||||
struct af_instance *af = talloc_zero(NULL, struct af_instance);
|
||||
*af = (struct af_instance) {
|
||||
.info = desc.p,
|
||||
.info = info,
|
||||
.mul = 1,
|
||||
.data = talloc_zero(af, struct mp_audio),
|
||||
.log = mp_log_new(af, s->log, name),
|
||||
.opts = s->opts,
|
||||
.metadata = s->metadata,
|
||||
.replaygain_data = s->replaygain_data,
|
||||
.out_pool = mp_audio_pool_create(af),
|
||||
};
|
||||
struct m_config *config =
|
||||
m_config_from_obj_desc_and_args(af, s->log, NULL, &desc,
|
||||
name, s->opts->af_defs, args);
|
||||
if (!config)
|
||||
struct m_config *config = m_config_from_obj_desc(af, s->log, &desc);
|
||||
if (m_config_apply_defaults(config, name, s->opts->af_defs) < 0)
|
||||
goto error;
|
||||
if (m_config_set_obj_params(config, args) < 0)
|
||||
goto error;
|
||||
af->priv = config->optstruct;
|
||||
|
||||
@@ -208,6 +249,29 @@ static struct af_instance *af_prepend(struct af_stream *s,
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Create and insert a new filter of type name after the filter in the
|
||||
argument. This function can be called during runtime, the return
|
||||
value is the new filter */
|
||||
static struct af_instance *af_append(struct af_stream *s,
|
||||
struct af_instance *af,
|
||||
char *name, char **args)
|
||||
{
|
||||
if (!af)
|
||||
af = s->first;
|
||||
if (af == s->last)
|
||||
af = s->last->prev;
|
||||
// Create the new filter and make sure it is OK
|
||||
struct af_instance *new = af_create(s, name, args);
|
||||
if (!new)
|
||||
return NULL;
|
||||
// Update pointers
|
||||
new->prev = af;
|
||||
new->next = af->next;
|
||||
af->next = new;
|
||||
new->next->prev = new;
|
||||
return new;
|
||||
}
|
||||
|
||||
// Uninit and remove the filter "af"
|
||||
static void af_remove(struct af_stream *s, struct af_instance *af)
|
||||
{
|
||||
@@ -226,7 +290,6 @@ static void af_remove(struct af_stream *s, struct af_instance *af)
|
||||
|
||||
if (af->uninit)
|
||||
af->uninit(af);
|
||||
af_forget_frames(af);
|
||||
talloc_free(af);
|
||||
}
|
||||
|
||||
@@ -248,186 +311,241 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
|
||||
|
||||
struct af_instance *af = s->first;
|
||||
while (af) {
|
||||
char b[128] = {0};
|
||||
mp_snprintf_cat(b, sizeof(b), " [%s] ", af->info->name);
|
||||
if (af->label)
|
||||
mp_snprintf_cat(b, sizeof(b), "\"%s\" ", af->label);
|
||||
if (af->data)
|
||||
mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data));
|
||||
if (af->auto_inserted)
|
||||
mp_snprintf_cat(b, sizeof(b), " [a]");
|
||||
MP_MSG(s, msg_level, " [%s] ", af->info->name);
|
||||
if (af->data) {
|
||||
char *info = mp_audio_config_to_str(af->data);
|
||||
MP_MSG(s, msg_level, "%s", info);
|
||||
talloc_free(info);
|
||||
}
|
||||
if (af == at)
|
||||
mp_snprintf_cat(b, sizeof(b), " <-");
|
||||
MP_MSG(s, msg_level, "%s\n", b);
|
||||
MP_MSG(s, msg_level, " <-");
|
||||
MP_MSG(s, msg_level, "\n");
|
||||
|
||||
af = af->next;
|
||||
}
|
||||
|
||||
MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output));
|
||||
MP_MSG(s, msg_level, " [ao] ");
|
||||
char *info = mp_audio_config_to_str(&s->output);
|
||||
MP_MSG(s, msg_level, "%s\n", info);
|
||||
talloc_free(info);
|
||||
}
|
||||
|
||||
static void reset_formats(struct af_stream *s)
|
||||
static int af_count_filters(struct af_stream *s)
|
||||
{
|
||||
struct mp_audio none = {0};
|
||||
for (struct af_instance *af = s->first; af; af = af->next) {
|
||||
if (af != s->first && af != s->last)
|
||||
mp_audio_copy_config(af->data, &none);
|
||||
int count = 0;
|
||||
for (struct af_instance *af = s->first; af; af = af->next)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// Finds the first conversion filter on the way from srcfmt to dstfmt.
|
||||
// Conversions form a DAG: each node is a format/filter pair, and possible
|
||||
// conversions are edges. We search the DAG for the shortest path.
|
||||
// Some cases visit the same filter multiple times, but with different formats
|
||||
// (like u24le->s8), so one node per format or filter separate is not enough.
|
||||
// Returns the filter and dest. format for the first conversion step.
|
||||
// (So we know what conversion filter with what format to insert next.)
|
||||
static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
|
||||
{
|
||||
#define MAX_NODES (64 * 32)
|
||||
int num_fmt = 0, num_filt = 0;
|
||||
for (int n = 0; filter_list[n]; n++)
|
||||
num_filt = n + 1;
|
||||
for (int n = 0; af_fmtstr_table[n].format; n++)
|
||||
num_fmt = n + 1;
|
||||
|
||||
int num_nodes = num_fmt * num_filt;
|
||||
assert(num_nodes < MAX_NODES);
|
||||
|
||||
bool visited[MAX_NODES] = {0};
|
||||
unsigned char distance[MAX_NODES];
|
||||
short previous[MAX_NODES] = {0};
|
||||
for (int n = 0; n < num_nodes; n++) {
|
||||
distance[n] = 255;
|
||||
if (af_fmtstr_table[n % num_fmt].format == srcfmt)
|
||||
distance[n] = 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int next = -1;
|
||||
for (int n = 0; n < num_nodes; n++) {
|
||||
if (!visited[n] && (next < 0 || (distance[n] < distance[next])))
|
||||
next = n;
|
||||
}
|
||||
if (next < 0 || distance[next] == 255)
|
||||
return NULL;
|
||||
visited[next] = true;
|
||||
|
||||
int fmt = next % num_fmt;
|
||||
if (af_fmtstr_table[fmt].format == *dstfmt) {
|
||||
// Best match found
|
||||
for (int cur = next; cur >= 0; cur = previous[cur] - 1) {
|
||||
if (distance[cur] == 1) {
|
||||
*dstfmt = af_fmtstr_table[cur % num_fmt].format;
|
||||
return (char *)filter_list[cur / num_fmt]->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int n = 0; filter_list[n]; n++) {
|
||||
const struct af_info *af = filter_list[n];
|
||||
if (!af->test_conversion)
|
||||
continue;
|
||||
for (int i = 0; af_fmtstr_table[i].format; i++) {
|
||||
if (i != fmt && af->test_conversion(af_fmtstr_table[fmt].format,
|
||||
af_fmtstr_table[i].format))
|
||||
{
|
||||
int other = n * num_fmt + i;
|
||||
int ndist = distance[next] + 1;
|
||||
if (ndist < distance[other]) {
|
||||
distance[other] = ndist;
|
||||
previous[other] = next + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
#undef MAX_NODES
|
||||
}
|
||||
|
||||
static int filter_reinit(struct af_instance *af)
|
||||
static bool af_is_conversion_filter(struct af_instance *af)
|
||||
{
|
||||
return af && af->info->test_conversion != NULL;
|
||||
}
|
||||
|
||||
// in is what af can take as input - insert a conversion filter if the actual
|
||||
// input format doesn't match what af expects.
|
||||
// Returns:
|
||||
// AF_OK: must call af_reinit() or equivalent, format matches (or is closer)
|
||||
// AF_FALSE: nothing was changed, format matches
|
||||
// else: error
|
||||
static int af_fix_format_conversion(struct af_stream *s,
|
||||
struct af_instance **p_af,
|
||||
struct mp_audio in)
|
||||
{
|
||||
int rv;
|
||||
struct af_instance *af = *p_af;
|
||||
struct af_instance *prev = af->prev;
|
||||
assert(prev);
|
||||
|
||||
// Check if this is the first filter
|
||||
struct mp_audio in = *prev->data;
|
||||
// Reset just in case...
|
||||
mp_audio_set_null_data(&in);
|
||||
|
||||
if (!mp_audio_config_valid(&in))
|
||||
struct mp_audio actual = *prev->data;
|
||||
if (actual.format == in.format)
|
||||
return AF_FALSE;
|
||||
int dstfmt = in.format;
|
||||
char *filter = af_find_conversion_filter(actual.format, &dstfmt);
|
||||
if (!filter)
|
||||
return AF_ERROR;
|
||||
|
||||
af->fmt_in = in;
|
||||
int rv = af->control(af, AF_CONTROL_REINIT, &in);
|
||||
if (rv == AF_OK && !mp_audio_config_equals(&in, prev->data))
|
||||
rv = AF_FALSE; // conversion filter needed
|
||||
if (rv == AF_FALSE)
|
||||
af->fmt_in = in;
|
||||
|
||||
if (rv == AF_OK) {
|
||||
if (!mp_audio_config_valid(af->data))
|
||||
return AF_ERROR;
|
||||
af->fmt_out = *af->data;
|
||||
if (strcmp(filter, prev->info->name) == 0) {
|
||||
if (prev->control(prev, AF_CONTROL_SET_FORMAT, &dstfmt) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
struct af_instance *new = af_prepend(s, af, filter, NULL);
|
||||
if (new == NULL)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_FORMAT, &dstfmt)))
|
||||
return rv;
|
||||
*p_af = new;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
static int filter_reinit_with_conversion(struct af_stream *s, struct af_instance *af)
|
||||
// same as af_fix_format_conversion - only wrt. channels
|
||||
static int af_fix_channels(struct af_stream *s, struct af_instance **p_af,
|
||||
struct mp_audio in)
|
||||
{
|
||||
int rv = filter_reinit(af);
|
||||
|
||||
// Conversion filter is needed
|
||||
if (rv == AF_FALSE) {
|
||||
// First try if we can change the output format of the previous
|
||||
// filter to the input format the current filter is expecting.
|
||||
struct mp_audio in = af->fmt_in;
|
||||
if (af->prev != s->first && !mp_audio_config_equals(af->prev->data, &in)) {
|
||||
// This should have been successful (because it succeeded
|
||||
// before), even if just reverting to the old output format.
|
||||
mp_audio_copy_config(af->prev->data, &in);
|
||||
rv = filter_reinit(af->prev);
|
||||
if (rv != AF_OK)
|
||||
return rv;
|
||||
}
|
||||
if (!mp_audio_config_equals(af->prev->data, &in)) {
|
||||
// Retry with conversion filter added.
|
||||
struct af_instance *new =
|
||||
af_prepend(s, af, "lavrresample", NULL);
|
||||
if (!new)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
mp_audio_copy_config(new->data, &in);
|
||||
rv = filter_reinit(new);
|
||||
if (rv != AF_OK)
|
||||
af_remove(s, new);
|
||||
}
|
||||
if (rv == AF_OK)
|
||||
rv = filter_reinit(af);
|
||||
int rv;
|
||||
struct af_instance *af = *p_af;
|
||||
struct af_instance *prev = af->prev;
|
||||
struct mp_audio actual = *prev->data;
|
||||
if (mp_chmap_equals(&actual.channels, &in.channels))
|
||||
return AF_FALSE;
|
||||
if (prev->control(prev, AF_CONTROL_SET_CHANNELS, &in.channels) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
return rv;
|
||||
char *filter = "lavrresample";
|
||||
struct af_instance *new = af_prepend(s, af, filter, NULL);
|
||||
if (new == NULL)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_CHANNELS, &in.channels)))
|
||||
return rv;
|
||||
*p_af = new;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
static int af_find_output_conversion(struct af_stream *s, struct mp_audio *cfg)
|
||||
static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
|
||||
struct mp_audio in)
|
||||
{
|
||||
assert(mp_audio_config_valid(&s->output));
|
||||
assert(s->initialized > 0);
|
||||
|
||||
if (mp_chmap_equals_reordered(&s->input.channels, &s->output.channels))
|
||||
return AF_ERROR;
|
||||
|
||||
// Heuristic to detect point of conversion. If it looks like something
|
||||
// more complicated is going on, better bail out.
|
||||
// We expect that the last filter converts channels.
|
||||
struct af_instance *conv = s->last->prev;
|
||||
if (!conv->auto_inserted)
|
||||
return AF_ERROR;
|
||||
if (!(mp_chmap_equals_reordered(&conv->fmt_in.channels, &s->input.channels) &&
|
||||
mp_chmap_equals_reordered(&conv->fmt_out.channels, &s->output.channels)))
|
||||
return AF_ERROR;
|
||||
// Also, should be the only one which does auto conversion.
|
||||
for (struct af_instance *af = s->first->next; af != s->last; af = af->next)
|
||||
{
|
||||
if (af != conv && af->auto_inserted &&
|
||||
!mp_chmap_equals_reordered(&af->fmt_in.channels, &af->fmt_out.channels))
|
||||
return AF_ERROR;
|
||||
int rv;
|
||||
struct af_instance *af = *p_af;
|
||||
struct af_instance *prev = af->prev;
|
||||
struct mp_audio actual = *prev->data;
|
||||
if (actual.rate == in.rate)
|
||||
return AF_FALSE;
|
||||
if (prev->control(prev, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
// And not if it's the only filter.
|
||||
if (conv->prev == s->first && conv->next == s->last)
|
||||
char *filter = "lavrresample";
|
||||
struct af_instance *new = af_prepend(s, af, filter, NULL);
|
||||
if (new == NULL)
|
||||
return AF_ERROR;
|
||||
|
||||
*cfg = s->output;
|
||||
new->auto_inserted = true;
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate)))
|
||||
return rv;
|
||||
*p_af = new;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
// Return AF_OK on success or AF_ERROR on failure.
|
||||
static int af_do_reinit(struct af_stream *s, bool second_pass)
|
||||
// Warning:
|
||||
// A failed af_reinit() leaves the audio chain behind in a useless, broken
|
||||
// state (for example, format filters that were tentatively inserted stay
|
||||
// inserted).
|
||||
// In that case, you should always rebuild the filter chain, or abort.
|
||||
static int af_reinit(struct af_stream *s)
|
||||
{
|
||||
struct mp_audio convert_early = {0};
|
||||
if (second_pass) {
|
||||
// If a channel conversion happens, and it is done by an auto-inserted
|
||||
// filter, then insert a filter to convert it early. Otherwise, do
|
||||
// nothing and return immediately.
|
||||
if (af_find_output_conversion(s, &convert_early) != AF_OK)
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
remove_auto_inserted_filters(s);
|
||||
af_chain_forget_frames(s);
|
||||
reset_formats(s);
|
||||
s->first->fmt_in = s->first->fmt_out = s->input;
|
||||
|
||||
if (mp_audio_config_valid(&convert_early)) {
|
||||
struct af_instance *new = af_prepend(s, s->first, "lavrresample", NULL);
|
||||
if (!new)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
mp_audio_copy_config(new->data, &convert_early);
|
||||
int rv = filter_reinit(new);
|
||||
if (rv != AF_DETACH && rv != AF_OK)
|
||||
return AF_ERROR;
|
||||
MP_VERBOSE(s, "Moving up output conversion.\n");
|
||||
}
|
||||
|
||||
// Start with the second filter, as the first filter is the special input
|
||||
// filter which needs no initialization.
|
||||
struct af_instance *af = s->first->next;
|
||||
// Up to 7 retries per filter (channel, rate, 5x format conversions)
|
||||
int max_retry = af_count_filters(s) * 7;
|
||||
int retry = 0;
|
||||
while (af) {
|
||||
int rv = filter_reinit_with_conversion(s, af);
|
||||
if (retry >= max_retry)
|
||||
goto negotiate_error;
|
||||
|
||||
// Check if this is the first filter
|
||||
struct mp_audio in = *af->prev->data;
|
||||
// Reset just in case...
|
||||
mp_audio_set_null_data(&in);
|
||||
|
||||
int rv = af->control(af, AF_CONTROL_REINIT, &in);
|
||||
if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data))
|
||||
rv = AF_FALSE; // conversion filter needed
|
||||
switch (rv) {
|
||||
case AF_OK:
|
||||
af = af->next;
|
||||
break;
|
||||
case AF_FALSE: {
|
||||
// If the format conversion is (probably) caused by spdif, then
|
||||
// (as a feature) drop the filter, instead of failing hard.
|
||||
int fmt_in1 = af->prev->data->format;
|
||||
int fmt_in2 = af->fmt_in.format;
|
||||
if (af_fmt_is_valid(fmt_in1) && af_fmt_is_valid(fmt_in2)) {
|
||||
bool spd1 = af_fmt_is_spdif(fmt_in1);
|
||||
bool spd2 = af_fmt_is_spdif(fmt_in2);
|
||||
if (spd1 != spd2 && af->next) {
|
||||
MP_WARN(af, "Filter %s apparently cannot be used due to "
|
||||
"spdif passthrough - removing it.\n",
|
||||
af->info->name);
|
||||
struct af_instance *aft = af->prev;
|
||||
af_remove(s, af);
|
||||
af = aft->next;
|
||||
continue;
|
||||
}
|
||||
case AF_FALSE: { // Configuration filter is needed
|
||||
if (af_fix_channels(s, &af, in) == AF_OK) {
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
if (af_fix_rate(s, &af, in) == AF_OK) {
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
// Do this last, to prevent "format->lavrresample" being added to
|
||||
// the filter chain when output formats not supported by
|
||||
// af_lavrresample are in use.
|
||||
if (af_fix_format_conversion(s, &af, in) == AF_OK) {
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
goto negotiate_error;
|
||||
}
|
||||
@@ -441,83 +559,60 @@ static int af_do_reinit(struct af_stream *s, bool second_pass)
|
||||
MP_ERR(s, "Reinitialization did not work, "
|
||||
"audio filter '%s' returned error code %i\n",
|
||||
af->info->name, rv);
|
||||
goto error;
|
||||
af_print_filter_chain(s, af, MSGL_ERR);
|
||||
return AF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
af_print_filter_chain(s, NULL, MSGL_V);
|
||||
|
||||
/* Set previously unset fields in s->output to those of the filter chain
|
||||
* output. This is used to make the output format fixed, and even if you
|
||||
* insert new filters or change the input format, the output format won't
|
||||
* change. (Audio outputs generally can't change format at runtime.) */
|
||||
af_copy_unset_fields(&s->output, &s->filter_output);
|
||||
if (mp_audio_config_equals(&s->output, &s->filter_output)) {
|
||||
s->initialized = 1;
|
||||
af_print_filter_chain(s, NULL, MSGL_V);
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
goto error;
|
||||
return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
|
||||
|
||||
negotiate_error:
|
||||
MP_ERR(s, "Unable to convert audio input format to output format.\n");
|
||||
error:
|
||||
s->initialized = -1;
|
||||
af_print_filter_chain(s, af, MSGL_ERR);
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
static int af_reinit(struct af_stream *s)
|
||||
{
|
||||
int r = af_do_reinit(s, false);
|
||||
if (r == AF_OK && mp_audio_config_valid(&s->output)) {
|
||||
r = af_do_reinit(s, true);
|
||||
if (r != AF_OK) {
|
||||
MP_ERR(s, "Failed second pass filter negotiation.\n");
|
||||
r = af_do_reinit(s, false);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Uninit and remove all filters
|
||||
void af_uninit(struct af_stream *s)
|
||||
{
|
||||
while (s->first->next && s->first->next != s->last)
|
||||
af_remove(s, s->first->next);
|
||||
af_chain_forget_frames(s);
|
||||
s->initialized = 0;
|
||||
}
|
||||
|
||||
struct af_stream *af_new(struct mpv_global *global)
|
||||
{
|
||||
struct af_stream *s = talloc_zero(NULL, struct af_stream);
|
||||
s->log = mp_log_new(s, global->log, "!af");
|
||||
|
||||
static const struct af_info in = { .name = "in" };
|
||||
s->first = talloc(s, struct af_instance);
|
||||
*s->first = (struct af_instance) {
|
||||
.info = &in,
|
||||
.log = s->log,
|
||||
.control = input_control,
|
||||
.filter_frame = dummy_filter,
|
||||
.filter = dummy_filter,
|
||||
.priv = s,
|
||||
.data = &s->input,
|
||||
.mul = 1.0,
|
||||
};
|
||||
|
||||
static const struct af_info out = { .name = "out" };
|
||||
s->last = talloc(s, struct af_instance);
|
||||
*s->last = (struct af_instance) {
|
||||
.info = &out,
|
||||
.log = s->log,
|
||||
.control = output_control,
|
||||
.filter_frame = dummy_filter,
|
||||
.filter = dummy_filter,
|
||||
.priv = s,
|
||||
.data = &s->filter_output,
|
||||
.mul = 1.0,
|
||||
};
|
||||
|
||||
s->first->next = s->last;
|
||||
s->last->prev = s->first;
|
||||
s->opts = global->opts;
|
||||
s->log = mp_log_new(s, global->log, "!af");
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -533,11 +628,15 @@ void af_destroy(struct af_stream *s)
|
||||
format of the preferred output respectively. The function is
|
||||
reentrant i.e. if called with an already initialized stream the
|
||||
stream will be reinitialized.
|
||||
If one of the preferred output parameters is 0 the one that needs
|
||||
If one of the prefered output parameters is 0 the one that needs
|
||||
no conversion is used (i.e. the output format in the last filter).
|
||||
The return value is 0 if success and -1 if failure */
|
||||
int af_init(struct af_stream *s)
|
||||
{
|
||||
// Sanity check
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
// Precaution in case caller is misbehaving
|
||||
mp_audio_set_null_data(&s->input);
|
||||
mp_audio_set_null_data(&s->output);
|
||||
@@ -547,20 +646,17 @@ int af_init(struct af_stream *s)
|
||||
// Add all filters in the list (if there are any)
|
||||
struct m_obj_settings *list = s->opts->af_settings;
|
||||
for (int i = 0; list && list[i].name; i++) {
|
||||
struct af_instance *af =
|
||||
af_prepend(s, s->last, list[i].name, list[i].attribs);
|
||||
if (!af) {
|
||||
if (!af_prepend(s, s->last, list[i].name, list[i].attribs)) {
|
||||
af_uninit(s);
|
||||
s->initialized = -1;
|
||||
return -1;
|
||||
}
|
||||
af->label = talloc_strdup(af, list[i].label);
|
||||
}
|
||||
}
|
||||
|
||||
if (af_reinit(s) != AF_OK) {
|
||||
// Something is stuffed audio out will not work
|
||||
MP_ERR(s, "Could not create audio filter chain.\n");
|
||||
af_uninit(s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -570,51 +666,60 @@ int af_init(struct af_stream *s)
|
||||
to the stream s. The filter will be inserted somewhere nice in the
|
||||
list of filters. The return value is a pointer to the new filter,
|
||||
If the filter couldn't be added the return value is NULL. */
|
||||
struct af_instance *af_add(struct af_stream *s, char *name, char *label,
|
||||
char **args)
|
||||
struct af_instance *af_add(struct af_stream *s, char *name, char **args)
|
||||
{
|
||||
assert(label);
|
||||
|
||||
if (af_find_by_label(s, label))
|
||||
struct af_instance *new;
|
||||
// Sanity check
|
||||
if (!s || !s->first || !name)
|
||||
return NULL;
|
||||
|
||||
struct af_instance *new = af_prepend(s, s->last, name, args);
|
||||
// Insert the filter somewhere nice
|
||||
if (af_is_conversion_filter(s->first->next))
|
||||
new = af_append(s, s->first->next, name, args);
|
||||
else
|
||||
new = af_prepend(s, s->first->next, name, args);
|
||||
if (!new)
|
||||
return NULL;
|
||||
new->label = talloc_strdup(new, label);
|
||||
|
||||
// Reinitialize the filter list
|
||||
if (af_reinit(s) != AF_OK) {
|
||||
af_remove_by_label(s, label);
|
||||
return NULL;
|
||||
}
|
||||
return af_find_by_label(s, label);
|
||||
}
|
||||
|
||||
struct af_instance *af_find_by_label(struct af_stream *s, char *label)
|
||||
{
|
||||
for (struct af_instance *af = s->first; af; af = af->next) {
|
||||
if (af->label && strcmp(af->label, label) == 0)
|
||||
return af;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove the first filter that matches this name. Return number of filters
|
||||
* removed (0, 1), or a negative error code if reinit after removing failed.
|
||||
*/
|
||||
int af_remove_by_label(struct af_stream *s, char *label)
|
||||
{
|
||||
struct af_instance *af = af_find_by_label(s, label);
|
||||
if (!af)
|
||||
return 0;
|
||||
af_remove(s, af);
|
||||
// Reinitalize the filter list
|
||||
if (af_reinit(s) != AF_OK) {
|
||||
af_uninit(s);
|
||||
af_init(s);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
return 1;
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Filter data chunk through the filters in the list.
|
||||
* On success, *data is set to the filtered data/format.
|
||||
* Warning: input audio data will be overwritten.
|
||||
*/
|
||||
int af_filter(struct af_stream *s, struct mp_audio *data, int flags)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
assert(mp_audio_config_equals(af->data, data));
|
||||
// Iterate through all filters
|
||||
while (af) {
|
||||
int r = af->filter(af, data, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(mp_audio_config_equals(af->data, data));
|
||||
af = af->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate average ratio of filter output samples to input samples.
|
||||
// e.g: num_output_samples = mul * num_input_samples
|
||||
double af_calc_filter_multiplier(struct af_stream *s)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
double mul = 1;
|
||||
do {
|
||||
mul *= af->mul;
|
||||
af = af->next;
|
||||
} while (af);
|
||||
|
||||
return mul;
|
||||
}
|
||||
|
||||
/* Calculate the total delay [seconds of output] caused by the filters */
|
||||
@@ -624,8 +729,6 @@ double af_calc_delay(struct af_stream *s)
|
||||
double delay = 0.0;
|
||||
while (af) {
|
||||
delay += af->delay;
|
||||
for (int n = 0; n < af->num_out_queued; n++)
|
||||
delay += af->out_queued[n]->samples / (double)af->data->rate;
|
||||
af = af->next;
|
||||
}
|
||||
return delay;
|
||||
@@ -652,148 +755,3 @@ void af_control_all(struct af_stream *s, int cmd, void *arg)
|
||||
for (struct af_instance *af = s->first; af; af = af->next)
|
||||
af->control(af, cmd, arg);
|
||||
}
|
||||
|
||||
int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label)
|
||||
{
|
||||
char *label_str = bstrdup0(NULL, label);
|
||||
struct af_instance *cur = af_find_by_label(s, label_str);
|
||||
talloc_free(label_str);
|
||||
if (cur) {
|
||||
return cur->control ? cur->control(cur, cmd, arg) : CONTROL_NA;
|
||||
} else {
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int af_send_command(struct af_stream *s, char *label, char *cmd, char *arg)
|
||||
{
|
||||
char *args[2] = {cmd, arg};
|
||||
if (strcmp(label, "all") == 0) {
|
||||
af_control_all(s, AF_CONTROL_COMMAND, args);
|
||||
return 0;
|
||||
} else {
|
||||
return af_control_by_label(s, AF_CONTROL_COMMAND, args, bstr0(label));
|
||||
}
|
||||
}
|
||||
|
||||
// Used by filters to add a filtered frame to the output queue.
|
||||
// Ownership of frame is transferred from caller to the filter chain.
|
||||
void af_add_output_frame(struct af_instance *af, struct mp_audio *frame)
|
||||
{
|
||||
if (frame) {
|
||||
assert(mp_audio_config_equals(&af->fmt_out, frame));
|
||||
MP_TARRAY_APPEND(af, af->out_queued, af->num_out_queued, frame);
|
||||
}
|
||||
}
|
||||
|
||||
static bool af_has_output_frame(struct af_instance *af)
|
||||
{
|
||||
if (!af->num_out_queued && af->filter_out) {
|
||||
if (af->filter_out(af) < 0)
|
||||
MP_ERR(af, "Error filtering frame.\n");
|
||||
}
|
||||
return af->num_out_queued > 0;
|
||||
}
|
||||
|
||||
static struct mp_audio *af_dequeue_output_frame(struct af_instance *af)
|
||||
{
|
||||
struct mp_audio *res = NULL;
|
||||
if (af_has_output_frame(af)) {
|
||||
res = af->out_queued[0];
|
||||
MP_TARRAY_REMOVE_AT(af->out_queued, af->num_out_queued, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void read_remaining(struct af_instance *af)
|
||||
{
|
||||
int num_frames;
|
||||
do {
|
||||
num_frames = af->num_out_queued;
|
||||
if (!af->filter_out || af->filter_out(af) < 0)
|
||||
break;
|
||||
} while (num_frames != af->num_out_queued);
|
||||
}
|
||||
|
||||
static int af_do_filter(struct af_instance *af, struct mp_audio *frame)
|
||||
{
|
||||
if (frame)
|
||||
assert(mp_audio_config_equals(&af->fmt_in, frame));
|
||||
int r = af->filter_frame(af, frame);
|
||||
if (r < 0)
|
||||
MP_ERR(af, "Error filtering frame.\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
// Input a frame into the filter chain. Ownership of frame is transferred.
|
||||
// Return >= 0 on success, < 0 on failure (even if output frames were produced)
|
||||
int af_filter_frame(struct af_stream *s, struct mp_audio *frame)
|
||||
{
|
||||
assert(frame);
|
||||
if (s->initialized < 1) {
|
||||
talloc_free(frame);
|
||||
return -1;
|
||||
}
|
||||
return af_do_filter(s->first, frame);
|
||||
}
|
||||
|
||||
// Output the next queued frame (if any) from the full filter chain.
|
||||
// The frame can be retrieved with af_read_output_frame().
|
||||
// eof: if set, assume there's no more input i.e. af_filter_frame() will
|
||||
// not be called (until reset) - flush all internally delayed frames
|
||||
// returns: -1: error, 0: no output, 1: output available
|
||||
int af_output_frame(struct af_stream *s, bool eof)
|
||||
{
|
||||
if (s->last->num_out_queued)
|
||||
return 1;
|
||||
if (s->initialized < 1)
|
||||
return -1;
|
||||
while (1) {
|
||||
struct af_instance *last = NULL;
|
||||
for (struct af_instance * cur = s->first; cur; cur = cur->next) {
|
||||
// Flush remaining frames on EOF, but do that only if the previous
|
||||
// filters have been flushed (i.e. they have no more output).
|
||||
if (eof && !last) {
|
||||
read_remaining(cur);
|
||||
int r = af_do_filter(cur, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (af_has_output_frame(cur))
|
||||
last = cur;
|
||||
}
|
||||
if (!last)
|
||||
return 0;
|
||||
if (!last->next)
|
||||
return 1;
|
||||
int r = af_do_filter(last->next, af_dequeue_output_frame(last));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
struct mp_audio *af_read_output_frame(struct af_stream *s)
|
||||
{
|
||||
if (!s->last->num_out_queued)
|
||||
af_output_frame(s, false);
|
||||
return af_dequeue_output_frame(s->last);
|
||||
}
|
||||
|
||||
void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame)
|
||||
{
|
||||
struct af_instance *af = s->last;
|
||||
MP_TARRAY_INSERT_AT(af, af->out_queued, af->num_out_queued, 0, frame);
|
||||
}
|
||||
|
||||
// Make sure the caller can change data referenced by the frame.
|
||||
// Return negative error code on failure (i.e. you can't write).
|
||||
int af_make_writeable(struct af_instance *af, struct mp_audio *frame)
|
||||
{
|
||||
return mp_audio_pool_make_writeable(af->out_pool, frame);
|
||||
}
|
||||
|
||||
void af_seek_reset(struct af_stream *s)
|
||||
{
|
||||
af_control_all(s, AF_CONTROL_RESET, NULL);
|
||||
af_chain_forget_frames(s);
|
||||
}
|
||||
+35
-46
@@ -1,18 +1,19 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_AF_H
|
||||
@@ -27,7 +28,6 @@
|
||||
#include "audio/chmap.h"
|
||||
#include "audio/audio.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/common.h"
|
||||
|
||||
struct af_instance;
|
||||
struct mpv_global;
|
||||
@@ -35,6 +35,10 @@ struct mpv_global;
|
||||
// Number of channels
|
||||
#define AF_NCH MP_NUM_CHANNELS
|
||||
|
||||
// Flags used for defining the behavior of an audio filter
|
||||
#define AF_FLAGS_REENTRANT 0x00000000
|
||||
#define AF_FLAGS_NOT_REENTRANT 0x00000001
|
||||
|
||||
// Flags for af->filter()
|
||||
#define AF_FILTER_FLAG_EOF 1
|
||||
|
||||
@@ -43,7 +47,9 @@ struct mpv_global;
|
||||
struct af_info {
|
||||
const char *info;
|
||||
const char *name;
|
||||
const int flags;
|
||||
int (*open)(struct af_instance *vf);
|
||||
bool (*test_conversion)(int src_format, int dst_format);
|
||||
int priv_size;
|
||||
const void *priv_defaults;
|
||||
const struct m_option *options;
|
||||
@@ -53,39 +59,28 @@ struct af_info {
|
||||
struct af_instance {
|
||||
const struct af_info *info;
|
||||
struct mp_log *log;
|
||||
struct MPOpts *opts;
|
||||
struct mp_tags *metadata;
|
||||
struct replaygain_data *replaygain_data;
|
||||
int (*control)(struct af_instance *af, int cmd, void *arg);
|
||||
void (*uninit)(struct af_instance *af);
|
||||
/* Feed a frame. The frame is NULL if EOF was reached, and the filter
|
||||
* should drain all remaining buffered data.
|
||||
* Use af_add_output_frame() to output data. The optional filter_out
|
||||
* callback can be set to produce output frames gradually.
|
||||
/* flags is a bit mask of AF_FILTER_FLAG_* values
|
||||
* returns 0 on success, negative value on error
|
||||
*/
|
||||
int (*filter_frame)(struct af_instance *af, struct mp_audio *frame);
|
||||
int (*filter_out)(struct af_instance *af);
|
||||
int (*filter)(struct af_instance *af, struct mp_audio *data, int flags);
|
||||
void *priv;
|
||||
struct mp_audio *data; // configuration and buffer for outgoing data stream
|
||||
|
||||
struct af_instance *next;
|
||||
struct af_instance *prev;
|
||||
double delay; /* Delay caused by the filter, in seconds of audio consumed
|
||||
* without corresponding output */
|
||||
double mul; /* length multiplier: how much does this instance change
|
||||
* the number of samples passed though. (Ratio of input
|
||||
* and output, e.g. mul=4 => 1 sample becomes 4 samples) .*/
|
||||
bool auto_inserted; // inserted by af.c, such as conversion filters
|
||||
char *label;
|
||||
|
||||
struct mp_audio fmt_in, fmt_out;
|
||||
|
||||
struct mp_audio **out_queued;
|
||||
int num_out_queued;
|
||||
|
||||
struct mp_audio_pool *out_pool;
|
||||
};
|
||||
|
||||
// Current audio stream
|
||||
struct af_stream {
|
||||
int initialized; // 0: no, 1: yes, -1: attempted to, but failed
|
||||
|
||||
// The first and last filter in the list
|
||||
struct af_instance *first;
|
||||
struct af_instance *last;
|
||||
@@ -97,21 +92,26 @@ struct af_stream {
|
||||
|
||||
struct mp_log *log;
|
||||
struct MPOpts *opts;
|
||||
struct mp_tags *metadata;
|
||||
struct replaygain_data *replaygain_data;
|
||||
};
|
||||
|
||||
// Return values
|
||||
#define AF_DETACH (CONTROL_OK + 1)
|
||||
#define AF_OK CONTROL_OK
|
||||
#define AF_TRUE CONTROL_TRUE
|
||||
#define AF_FALSE CONTROL_FALSE
|
||||
#define AF_UNKNOWN CONTROL_UNKNOWN
|
||||
#define AF_ERROR CONTROL_ERROR
|
||||
#define AF_DETACH 2
|
||||
#define AF_OK 1
|
||||
#define AF_TRUE 1
|
||||
#define AF_FALSE 0
|
||||
#define AF_UNKNOWN -1
|
||||
#define AF_ERROR -2
|
||||
#define AF_FATAL -3
|
||||
|
||||
// Parameters for af_control_*
|
||||
enum af_control {
|
||||
AF_CONTROL_REINIT = 1,
|
||||
AF_CONTROL_RESET,
|
||||
AF_CONTROL_SET_RESAMPLE_RATE,
|
||||
AF_CONTROL_SET_FORMAT,
|
||||
AF_CONTROL_SET_CHANNELS,
|
||||
AF_CONTROL_SET_VOLUME,
|
||||
AF_CONTROL_GET_VOLUME,
|
||||
AF_CONTROL_SET_PAN_LEVEL,
|
||||
@@ -119,9 +119,6 @@ enum af_control {
|
||||
AF_CONTROL_SET_PAN_BALANCE,
|
||||
AF_CONTROL_GET_PAN_BALANCE,
|
||||
AF_CONTROL_SET_PLAYBACK_SPEED,
|
||||
AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE,
|
||||
AF_CONTROL_GET_METADATA,
|
||||
AF_CONTROL_COMMAND,
|
||||
};
|
||||
|
||||
// Argument for AF_CONTROL_SET_PAN_LEVEL
|
||||
@@ -134,28 +131,20 @@ struct af_stream *af_new(struct mpv_global *global);
|
||||
void af_destroy(struct af_stream *s);
|
||||
int af_init(struct af_stream *s);
|
||||
void af_uninit(struct af_stream *s);
|
||||
struct af_instance *af_add(struct af_stream *s, char *name, char *label,
|
||||
char **args);
|
||||
int af_remove_by_label(struct af_stream *s, char *label);
|
||||
struct af_instance *af_find_by_label(struct af_stream *s, char *label);
|
||||
struct af_instance *af_add(struct af_stream *s, char *name, char **args);
|
||||
int af_filter(struct af_stream *s, struct mp_audio *data, int flags);
|
||||
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
|
||||
void af_control_all(struct af_stream *s, int cmd, void *arg);
|
||||
int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label);
|
||||
void af_seek_reset(struct af_stream *s);
|
||||
int af_send_command(struct af_stream *s, char *label, char *cmd, char *arg);
|
||||
|
||||
void af_add_output_frame(struct af_instance *af, struct mp_audio *frame);
|
||||
int af_filter_frame(struct af_stream *s, struct mp_audio *frame);
|
||||
int af_output_frame(struct af_stream *s, bool eof);
|
||||
struct mp_audio *af_read_output_frame(struct af_stream *s);
|
||||
void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame);
|
||||
int af_make_writeable(struct af_instance *af, struct mp_audio *frame);
|
||||
|
||||
double af_calc_filter_multiplier(struct af_stream *s);
|
||||
double af_calc_delay(struct af_stream *s);
|
||||
|
||||
int af_test_output(struct af_instance *af, struct mp_audio *out);
|
||||
|
||||
int af_from_dB(int n, float *in, float *out, float k, float mi, float ma);
|
||||
int af_to_dB(int n, float *in, float *out, float k);
|
||||
int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma);
|
||||
int af_to_ms(int n, int *in, float *out, int rate);
|
||||
float af_softclip(float a);
|
||||
|
||||
#endif /* MPLAYER_AF_H */
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* The Bauer stereophonic-to-binaural DSP using bs2b library:
|
||||
* http://bs2b.sourceforge.net/
|
||||
*
|
||||
* Copyright (c) 2009 Andrew Savchenko
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <bs2b.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "af.h"
|
||||
#include "options/m_option.h"
|
||||
|
||||
/// Internal specific data of the filter
|
||||
struct af_bs2b {
|
||||
int fcut; ///< cut frequency in Hz
|
||||
int feed; ///< feed level for low frequencies in 0.1*dB
|
||||
int profile ; ///< profile (available crossfeed presets)
|
||||
t_bs2bdp filter; ///< instance of a library filter
|
||||
};
|
||||
|
||||
#define FILTER(name, type) \
|
||||
static int filter_##name(struct af_instance *af, struct mp_audio *data, int f) \
|
||||
{ \
|
||||
/* filter is called for all pairs of samples available in the buffer */ \
|
||||
bs2b_cross_feed_##name(((struct af_bs2b*)(af->priv))->filter, \
|
||||
(type*)(data->planes[0]), data->samples); \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
FILTER(f, float)
|
||||
FILTER(fbe, float)
|
||||
FILTER(fle, float)
|
||||
FILTER(s32be, int32_t)
|
||||
FILTER(u32be, uint32_t)
|
||||
FILTER(s32le, int32_t)
|
||||
FILTER(u32le, uint32_t)
|
||||
FILTER(s24be, bs2b_int24_t)
|
||||
FILTER(u24be, bs2b_uint24_t)
|
||||
FILTER(s24le, bs2b_int24_t)
|
||||
FILTER(u24le, bs2b_uint24_t)
|
||||
FILTER(s16be, int16_t)
|
||||
FILTER(u16be, uint16_t)
|
||||
FILTER(s16le, int16_t)
|
||||
FILTER(u16le, uint16_t)
|
||||
FILTER(s8, int8_t)
|
||||
FILTER(u8, uint8_t)
|
||||
|
||||
|
||||
/// Initialization and runtime control
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
struct af_bs2b *s = af->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
int format;
|
||||
// Sanity check
|
||||
if (!arg) return AF_ERROR;
|
||||
|
||||
format = ((struct mp_audio*)arg)->format;
|
||||
af->data->rate = ((struct mp_audio*)arg)->rate;
|
||||
mp_audio_set_num_channels(af->data, 2); // bs2b is useful only for 2ch audio
|
||||
mp_audio_set_format(af->data, format);
|
||||
|
||||
/* check for formats supported by libbs2b
|
||||
and assign corresponding handlers */
|
||||
switch (format) {
|
||||
case AF_FORMAT_FLOAT_BE:
|
||||
af->filter = filter_fbe;
|
||||
break;
|
||||
case AF_FORMAT_FLOAT_LE:
|
||||
af->filter = filter_fle;
|
||||
break;
|
||||
case AF_FORMAT_S32_BE:
|
||||
af->filter = filter_s32be;
|
||||
break;
|
||||
case AF_FORMAT_U32_BE:
|
||||
af->filter = filter_u32be;
|
||||
break;
|
||||
case AF_FORMAT_S32_LE:
|
||||
af->filter = filter_s32le;
|
||||
break;
|
||||
case AF_FORMAT_U32_LE:
|
||||
af->filter = filter_u32le;
|
||||
break;
|
||||
case AF_FORMAT_S24_BE:
|
||||
af->filter = filter_s24be;
|
||||
break;
|
||||
case AF_FORMAT_U24_BE:
|
||||
af->filter = filter_u24be;
|
||||
break;
|
||||
case AF_FORMAT_S24_LE:
|
||||
af->filter = filter_s24le;
|
||||
break;
|
||||
case AF_FORMAT_U24_LE:
|
||||
af->filter = filter_u24le;
|
||||
break;
|
||||
case AF_FORMAT_S16_BE:
|
||||
af->filter = filter_s16be;
|
||||
break;
|
||||
case AF_FORMAT_U16_BE:
|
||||
af->filter = filter_u16be;
|
||||
break;
|
||||
case AF_FORMAT_S16_LE:
|
||||
af->filter = filter_s16le;
|
||||
break;
|
||||
case AF_FORMAT_U16_LE:
|
||||
af->filter = filter_u16le;
|
||||
break;
|
||||
case AF_FORMAT_S8:
|
||||
af->filter = filter_s8;
|
||||
break;
|
||||
case AF_FORMAT_U8:
|
||||
af->filter = filter_u8;
|
||||
break;
|
||||
default:
|
||||
af->filter = filter_f;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
break;
|
||||
}
|
||||
|
||||
// bs2b have srate limits, try to resample if needed
|
||||
if (af->data->rate > BS2B_MAXSRATE || af->data->rate < BS2B_MINSRATE) {
|
||||
af->data->rate = BS2B_DEFAULT_SRATE;
|
||||
MP_WARN(af, "Requested sample rate %d Hz is out of bounds [%d..%d] Hz.\n"
|
||||
"Trying to resample to %d Hz.\n",
|
||||
af->data->rate, BS2B_MINSRATE, BS2B_MAXSRATE, BS2B_DEFAULT_SRATE);
|
||||
}
|
||||
bs2b_set_srate(s->filter, (long)af->data->rate);
|
||||
MP_VERBOSE(af, "using format %s\n",
|
||||
af_fmt_to_str(af->data->format));
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
/// Deallocate memory and close library
|
||||
static void uninit(struct af_instance *af)
|
||||
{
|
||||
struct af_bs2b *s = af->priv;
|
||||
if (s->filter)
|
||||
bs2b_close(s->filter);
|
||||
}
|
||||
|
||||
/// Allocate memory, set function pointers and init library
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
struct af_bs2b *s = af->priv;
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
|
||||
// NULL means failed initialization
|
||||
if (!(s->filter = bs2b_open())) {
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
if (s->profile)
|
||||
bs2b_set_level(s->filter, s->profile);
|
||||
// set fcut and feed only if specified, otherwise defaults will be used
|
||||
if (s->fcut)
|
||||
bs2b_set_level_fcut(s->filter, s->fcut);
|
||||
if (s->feed)
|
||||
bs2b_set_level_feed(s->filter, s->feed);
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct af_bs2b
|
||||
|
||||
/// Description of this filter
|
||||
const struct af_info af_info_bs2b = {
|
||||
.info = "Bauer stereophonic-to-binaural audio filter",
|
||||
.name = "bs2b",
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(struct af_bs2b),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_INTRANGE("fcut", fcut, 0, BS2B_MINFCUT, BS2B_MAXFCUT),
|
||||
OPT_INTRANGE("feed", feed, 0, BS2B_MINFEED, BS2B_MAXFEED),
|
||||
OPT_CHOICE("profile", profile, 0,
|
||||
({"default", BS2B_DEFAULT_CLEVEL},
|
||||
{"cmoy", BS2B_CMOY_CLEVEL},
|
||||
{"jmeier", BS2B_JMEIER_CLEVEL})),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This filter adds a center channel to the audio stream by
|
||||
* averaging the left and right channel.
|
||||
* There are two runtime controls one for setting which channel
|
||||
* to insert the center-audio into called AF_CONTROL_SUB_CH.
|
||||
*
|
||||
* FIXME: implement a high-pass filter for better results.
|
||||
*
|
||||
* copyright (c) 2005 Alex Beregszaszi
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_center_s
|
||||
{
|
||||
int ch; // Channel number which to insert the filtered data
|
||||
}af_center_t;
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_center_t* s = af->priv;
|
||||
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:{
|
||||
// Sanity check
|
||||
if(!arg) return AF_ERROR;
|
||||
|
||||
af->data->rate = ((struct mp_audio*)arg)->rate;
|
||||
mp_audio_set_channels_old(af->data, MPMAX(s->ch+1,((struct mp_audio*)arg)->nch));
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_center_t* s = af->priv; // Setup for this instance
|
||||
float* a = c->planes[0]; // Audio data
|
||||
int nch = c->nch; // Number of channels
|
||||
int len = c->samples*c->nch; // Number of samples in current audio block
|
||||
int ch = s->ch; // Channel in which to insert the center audio
|
||||
register int i;
|
||||
|
||||
// Run filter
|
||||
for(i=0;i<len;i+=nch){
|
||||
// Average left and right
|
||||
a[i+ch] = (a[i]/2) + (a[i+1]/2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_center_t
|
||||
const struct af_info af_info_center = {
|
||||
.info = "Audio filter for adding a center channel",
|
||||
.name = "center",
|
||||
.flags = AF_FLAGS_NOT_REENTRANT,
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_center_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_INTRANGE("channel", ch, 0, 0, AF_NCH - 1, OPTDEF_INT(1)),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
+15
-17
@@ -5,20 +5,21 @@
|
||||
*
|
||||
* Original author: Anders
|
||||
*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -180,20 +181,15 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
struct mp_audio* l = af->data; // Local data
|
||||
af_channels_t* s = af->priv;
|
||||
int i;
|
||||
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
|
||||
if (!l) {
|
||||
talloc_free(c);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(l, c);
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
// Reset unused channels
|
||||
memset(l->planes[0],0,mp_audio_psize(c) / c->nch * l->nch);
|
||||
@@ -203,15 +199,17 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
copy(af, c->planes[0],l->planes[0],c->nch,s->route[i][FR],
|
||||
l->nch,s->route[i][TO],mp_audio_psize(c),c->bps);
|
||||
|
||||
talloc_free(c);
|
||||
af_add_output_frame(af, l);
|
||||
// Set output data
|
||||
c->planes[0] = l->planes[0];
|
||||
mp_audio_set_channels(c, &l->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
af_channels_t *s = af->priv;
|
||||
|
||||
// If router scan commandline for routing pairs
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "audio/format.h"
|
||||
#include "af.h"
|
||||
|
||||
static bool test_conversion(int src_format, int dst_format)
|
||||
{
|
||||
return (src_format == AF_FORMAT_U24 && dst_format == AF_FORMAT_U32) ||
|
||||
(src_format == AF_FORMAT_S24 && dst_format == AF_FORMAT_S32) ||
|
||||
(src_format == AF_FORMAT_U32 && dst_format == AF_FORMAT_U24) ||
|
||||
(src_format == AF_FORMAT_S32 && dst_format == AF_FORMAT_S24);
|
||||
}
|
||||
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
struct mp_audio *in = arg;
|
||||
struct mp_audio orig_in = *in;
|
||||
struct mp_audio *out = af->data;
|
||||
|
||||
if (!test_conversion(in->format, out->format))
|
||||
return AF_DETACH;
|
||||
|
||||
if ((in->format & AF_FORMAT_BITS_MASK) == AF_FORMAT_24BIT) {
|
||||
mp_audio_set_format(out, af_fmt_change_bits(in->format, 32));
|
||||
} else if ((in->format & AF_FORMAT_BITS_MASK) == AF_FORMAT_32BIT) {
|
||||
mp_audio_set_format(out, af_fmt_change_bits(in->format, 24));
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
out->rate = in->rate;
|
||||
mp_audio_set_channels(out, &in->channels);
|
||||
|
||||
assert(test_conversion(in->format, out->format));
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
case AF_CONTROL_SET_FORMAT: {
|
||||
mp_audio_set_format(af->data, *(int*)arg);
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// The LSB is always ignored.
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define SHIFT(x) ((3-(x))*8)
|
||||
#else
|
||||
#define SHIFT(x) (((x)+1)*8)
|
||||
#endif
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
struct mp_audio *out = af->data;
|
||||
size_t len = mp_audio_psize(data) / data->bps;
|
||||
|
||||
if (data->bps == 4) {
|
||||
for (int s = 0; s < len; s++) {
|
||||
uint32_t val = *((uint32_t *)data->planes[0] + s);
|
||||
uint8_t *ptr = (uint8_t *)out->planes[0] + s * 3;
|
||||
ptr[0] = val >> SHIFT(0);
|
||||
ptr[1] = val >> SHIFT(1);
|
||||
ptr[2] = val >> SHIFT(2);
|
||||
}
|
||||
mp_audio_set_format(data, af_fmt_change_bits(data->format, 24));
|
||||
} else {
|
||||
for (int s = 0; s < len; s++) {
|
||||
uint8_t *ptr = (uint8_t *)data->planes[0] + s * 3;
|
||||
uint32_t val = ptr[0] << SHIFT(0)
|
||||
| ptr[1] << SHIFT(1)
|
||||
| ptr[2] << SHIFT(2);
|
||||
*((uint32_t *)out->planes[0] + s) = val;
|
||||
}
|
||||
mp_audio_set_format(data, af_fmt_change_bits(data->format, 32));
|
||||
}
|
||||
|
||||
data->planes[0] = out->planes[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter = filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
const struct af_info af_info_convert24 = {
|
||||
.info = "Convert between 24 and 32 bit sample format",
|
||||
.name = "convert24",
|
||||
.open = af_open,
|
||||
.test_conversion = test_conversion,
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "af.h"
|
||||
#include "audio/format.h"
|
||||
#include "compat/mpbswap.h"
|
||||
|
||||
static bool test_conversion(int src_format, int dst_format)
|
||||
{
|
||||
if ((src_format & AF_FORMAT_PLANAR) ||
|
||||
(dst_format & AF_FORMAT_PLANAR))
|
||||
return false;
|
||||
int src_noend = src_format & ~AF_FORMAT_END_MASK;
|
||||
int dst_noend = dst_format & ~AF_FORMAT_END_MASK;
|
||||
// We can swap endian for all formats, but sign only for integer formats.
|
||||
if (src_noend == dst_noend)
|
||||
return true;
|
||||
if (((src_noend & ~AF_FORMAT_SIGN_MASK) ==
|
||||
(dst_noend & ~AF_FORMAT_SIGN_MASK)) &&
|
||||
((src_noend & AF_FORMAT_POINT_MASK) == AF_FORMAT_I))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
struct mp_audio *in = arg;
|
||||
struct mp_audio orig_in = *in;
|
||||
struct mp_audio *out = af->data;
|
||||
|
||||
if (!test_conversion(in->format, out->format))
|
||||
return AF_DETACH;
|
||||
|
||||
out->rate = in->rate;
|
||||
mp_audio_set_channels(out, &in->channels);
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
case AF_CONTROL_SET_FORMAT: {
|
||||
mp_audio_set_format(af->data, *(int*)arg);
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static void endian(void *data, int len, int bps)
|
||||
{
|
||||
switch (bps) {
|
||||
case 2:
|
||||
for (int i = 0; i < len; i++) {
|
||||
((uint16_t*)data)[i] = bswap_16(((uint16_t *)data)[i]);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for(int i = 0; i < len; i++) {
|
||||
uint8_t s = ((uint8_t *)data)[3 * i];
|
||||
((uint8_t *)data)[3 * i] = ((uint8_t *)data)[3 * i + 2];
|
||||
((uint8_t *)data)[3 * i + 2] = s;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for(int i = 0; i < len; i++) {
|
||||
((uint32_t*)data)[i] = bswap_32(((uint32_t *)data)[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void si2us(void *data, int len, int bps, bool le)
|
||||
{
|
||||
ptrdiff_t i = -(len * bps);
|
||||
uint8_t *p = &((uint8_t *)data)[len * bps];
|
||||
if (le && bps > 1)
|
||||
p += bps - 1;
|
||||
if (len <= 0)
|
||||
return;
|
||||
do {
|
||||
p[i] ^= 0x80;
|
||||
} while (i += bps);
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
int infmt = data->format;
|
||||
int outfmt = af->data->format;
|
||||
size_t len = data->samples * data->nch;
|
||||
|
||||
if ((infmt & AF_FORMAT_END_MASK) != (outfmt & AF_FORMAT_END_MASK))
|
||||
endian(data->planes[0], len, data->bps);
|
||||
|
||||
if ((infmt & AF_FORMAT_SIGN_MASK) != (outfmt & AF_FORMAT_SIGN_MASK))
|
||||
si2us(data->planes[0], len, data->bps,
|
||||
(outfmt & AF_FORMAT_END_MASK) == AF_FORMAT_LE);
|
||||
|
||||
mp_audio_set_format(data, outfmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter = filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
const struct af_info af_info_convertsignendian = {
|
||||
.info = "Convert between sample format sign/endian",
|
||||
.name = "convertsignendian",
|
||||
.open = af_open,
|
||||
.test_conversion = test_conversion,
|
||||
};
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* This audio filter delays the output signal for the different
|
||||
* channels and can be used for simple position panning.
|
||||
* An extension for this filter would be a reverb.
|
||||
*
|
||||
* Original author: Anders
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
#define L 65536
|
||||
|
||||
#define UPDATEQI(qi) qi=(qi+1)&(L-1)
|
||||
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_delay_s
|
||||
{
|
||||
void* q[AF_NCH]; // Circular queues used for delaying audio signal
|
||||
int wi[AF_NCH]; // Write index
|
||||
int ri; // Read index
|
||||
float d[AF_NCH]; // Delay [ms]
|
||||
char *delaystr;
|
||||
}af_delay_t;
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_delay_t* s = af->priv;
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:{
|
||||
int i;
|
||||
struct mp_audio *in = arg;
|
||||
|
||||
if (in->bps != 1 && in->bps != 2 && in->bps != 4) {
|
||||
MP_FATAL(af, "Sample format not supported\n");
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
// Free prevous delay queues
|
||||
for(i=0;i<af->data->nch;i++)
|
||||
free(s->q[i]);
|
||||
|
||||
mp_audio_force_interleaved_format(in);
|
||||
mp_audio_copy_config(af->data, in);
|
||||
|
||||
// Allocate new delay queues
|
||||
for(i=0;i<af->data->nch;i++){
|
||||
s->q[i] = calloc(L,af->data->bps);
|
||||
if(NULL == s->q[i])
|
||||
MP_FATAL(af, "Out of memory\n");
|
||||
}
|
||||
|
||||
if(AF_OK != af_from_ms(AF_NCH, s->d, s->wi, af->data->rate, 0.0, 1000.0))
|
||||
return AF_ERROR;
|
||||
s->ri = 0;
|
||||
for(i=0;i<AF_NCH;i++){
|
||||
MP_DBG(af, "Channel %i delayed by %0.3fms\n",
|
||||
i,MPCLAMP(s->d[i],0.0,1000.0));
|
||||
MP_TRACE(af, "Channel %i delayed by %i samples\n",
|
||||
i,s->wi[i]);
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Deallocate memory
|
||||
static void uninit(struct af_instance* af)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<AF_NCH;i++)
|
||||
free(((af_delay_t*)(af->priv))->q[i]);
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_delay_t* s = af->priv; // Setup for this instance
|
||||
int nch = c->nch; // Number of channels
|
||||
int len = mp_audio_psize(c)/c->bps; // Number of sample in data chunk
|
||||
int ri = 0;
|
||||
int ch,i;
|
||||
for(ch=0;ch<nch;ch++){
|
||||
switch(c->bps){
|
||||
case 1:{
|
||||
int8_t* a = c->planes[0];
|
||||
int8_t* q = s->q[ch];
|
||||
int wi = s->wi[ch];
|
||||
ri = s->ri;
|
||||
for(i=ch;i<len;i+=nch){
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
}
|
||||
s->wi[ch] = wi;
|
||||
break;
|
||||
}
|
||||
case 2:{
|
||||
int16_t* a = c->planes[0];
|
||||
int16_t* q = s->q[ch];
|
||||
int wi = s->wi[ch];
|
||||
ri = s->ri;
|
||||
for(i=ch;i<len;i+=nch){
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
}
|
||||
s->wi[ch] = wi;
|
||||
break;
|
||||
}
|
||||
case 4:{
|
||||
int32_t* a = c->planes[0];
|
||||
int32_t* q = s->q[ch];
|
||||
int wi = s->wi[ch];
|
||||
ri = s->ri;
|
||||
for(i=ch;i<len;i+=nch){
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
}
|
||||
s->wi[ch] = wi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->ri = ri;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->filter=filter;
|
||||
af_delay_t *s = af->priv;
|
||||
int n = 1;
|
||||
int i = 0;
|
||||
char* cl = s->delaystr;
|
||||
while(cl && n && i < AF_NCH ){
|
||||
sscanf(cl,"%f%n",&s->d[i],&n);
|
||||
if(n==0 || cl[n-1] == '\0')
|
||||
break;
|
||||
cl=&cl[n];
|
||||
if (*cl != ',')
|
||||
break;
|
||||
cl++;
|
||||
i++;
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_delay_t
|
||||
const struct af_info af_info_delay = {
|
||||
.info = "Delay audio filter",
|
||||
.name = "delay",
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_delay_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("delays", delaystr, 0),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
+12
-19
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Alex Beregszaszi & Pierre Lombard
|
||||
*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -131,7 +132,7 @@ static void method1_int16(af_drc_t *s, struct mp_audio *c)
|
||||
data[i] = tmp;
|
||||
}
|
||||
|
||||
// Evaluation of newavg (not 100% accurate because of values clamping)
|
||||
// Evaulation of newavg (not 100% accurate because of values clamping)
|
||||
newavg = s->mul * curavg;
|
||||
|
||||
// Stores computed values for future smoothing
|
||||
@@ -168,7 +169,7 @@ static void method1_float(af_drc_t *s, struct mp_audio *c)
|
||||
for (i = 0; i < len; i++)
|
||||
data[i] *= s->mul;
|
||||
|
||||
// Evaluation of newavg (not 100% accurate because of values clamping)
|
||||
// Evaulation of newavg (not 100% accurate because of values clamping)
|
||||
newavg = s->mul * curavg;
|
||||
|
||||
// Stores computed values for future smoothing
|
||||
@@ -216,7 +217,7 @@ static void method2_int16(af_drc_t *s, struct mp_audio *c)
|
||||
data[i] = tmp;
|
||||
}
|
||||
|
||||
// Evaluation of newavg (not 100% accurate because of values clamping)
|
||||
// Evaulation of newavg (not 100% accurate because of values clamping)
|
||||
newavg = s->mul * curavg;
|
||||
|
||||
// Stores computed values for future smoothing
|
||||
@@ -262,7 +263,7 @@ static void method2_float(af_drc_t *s, struct mp_audio *c)
|
||||
for (i = 0; i < len; i++)
|
||||
data[i] *= s->mul;
|
||||
|
||||
// Evaluation of newavg (not 100% accurate because of values clamping)
|
||||
// Evaulation of newavg (not 100% accurate because of values clamping)
|
||||
newavg = s->mul * curavg;
|
||||
|
||||
// Stores computed values for future smoothing
|
||||
@@ -271,18 +272,10 @@ static void method2_float(af_drc_t *s, struct mp_audio *c)
|
||||
s->idx = (s->idx + 1) % NSAMPLES;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
af_drc_t *s = af->priv;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(af->data->format == (AF_FORMAT_S16))
|
||||
{
|
||||
if (s->method == 2)
|
||||
@@ -297,7 +290,6 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
else
|
||||
method1_float(s, data);
|
||||
}
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -305,7 +297,7 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int af_open(struct af_instance* af){
|
||||
int i = 0;
|
||||
af->control=control;
|
||||
af->filter_frame = filter;
|
||||
af->filter=filter;
|
||||
af_drc_t *priv = af->priv;
|
||||
|
||||
priv->mul = MUL_INIT;
|
||||
@@ -324,6 +316,7 @@ static int af_open(struct af_instance* af){
|
||||
const struct af_info af_info_drc = {
|
||||
.info = "Dynamic range compression filter",
|
||||
.name = "drc",
|
||||
.flags = AF_FLAGS_NOT_REENTRANT,
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_drc_t),
|
||||
.options = (const struct m_option[]) {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* The name speaks for itself. This filter is a dummy and will
|
||||
* not blow up regardless of what you do with it.
|
||||
*
|
||||
* Original author: Anders
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "af.h"
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT: ;
|
||||
*af->data = *(struct mp_audio*)arg;
|
||||
MP_VERBOSE(af, "Was reinitialized: %iHz/%ich/%s\n",
|
||||
af->data->rate,af->data->nch,af_fmt_to_str(af->data->format));
|
||||
return AF_OK;
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
// Description of this filter
|
||||
const struct af_info af_info_dummy = {
|
||||
.info = "dummy",
|
||||
.name = "dummy",
|
||||
.open = af_open,
|
||||
};
|
||||
@@ -6,20 +6,21 @@
|
||||
*
|
||||
* Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
|
||||
*
|
||||
* This file is part of mpv.
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -140,20 +141,14 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance* af, struct mp_audio* data)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
if (!c)
|
||||
return 0;
|
||||
af_equalizer_t* s = (af_equalizer_t*)af->priv; // Setup
|
||||
uint32_t ci = af->data->nch; // Index for channels
|
||||
uint32_t nch = af->data->nch; // Number of channels
|
||||
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(ci--){
|
||||
float* g = s->g[ci]; // Gain factor
|
||||
float* in = ((float*)c->planes[0])+ci;
|
||||
@@ -182,14 +177,13 @@ static int filter(struct af_instance* af, struct mp_audio* data)
|
||||
out+=nch;
|
||||
}
|
||||
}
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter;
|
||||
af->filter=filter;
|
||||
af_equalizer_t *priv = af->priv;
|
||||
for(int i=0;i<AF_NCH;i++){
|
||||
for(int j=0;j<KM;j++){
|
||||
@@ -203,6 +197,7 @@ static int af_open(struct af_instance* af){
|
||||
const struct af_info af_info_equalizer = {
|
||||
.info = "Equalizer audio filter",
|
||||
.name = "equalizer",
|
||||
.flags = AF_FLAGS_NOT_REENTRANT,
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_equalizer_t),
|
||||
.options = (const struct m_option[]) {
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* This audio filter exports the incoming signal to other processes
|
||||
* using memory mapping. The memory mapped area contains a header:
|
||||
* int nch,
|
||||
* int size,
|
||||
* unsigned long long counter (updated every time the contents of
|
||||
* the area changes),
|
||||
* the rest is payload (non-interleaved).
|
||||
*
|
||||
* Authors: Anders; Gustavo Sverzut Barbieri <gustavo.barbieri@ic.unicamp.br>
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "osdep/io.h"
|
||||
|
||||
#include "talloc.h"
|
||||
#include "af.h"
|
||||
#include "options/path.h"
|
||||
|
||||
#define DEF_SZ 512 // default buffer size (in samples)
|
||||
#define SHARED_FILE "mpv-af_export" /* default file name
|
||||
(relative to ~/.mpv/ */
|
||||
|
||||
#define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long))
|
||||
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_export_s
|
||||
{
|
||||
unsigned long long count; // Used for sync
|
||||
void* buf[AF_NCH]; // Buffers for storing the data before it is exported
|
||||
int sz; // Size of buffer in samples
|
||||
int wi; // Write index
|
||||
int fd; // File descriptor to shared memory area
|
||||
char* filename; // File to export data
|
||||
uint8_t *mmap_area; // MMap shared area
|
||||
} af_export_t;
|
||||
|
||||
|
||||
/* Initialization and runtime control
|
||||
af audio filter instance
|
||||
cmd control command
|
||||
arg argument
|
||||
*/
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_export_t* s = af->priv;
|
||||
switch (cmd){
|
||||
case AF_CONTROL_REINIT:{
|
||||
int i=0;
|
||||
int mapsize;
|
||||
|
||||
// Free previous buffers
|
||||
if (s->buf)
|
||||
free(s->buf[0]);
|
||||
|
||||
// unmap previous area
|
||||
if(s->mmap_area)
|
||||
munmap(s->mmap_area, SIZE_HEADER + (af->data->bps*s->sz*af->data->nch));
|
||||
// close previous file descriptor
|
||||
if(s->fd)
|
||||
close(s->fd);
|
||||
|
||||
// Accept only int16_t as input format (which sucks)
|
||||
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
|
||||
mp_audio_set_format(af->data, AF_FORMAT_S16);
|
||||
|
||||
// Allocate new buffers (as one continuous block)
|
||||
s->buf[0] = calloc(s->sz*af->data->nch, af->data->bps);
|
||||
if(NULL == s->buf[0])
|
||||
MP_FATAL(af, "Out of memory\n");
|
||||
for(i = 1; i < af->data->nch; i++)
|
||||
s->buf[i] = (uint8_t *)s->buf[0] + i*s->sz*af->data->bps;
|
||||
|
||||
if (!s->filename) {
|
||||
MP_FATAL(af, "No filename set.\n");
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
// Init memory mapping
|
||||
s->fd = open(s->filename, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
|
||||
MP_INFO(af, "Exporting to file: %s\n", s->filename);
|
||||
if(s->fd < 0) {
|
||||
MP_FATAL(af, "Could not open/create file: %s\n",
|
||||
s->filename);
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
// header + buffer
|
||||
mapsize = (SIZE_HEADER + (af->data->bps * s->sz * af->data->nch));
|
||||
|
||||
// grow file to needed size
|
||||
for(i = 0; i < mapsize; i++){
|
||||
char null = 0;
|
||||
write(s->fd, (void*) &null, 1);
|
||||
}
|
||||
|
||||
// mmap size
|
||||
s->mmap_area = mmap(0, mapsize, PROT_READ|PROT_WRITE,MAP_SHARED, s->fd, 0);
|
||||
if(s->mmap_area == NULL)
|
||||
MP_FATAL(af, "Could not mmap file %s\n", s->filename);
|
||||
MP_INFO(af, "Memory mapped to file: %s (%p)\n",
|
||||
s->filename, s->mmap_area);
|
||||
|
||||
// Initialize header
|
||||
*((int*)s->mmap_area) = af->data->nch;
|
||||
*((int*)s->mmap_area + 1) = s->sz * af->data->bps * af->data->nch;
|
||||
msync(s->mmap_area, mapsize, MS_ASYNC);
|
||||
|
||||
// Use test_output to return FALSE if necessary
|
||||
return af_test_output(af, (struct mp_audio*)arg);
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Free allocated memory and clean up other stuff too.
|
||||
af audio filter instance
|
||||
*/
|
||||
static void uninit( struct af_instance* af )
|
||||
{
|
||||
af_export_t* s = af->priv;
|
||||
if (s->buf)
|
||||
free(s->buf[0]);
|
||||
|
||||
// Free mmaped area
|
||||
if(s->mmap_area)
|
||||
munmap(s->mmap_area, sizeof(af_export_t));
|
||||
|
||||
if(s->fd > -1)
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
/* Filter data through filter
|
||||
af audio filter instance
|
||||
data audio data
|
||||
*/
|
||||
static int filter( struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_export_t* s = af->priv; // Setup for this instance
|
||||
int16_t* a = c->planes[0]; // Incomming sound
|
||||
int nch = c->nch; // Number of channels
|
||||
int len = c->samples*c->nch; // Number of sample in data chunk
|
||||
int sz = s->sz; // buffer size (in samples)
|
||||
int flag = 0; // Set to 1 if buffer is filled
|
||||
|
||||
int ch, i;
|
||||
|
||||
// Fill all buffers
|
||||
for(ch = 0; ch < nch; ch++){
|
||||
int wi = s->wi; // Reset write index
|
||||
int16_t* b = s->buf[ch]; // Current buffer
|
||||
|
||||
// Copy data to export buffers
|
||||
for(i = ch; i < len; i += nch){
|
||||
b[wi++] = a[i];
|
||||
if(wi >= sz){ // Don't write outside the end of the buffer
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->wi = wi % s->sz;
|
||||
}
|
||||
|
||||
// Export buffer to mmaped area
|
||||
if(flag){
|
||||
// update buffer in mapped area
|
||||
memcpy(s->mmap_area + SIZE_HEADER, s->buf[0], sz * c->bps * nch);
|
||||
s->count++; // increment counter (to sync)
|
||||
memcpy(s->mmap_area + SIZE_HEADER - sizeof(s->count),
|
||||
&(s->count), sizeof(s->count));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate memory and set function pointers
|
||||
af audio filter instance
|
||||
returns AF_OK or AF_ERROR
|
||||
*/
|
||||
static int af_open( struct af_instance* af )
|
||||
{
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->filter = filter;
|
||||
af_export_t *priv = af->priv;
|
||||
|
||||
if (!priv->filename || !priv->filename[0]) {
|
||||
MP_FATAL(af, "no export filename given");
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_export_t
|
||||
const struct af_info af_info_export = {
|
||||
.info = "Sound export filter",
|
||||
.name = "export",
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_export_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("filename", filename, 0),
|
||||
OPT_INTRANGE("buffersamples", sz, 0, 1, 2048, OPTDEF_INT(DEF_SZ)),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Alex Beregszaszi & Pierre Lombard
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_extrastereo_s
|
||||
{
|
||||
float mul;
|
||||
}af_extrastereo_t;
|
||||
|
||||
static int play_s16(struct af_instance* af, struct mp_audio* data, int f);
|
||||
static int play_float(struct af_instance* af, struct mp_audio* data, int f);
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:{
|
||||
// Sanity check
|
||||
if(!arg) return AF_ERROR;
|
||||
|
||||
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
|
||||
mp_audio_force_interleaved_format(af->data);
|
||||
mp_audio_set_num_channels(af->data, 2);
|
||||
if (af->data->format == AF_FORMAT_FLOAT)
|
||||
{
|
||||
af->filter = play_float;
|
||||
}// else
|
||||
{
|
||||
mp_audio_set_format(af->data, AF_FORMAT_S16);
|
||||
af->filter = play_s16;
|
||||
}
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int play_s16(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
af_extrastereo_t *s = af->priv;
|
||||
register int i = 0;
|
||||
int16_t *a = (int16_t*)data->planes[0]; // Audio data
|
||||
int len = data->samples*data->nch; // Number of samples
|
||||
int avg, l, r;
|
||||
|
||||
for (i = 0; i < len; i+=2)
|
||||
{
|
||||
avg = (a[i] + a[i + 1]) / 2;
|
||||
|
||||
l = avg + (int)(s->mul * (a[i] - avg));
|
||||
r = avg + (int)(s->mul * (a[i + 1] - avg));
|
||||
|
||||
a[i] = MPCLAMP(l, SHRT_MIN, SHRT_MAX);
|
||||
a[i + 1] = MPCLAMP(r, SHRT_MIN, SHRT_MAX);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int play_float(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
af_extrastereo_t *s = af->priv;
|
||||
register int i = 0;
|
||||
float *a = (float*)data->planes[0]; // Audio data
|
||||
int len = data->samples * data->nch; // Number of samples
|
||||
float avg, l, r;
|
||||
|
||||
for (i = 0; i < len; i+=2)
|
||||
{
|
||||
avg = (a[i] + a[i + 1]) / 2;
|
||||
|
||||
l = avg + (s->mul * (a[i] - avg));
|
||||
r = avg + (s->mul * (a[i + 1] - avg));
|
||||
|
||||
a[i] = af_softclip(l);
|
||||
a[i + 1] = af_softclip(r);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter=play_s16;
|
||||
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_extrastereo_t
|
||||
const struct af_info af_info_extrastereo = {
|
||||
.info = "Increase difference between audio channels",
|
||||
.name = "extrastereo",
|
||||
.flags = AF_FLAGS_NOT_REENTRANT,
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_extrastereo_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_FLOAT("mul", mul, 0, OPTDEF_FLOAT(2.5)),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
Loaded 100 of 675 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user