Compare commits

..
70 Commits
Author SHA1 Message Date
wm4 d276f753f7 Release 0.3.3 2014-01-15 21:03:02 +01:00
Grzegorz Blach c06000eef8 Detect Lua on FreeBSD 2014-01-15 20:57:17 +01:00
wm4 1bc1cd2305 player: avoid stalling when starting a network stream
Starting a network stream could stall by executing uncacheable stream
control requests (STREAM_CTRL_GET_LANG and STREAM_CTRL_GET_DVD_INFO).
Being uncacheable means the player has to wait until the cache is done
reading the current block of data. These requests can't be cached
because they're too complicated, so the only way to avoid them is
special casing the DVD and Bluray streams (which are the only things
which need these requests), and not doing them in other cases.

(This is kind of inelegant, but so is the rest of the DVD/BD code.)
2014-01-15 20:57:09 +01:00
wm4 a735a2abd7 demux_mkv: improve robustness by explicitly checking for level 1 elements
Matroska makes it pretty hard to resync correctly on broken files:
random data returns "valid" EBML IDs with a high probability, and when
trying to skip them it's likely that you skip a random amount of data
(instead of considering the element length invalid).

Improve upon this by skipping known level 1 elements only. Consider
everything else invalid and call the resync code. This might result in
annoying behavior when Matroska adds new level 1 elements, although it
won't be particularly harmful. Matroska doesn't really allow us to do
better (even mkvtoolnix explicitly checks for known level 1 elements).

Since we now don't always want to combine EBML element skipping and
resyncing, remove ebml_read_skip_or_resync_cluster(), and make
ebml_read_skip() more tolerant against skipping broken elements.

Also, don't resync when reading sub-elements, and instead do resyncing
when reading them results in an error.
2014-01-15 20:56:16 +01:00
wm4 112c1abe31 demux_mkv: avoid skipping too much data in corrupted files
Until now, corrupted files were detected if the size of an element (that
should be skipped) was larger than the remaining file. This still could
skip larger regions of the file itself if the broken size happened to be
within the file.

Change it so that it's never allowed to skip outside the parent's
element.
2014-01-15 20:56:13 +01:00
wm4 362b35b631 manpage: document --term-osd=force
Apparently this was forgotten when it was first added, or maybe it's an
arrifact from the rst conversion.

Conflicts:
	DOCS/man/en/options.rst
2014-01-15 20:54:32 +01:00
wm4 49cf0af294 player: don't block terminal OSD while seeking
Seeking usually show the status on OSD. In terminal OSD mode, no status
is shown, because there is already a separate status line.
Unfortunately, the mechanism for showing the status was still active,
which forced showing no message while the code for showing seek status
was active.
2014-01-15 20:53:44 +01:00
wm4 1b26874710 player: mention subtitles in av_desync_help_text
Insane .ass subtitle scripts can cause severe slowdown (depending on the
speed of the machine, or the insanity of the script), so mention how to
test without subtitles. This is mainly to make the user aware that
subtitle rendering can be a problem. For longwinded explanation, there
isn't enough space.
2014-01-15 20:53:41 +01:00
Stefano Pigozzi 8fe636da7a cocoa: fix window placement on secondary screens
For a long time the cocoa backend set the xinerama_x/y and used dx/dy from the
VO instance. This somewhat worked with some workarounds but wasn't really
what was supposed to be happening. Moreover 27e4360, which touched this
workaround introduced a regression.

New code doesn't set the xinerama_x/y values so that dx/dy are offsets in the
current screen (not a virtual screen composed of all the screens). The screen
reference detected during VOCTRL_UPDATE_SCREENINFO is also passed down to the
window initialization code.

Fixes #472
2014-01-15 20:53:19 +01:00
Stefano Pigozzi 812f149585 cocoa: refactor init window positioning code 2014-01-15 20:53:14 +01:00
wm4 635424c8f0 demux_lavf: add hack for MicroDVD for assuming frame based timing
MicroDVD files _can_ contain real timestamps instead of frame timestamps
if they declare a FPS. But this seems to be rare, so ignore that if the
FPS happens to match with the libavformat microdvd parser's default FPS.

This might actually break files that declare 23.976 FPS, but the video
file is not 23.976 FPS, but the chance that this happens is probably
very low, and the commit fixes the more common breakage with 25 FPS
video.
2014-01-15 20:51:50 +01:00
wm4 2319918721 sub: fix frame based subtitle timestamp handling
Subtitle formats with frame based timing require using the video FPS to
compute proper subtitle timestamps. But it looks like the calculation to
do that was inversed.
2014-01-15 20:51:47 +01:00
Alexander Preisinger 9fabf85a44 wayland: properly empty output list 2014-01-15 20:51:39 +01:00
Alexander Preisinger 54fd5d0979 wayland/shm: don't crash if initialization failed 2014-01-15 20:51:37 +01:00
wm4 d141d281ca wayland: fix crash when initialization fails
On X11, if no wayland compositor is running, wl_list_init() will never
be called. This will cause destroy_display() to segfault when trying to
iterate over the list.
2014-01-15 20:51:32 +01:00
Alexander Preisinger ebc3d74b04 wayland/shm: tone down warnings
Those warnings are printed far too often and actually aren't usefull at all.
2014-01-15 20:51:19 +01:00
Alexander Preisinger a63fab8921 wayland: fix memory leaks
There are still some leaks from wayland-cursor stuff, but there is no way to
free the memory as user of the cursor library.

Conflicts:
	video/out/wayland_common.c
2014-01-15 20:50:52 +01:00
wm4 4ee8d8d3f9 player: fix setting smaller timeout on Windows systems
On Windows, we don't have proper input event wakeup handling, so we
need to lower the playloop timeout in order to react fast to input.

Closes #387.
2014-01-15 20:50:02 +01:00
Alexander Preisinger 574a2484c1 wayland: cleanup registry_handle_global
The wl_registry object is already passed as a parameter. No need to create
a temporary variable.
2014-01-15 20:49:57 +01:00
Alexander Preisinger f5b92bee5e wayland: remove set_user_data from seat_listener
The user_data is passed on add_listener and can later be changed with
set_user_data. But because we don't want to change it later and because it is
the same object remove the set_user_data call.

This might be a copy&paste leftover from the initial draft for the wayland
backend.
2014-01-15 20:49:55 +01:00
Alexander Preisinger ca3d7144db wayland: use static consistently
Declare everything that is only needed inside wayland_common.c as static.
2014-01-15 20:49:52 +01:00
wm4 86e7c3defb terminal: don't initialize termcap etc. if stdout is not a terminal
Otherwise, it seems one of the term* libraries will write escape
sequences to stdout, for whatever reason.
2014-01-15 20:49:42 +01:00
Alexander Preisinger 0fe1385d80 wayland: fix fullscreen & resizing for good
I added enough logic to never set ontop or fullscreen twitce.
This commit keeps also the size of the video if multiple videos are played.
If the ratio differs the width will be kept at the same size and only the
height changes.
2014-01-15 20:49:32 +01:00
wm4 f4e9371d0f manpage: mention how to get a list of codecs for use with --hwdec-codecs 2014-01-15 20:49:26 +01:00
wm4 909185d49e wayland: silence annoying libwayland-client message
libwayland-client contains the following code [1]:

	runtime_dir = getenv("XDG_RUNTIME_DIR");
	if (!runtime_dir) {
		fprintf(stderr,
			"error: XDG_RUNTIME_DIR not set in the environment.\n");

This means this message will unconditionally and unavoidably be printed
if XDG_RUNTIME_DIR is not set. Since mpv is a terminal program, and we
want to avoid unnecessary output, work it around by not attempting to
use wayland if this environment variable is not set.

[1] http://cgit.freedesktop.org/wayland/wayland/tree/src/wayland-client.c#n636
    (cd0dccd01e16fa404e03974d30ded3aebdb1c4bc)
2014-01-15 20:49:22 +01:00
wm4 c18c324c6f wayland: fix some memory leaks on initialization failure
This commonly happens when initializing vo_opengl on a X11-only system.

Unfortunately, most wl_*_destroy() functions appear not to accept NULL
pointers, making partial deinitialization a pain: you have to add your
own NULL checks everywhere to avoid crashes.

xkb.context is uninitialized separately, because you can initialize it
just fine, even if the rest of input initialization fails.
2014-01-15 20:49:19 +01:00
wm4 6b20c24413 Release 0.3.2 2014-01-06 20:32:24 +01:00
Stefano Pigozzi 5c42d1eb92 cocoa: don't reset window size when the video size doesn't change
Fixes #459
2014-01-06 20:27:55 +01:00
Martin Herkt e34132f8d5 w32_common: don't force topmost on fullscreen
Fixes #457, #444.
2014-01-06 20:27:53 +01:00
Martin Herkt bd7ff23f96 Windows: use roaming AppData instead of local
Whatever. Fixes #458.
2014-01-06 20:27:47 +01:00
wm4 e6c184e2b1 build: don't depend on both libavresample and libswresample
When both libavresample and libswresample were detected, the script
enabled both at the same time. This is not supported; although nothing
bad happened apparently. Make the dependencies both mutually exclusive.
2014-01-06 20:23:10 +01:00
wm4 33c4920967 player: always ise [statusline] for terminal OSD
This was inconsistent: the actual statusline used [statusline] as
message prefix, while other parts of the terminal OSD used [cplayer]
(and MSGL_STATUS). This commit makes it consistent.
2014-01-06 20:23:06 +01:00
wm4 0c36f655e1 player: print an error message if run command fails
Note that we can't use mp_msg, because it's not async-signal safe (we
might be running other threads while forking, so only functions
specified to be async-signal safe can be called, and this doesn't
include stdio; mp_msg acquires a mutex too).

Also, always print a \n before running the program to flush the status
line. The effect is that a program running successfully as well as the
error message will effectively start on a new line.
2014-01-06 20:23:03 +01:00
wm4 cd31697dd8 manpage: fix typo 2014-01-06 20:22:57 +01:00
wm4 c497b82583 player: don't select subtitles added from quvi by default
Quvi subtitles are considered external subtitles (simply because they're
separate from the audio/video stream), but for the sake of subtitle
auto-selection, they should not be considered external.

Change this so that quvi subtitles are treated like muxed subtitles
(with default flag never set). This means subtitles won't be selected by
default, unless explicitly requested with --sid or --slang.
2014-01-06 20:22:53 +01:00
Alexander Preisinger 6f5dfb5102 Revert "wayland/egl: use redraw callback"
Because of this commit there were problems displaying the frmase in their right
order.

This reverts commit 96e75d234a.

Conflicts:
	video/out/gl_wayland.c
	video/out/wayland_common.h
2014-01-06 20:22:43 +01:00
Alexander Preisinger 59f970d492 wayland: remove workaround
The changes in the vo_wayland_ontop function have no effect on the workaround.

Somehow the problem just disappeared. I guess it is because of the new control
function in gl_wayland.c where the resize happens immediatly after the event
dispatch/flush.
2014-01-06 20:22:41 +01:00
wm4 29c74b42b4 demux_subreader: reject file if not opened by --sub
demux_subreader.c contains the old MPlayer subtitle parser, and I have
absolutely no confidence in this (very crappy) code. There might be
one or two security risks associated with running that code on
arbitrary input.
2014-01-06 20:22:26 +01:00
Alexander Preisinger 4b2a3e50e2 wayland/egl: misc fixes and cleanups 2014-01-06 20:22:11 +01:00
Alexander Preisinger 35b01c9604 wayland/egl: use redraw callback
This solves the issue where we would not receive any frame events. The
difference to my earlier tests is that now it looks like eglSwapBuffers uses
it's own event queue or something similiar along the lines. Becaues the
performance is the same as without any redraw callback.
2014-01-06 20:22:08 +01:00
Alexander Preisinger 09b95257fe wayland/egl: add egl_context to the wayland state
At the moment there are visual glitches when we resize the window. This happens
because in wayland there a special function for resizing EGL windows.

To prevent the glitches move the egl_context to the wayland state in
wayland_common.h and add a new control function to gl_wayland.c to wrap the
vo_wayland_control function to check for resize events.

With the new control wrapper the glitches are gone and the resizing is fluid.
2014-01-06 20:22:06 +01:00
Alexander Preisinger 0cf2df38d1 wayland: Remove nonsense comment and add warning
The reason a segmentation happend here was because we couldn't get the
requested minor version. The major version is enough for differentiating
between OpenGL 3 and OpenGL 2. If it fails there is still a fallback to any
version available.

Also add a warning if we use the fallback.
2014-01-06 20:22:03 +01:00
Alexander Preisinger 4326fdfe2a wayland: move workaround to fullscreen code
Because of this workaround there was a bug in the wayland vo.
Now it works on both vos (opengl and shm) as it should.
2014-01-06 20:21:55 +01:00
Martin Herkt 9755850b3d manpage: mention --pause 2014-01-06 20:21:45 +01:00
wm4 96b50e770b dvdnav: set correct stride for fake highlights
This didn't really matter, because the fake highlight rectangle is in a
single color, and every pixel has the same color value.
2014-01-06 20:21:43 +01:00
wm4 9f6551160a stream_pvr: fix crash on initialization
Fallout from the mp_msg conversions.
2014-01-06 20:21:39 +01:00
wm4 89b854165e audio: check for overflows 2014-01-06 20:21:37 +01:00
wm4 0beece4397 ta: check overflow in array realloc macros 2014-01-06 20:21:19 +01:00
Stefano Pigozzi 8abdf1f56e vda: fix build on OS X 10.7
Looks like on 10.8 OpenGL.h recursively includes CGLIOSurface.h. That is not
the case for 10.7 so the build was broken on that version of OS X.
2014-01-06 20:21:17 +01:00
Stefano Pigozzi 5a81f7678e build: fix cocoa configure check on OS X 10.7
It failed because the 10.7 SDK doesn't natively support array and dictionary
subscripting.
2014-01-06 20:21:14 +01:00
Alexander Preisinger e26286dfdb wayland/opengl: fix garbage borders
It seems mpv draws garbage in those regions. Now we calculate the aspect and
let weston draw the black borders.
2014-01-06 20:21:11 +01:00
Alexander Preisinger 389232e5a2 wayland/shm: only commit new frames
Only attach and commit new buffers. This also increases performance when
paused.
2014-01-06 20:21:09 +01:00
Alexander Preisinger c5de0b0a6c wayland: don't change set fullscreen twice
Newest weston chrashes if we call set_fullscreen twice. This is a major bug
I which I should probably report.
2014-01-06 20:21:07 +01:00
Martin Herkt f9bdfc0782 ao_alsa: Unbreak pause/resume
Well that was dumb.
2014-01-06 20:20:57 +01:00
Martin Herkt 5c9a7e24f6 ao_alsa: Fix PCM resume after suspend
Fixes #324
2014-01-06 20:20:55 +01:00
wm4 b56f61d2ab stream: always respect sector_size, fixes cdda://
Streams like CDDA have special requirements in what quantities data can
be read: you can only read a sector at once, not more and not less. The
stream_peek() function didn't respect that and set less (used internal
buffer size of 2048 bytes, instead of CD sector size of 2352 bytes), so
no data was read and EOF was accidentally set, making playback with
cdda:// fail.

This is a regression since commit 9a723f, but that commit merely exposed
the issue (the redundant seek would clear the EOF flag).
2014-01-06 20:20:48 +01:00
Stefano Pigozzi 82ab3a8160 build: fix typo 2014-01-01 21:50:42 +01:00
wm4 e371f2ebd3 Release 0.3.1 2014-01-01 21:03:51 +01:00
Stefano Pigozzi 29b68d69c0 build: make configure fail if both __atomic and __sync are not available 2014-01-01 20:57:27 +01:00
wm4 6c770eb6df manpage: clarifications about bitmap subtitles and --secondary-sid 2014-01-01 20:57:25 +01:00
wm4 965f336917 options: make --msglevel=help print something helpful 2014-01-01 20:57:22 +01:00
wm4 47fae324c7 manpage: fix description on the slave mode msglevel 2014-01-01 20:57:18 +01:00
wm4 6ab0dbf2ed player: load encoding-profiles.conf before the main config
Otherwise one can't add profiles based on the encoding profiles.
2014-01-01 20:57:16 +01:00
Miro Hrončok c002196ffe mpv.desktop: Add Czech translations 2014-01-01 20:57:14 +01:00
wm4 3c8fc4588d player: fix DVD playback
Crashed in case of lazily added subtitle streams, which add tracks with
track->stream set to NULL.

Fixes gituhub issue #439.
2014-01-01 20:57:12 +01:00
Alessandro Ghedini 416015f059 compat: use __atomic operations instead of __sync, when present
Fixes #434
Fixes #437
2014-01-01 20:57:09 +01:00
Alessandro Ghedini 773db053aa build: check for libatomic and __atomic operations
Add check in old-configure as well. Reformat the check to use a maximum of 80
columns in the wscript.
Signed-off-by: Stefano Pigozzi <stefano.pigozzi@gmail.com>
2014-01-01 20:57:06 +01:00
wm4 a8c09d003f manpage: fix vf_noise parameter name 2014-01-01 20:57:02 +01:00
wm4 1284a6b6b0 video: fix --brightness etc. options
They were set before the VO was intitialized, which silently failed.
2013-12-29 22:17:50 +01:00
wm4 78c35e42ea Release 0.3.0 2013-12-29 18:06:41 +01:00
554 changed files with 48032 additions and 63062 deletions

No files matched your search

+6 -6
View File
@@ -20,12 +20,12 @@
/demux/ebml_types.h
/sub/osd_font.h
/player/lua/*.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
/build
+9 -41
View File
@@ -1,41 +1,16 @@
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="
- 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: ./travis-deps libass-stable $LIBAV
script:
@@ -43,20 +18,13 @@ script:
- ./waf configure
- ./waf build
notifications-policy: &notifications-policy
on_success: change
on_failure: always
notifications:
email: false
irc:
channels:
- "irc.freenode.org#mpv-player-dev"
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
<<: *notifications-policy
+160
View File
@@ -0,0 +1,160 @@
1. Input layer, supported devices, methods:
- plain file, with seeking
- STDIN, without seeking backward
- network streaming (currently plain wget-like HTTP and MMS (.asx))
- VCD (Video CD) track, by direct CDROM device access (not requires mounting disc)
- DVD titles using .IFO structure, by direct DVD device access (not requires mounting disc)
- DVD titles using menu navigation (experimental/alpha, not yet finished!!!)
- CDDA - raw audio from audio CD-ROM discs (using cdparanoia libs)
- RTP streaming (mpeg-ps over multicast only)
- LIVE555 streaming - support SDP/RTSP (using the LIVE555 libs)
- SMB - file access over samba (experimental)
2. Demuxer/parser layer, supported file/media formats:
- MPEG streams (ES,PES,PS. no TS support yet)
note: mpeg demuxer silently ignore non-mpeg content, and find mpeg packets
in arbitrary streams. it means you can play directly VCD images (for example
CDRwin's .BIN files) without extracting mpeg files first (with tools like vcdgear)
It accepts all PES variants, including files created by VDR.
Note: VOB (video object) is simple mpeg stream, but it usually has 01BD
packets which may contain subtitles and non-mpeg audio. Usually found on DVD discs.
Headers: mpeg streams has no global header. each frame sequence (also called GOP,
group of pictures) contains an sequence header, it describes that block.
In normal mpeg 1/2 content there are groups of 12-15 frames (24/30 fps).
It means you can freely seek in mpeg streams, and even can cut it to
small parts with standard file tools (dd, cut) without destroying it.
Codecs: video is always mpeg video (mpeg1, mpeg2 or mpeg4).
audio is usually mpeg audio (any layer allowed, but it's layer 2 in most files)
but 01BD packets may contain AC3, DTS or LPCM too.
FPS: mpeg2 content allows variable framerate, in form of delayed frames.
It's mostly used for playback 24fps content at 29.97/30 fps (NTSC) rate.
(so called Telecine or 3:2 pulldown effect)
It means you see 30 frames per second, but there are only 24 different
pictures and some of them are shown longer to fill 30 frame time.
If you encode such files with mencoder, using -ofps 24 or -ofps 23.976
is recommended.
- AVI streams.
Two kind of RIFF AVI files exists:
1. interleaved: audio and video content is interleaved. it's faster and
requires only 1 reading thread, so it's recommended (and mostly used).
2. non-interleaved: audio and video aren't interleaved, i mean first come
whole video followed by whole audio. it requires 2 reading process or
1 reading with lots of seeking. very bad for network or cdrom.
3. badly interleaved streams: mplayer detects interleaving at startup and
enables -ni option if it finds non-interleaved content. but sometimes
the stream seems to be interleaved, but with bad sync so it should be
played as non-interleaved otherwise you get a-v desync or buffer overflow.
MPlayer supports 2 kind of timing for AVI files:
- bps-based: it is based on bitrate/samplerate of video/audio stream.
this method is used by most players, including avifile and wmp.
files with broken headers, and files created with VBR audio but not
vbr-compliant encoder will result a-v desync with this method.
(mostly at seeking).
- interleaving-based: note: it can't be used togethwer with -ni
it doesn't use bitrate stuff of header, it uses the relative position
of interleaved audio and video chunks. makes some badly encoded file
with vbr audio playable.
Headers: AVI files has a mandatory header at the begin of the file,
describing video parameters (resolution, fps) and codecs. Optionally
they have an INDEX block at the end of the file. It's optional, but
most files has such block, because it's REQUIRED for seeking.
Btw usually it can be rebuilt from file content, mplayer does it with
the -idx switch. MPlayer can recreate broken index blocks using -forceidx.
As AVI files needs index for random access, broken files with no index
are usually unplayable.
Of course, cutting/joining AVI files needs special programs.
Codecs: any audio and video codecs allowed, but I note that VBR audio is
not well supported by most players. The file format makes it possible to
use VBR audio, but most players expect CBR audio and fails with VBR,
as VBR is unusual, and Microsoft's AVI specs only describe CBR audio.
I also note, that most AVI encoders/multiplexers create bad files if
using VBR audio. only 2 exception (known by me): NaNDub and MEncoder.
FPS: only constant framerate allowed, but it's possible to skip frames.
- ASF streams:
ASF (active streaming format) comes from Microsoft. they developed two
variant of ASF, v1.0 and v2.0. v1.0 is used by their media tools (wmp and
wme) and v2.0 is published and patented :). of course, they differ,
no compatibility at all. (it's just a legality game)
MPlayer supports only v1.0, as nobody ever seen v2.0 files :)
Note, that .ASF files are nowdays come with extension .WMA or .WMV.
UPDATE: MS recently released the ASF v1.0 specs too, but it has some
restrictions making it illegal to read by us :)
Headers: Stream headers (codecs parameters) can be everywhere (in theory),
but all files i've seen had it at the beginning of the file.
Asf uses fixed packet size, so it is seekable without any INDEX block,
and broken files are playable well.
Codecs: video is mostly microsoft's mpeg4 variants: MP42, MP43 (aka DivX),
WMV1 and WMV2. but any codecs allowed.
audio is usually wma or voxware, sometimes mp3, but any codecs allowed.
FPS: no fixed fps, every video frame has an exact timestamp instead.
I've got stream with up to 3 sec frame display times.
- QuickTime / MOV files:
They come from Mac users, usually with .mov or .qt extension, but as
MPEG Group chose quicktime as recommended file format for MPEG4,
sometimes you meet quicktime files with .mpg or .mp4 extension.
At first look, it's a mixture of ASF and AVI.
It requires INDEX block for random access and seeking, and even for
playback, like AVI, but uses timestamps instead of constant framerate
and has more flexible stream options (including network stuff) like ASF.
Headers: header can be placed at the beginning or at the end of file.
About half of my files have it at the beginning, others have it at the end.
Broken files are only playable if they have header at the beginning!
Codecs: any codecs allowed, both CBR and VBR.
Note: most new mov files use Sorenson video and QDesign Music audio,
they are patented, closed, secret, (TM)-ed etc formats, only Apple's
quicktime player is able to playback these files (on win/mac only).
- VIVO files:
They are funny streams. They have a human-readable ascii header at
the beginning, followed by interleaved audio and video chunks.
It has no index block, has no fixed packetsize or sync bytes, and most
files even has no keyframes, so forget seeking!
Video is standard h.263 (in vivo/2.0 files it's modified, non-standard
h.263), audio is either standard g.723 or Vivo Siren codec.
Note, that microsoft licensed vivo stuff, and included in their netshow
v2.0 program, so there are VfW/ACM codecs for vivo video and audio.
- RealMedia files:
A mixture of AVI and ASF features. It has mandatory headers at the
beginning and an optional INDEX (missing in most files).
The file is constructed of variable size chunks, with small header
telling the stream ID, timestamp, flags (keyframe...) and size.
But it has some features found in ASF files:
The video is actually double-muxed, the video chunks are really
appended fragments of the video frame. RV30+ supports B frames, so
you have to parse some bits of the first fragment to get the real PTS.
The audio frames are fixed size (CBR) but using the same scrambling
(out-of-order interleaving) as in the ASF files.
Codecs: Audio is either COOK(er), SIPR(o), ATRAC3 or DNET.
The DNET is actually a byte-swapped low-bitrate Dolby AC3 variant :)
Video is RV10 (h263 variant), RV20 (rp G2), RV30 (rp v8) or RV40 (rp v9).
FPS: variable, just like in ASF.
Note, that similarity of real and asf has some background - they worked
together on the (never finished/used) ASF v2 spec for some time.
- GIF files:
The GIF format is a common format for web graphics that supports
animation. These are read through libungif or compatible library.
Variable frame delays are supported, but seeking is not supported.
Seeking will be supported once an index of gif frames can be built.
+228
View File
@@ -0,0 +1,228 @@
So, I'll describe how this stuff works.
The main modules:
1. stream.c: this is the input layer, this reads the input media (file, stdin,
vcd, dvd, network etc). what it has to know: appropriate buffering by
sector, seek, skip functions, reading by bytes, or blocks with any size.
The stream_t (stream.h) structure describes the input stream, file/device.
There is a stream cache layer (cache2.c), it's a wrapper for the stream
API. It does fork(), then emulates stream driver in the parent process,
and stream user in the child process, while proxying between them using
preallocated big memory chunk for FIFO buffer.
2. demuxer.c: this does the demultiplexing (separating) of the input to
audio, video or dvdsub channels, and their reading by buffered packages.
The demuxer.c is basically a framework, which is the same for all the
input formats, and there are parsers for each of them (mpeg-es,
mpeg-ps, avi, avi-ni, asf), these are in the demux_*.c files.
The structure is the demuxer_t. There is only one demuxer.
2.a. demux_packet_t, that is DP.
Contains one chunk (avi) or packet (asf,mpg). They are stored in memory as
in linked list, cause of their different size.
2.b. demuxer stream, that is DS.
Struct: demux_stream_t
Every channel (a/v/s) has one. This contains the packets for the stream
(see 2.a). For now, there can be 3 for each demuxer :
- audio (d_audio)
- video (d_video)
- DVD subtitle (d_dvdsub)
2.c. stream header. There are 2 types (for now): sh_audio_t and sh_video_t
This contains every parameter essential for decoding, such as input/output
buffers, chosen codec, fps, etc. There are each for every stream in
the file. At least one for video, if sound is present then another,
but if there are more, then there'll be one structure for each.
These are filled according to the header (avi/asf), or demux_mpg.c
does it (mpg) if it founds a new stream. If a new stream is found,
the ====> Found audio/video stream: <id> messages is displayed.
The chosen stream header and its demuxer are connected together
(ds->sh and sh->ds) to simplify the usage. So it's enough to pass the
ds or the sh, depending on the function.
For example: we have an asf file, 6 streams inside it, 1 audio, 5
video. During the reading of the header, 6 sh structs are created, 1
audio and 5 video. When it starts reading the packet, it chooses the
stream for the first found audio & video packet, and sets the sh
pointers of d_audio and d_video according to them. So later it reads
only these streams. Of course the user can force choosing a specific
stream with
-vid and -aid switches.
A good example for this is the DVD, where the english stream is not
always the first, so every VOB has different language :)
That's when we have to use for example the -aid 128 switch.
Now, how this reading works?
- demuxer.c/demux_read_data() is called, it gets how many bytes,
and where (memory address), would we like to read, and from which
DS. The codecs call this.
- this checks if the given DS's buffer contains something, if so, it
reads from there as much as needed. If there isn't enough, it calls
ds_fill_buffer(), which:
- checks if the given DS has buffered packages (DP's), if so, it moves
the oldest to the buffer, and reads on. If the list is empty, it
calls demux_fill_buffer() :
- this calls the parser for the input format, which reads the file
onward, and moves the found packages to their buffers.
Well it we'd like an audio package, but only a bunch of video
packages are available, then sooner or later the:
DEMUXER: Too many (%d in %d bytes) audio packets in the buffer
error shows up.
2.d. video.c: this file/function handle the reading and assembling of the
video frames. each call to video_read_frame() should read and return a
single video frame, and it's duration in seconds (float).
The implementation is splitted to 2 big parts - reading from mpeg-like
streams and reading from one-frame-per-chunk files (avi, asf, mov).
Then it calculates duration, either from fixed FPS value, or from the
PTS difference between and after reading the frame.
2.e. other utility functions: there are some useful code there, like
AVI muxer, or mp3 header parser, but leave them for now.
So everything is ok 'till now. It can be found in libmpdemux/ library.
It should compile outside of mplayer tree, you just have to implement few
simple functions, like mp_msg() to print messages, etc.
See libmpdemux/test.c for example.
See also formats.txt, for description of common media file formats and their
implementation details in libmpdemux.
Now, go on:
3. mplayer.c - ooh, he's the boss :)
Its main purpose is connecting the other modules, and maintaining A/V
sync.
The given stream's actual position is in the 'timer' field of the
corresponding stream header (sh_audio / sh_video).
The structure of the playing loop :
while(not EOF) {
fill audio buffer (read & decode audio) + increase a_frame
read & decode a single video frame + increase v_frame
sleep (wait until a_frame>=v_frame)
display the frame
apply A-V PTS correction to a_frame
handle events (keys,lirc etc) -> pause,seek,...
}
When playing (a/v), it increases the variables by the duration of the
played a/v.
- with audio this is played bytes / sh_audio->o_bps
Note: i_bps = number of compressed bytes for one second of audio
o_bps = number of uncompressed bytes for one second of audio
(this is = bps*samplerate*channels)
- with video this is usually == 1.0/fps, but I have to note that
fps doesn't really matters at video, for example asf doesn't have that,
instead there is "duration" and it can change per frame.
MPEG2 has "repeat_count" which delays the frame by 1-2.5 ...
Maybe only AVI and MPEG1 has fixed fps.
So everything works right until the audio and video are in perfect
synchronity, since the audio goes, it gives the timing, and if the
time of a frame passed, the next frame is displayed.
But what if these two aren't synchronized in the input file?
PTS correction kicks in. The input demuxers read the PTS (presentation
timestamp) of the packages, and with it we can see if the streams
are synchronized. Then MPlayer can correct the a_frame, within
a given maximal bounder (see -mc option). The summary of the
corrections can be found in c_total .
Of course this is not everything, several things suck.
For example the soundcards delay, which has to be corrected by
MPlayer! The audio delay is the sum of all these:
- bytes read since the last timestamp:
t1 = d_audio->pts_bytes/sh_audio->i_bps
- if Win32/ACM then the bytes stored in audio input buffer
t2 = a_in_buffer_len/sh_audio->i_bps
- uncompressed bytes in audio out buffer
t3 = a_buffer_len/sh_audio->o_bps
- not yet played bytes stored in the soundcard's (or DMA's) buffer
t4 = get_audio_delay()/sh_audio->o_bps
From this we can calculate what PTS we need for the just played
audio, then after we compare this with the video's PTS, we have
the difference!
Life didn't get simpler with AVI. There's the "official" timing
method, the BPS-based, so the header contains how many compressed
audio bytes or chunks belong to one second of frames.
In the AVI stream header there are 2 important fields, the
dwSampleSize, and dwRate/dwScale pairs:
- If the dwSampleSize is 0, then it's VBR stream, so its bitrate
isn't constant. It means that 1 chunk stores 1 sample, and
dwRate/dwScale gives the chunks/sec value.
- If the dwSampleSize is >0, then it's constant bitrate, and the
time can be measured this way: time = (bytepos/dwSampleSize) /
(dwRate/dwScale) (so the sample's number is divided with the
samplerate). Now the audio can be handled as a stream, which can
be cut to chunks, but can be one chunk also.
The other method can be used only for interleaved files: from
the order of the chunks, a timestamp (PTS) value can be calculated.
The PTS of the video chunks are simple: chunk number * fps
The audio is the same as the previous video chunk was.
We have to pay attention to the so called "audio preload", that is,
there is a delay between the audio and video streams. This is
usually 0.5-1.0 sec, but can be totally different.
The exact value was measured until now, but now the demux_avi.c
handles it: at the audio chunk after the first video, it calculates
the A/V difference, and take this as a measure for audio preload.
3.a. audio playback:
Some words on audio playback:
Not the playing is hard, but:
1. knowing when to write into the buffer, without blocking
2. knowing how much was played of what we wrote into
The first is needed for audio decoding, and to keep the buffer
full (so the audio will never skip). And the second is needed for
correct timing, because some soundcards delay even 3-7 seconds,
which can't be forgotten about.
To solve this, the OSS gives several possibilities:
- ioctl(SNDCTL_DSP_GETODELAY): tells how many unplayed bytes are in
the soundcard's buffer -> perfect for timing, but not all drivers
support it :(
- ioctl(SNDCTL_DSP_GETOSPACE): tells how much can we write into the
soundcard's buffer, without blocking. If the driver doesn't
support GETODELAY, we can use this to know how much the delay is.
- select(): should tell if we can write into the buffer without
blocking. Unfortunately it doesn't say how much we could :((
Also, doesn't/badly works with some drivers.
Only used if none of the above works.
4. Codecs. Consists of libmpcodecs/* and separate files or libs,
for example libmpeg2, loader, mp3lib.
mplayer.c doesn't call them directly, but through the dec_audio.c and
dec_video.c files, so the mplayer.c doesn't have to know anything about
the codecs.
libmpcodecs contains wrapper for every codecs, some of them include the
codec function implementation, some calls functions from other files
included with mplayer, some calls optional external libraries.
file naming convention in libmpcodecs:
ad_*.c - audio decoder (called through dec_audio.c)
vd_*.c - video decoder (called through dec_video.c)
ve_*.c - video encoder (used by mencoder)
vf_*.c - video filter (see option -vf)
On this topic, see also:
libmpcodecs.txt - The structure of the codec-filter path, with explanation
dr-methods.txt - Direct rendering, MPI buffer management for video codecs
codecs.conf.txt - How to write/edit codec configuration file (codecs.conf)
codec-devel.txt - Mike's hints about codec development - a bit OUTDATED
hwac3.txt - about SP/DIF audio passthrough
5. libvo: this displays the frame.
for details on this, read libvo.txt
6. libao2: this control audio playing
6.a audio plugins
for details on this, read libao2.txt
+145
View File
@@ -0,0 +1,145 @@
mails by A'rpi and Marcus Blomenkamp <Marcus.Blomenkamp@epost.de>
describing how this ac3-passtrough hack work under linux and mplayer...
-----------------------------------------------------------------------
Hi,
> I received the following patch from Steven Brookes <stevenjb@mda.co.uk>.
> He is working on fixing the digital audio output of the dxr3 driver and
> told me he fixed some bugs in mplayer along the way. I don't know shit
> about hwac3 output so all I did was to make sure the patch applied
> against latest cvs.
> This is from his e-mail to me:
>
> "Secondly there is a patch to dec_audio.c and
> ac3-iec958 to fix the -ac hwac3 codec stuff and to use liba52 to sync it.
> Seems to work for everything I've thrown at and maintains sync for all audio
> types through the DXR3."
patch applied (with some comments added and an unwanted change (in software
a52 decoder) removed)
now i understand how this whole hwac3 mess work.
it's very very tricky. it virtually decodes ac3 to LPCM packets, but really
it keeps the original compressed data padded by zeros. this way it's
constant bitrate, and sync is calculated just like for stereo PCM.
(so it bypass LPCM-capable media converters...)
so, every ac3 frame is translated to 6144 byte long tricky LPCM packet.
6144 = 4*(6*256) = 4 * samples_per_ac3_frame = LPCM size of uncompressed ac3
frame.
i wanna know if it works for sblive and other ac3-capable cards too?
(i can't test it, lack of ac3 decoder)
A'rpi / Astral & ESP-team
-----------------------------------------------------------------------
Hi folks.
I spend some time fiddling with ac3 passthrough in mplayer. The
traditional way of setting the output format to AFMT_AC3 was no ideal
solution since not all digital io cards/drivers supported this format or
honoured it to set the spdif non-audio bit. To make it short, it only
worked with oss sblive driver IIRC.
Inspired by alsa's ac3dec program I found an alternative way by
inspecting to which format the alsa device had been set. Suprise: it was
simple 16bit_le 2_channel pcm. So setting the non-audio bit doesn't
necessarily mean the point. The only important thing seems to be
bit-identical output at the correct samplerate. Modern AV-Receivers seem
to be quite tolerant/compatible.
So I changed the output format of hwac3 from
AFMT_AC3 channels=1
to
AFMT_S16_LE channels=2
and corrected the absolute time calculation. That was all to get it
running for me.
-----------------------------------------------------------------------
Hi there.
Perhaps I can clear up some mystification about AC3 passthrough in
general and mplayer in special:
To get the external decoder solution working, it must be fed with data
which is bitidentical to the chunks in the source ac3 file (compressed
data is very picky about bit errors). Additionally - or better to say
'historically' - the non-audio bit should be set in the spdif status
fields to prevent old spdif hardware from reproducing ugly scratchy
noise. Note: for current decoders (probably those with DTS capability)
this safety bit isn't needed anymore. At least I can state that for my
Sherwood RVD-6095RDS. I think it is due to DTS because DTS sound can
reside on a ordinary AudioCD and an ordinary AudioCD-Player will always
have it's audio-bit set.
The sample format of the data must be 2channel 16bit (little endian
IIRC). Samplerates are 48kHz - although my receiver also accepts
44100Hz. I do not know if this is due to an over-compatability of my
receiver or if 44100 is also possible in the ac3 specs. For safety's
sake lets keep this at 48000Hz. AC3 data chunks are inserted into the
stream every 0x1600 bytes (don't bite me on that, look into
'ac3-iec958.c': 'ac3_iec958_build_burst').
To come back to the problem: data must be played bit-identically through
the soundcard at the correct samplerate and should optionally have it's
non-audio bit set. There are two ways to accomplish this:
1) Some OSS guy invented the format AFMT_AC3. Soundcard drivers
implementing this format should therefore adjust it's mixers and
switches to produce the desired output. Unfortunately some soundcard
drivers do not support this format correctly and most do not even
support it at all (including ALSA).
2) The alternative approach currently in mplayer CVS is to simply set
the output format to 48kHz16bitLE and rely on the user to have the
soundcard mixers adjusted properly.
I do have two soundcards with digital IO facilities (CMI8738 and
Trident4DWaveNX based) plus the mentioned decoder. I'm currently running
Linux-2.4.17. Following configurations are happily running here:
1. Trident with ALSA drivers (OSS does not support Hoontech's dig. IO)
2. CMI with ALSA drivers
3. CMI with OSS drivers
For Linux I'd suggest using ALSA because of it's cleaner architecture
and more consitent user interface. Not to mention that it'll be the
standard sound support in Linux soon.
For those who want to stick to OSS drivers: The CMI8738 drivers works
out-of-the-box, if the PCM/Wave mixer is set to 100%.
For ALSA I'd suggest using its OSS emulation. More on that later.
ALSA-0.9 invented the idea of cards, devices and dubdevices. You can
reach the digital interface of all supported cards consitently by using
the device 'hw:x,2' (x counting from 0 is the number of your soundcard).
So most people would end up at 'hw:0,2'. This device can only be opened
in sample formats and rates which are directly supported in hardware
hence no samplerate conversion is done keeping the stream as-is. However
most consumer soundcards do not support 44kHz so it would definitively
be a bad idea to use this as your standard device if you wanted to
listen to some mp3s (most of them are 44kHz due to CD source). Here the
OSS comes to play again. You can configure which OSS device (/dev/dsp
and /dev/adsp) uses which ALSA device. So I'd suggest pointing the
standard '/dev/dsp' to standard 'hw:0,0' which suports mixing and
samplerate conversion. No further reconfiguration would be needed for
your sound apps. For movies I'd point '/dev/adsp' to 'hw:0,2' and
configure mplayer to use adsp instead of dsp. The samplerate constrain
is no big deal here since movies usually are in 48Khz anyway. The
configuration in '/etc/modules.conf' is no big deal also:
alias snd-card-0 snd-card-cmipci # insert your card here
alias snd-card-1 snd-pcm-oss # load OSS emulation
options snd-pcm-oss snd_dsp_map=0 snd_adsp_map=2 # do the mapping
This works flawlessly in combination with alsa's native
SysVrc-init-script 'alsasound'. Be sure to disable any distribution
dependent script (e.g. Mandrake-8.1 has an 'alsa' script which depends
on ALSA-0.5).
Sorry for you *BSD'lers out there. I have no grasp on sound support there.
HTH Marcus
+56
View File
@@ -0,0 +1,56 @@
6. libao2: this control audio playing
As in libvo (see 5.) also here are some drivers, based on the same API:
static int control(int cmd, int arg);
This is for reading/setting driver-specific and other special parameters.
Not really used for now.
static int init(int rate,int channels,int format,int flags);
The init of driver, opens device, sets sample rate, channels, sample format
parameters.
Sample format: usually AFMT_S16_LE or AFMT_U8, for more definitions see
dec_audio.c and linux/soundcards.h files!
static void uninit(void);
Guess what.
Ok I help: closes the device, not (yet) called when exit.
static void reset(void);
Resets device. To be exact, it's for deleting buffers' contents,
so after reset() the previously received stuff won't be output.
(called if pause or seek)
static int get_space(void);
Returns how many bytes can be written into the audio buffer without
blocking (making caller process wait). MPlayer occasionally checks the
remaining space and tries to fill the buffer with play() if there's free
space. The buffer size used should be sane; a buffer that is too small
could run empty before MPlayer tries filling it again (normally once per
video frame), a buffer that is too big would force MPlayer decode the file
far ahead trying to find enough audio data to fill it.
static int play(void* data,int len,int flags);
Plays a bit of audio, which is received throught the "data" memory area, with
a size of "len". It has to copy the data, because they can be overwritten
after the call is made. Doesn't have to use all the bytes; it has to
return the number of bytes used used (copied to buffer). If
flags|AOPLAY_FINAL_CHUNK is true then this is the last audio in the file.
The purpose of this flag is to tell aos that round down the audio played
from "len" to a multiple of some chunksize that this "len" should not be
rounded down to 0 or the data will never be played (as MPlayer will never
call play() with a larger len).
static float get_delay(void);
Returns how long time it will take to play the data currently in the
output buffer. Be exact, if possible, since the whole timing depends
on this! In the worst case, return the maximum delay.
!!! Because the video is synchronized to the audio (card), it's very important
!!! that the get_delay function is correctly implemented!
static void audio_pause(void);
Pause playing but do not delete buffered data if possible.
static void audio_resume(void);
Continue playing after audio_pause().
+173
View File
@@ -0,0 +1,173 @@
libvo --- the library to handle video output by A'rpi, 2002.04
============================================
Note: before start on this, read colorspaces.txt !
The constants for different pixelformats are defined in img_format.h,
their usage is mandatory.
WARNING: Please keep in mind that some of this information may be out-dated,
so if you are working on a new vo, consider submitting preliminary patches
very early on. Currently vo_gl is one of the more up-to-date VOs to use
as reference if you are unsure about something and do not want to ask on the
list.
vo_vdpau and vo_direct3d may be a good choice, too, they use different
approaches closer to the sometimes convoluted way DirectX works.
Each vo driver _has_ to implement these:
preinit():
init the video system (to support querying for supported formats)
uninit():
Uninit the whole system, this is on the same "level" as preinit.
control():
Current controls (VOCTRL_QUERY_FORMAT must be implemented,
VOCTRL_DRAW_IMAGE, VOCTRL_FULLSCREEN, VOCTRL_UPDATE_SCREENINFO
should be implemented):
VOCTRL_QUERY_FORMAT - queries if a given pixelformat is supported.
It also returns various flags decsirbing the capabilities
of the driver with teh given mode. for the flags, see
file vfcaps.h !
the most important flags, every driver must properly report
these:
0x1 - supported (with or without conversion)
0x2 - supported without conversion (define 0x1 too!)
0x100 - driver/hardware handles timing (blocking)
also SET sw/hw scaling and osd support flags, and flip,
and accept_stride if you implement VOCTRL_DRAW_IMAGE (see bellow)
NOTE: VOCTRL_QUERY_FORMAT may be called _before_ first config()
but is always called between preinit() and uninit()
VOCTRL_GET_IMAGE
libmpcodecs Direct Rendering interface
You need to update mpi (mp_image.h) structure, for example,
look at vo_x11, vo_sdl, vo_xv or mga_common.
VOCTRL_DRAW_IMAGE
replacement for the current draw_slice/draw_frame way of
passing video frames. by implementing SET_IMAGE, you'll get
image in mp_image struct instead of by calling draw_*.
unless you return VO_TRUE for VOCTRL_DRAW_IMAGE call, the
old-style draw_* functils will be called!
Note: draw_slice is still mandatory, for per-slice rendering!
VOCTRL_RESET - reset the video device
This is sent on seeking and similar and is useful if you are
using a device which prebuffers frames that need to flush them
before refilling audio/video buffers.
VOCTRL_PAUSE
VOCTRL_RESUME
VOCTRL_GUISUPPORT
return true only if driver supports co-operation with
MPlayer's GUI (not yet used by GUI)
VOCTRL_SET_EQUALIZER
set the video equalizer to the given values
two arguments are provided: item and value
item is a string, the possible values are (currently):
brightness, contrast, saturation, hue
VOCTRL_GET_EQUALIZER
get the current video equalizer values
two arguments are provided: item and value
item is a string, the possible values are (currently):
brightness, contrast, saturation, hue
VOCTRL_ONTOP
Makes the player window stay-on-top. Only supported (currently)
by drivers which use X11, except SDL, as well as directx and
gl2 under Windows.
VOCTRL_BORDER
Makes the player window borderless.
VOCTRL_FULLSCREEN
Switch from and to fullscreen mode
VOCTRL_GET_PANSCAN
VOCTRL_SET_PANSCAN
Needed to implement pan-scan support ('w' and 'e' keys during
playback in fullscreen mode)
VOCTRL_START_SLICE
Called before the first draw_slice of each frame, useful if
you need to do some set-up work.
VOCTRL_DRAW_EOSD
Required for EOSD (ASS subtitle) support. Provides all
information necessary to draw the EOSD for the current video
frame.
VOCTRL_GET_EOSD_RES
Required for EOSD (ASS subtitle) support. Informs the ASS
renderer about the properties of the drawing area (size,
borders).
VOCTRL_SET_DEINTERLACE
VOCTRL_GET_DEINTERLACE
Get or set deinterlacing status for VOs that support some kind
of deinterlacing.
VOCTRL_UPDATE_SCREENINFO
Should set the xinerama_x, xinerama_y, vo_screenwidth and
vo_screenheight appropriately for the currently used
monitor and -xineramascreen option.
Usually should simply call the w32_update_xinerama_info or
update_xinerama_info function.
By supporting this, the VO also requests the newer API
that sets vo_dx, vo_dy etc. appropriately before config()
is called.
config():
Set up the video system. You get the dimensions and flags.
width, height: size of the source image
d_width, d_height: wanted scaled/display size (it's a hint)
Flags:
0x01 - force fullscreen (-fs)
0x02 - allow mode switching (-vm)
0x04 - allow software scaling (-zoom)
0x08 - flipping (-flip)
They're defined as VOFLAG_* (see libvo/video_out.h)
IMPORTANT NOTE: config() may be called 0 (zero), 1 or more (2,3...)
times between preinit() and uninit() calls. You MUST handle it, and
you shouldn't crash at second config() call or at uninit() without
any config() call! To make your life easier, vo_config_count is
set to the number of previous config() call, counted from preinit().
It's set by the caller (vf_vo.c), you don't have to increase it!
So, you can check for vo_config_count>0 in uninit() when freeing
resources allocated in config() to avoid crash!
You should implement VOCTRL_UPDATE_SCREENINFO so that vo_dx, vo_dy,
vo_dwidth and vo_dheight are already pre-set to values that take
aspect and -geometry into account. It is also necessary to properly
support multi-monitor setups (if based on x11_common, w32_common).
draw_slice(): this displays YV12 pictures (3 planes, one full sized that
contains brightness (Y), and 2 quarter-sized which the colour-info
(U,V). MPEG codecs (libmpeg2, opendivx) use this. This doesn't have
to display the whole frame, only update small parts of it.
If this is not supported, it must be signaled in QUERY_FORMAT with
VOCAP_NOSLICES.
draw_frame(): this is the older interface, this displays only complete
frames, and can do only packed format (YUY2, RGB/BGR).
Win32 codecs use this (DivX, Indeo, etc).
If you implement VOCTRL_DRAW_IMAGE, you do not need to implement draw_frame.
draw_osd(): this displays subtitles and OSD.
It's a bit tricky to use it, since it's a callback-style stuff.
It should call vo_draw_text() with screen dimension and your
draw_alpha implementation for the pixelformat (function pointer).
The vo_draw_text() checks the characters to draw, and calls
draw_alpha() for each. As a help, osd.c contains draw_alpha for
each pixelformats, use this if possible!
Note that if you do not draw directly onto the video you should
use vo_draw_text_ext() which allows you to specify the border
values etc. needed to draw DVD menu highlights at the correct place.
If you do not want to implement this, you can still use -vf
expand=osd=1 to draw the OSD, or even implement code to insert
this filter automatically.
Make sure you set VFCAP_OSD depending on whether you implemented it
or not.
NOTE: This one will be obsolete soon! But it's still useful when
you want to do tricks, like rendering osd _after_ hardware scaling
(tdfxfb) or render subtitles under of the image (vo_mpegpes, sdl)
NOTE2: above NOTE is probably wrong, there are currently no plans to
obsolete draw_osd, though there is the more advanced EOSD support for
ASS subtitles.
flip_page(): this is called after each frame, this displays the buffer for
real. This is 'swapbuffers' when doublebuffering.
Try to do as little work here as possible, since that affect jitter/
A-V sync.
+100
View File
@@ -0,0 +1,100 @@
TITLE=Weird Al Yankovic - The Saga Begins (clip)
# just to be informative (maybe future
# use?)
FILE=14233792,7972c637f619e01854ecb453b7339e3f # size,md5
AUTHOR=Gabucino
TYPE=VIDEO # maybe AUDIO in future (for displaying
# mp3 lyrics while playing or whatever)
FORMAT=TIME # this file contains measures based on
# TIME, not frames.
# if FORMAT is a number, then it's frame based, i.e.:
# FORMAT=25
NOTE=MPlayerSub test file v0.1
# first number : wait this much after previous subtitle disappeared
# second number : display the current subtitle for this many seconds
15 3
A long, long time ago...
0 3
in a galaxy far away...
0 3
Naboo was under an attack.
1 2.5
And I thought me and
Qui-Gon Jinn could
0 2.5
talk the Federation into
0 4
...maybe cutting them a
little slack.
2 3
But their response, it
didn't thrill us,
0 3
They locked the doors,
and tried to kill us.
0 2.5
We escaped from that gas,
0 3.5
then met Jar-jar and
Boss-Nass.
1 6
We took a bongo from the
scene and we went to
Theed to see the Queen.
0 5
We all wound' up on
Tatooine.
0 6
That's where, we've found
this boy.
0 4
Oh my, my this here
Anakin guy,
0 5
maybe Vader someday
later now he's just
a small fry.
0 4
And he left his home and
kissed his mommy goodbye,
0 5
singing "Soon I'm gonna be
a Jedi!"
6 6
Did you know this junkyard
slave isn't even old enough
to shave,
0 3
but he can use the Force,
they say.
1 6
Ahh, do you see him hitting
on the queen though he's
just nine and she's fourteen
0 6
yeah, he's probably gonna
marry her, someday!
+19
View File
@@ -0,0 +1,19 @@
software scaler filter docs
-ssf cgb=<float> chrominance gaussian blur
useful for videos with some chroma (color) noise (TV captures, VHS, ...)
-ssf lgb=<float> -> luminance gaussian blur
hmm, mostly special effect, could be used as lame noise reducer though
-ssf chs=<int> -> shift chrominance horizontally
-ssf cvs=<int> -> shift chrominance vertically
useful if the luma & chroma are not aligned exactly
-ssf cs=<float> -> chrominance sharpen
-ssf ls=<float> -> luminance sharpen
simple sharpening filter
note: these will only work if the swscaler is used at all (use -vf scale)
example: mplayer foobar.avi -vf scale -ssf lgb=3.0
+68
View File
@@ -0,0 +1,68 @@
artifact types:
---------------------------------------------------------------------
ringing
wave or noise like patterns around sharp edges
bad: sinc, lanczos (with high filter length)
acceptable: lanczos (with low filter length), cubic, spline
ok: area, (fast)blinear, gauss, point
blur
loss of detail / high frequency
bad: gauss with high variance
acceptable: (fast)bilinear, area
ok: others
aliasing (only downscale)
straight lines look like staircases
areas of high detail look worse
regular patterns turn into a funny looking mess (moire patterns)
bad: fast bilinear, point, gauss with low variance
acceptable: area
ok: others
blocky (upscale only)
looks like the image is made of rectangular blocks like a mosaic
bad: point
ok: others
recommendations: (based upon my personal opinion many ppl might disagree ...)
---------------------------------------------------------------------
the recommended scalers for upscaling:
fast_bilinear, point if speed is important
cubic, spline, lanczos if quality is important
the recommended scalers for downscaling:
fast_bilinear, point if speed is important
gauss, bilinear if quality is important
cubic, spline, lanczos if a sharper picture is important
note: when encoding at a limited amount of bits (not constant quantizer)
then a slightly blurred input might look better after decoding than a slightly
sharpened one, especially for lower bitrates
sws numbers / names / artifact types
-------------------------------------------------------------------------
r ringing
b blurry
a aliasing (downscale only)
m mosaic (blocky) (upscale only)
-sws 0 fast bilinear bA
-sws 1 bilinear b
-sws 2 bicubic high sharpness r
low sharpness b
-sws 3 experimental ????
-sws 4 nearest neighbour AM
-sws 5 area ba
-sws 6 luma bicubic / chroma bilinear r
-sws 7 gauss low sharpness B
high sharpness AM
-sws 8 sinc R
-sws 9 lanczos long filter R
short filter b
-sws 10 bicubic spline r
Notes:
area upscale is identical to bilinear
-74
View File
@@ -1,74 +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, this list is interesting for other uses of mpv, such as the Lua
scripting interface, key bindings in ``input.rst``, or plain command line
usage.
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``.
API changes
===========
::
--- mpv 0.7.0 is released ---
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 is released ---
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 is released ---
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 is released ---
1.0 - the API is declared stable
-181
View File
@@ -1,181 +0,0 @@
// Plays a video from the command line in a window provided by mpv.
// You likely want to play the video in your own window instead,
// but that's not quite ready yet.
// You may need a basic Info.plist and MainMenu.xib to make this work.
#include "../../libmpv/client.h"
#include "shared.h"
#import <Cocoa/Cocoa.h>
@interface CocoaWindow : NSWindow
@end
@implementation CocoaWindow
- (BOOL)canBecomeMainWindow { return YES; }
- (BOOL)canBecomeKeyWindow { return YES; }
@end
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
mpv_handle *mpv;
dispatch_queue_t queue;
NSWindow *w;
}
@end
static void wakeup(void *);
@implementation AppDelegate
- (void)createWindow {
int mask = NSTitledWindowMask|NSClosableWindowMask|
NSMiniaturizableWindowMask|NSResizableWindowMask;
self->w = [[CocoaWindow alloc]
initWithContentRect:NSMakeRect(0,0, 1280, 720)
styleMask:mask
backing:NSBackingStoreBuffered
defer:NO];
[self->w setTitle:@"cocoabasic example"];
[self->w makeMainWindow];
[self->w makeKeyAndOrderFront:nil];
NSMenu *m = [[NSMenu alloc] initWithTitle:@"AMainMenu"];
NSMenuItem *item = [m addItemWithTitle:@"Apple" action:nil keyEquivalent:@""];
NSMenu *sm = [[NSMenu alloc] initWithTitle:@"Apple"];
[m setSubmenu:sm forItem:item];
[sm addItemWithTitle: @"Shutdown mpv" action:@selector(shutdown) keyEquivalent:@"s"];
[NSApp setMenu:m];
[NSApp activateIgnoringOtherApps:YES];
}
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
atexit_b(^{
// Because activation policy has just been set to behave like a real
// application, that policy must be reset on exit to prevent, among
// other things, the menubar created here from remaining on screen.
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
});
// Read filename
NSArray *args = [NSProcessInfo processInfo].arguments;
if (args.count < 2) {
NSLog(@"Expected filename on command line");
exit(1);
}
NSString *filename = args[1];
[self createWindow];
// Deal with MPV in the background.
queue = dispatch_queue_create("mpv", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
mpv = mpv_create();
if (!mpv) {
printf("failed creating context\n");
exit(1);
}
int64_t wid = (intptr_t) [self->w contentView];
check_error(mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid));
// Maybe set some options here, like default key bindings.
// NOTE: Interaction with the window seems to be broken for now.
check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes"));
// for testing!
check_error(mpv_set_option_string(mpv, "input-media-keys", "yes"));
check_error(mpv_set_option_string(mpv, "input-cursor", "no"));
check_error(mpv_set_option_string(mpv, "input-vo-keyboard", "yes"));
// request important errors
check_error(mpv_request_log_messages(mpv, "warn"));
check_error(mpv_initialize(mpv));
// Register to be woken up whenever mpv generates new events.
mpv_set_wakeup_callback(mpv, wakeup, (__bridge void *) self);
// Load the indicated file
const char *cmd[] = {"loadfile", filename.UTF8String, NULL};
check_error(mpv_command(mpv, cmd));
});
}
- (void) handleEvent:(mpv_event *)event
{
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN:
// Clean up and shut down.
mpv_terminate_destroy(mpv);
mpv = NULL;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSApplication sharedApplication] terminate:nil];
});
break;
case MPV_EVENT_LOG_MESSAGE: {
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
printf("[%s] %s: %s", msg->prefix, msg->level, msg->text);
}
case MPV_EVENT_VIDEO_RECONFIG:
dispatch_async(dispatch_get_main_queue(), ^{
[self->w selectNextKeyView:nil];
});
default:
printf("event: %s\n", mpv_event_name(event->event_id));
}
}
- (void) readEvents
{
dispatch_async(queue, ^{
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
[self handleEvent:event];
}
});
}
static void wakeup(void *context) {
AppDelegate *a = (__bridge AppDelegate *) context;
[a readEvents];
}
// Ostensibly, mpv's window would be hooked up to this.
- (BOOL) windowShouldClose:(id)sender
{
[self shutdown];
if (self->w)
[self->w release];
return YES;
}
- (void) shutdown
{
if (mpv) {
const char *args[] = {"quit", NULL};
mpv_command(mpv, args);
}
}
@end
// Delete this if you already have a main.m.
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *delegate = [AppDelegate new];
app.delegate = delegate;
[app run];
}
return EXIT_SUCCESS;
}
-219
View File
@@ -1,219 +0,0 @@
// License: pick one of: public domain, WTFPL, ISC, Ms-PL, AGPLv3
// This example can be built with: qmake && make
#include <clocale>
#include <sstream>
#include <QtGlobal>
#include <QFileDialog>
#include <QStatusBar>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QApplication>
#include <QTextEdit>
#if QT_VERSION >= 0x050000
#include <QJsonDocument>
#endif
#include <mpv/qthelper.hpp>
#include "qtexample.h"
static void wakeup(void *ctx)
{
// This callback is invoked from any mpv thread (but possibly also
// recursively from a thread that is calling the mpv API). Just notify
// the Qt GUI thread to wake up (so that it can process events with
// mpv_wait_event()), and return as quickly as possible.
MainWindow *mainwindow = (MainWindow *)ctx;
QCoreApplication::postEvent(mainwindow, new QEvent(QEvent::User));
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setWindowTitle("Qt embedding demo");
setMinimumSize(640, 480);
QMenu *menu = menuBar()->addMenu(tr("&File"));
QAction *on_open = new QAction(tr("&Open"), this);
on_open->setShortcuts(QKeySequence::Open);
on_open->setStatusTip(tr("Open a file"));
connect(on_open, SIGNAL(triggered()), this, SLOT(on_file_open()));
menu->addAction(on_open);
statusBar();
QMainWindow *log_window = new QMainWindow(this);
log = new QTextEdit(log_window);
log->setReadOnly(true);
log_window->setCentralWidget(log);
log_window->setWindowTitle("mpv log window");
log_window->setMinimumSize(500, 50);
log_window->show();
mpv = mpv_create();
if (!mpv)
throw "can't create mpv instance";
// Create a video child window. Force Qt to create a native window, and
// pass the window ID to the mpv wid option. Works on: X11, win32, Cocoa
mpv_container = new QWidget(this);
setCentralWidget(mpv_container);
mpv_container->setAttribute(Qt::WA_DontCreateNativeAncestors);
mpv_container->setAttribute(Qt::WA_NativeWindow);
// If you have a HWND, use: int64_t wid = (intptr_t)hwnd;
int64_t wid = mpv_container->winId();
mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);
// Enable default bindings, because we're lazy. Normally, a player using
// mpv as backend would implement its own key bindings.
mpv_set_option_string(mpv, "input-default-bindings", "yes");
// Enable keyboard input on the X11 window. For the messy details, see
// --input-vo-keyboard on the manpage.
mpv_set_option_string(mpv, "input-vo-keyboard", "yes");
// Let us receive property change events with MPV_EVENT_PROPERTY_CHANGE if
// this property changes.
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE);
mpv_observe_property(mpv, 0, "chapter-list", MPV_FORMAT_NODE);
// Request log messages with level "info" or higher.
// They are received as MPV_EVENT_LOG_MESSAGE.
mpv_request_log_messages(mpv, "info");
// From this point on, the wakeup function will be called. The callback
// can come from any thread, so we use the Qt QEvent mechanism to relay
// the wakeup in a thread-safe way.
mpv_set_wakeup_callback(mpv, wakeup, this);
if (mpv_initialize(mpv) < 0)
throw "mpv failed to initialize";
}
void MainWindow::handle_mpv_event(mpv_event *event)
{
switch (event->event_id) {
case MPV_EVENT_PROPERTY_CHANGE: {
mpv_event_property *prop = (mpv_event_property *)event->data;
if (strcmp(prop->name, "time-pos") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double *)prop->data;
std::stringstream ss;
ss << "At: " << time;
statusBar()->showMessage(QString::fromStdString(ss.str()));
} else if (prop->format == MPV_FORMAT_NONE) {
// The property is unavailable, which probably means playback
// was stopped.
statusBar()->showMessage("");
}
} else if (strcmp(prop->name, "chapter-list") == 0 ||
strcmp(prop->name, "track-list") == 0)
{
// Dump the properties as JSON for demo purposes.
#if QT_VERSION >= 0x050000
if (prop->format == MPV_FORMAT_NODE) {
QVariant v = mpv::qt::node_to_variant((mpv_node *)prop->data);
// Abuse JSON support for easily printing the mpv_node contents.
QJsonDocument d = QJsonDocument::fromVariant(v);
append_log("Change property " + QString(prop->name) + ":\n");
append_log(d.toJson().data());
}
#endif
}
break;
}
case MPV_EVENT_VIDEO_RECONFIG: {
// Retrieve the new video size.
int64_t w, h;
if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 &&
mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 &&
w > 0 && h > 0)
{
// Note that the MPV_EVENT_VIDEO_RECONFIG event doesn't necessarily
// imply a resize, and you should check yourself if the video
// dimensions really changed.
// mpv itself will scale/letter box the video to the container size
// if the video doesn't fit.
std::stringstream ss;
ss << "Reconfig: " << w << " " << h;
statusBar()->showMessage(QString::fromStdString(ss.str()));
}
break;
}
case MPV_EVENT_LOG_MESSAGE: {
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
std::stringstream ss;
ss << "[" << msg->prefix << "] " << msg->level << ": " << msg->text;
append_log(QString::fromStdString(ss.str()));
break;
}
case MPV_EVENT_SHUTDOWN: {
mpv_terminate_destroy(mpv);
mpv = NULL;
break;
}
default: ;
// Ignore uninteresting or unknown events.
}
}
bool MainWindow::event(QEvent *event)
{
// QEvent::User is sent by wakeup().
if (event->type() == QEvent::User) {
// Process all events, until the event queue is empty.
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
handle_mpv_event(event);
}
return true;
}
return QMainWindow::event(event);
}
void MainWindow::on_file_open()
{
QString filename = QFileDialog::getOpenFileName(this, "Open file");
if (mpv) {
const QByteArray c_filename = filename.toUtf8();
const char *args[] = {"loadfile", c_filename.data(), NULL};
mpv_command_async(mpv, 0, args);
}
}
void MainWindow::append_log(const QString &text)
{
QTextCursor cursor = log->textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertText(text);
log->setTextCursor(cursor);
}
MainWindow::~MainWindow()
{
if (mpv)
mpv_terminate_destroy(mpv);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Qt sets the locale in the QApplication constructor, but libmpv requires
// the LC_NUMERIC category to be set to "C", so change it back.
std::setlocale(LC_NUMERIC, "C");
MainWindow w;
w.show();
return a.exec();
}
-35
View File
@@ -1,35 +0,0 @@
#ifndef QTEXAMPLE_H
#define QTEXAMPLE_H
#include <QMainWindow>
#include <mpv/client.h>
class QTextEdit;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
virtual bool event(QEvent *event);
private slots:
void on_file_open();
private:
QWidget *mpv_container;
mpv_handle *mpv;
QTextEdit *log;
void append_log(const QString &text);
void create_player();
void handle_mpv_event(mpv_event *event);
};
#endif // QTEXAMPLE_H
-12
View File
@@ -1,12 +0,0 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qtexample
TEMPLATE = app
CONFIG += link_pkgconfig debug
PKGCONFIG = mpv
SOURCES += qtexample.cpp
HEADERS += qtexample.h
-10
View File
@@ -1,10 +0,0 @@
#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);
}
}
-45
View File
@@ -1,45 +0,0 @@
#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"));
mpv_set_option_string(ctx, "input-x11-keyboard", "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;
}
-147
View File
@@ -1,147 +0,0 @@
How to contribute
=================
General
-------
The main contact for mpv development is IRC, specifically #mpv-player and
#mpv-player-dev on Freenode.
Sending patches
---------------
- Make a github pull request, or send a link to a plaintext patch created with
``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.
- Write informative commit messages. Use present tense to describe the
situation with the patch applied, and past tense for the situation before
the change.
- The subject line (the first line in a commit message) should contain a
prefix identifying the sub system, followed by a short description what
impact this commit has. This subject line shouldn't be longer than 72
characters, because it messes up the output of many git tools otherwise.
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``
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``.
- The body of the commit message (everything else after the subject line) should
be as informative as possible and contain everything that isn't obvious. Don't
hesitate to dump as much information as you can - it doesn't cost you
anything. Put some effort into it. If someone finds a bug months or years
later, and finds that it's caused by your commit (even though your commit was
supposed to fix another bug), it would be bad if there wasn't enough
information to test the original bug. The old bug might be reintroduced while
fixing the new bug.
The commit message should be wrapped on 72 characters per line, because git
tools usually do not break text automatically. On the other hand, you do not
need to break text that would be unnatural to break (like data for test cases,
or long URLs).
Important: put an empty line between the subject line and the commit message.
If this is missing, it will break display in common git tools.
- Try to separate cosmetic and functional changes. It's ok to make a few
additional cosmetic changes in the same file you're working on. But don't do
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.
Code formatting
---------------
mpv uses C99 with K&R formatting, with some exceptions.
- Use the K&R indent style.
- Use 4 spaces of indentation, never use tabs (except in Makefiles).
- Add a single space between keywords and binary operators. There are some other
cases where spaces should be added. Example:
```C
if ((a * b) > c) {
// code
some_function(a, b, c);
}
```
- Break lines on 80 columns. There is a hard limit of 85 columns. You may ignore
this limit if there's a strong case that not breaking the line will increase
readability. Going over 85 columns might provoke endless discussions about
whether such a limit is needed or not, so avoid it.
- If the body of an if/for/while statement has more than 1 physical lines, then
always add braces, even if they're technically redundant.
Bad:
```C
if (a)
// do something if b
if (b)
do_something();
```
Good:
```C
if (a) {
// do something if b
if (b)
do_something();
}
```
- If the body of an if statement uses braces, the else branch should also
use braces (and reverse).
Example:
```C
if (a) {
// do something
something();
something_else();
} else {
one_line();
}
```
- If an if condition spans multiple physical lines, then put the opening brace
for the if body on the next physical line. (Also, preferably always add a
brace, even if technically none is needed.)
Example:
```C
if (very_long_condition_a &&
very_long_condition_b)
{
code();
}
```
- Remove any trailing whitespace.
- If the file you're editing uses formatting different from from what is
described here, it's probably an old file from times when nobody followed a
consistent style. You're free to use the existing style, or the new style, or
to send a patch to reformat the file to the new style before making functional
changes.
General coding
--------------
- Use C99. Also freely make use of C99 features if it's appropriate, such as
stdbool.h.
- Don't use GNU-only features. In some cases they may be warranted, if they
are optional (such as attributes enabling printf-like format string checks).
But in general, standard C99 should be used.
- The same applies to libc functions. We have to be Windows-compatible too. Use
functions guaranteed by C99 or POSIX only, unless your use is guarded by a
configure check.
- Prefer fusing declaration and initialization, rather than putting declarations
on the top of a block. Obvious data flow is more important than avoiding
mixing declarations and statements, which is just a C90 artifact.
- tech-overview.txt might help to get an overview how mpv is structured.
- If you add features that require intrusive changes, discuss them on the dev
channel first. There might be a better way to add a feature and it can avoid
wasted work.
-83
View File
@@ -1,83 +0,0 @@
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.
Additional dependencies
-----------------------
You need a pthread wrapper. It must be interoperable with native Windows
threads. pthreads-win32 or MinGW pthreads might work.
If you want ``--input-file=...`` to work, you need libwaio. It's available
from: git://midipix.org/waio
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
```
+52
View File
@@ -0,0 +1,52 @@
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:
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
Using mingw-w64-cmake to setup a MinGW-w64 environment is recommended (this will
also build mpv and its dependencies): https://github.com/lachs0r/mingw-w64-cmake
Alternatively, use MXE: http://mxe.cc
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
================
# Download MXE. Note that compiling the required packages requires about 1 GB
# or more!
cd /opt
git clone https://github.com/mxe/mxe mingw
cd mingw
# Edit the MXE target, so that MinGW-w64 for 32 bit targets is built.
echo "MXE_TARGETS := i686-w64-mingw32" > settings.mk
# Build required packages. The following provide a minimum required to build
# mpv. (Not all of the following packages are strictly required.)
make gcc
make ffmpeg
make libass
make jpeg
make pthreads
# 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).
git clone https://github.com/mpv-player/mpv.git
cd mpv
export PATH=/opt/mingw/usr/bin/:$PATH
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
./waf build
# This should work. Note however that MXE’s ffmpeg package might be very old
# in order to avoid breaking e.g. xine-lib, so you might want to update that
# or build it manually as well.
+5 -21
View File
@@ -27,13 +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::
mpv can't use ordered chapter files in EDL entries. Usage of relative or
absolute paths as well as any protocol prefixes is 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
@@ -78,7 +78,7 @@ The parameter name defines the meaning of the parameter:
2) ``start``, a time value that specifies the start offset into the source file.
3) ``length``, a time value that specifies the length of the segment.
See the section below for the format of timestamps.
(Currently, time values are floating point values in seconds.)
Unnamed parameters carry implicit names. The parameter position determines
which of the parameters listed above is set. For example, the second parameter
@@ -95,22 +95,6 @@ to ``20``, ``param3`` to ``value,escaped``, ``param4`` to ``value2``.
Instead of line breaks, the character ``;`` can be used. Line feed bytes and
``;`` are treated equally.
Timestamp format
================
Currently, time values are floating point values in seconds.
As an extension, you can set the ``timestamps=chapters`` option. If this option
is set, timestamps have to be integers, and refer to chapter numbers, starting
with 0.
Example::
# mpv EDL v0
file.mkv,2,4,timestamps=chapters
Plays chapter 3 and ends with the start of chapter 7 (4 chapters later).
Syntax of EDL URIs
==================
+2 -7
View File
@@ -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]
@@ -38,11 +38,6 @@ section::
oac = aac
oacopts-add = b=96k
It's also possible to define default encoding options by putting them into
the section named ``[encoding]``. (This behavior changed after mpv 0.3.x. In
mpv 0.3.x, config options in the default section / no section were applied
to encoding. This is not the case anymore.)
One can then encode using this profile using the command::
mpv infile -o outfile.mp4 -profile myencprofile
@@ -139,9 +134,9 @@ What works
* Deinterlacing/Inverse Telecine with any of mpv's filters for that
* Audio file converting: mpv -o outfile.mp3 infile.flac -no-video -oac
libmp3lame -oacopts ab=320k
* inverse telecine filters (confirmed working: detc, pullup, filmdint)
What does not work yet
======================
* 3-pass encoding (ensuring constant total size and bitrate constraints while
having VBR audio; mencoder calls this "frameno")
-438
View File
@@ -1,438 +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.
.. note::
These lists are incomplete.
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.
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).
* 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``).
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, and
``ytdl=yes`` 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``
``-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 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 readded in 0.5.1 and sets exactly these options.)
* 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.
+19
View File
@@ -0,0 +1,19 @@
[latex2e writer]
use-latex-docinfo: yes
use-latex-toc: yes
hyperlink-color: Blue!30!RoyalPurple!70!Black
latex-preamble: \usepackage[usenames,dvipsnames]{xcolor}
\usepackage{fullpage}
\usepackage{graphicx}
\renewcommand{\familydefault}{\sfdefault}
\makeatletter
\renewcommand{\maketitle}{
\begin{center}
\vspace*{-1.5em}
\begin{Huge}
\@title
\end{Huge}
\end{center}
}
\makeatother
+30 -49
View File
@@ -72,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
@@ -94,7 +92,7 @@ Available filters are:
``minchn=<n>``
If the input channel number is less than ``<minchn>``, the filter will
detach itself (default: 3).
detach itself (default: 5).
``sweep[=speed]``
Produces a sine sweep.
@@ -103,7 +101,7 @@ Available filters are:
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/60 Hz
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>``
@@ -149,7 +147,7 @@ Available filters are:
0 no matrix decoding (default)
==== ===================================
``equalizer=g1:g2:g3:...:g10``
``equalizer=[g1:g2:g3:...:g10]``
10 octave band graphic equalizer, implemented using 10 IIR band-pass
filters. This means that it works regardless of what type of audio is
being played back. The center frequencies for the 10 bands are:
@@ -184,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
@@ -243,7 +241,7 @@ Available filters are:
48000 for example.
``<channels>``
Force mixing to a specific channel layout. See ``--audio-channels`` option
Force mixing to a specific channel layout. See ``--channels`` option
for possible values.
``<out-format>``
@@ -252,9 +250,8 @@ Available filters are:
``<out-channels>``
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
See also ``--format``, ``--srate``, and ``--channels`` for related options.
Keep in mind that ``--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
@@ -265,10 +262,11 @@ Available filters are:
Filter for internal use only. Converts between 24-bit and 32-bit sample
formats.
``convertsign``
Filter for internal use only. Converts between signed/unsigned formats.
``convertsignendian``
Filter for internal use only. Converts between signed/unsigned formats
and formats with different endian.
``volume[=<volumedb>[:...]]``
``volume[=volumedb[:softclip[:s16]]]``
Implements software volume control. Use this filter with caution since it
can reduce the signal to noise ratio of the sound. In most cases it is
best to use the *Master* volume control of your sound card or the volume
@@ -278,44 +276,27 @@ 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
in the file metadata.
``replaygain-album``
Like replaygain-track, but using the album-gain value instead.
``replaygain-preamp``
Pre-amplification gain in dB to apply to the selected replaygain gain
(default: 0).
``replaygain-clip=yes|no``
Prevent clipping caused by replaygain by automatically lowering the
gain (default). Use ``replaygain-clip=no`` to disable this.
``softclip``
``<softclip>``
Turns soft clipping on. Soft-clipping can make the
sound more smooth if very high volume levels are used. Enable this
option if the dynamic range of the loudspeakers is very low.
*WARNING*: This feature creates distortion and should be considered a
last resort.
``s16``
``<s16>``
Force S16 sample format if set. Lower quality, but might be faster
in some situations.
``detach``
Remove the filter if the volume is not changed at audio filter config
time. Useful with replaygain: if the current file has no replaygain
tags, then the filter will be removed if this option is enabled.
(If ``--softvol=yes`` is used and the player volume controls are used
during playback, a different volume filter will be inserted.)
.. 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>]``
``pan=n[:<matrix>]``
Mixes channels arbitrarily. Basically a combination of the volume and the
channels filter that can be used to down-mix many channels to only a few,
e.g. stereo to mono, or vary the "width" of the center speaker in a
@@ -352,7 +333,7 @@ Available filters are:
If you just want to force remixing to a certain output channel layout,
it is easier to use the ``format`` filter. For example,
``mpv '--af=format=channels=5.1' '--audio-channels=5.1'`` would always force
``mpv '--af=format=channels=5.1' '--channels=5.1'`` would always force
remixing audio to 5.1 and output it like this.
``sub[=fc:ch]``
@@ -369,8 +350,8 @@ Available filters are:
to the subwoofer.
``<fc>``
cutoff frequency in Hz for the low-pass filter (20 Hz to 300 Hz)
(default: 60 Hz) For the best result try setting the cutoff frequency
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>``
@@ -381,8 +362,8 @@ Available filters are:
.. admonition:: Example
``mpv --af=sub=100:4 --audio-channels=5 media.avi``
Would add a subwoofer channel with a cutoff frequency of 100 Hz to
``mpv --af=sub=100:4 --channels=5 media.avi``
Would add a subwoofer channel with a cutoff frequency of 100Hz to
output channel 4.
``center``
@@ -409,8 +390,8 @@ Available filters are:
.. admonition:: Example
``mpv --af=surround=15 --audio-channels=4 media.avi``
Would add surround sound decoding with 15 ms delay for the sound to
``mpv --af=surround=15 --channels=4 media.avi``
Would add surround sound decoding with 15ms delay for the sound to
the rear speakers.
``delay[=[ch1,ch2,...]]``
@@ -438,8 +419,8 @@ Available filters are:
.. admonition:: Example
``mpv --af=delay=[10.5,10.5,0,0,7,0] media.avi``
Would delay front left and right by 10.5 ms, the two rear channels
and the subwoofer by 0 ms and the center channel by 7 ms.
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
@@ -589,7 +570,7 @@ 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
@@ -601,7 +582,7 @@ Available filters are:
1.2x.
``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
+12 -69
View File
@@ -18,12 +18,7 @@ normal driver parameters.
.. 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 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 OS X systems, use ``--ao=coreaudio``.
See ``--ao=help`` for a list of compiled-in audio output drivers.
.. admonition:: Examples
@@ -36,14 +31,14 @@ Available audio output drivers are:
``alsa`` (Linux only)
ALSA audio output driver
``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.)
``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.
``mixer-device=<device>``
Set the mixer device used with ``--no-softvol`` (default: ``default``).
``mixer-name=<name>``
@@ -53,10 +48,6 @@ Available audio output drivers are:
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.
``non-interleaved``
Allow output of non-interleaved formats (if the audio decoder uses
this format). Currently disabled by default, because some popular
ALSA plugins are utterly broken with non-interleaved formats.
.. note::
@@ -90,6 +81,9 @@ Available audio output drivers are:
``name=<client>``
Client name that is passed to JACK (default: ``mpv``). Useful
if you want to have certain connections established automatically.
``(no-)estimate``
Estimate the audio delay, supposed to make the video playback smoother
(default: enabled).
``(no-)autostart``
Automatically start jackd if necessary (default: disabled). Note that
this tends to be unreliable and will flood stdout with server messages.
@@ -114,24 +108,16 @@ 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.
``coreaudio_exclusive`` (Mac OS X only)
Native Mac OS X audio output driver using direct device access and
exclusive mode (bypasses the sound server).
Supports only compressed formats (AC3 and DTS).
``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
.. note:: This driver is not very useful. Playing multi-channel audio with
it is slow.
``pulse``
PulseAudio audio output driver
@@ -140,26 +126,10 @@ Available audio output drivers are:
string uses a local connection, "localhost" uses network transfer
(most likely not what you want).
``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.
``latency-hacks=<yes|no>``
Enable hacks to workaround PulseAudio timing bugs (default: yes). 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.
``portaudio``
PortAudio audio output driver. This works on all platforms, and has
extensive MS Windows support.
.. 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,
@@ -168,24 +138,15 @@ Available audio output drivers are:
``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.
``buffersize=<ms>``
DirectSound buffer size in milliseconds (default: 200).
``sdl``
SDL 1.2+ audio output driver. Should work on any platform supported by SDL
1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
appropriately for your system.
.. note:: This driver is for compatibility with extremely foreign
environments, such as systems where none of the other drivers
are available.
``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
@@ -211,18 +172,6 @@ Available audio output drivers are:
``outburst``
Simulated chunk size in samples.
``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 simulating this.
``latency``
Simulated device latency. This is additional to EOF.
``broken-eof``
Simulate broken audio drivers, which always add the fixed device
latency to the reported audio playback position.
``pcm``
Raw PCM/WAVE file writer audio output
@@ -237,10 +186,6 @@ Available audio output drivers are:
``rsound``
Audio output to an RSound daemon
.. note:: Completely useless, unless you intend to run RSound. Not to be
confused with RoarAudio, which is something completely
different.
``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
@@ -252,8 +197,6 @@ Available audio output drivers are:
``sndio``
Audio output to the OpenBSD sndio sound system
.. note:: Experimental. There are known bugs and issues.
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
layouts.)
+293
View File
@@ -0,0 +1,293 @@
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. Some changes are incompatible, or completely change how the
player behaves.
General Changes for MPlayer to mplayer2
---------------------------------------
* Removal of the internal GUI, MEncoder, OSD menu
* Better pause handling (do not unpause on a command)
* Better MKV support (such as ordered chapters)
* vo_vdpau improvements
* Precise seeking support
* No embedded copy of ffmpeg and other libraries
* 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
* General code cleanups
* Many more changes
General Changes for mplayer2 to mpv
-----------------------------------
* Switch back to GPLv2+.
* Removal of lots of unneeded code to encourage developer activity (less
obscure scary zombie code that kills any desire for hacking the codebase)
* Removal of dust and dead bodies (code-wise), such as kernel drivers for
decades old hardware
* Removal of support for dead platforms
* 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.
* 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 in the near future. However, the new
syntax is mentioned in all documentation and so on, so it is a good thing to
know about this change.
(The new syntax was introduced in mplayer2.)
* In general, negating switches like ``-noopt`` now have to be written as
``-no-opt``, or better ``--no-opt``.
* Per-file options are not the default anymore. You can explicitly specify
file-local options. See ``Usage`` section.
* Table of renamed/replaced switches:
=========================== ========================================
Old New
=========================== ========================================
``-no<opt>`` ``--no-<opt>`` (add a dash)
``-nosound`` ``--no-audio``
``-use-filename-title`` ``--title='${filename}'``
``-loop 0`` ``--loop=inf``
``-hardframedrop`` ``--framedrop=hard``
``-osdlevel`` ``--osd-level``
``-delay`` ``--audio-delay``
``-subdelay`` ``--sub-delay``
``-subpos`` ``--sub-pos``
``-forcedsubsonly`` ``--sub-forced-only``
``-benchmark`` ``--untimed`` (no stats)
``-xineramascreen`` ``--screen`` (different values)
``-ss`` ``--start``
``-endpos`` ``--length``
``-cursor-autohide-delay`` ``--cursor-autohide``
``-sub-fuzziness`` ``--autosub-match``
``-subfont`` ``--sub-text-font``
``-font`` ``--osd-font``
``-subfont-*`` ``--sub-text-*``, ``--osd-*``
``-subfont-text-scale`` ``--sub-scale``
``-spugauss`` ``--sub-gauss``
``-vobsub`` ``--sub`` (pass the .idx file)
``-ass-bottom-margin`` ``--vf=sub=bottom:top``
``-vc ffh264vdpau`` (etc.) ``--hwdec=vdpau``
``-ac spdifac3`` ``--ad=spdif:ac3`` (see ``--ad=help``)
``-afm hwac3`` ``--ad=spdif:ac3,spdif:dts``
``-x W``, ``-y H`` ``--geometry=WxH`` + ``--no-keepaspect``
``-xy W`` ``--autofit=W``
``-a52drc level`` ``--ad-lavc-ac3drc=level``
``-dumpstream`` ``--stream-dump=<filename>``
``-capture`` ``--stream-capture=<filename>``
``-stop-xscreensaver`` ``--stop-screensaver``
``-subfile`` ``--sub``
``-lavdopts ...`` ``--vd-lavc-...``
``-lavfdopts`` ``--demuxer-lavf-...``
``-rawaudio ...`` ``--demuxer-rawaudio-...``
``-rawvideo ...`` ``--demuxer-rawvideo-...``
``-mixer`` AO suboptions (``alsa``, ``oss``)
``-mixer-channel`` AO suboptions (``alsa``, ``oss``)
``-ao alsa:device=hw=0.3`` ``--ao=alsa:device=[hw:0,3]``
``-af volnorm`` ``--af=drc`` (renamed)
``-zoom`` Inverse available as ``--video-unscaled``
``-panscanrange`` ``--video-zoom``, ``--video-pan-x/y``
``-pp ...`` ``'--vf=pp=[...]'``
``-pphelp`` ``--vf=pp:help``
``dvdnav://`` ``dvdnav://menu``
=========================== ========================================
.. 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 aspect <ratio>`` |
| | |
| | ``set aspect 0`` (to 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|...`` |
+--------------------------------+----------------------------------------+
Other
~~~~~
* The playtree has been removed. **mpv**'s internal playlist is a simple and
flat list now. This simplifies the code and makes **mpv** usage less
confusing.
* 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.
Policy for Removed Features
---------------------------
Features are a good thing, because they make users happy. As such, it is
attempted to preserve useful features as far as possible. But if a feature is
likely to be not used by many, and causes problems otherwise, it will be
removed. Developers should not be burdened with fixing or cleaning up code that
has no actual use.
It is always possible to add back removed features. File a feature request if a
feature you relied on has been removed, and you want it back. Though it might be
rejected in the worst case, it is much more likely that it will be either added
back, or that a better solution will be implemented.
Why this Fork?
--------------
* MPlayer wants to maintain old code, even if it is very bad code. It seems
mplayer2 was forked because MPlayer developers refused to get rid of all the
cruft. The mplayer2 and MPlayer codebases also deviated enough to make a
reunification unlikely.
* mplayer2 development is slow, and it is hard to get in changes. Details
withheld as to not turn this into a rant.
* MPlayer rarely merged from mplayer2, and mplayer2 practically stopped
merging from MPlayer (not even code cleanups or new features are merged)
* **mpv** intends to continuously merge from mplayer-svn and mplayer2, while
speeding up development. There is willingness for significant changes, even
if this means breaking compatibility.
@@ -3,7 +3,7 @@ ENCODING
You can encode files from one format/codec to another using this facility.
``--o=<filename>``
``-o <filename>``
Enables encoding mode and specifies the output file name.
``--of=<format>``
@@ -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.
@@ -149,7 +149,3 @@ You can encode files from one format/codec to another using this facility.
container formats, e.g. AVI). In this mode, discontinuities are not fixed
and all pts are passed through as-is. Never seek backwards or use multiple
input files in this mode!
``--no-ometadata``
Turns off copying of metadata from input files to output files when
encoding (which is enabled by default).
+701
View File
@@ -0,0 +1,701 @@
INPUT.CONF
==========
The input.conf file consists of a list of key bindings, for example::
s screenshot # take a screenshot with the s key
Each line maps a key to an input command. Keys are specified with their literal
value (upper case if combined with ``Shift``), or a name for special keys. For
example, ``a`` maps to the ``a`` key without shift, and ``A`` maps to ``a``
with shift.
A list of special keys can be obtained with
``mpv --input-keylist``
In general, keys can be combined with ``Shift``, ``Ctrl`` and ``Alt``::
ctrl+q quit
**mpv** can be started in input test mode, which displays key bindings and the
commands they're bound to on the OSD, instead of executing the commands::
mpv --input-test --demuxer=rawvideo --demuxer-rawvideo=w=1280:h=720 /dev/zero
(Commands which normally close the player will not work in this mode, and you
must kill **mpv** externally to make it exit.)
General Input Command Syntax
----------------------------
``[Shift+][Ctrl+][Alt+][Meta+]<key> [{<section>}] [<prefixes>] <command> (<argument>)* [; <command>]``
Note that by default, the right Alt key can be used to create special
characters, and thus does not register as a modifier. The option
``--no-right-alt-gr`` changes this behavior.
Newlines always start a new binding. ``#`` starts a comment (outside of quoted
string arguments). To bind commands to the ``#`` key, ``SHARP`` can be used.
``<key>`` is either the literal character the key produces (ASCII or Unicode
character), or a symbolic name (as printed by ``--input-keylist``).
``<section>`` (braced with ``{`` and ``}``) is the input section for this
command.
Arguments are separated by whitespace. This applies even to string arguments.
For this reason, string arguments should be quoted with ``"``. Inside quotes,
C-style escaping can be used.
You can bind multiple commands to one key. For example:
| a show_text "command 1" ; show_text "command 2"
Note that some magic is disabled for keys: seek commands inside lists are not
coalesced (seeking will appear slower), and no check is done for abort commands
(so these commands can't be used to abort playback if the network cache is
stuck).
List of Input Commands
----------------------
``ignore``
Use this to "block" keys that should be unbound, and do nothing. Useful for
disabling default bindings, without disabling all bindings with
``--no-input-default-bindings``.
``seek <seconds> [relative|absolute|absolute-percent|- [default-precise|exact|keyframes]]``
Change the playback position. By default, seeks by a relative amount of
seconds.
The second argument sets the seek mode:
relative (default)
Seek relative to current position (a negative value seeks backwards).
absolute
Seek to a given time.
absolute-percent
Seek to a given percent position.
The third argument defines how exact the seek is:
default-precise (default)
Follow the default behavior as set by ``--hr-seek``, which by default
does imprecise seeks (like ``keyframes``).
exact
Always do exact/hr/precise seeks (slow).
keyframes
Always restart playback at keyframe boundaries (fast).
``revert_seek``
Undoes the ``seek`` command, and some other commands that seek (but not
necessarily all of them). Calling this command once will jump to the
playback position before the seek. Calling it a second time undoes the
``revert_seek`` command itself.
``frame_step``
Play one frame, then pause.
``frame_back_step``
Go back by one frame, then pause. Note that this can be very slow (it tries
to be precise, not fast), and sometimes fails to behave as expected. How
well this works depends on whether precise seeking works correctly (e.g.
see the ``--hr-seek-demuxer-offset`` option). Video filters or other video
postprocessing that modifies timing of frames (e.g. deinterlacing) should
usually work, but might make backstepping silently behave incorrectly in
corner cases.
This does not work with audio-only playback.
``set <property> "<value>"``
Set the given property to the given value.
``add <property> [<value>]``
Add the given value to the property. On overflow or underflow, clamp the
property to the maximum. If ``<value>`` is omitted, assume ``1``.
``cycle <property> [up|down]``
Cycle the given property. ``up`` and ``down`` set the cycle direction. On
overflow, set the property back to the minimum, on underflow set it to the
maximum. If ``up`` or ``down`` is omitted, assume ``up``.
``multiply <property> <factor>``
Multiplies the value of a property with the numeric factor.
``screenshot [subtitles|video|window|- [single|each-frame]]``
Take a screenshot.
First argument:
<subtitles> (default)
Save the video image, in its original resolution, and with subtitles.
Some video outputs may still include the OSD in the output under certain
circumstances.
<video>
Like ``subtitles``, but typically without OSD or subtitles. The exact
behavior depends on the selected video output.
<window>
Save the contents of the mpv window. Typically scaled, with OSD and
subtitles. The exact behavior depends on the selected video output, and
if no support is available, this will act like ``video``.
Second argument:
<single> (default)
Take a single screenshot.
<each-frame>
Take a screenshot each frame. Issue this command again to stop taking
screenshots.
``screenshot_to_file "<filename>" [subtitles|video|window]``
Take a screenshot and save it to a given file. The format of the file will
be guessed by the extension (and ``--screenshot-format`` is ignored - the
behavior when the extension is missing or unknown is arbitrary).
The second argument is like the first argument to ``screenshot``.
This command tries to never overwrite files. If the file already exists,
it fails.
Like all input command parameters, the filename is subject to property
expansion as described in `Property Expansion`_.
``playlist_next [weak|force]``
Go to the next entry on the playlist.
weak (default)
If the last file on the playlist is currently played, do nothing.
force
Terminate playback if there are no more files on the playlist.
``playlist_prev [weak|force]``
Go to the previous entry on the playlist.
weak (default)
If the first file on the playlist is currently played, do nothing.
force
Terminate playback if the first file is being played.
``loadfile "<file>" [replace|append]``
Load the given file and play it.
Second argument:
<replace> (default)
Stop playback of the current file, and play the new file immediately.
<append>
Append the file to the playlist.
``loadlist "<playlist>" [replace|append]``
Load the given playlist file (like ``--playlist``).
``playlist_clear``
Clear the playlist, except the currently played file.
``playlist_remove current|<index>``
Remove the playlist entry at the given index. Index values start counting
with 0. The special value ``current`` removes the current entry. Note that
removing the current entry also stops playback and starts playing the next
entry.
``playlist_move <index1> <index2>``
Move the playlist entry at index1, so that it takes the place of the
entry index2. (Paradoxically, the moved playlist entry will not have
the index value index2 after moving if index1 was lower than index2,
because index2 refers to the target entry, not the index the entry
will have after moving.)
``run "command" "arg1" "arg2" ...``
(Unix only)
Run the given command. Unlike in MPlayer/mplayer2 and earlier versions of
mpv (0.2.x and older), this doesn't call the shell. Instead, the command
is run directly, with each argument passed separately. Each argument is
expanded like in `Property Expansion`_. Note that there is a static limit
of (as of this writing) 10 arguments (this limit could be raised on demand).
The program is run in a detached way. mpv doesn't wait until the command
is completed, but continues playback right after spawning it.
To get the old behavior, use ``/bin/sh`` and ``-c`` as the first two
arguments.
.. admonition:: Example
``run "/bin/sh" "-c" "echo ${title} > /tmp/playing"``
This is not a particularly good example, because it doesn't handle
escaping, and a specially prepared file might allow an attacker to
execute arbitrary shell commands. It is recommended to write a small
shell script, and call that with ``run``.
``quit [<code>]``
Exit the player using the given exit code.
``quit_watch_later``
Exit player, and store current playback position. Playing that file later
will seek to the previous position on start.
``sub_add "<file>"``
Load the given subtitle file. It is not selected as current subtitle after
loading.
``sub_remove [<id>]``
Remove the given subtitle track. If the ``id`` argument is missing, remove
the current track. (Works on external subtitle files only.)
``sub_reload [<id>]``
Reload the given subtitle tracks. If the ``id`` argument is missing, remove
the current track. (Works on external subtitle files only.)
This works by unloading and re-adding the subtitle track.
``sub_step <skip>``
Change subtitle timing such, that the subtitle event after the next
``<skip>`` subtitle events is displayed. ``<skip>`` can be negative to step
backwards.
``sub_seek <skip>``
Seek to the next (skip set to 1) or the previous (skip set to -1) subtitle.
This is similar to ``sub_step``, except that it seeks video and audio
instead of adjusting the subtitle delay.
Like with ``sub_step``, this works with external text subtitles only. For
embedded text subtitles (like with Matroska), this works only with subtitle
events that have already been displayed.
``osd [<level>]``
Toggle OSD level. If ``<level>`` is specified, set the OSD mode
(see ``--osd-level`` for valid values).
``print_text "<string>"``
Print text to stdout. The string can contain properties (see
`Property Expansion`_).
``show_text "<string>" [<duration>|- [<level>]]``
Show text on the OSD. The string can contain properties, which are expanded
as described in `Property Expansion`_. This can be used to show playback
time, filename, and so on.
<duration>
The time in ms to show the message for. By default, it uses the same
value as ``--osd-duration``.
<level>
The minimum OSD level to show the text at (see ``--osd-level``).
``show_progress``
Show the progress bar, the elapsed time and the total duration of the file
on the OSD.
Input Commands that are Possibly Subject to Change
--------------------------------------------------
``af set|add|toggle|del|clr "filter1=params,filter2,..."``
Change audio filter chain. See ``vf`` command.
``vf set|add|toggle|del|clr "filter1=params,filter2,..."``
Change video filter chain.
The first argument decides what happens:
set
Overwrite the previous filter chain with the new one.
add
Append the new filter chain to the previous one.
toggle
Check if the given filter (with the exact parameters) is already
in the video chain. If yes, remove the filter. If no, add the filter.
(If several filters are passed to the command, this is done for
each filter.)
del
Remove the given filters from the video chain. Unlike in the other
cases, the second parameter is a comma separated list of filter names
or integer indexes. ``0`` would denote the first filter. Negative
indexes start from the last filter, and ``-1`` denotes the last
filter.
clr
Remove all filters. Note that like the other sub-commands, this does
not control automatically inserted filters.
You can assign labels to filter by prefixing them with ``@name:`` (where
``name`` is a user-chosen arbitrary identifier). Labels can be used to
refer to filters by name in all of the filter chain modification commands.
For ``add``, using an already used label will replace the existing filter.
The ``vf`` command shows the list of requested filters on the OSD after
changing the filter chain. This is roughly equivalent to
``show_text ${vf}``. Note that auto-inserted filters for format conversion
are not shown on the list, only what was requested by the user.
.. admonition:: Example for input.conf
- ``a vf set flip`` turn video upside-down on the ``a`` key
- ``b vf set ""`` remove all video filters on ``b``
- ``c vf toggle lavfi=gradfun`` toggle debanding on ``c``
``cycle_values ["!reverse"] <property> "<value1>" "<value2>" ...``
Cycle through a list of values. Each invocation of the command will set the
given property to the next value in the list. The command maintains an
internal counter which value to pick next, and which is initially 0. It is
reset to 0 once the last value is reached.
The internal counter is associated using the property name and the value
list. If multiple commands (bound to different keys) use the same name
and value list, they will share the internal counter.
The special argument ``!reverse`` can be used to cycle the value list in
reverse. Compared with a command that just lists the value in reverse, this
command will actually share the internal counter with the forward-cycling
key binding.
Note that there is a static limit of (as of this writing) 10 arguments
(this limit could be raised on demand).
``enable_section "<section>" [default|exclusive]``
Enable all key bindings in the named input section.
The enabled input sections form a stack. Bindings in sections on the top of
the stack are preferred to lower sections. This command puts the section
on top of the stack. If the section was already on the stack, it is
implicitly removed beforehand. (A section cannot be on the stack more than
once.)
If ``exclusive`` is specified as second argument, all sections below the
newly enabled section are disabled. They will be re-enabled as soon as
all exclusive sections above them are removed.
``disable_section "<section>"``
Disable the named input section. Undoes ``enable_section``.
``overlay_add <id> <x> <y> "<file>" <offset> "<fmt>" <w> <h> <stride>``
Add an OSD overlay sourced from raw data. This might be useful for scripts
and applications controlling mpv, and which want to display things on top
of the video window.
Overlays are usually displayed in screen resolution, but with some VOs,
the resolution is reduced to that of the video's. You can read the
``osd-width`` and ``osd-height`` properties. At least with ``--vo-xv`` and
anamorphic video (such as DVD), ``osd-par`` should be read as well, and the
overlay should be aspect-compensated. (Future directions: maybe mpv should
take care of some of these things automatically, but it's hard to tell
where to draw the line.)
``id`` is an integer between 0 and 63 identifying the overlay element. The
ID can be used to add multiple overlay parts, update a part by using this
command with an already existing ID, or to remove a part with
``overlay_remove``. Using a previously unused ID will add a new overlay,
while reusing an ID will update it. (Future directions: there should be
something to ensure different programs wanting to create overlays don't
conflict with each others, should that ever be needed.)
``x`` and ``y`` specify the position where the OSD should be displayed.
``file`` specifies the file the raw image data is read from. It can be
either a numeric UNIX file descriptor prefixed with ``@`` (e.g. ``@4``),
or a filename. The file will be mapped into memory with ``mmap()``. Some VOs
will pass the mapped pointer directly to display APIs (e.g. opengl or
vdpau), so no actual copying is involved. Truncating the source file while
the overlay is active will crash the player. You shouldn't change the data
while the overlay is active, because the data is essentially accessed at
random points. Instead, call ``overlay_add`` again (preferably with a
different memory region to prevent tearing).
``offset`` is the offset of the first pixel in the source file. It is
passed directly to ``mmap`` and is subject to certain restrictions
(see ``man mmap`` for details). In particular, this value has to be a
multiple of the system's page size.
``fmt`` is a string identifying the image format. Currently, only ``bgra``
is defined. This format has 4 bytes per pixels, with 8 bits per component.
The least significant 8 bits are blue, and the most significant 8 bits
are alpha (in little endian, the components are B-G-R-A, with B as first
byte). This uses premultiplied alpha: every color component is already
multiplied with the alpha component. This means the numeric value of each
component is equal to or smaller than the alpha component. (Violating this
rule will lead to different results with different VOs: numeric overflows
resulting from blending broken alpha values is considered something that
shouldn't happen, and consequently implementations don't ensure that you
get predictable behavior in this case.)
``w``, ``h``, and ``stride`` specify the size of the overlay. ``w`` is the
visible width of the overlay, while ``stride`` gives the width in bytes in
memory. In the simple case, and with the ``bgra`` format, ``stride==4*w``.
In general, the total amount of memory accessed is ``stride * h``.
(Technically, the minimum size would be ``stride * (h - 1) + w * 4``, but
for simplicity, the player will access all ``stride * h`` bytes.)
.. admonition:: Warning
When updating the overlay, you should prepare a second shared memory
region (e.g. make use of the offset parameter) and add this as overlay,
instead of reusing the same memory every time. Otherwise, you might
get the equivalent of tearing, when your application and mpv write/read
the buffer at the same time. Also, keep in mind that mpv might access
an overlay's memory at random times whenever it feels the need to do
so, for example when redrawing the screen.
``overlay_remove <id>``
Remove an overlay added with ``overlay_add`` and the same ID. Does nothing
if no overlay with this ID exists.
Undocumented commands: ``tv_start_scan``, ``tv_step_channel``, ``tv_step_norm``,
``tv_step_chanlist``, ``tv_set_channel``, ``tv_last_channel``, ``tv_set_freq``,
``tv_step_freq``, ``tv_set_norm``, ``dvb_set_channel`` (all of these
should be replaced by properties), ``stop`` (questionable use), ``get_property``
(?), ``vo_cmdline`` (experimental).
Input Command Prefixes
----------------------
These prefixes are placed between key name and the actual command. Multiple
prefixes can be specified. They are separated by whitespace.
``osd-auto`` (default)
Use the default behavior for this command.
``no-osd``
Do not use any OSD for this command.
``osd-bar``
If possible, show a bar with this command. Seek commands will show the
progress bar, property changing commands may show the newly set value.
``osd-msg``
If possible, show an OSD message with this command. Seek command show
the current playback time, property changing commands show the newly set
value as text.
``osd-msg-bar``
Combine osd-bar and osd-msg.
``raw``
Do not expand properties in string arguments. (Like ``"${property-name}"``.)
``expand-properties`` (default)
All string arguments are expanded as described in `Property Expansion`_.
All of the osd prefixes are still overridden by the global ``--osd-level``
settings.
Undocumented prefixes: ``pausing``, ``pausing_keep``, ``pausing_toggle``,
``pausing_keep_force``. (Should these be made official?)
Input Sections
--------------
Input sections group a set of bindings, and enable or disable them at once.
In ``input.conf``, each key binding is assigned to an input section, rather
than actually having explicit text sections.
Also see ``enable_section`` and ``disable_section`` commands.
Predefined bindings:
``default``
Bindings without input section are implicitly assigned to this section. It
is enabled by default during normal playback.
``encode``
Section which is active in encoding mode. It is enabled exclusively, so
that bindings in the ``default`` sections are ignored.
Properties
----------
Properties are used to set mpv options during runtime, or to query arbitrary
information. They can be manipulated with the ``set``/``add``/``cycle``
commands, and retrieved with ``show_text``, or anything else that uses property
expansion. (See `Property Expansion`_.)
The ``W`` column indicates whether the property is generally writable. If an
option is referenced, the property should take/return exactly the same values
as the option.
=============================== = ==================================================
Name W Comment
=============================== = ==================================================
``osd-level`` x see ``--osd-level``
``osd-scale`` x osd font size multiplicator, see ``--osd-scale``
``loop`` x see ``--loop``
``speed`` x see ``--speed``
``filename`` currently played file (path stripped)
``path`` currently played file (full path)
``media-title`` filename, title tag, or libquvi ``QUVIPROP_PAGETITLE``
``demuxer``
``stream-path`` filename (full path) of stream layer filename
``stream-pos`` x byte position in source stream
``stream-start`` start byte offset in source stream
``stream-end`` end position in bytes in source stream
``stream-length`` length in bytes (``${stream-end} - ${stream-start}``)
``stream-time-pos`` x time position in source stream (also see ``time-pos``)
``length`` length of the current file in seconds
``avsync`` last A/V synchronization difference
``percent-pos`` x position in current file (0-100)
``ratio-pos`` x position in current file (0.0-1.0)
``time-pos`` x position in current file in seconds
``time-remaining`` estimated remaining length of the file in seconds
``playtime-remaining`` ``time-remaining`` scaled by the the current ``speed``
``chapter`` x current chapter number
``edition`` x current MKV edition number
``titles`` number of DVD titles
``chapters`` number of chapters
``editions`` number of MKV editions
``angle`` x current DVD angle
``metadata`` metadata key/value pairs
``metadata/<key>`` value of metadata entry ``<key>``
``chapter-metadata`` metadata of current chapter (works similar)
``pause`` x pause status (bool)
``cache`` network cache fill state (0-100)
``pts-association-mode`` x see ``--pts-association-mode``
``hr-seek`` x see ``--hr-seek``
``volume`` x current volume (0-100)
``mute`` x current mute status (bool)
``audio-delay`` x see ``--audio-delay``
``audio-format`` audio format (string)
``audio-codec`` audio codec selected for decoding
``audio-bitrate`` audio bitrate
``samplerate`` audio samplerate
``channels`` number of audio channels
``aid`` x current audio track (similar to ``--aid``)
``audio`` x alias for ``aid``
``balance`` x audio channel balance
``fullscreen`` x see ``--fullscreen``
``deinterlace`` x similar to ``--deinterlace``
``colormatrix`` x see ``--colormatrix``
``colormatrix-input-range`` x see ``--colormatrix-input-range``
``colormatrix-output-range`` x see ``--colormatrix-output-range``
``ontop`` x see ``--ontop``
``border`` x see ``--border``
``framedrop`` x see ``--framedrop``
``gamma`` x see ``--gamma``
``brightness`` x see ``--brightness``
``contrast`` x see ``--contrast``
``saturation`` x see ``--saturation``
``hue`` x see ``--hue``
``panscan`` x see ``--panscan``
``video-format`` video format (string)
``video-codec`` video codec selected for decoding
``video-bitrate`` video bitrate
``width`` video width (container or decoded size)
``height`` video height
``fps`` container FPS (may contain bogus values)
``dwidth`` video width (after filters and aspect scaling)
``dheight`` video height
``window-scale`` x window size multiplier (1 means video size)
``aspect`` x video aspect
``osd-width`` last known OSD width (can be 0)
``osd-height`` last known OSD height (can be 0)
``osd-par`` last known OSD display pixel aspect (can be 0)
``vid`` x current video track (similar to ``--vid``)
``video`` x alias for ``vid``
``video-align-x`` x see ``--video-align-x``
``video-align-y`` x see ``--video-align-y``
``video-pan-x`` x see ``--video-pan-x``
``video-pan-y`` x see ``--video-pan-y``
``video-zoom`` x see ``--video-zoom``
``video-unscaled`` x see ``--video-unscaled``
``program`` x switch TS program (write-only)
``sid`` x current subtitle track (similar to ``--sid``)
``secondary-sid`` x secondary subtitle track (``--secondary-sid``)
``sub`` x alias for ``sid``
``sub-delay`` x see ``--sub-delay``
``sub-pos`` x see ``--sub-pos``
``sub-visibility`` x see ``--sub-visibility``
``sub-forced-only`` x see ``--sub-forced-only``
``sub-scale`` x subtitle font size multiplicator
``ass-use-margins`` x see ``--ass-use-margins``
``ass-vsfilter-aspect-compat`` x see ``--ass-vsfilter-aspect-compat``
``ass-style-override`` x see ``--ass-style-override``
``stream-capture`` x a filename, see ``--capture``
``tv-brightness`` x
``tv-contrast`` x
``tv-saturation`` x
``tv-hue`` x
``playlist-pos`` current position on playlist
``playlist-count`` number of total playlist entries
``playlist`` playlist, current entry marked
``track-list`` list of audio/video/sub tracks, current entry marked
``chapter-list`` list of chapters, current entry marked
``quvi-format`` x see ``--quvi-format``
``af`` x see ``--af``
``vf`` x see ``--vf``
``options/name`` read-only access to value of option ``--name``
=============================== = ==================================================
Property Expansion
------------------
All string arguments to input commands as well as certain options (like
``--playing-msg``) are subject to property expansion.
.. admonition:: Example for input.conf
``i show_text "Filename: ${filename}"``
shows the filename of the current file when pressing the ``i`` key
Within ``input.conf``, property expansion can be inhibited by putting the
``raw`` prefix in front of commands.
The following expansions are supported:
``${NAME}``
Expands to the value of the property ``NAME``. If retrieving the property
fails, expand to an error string. (Use ``${NAME:}`` with a trailing
``:`` to expand to an empty string instead.)
If ``NAME`` is prefixed with ``=``, expand to the raw value of the property
(see section below).
``${NAME:STR}``
Expands to the value of the property ``NAME``, or ``STR`` if the
property cannot be retrieved. ``STR`` is expanded recursively.
``${?NAME:STR}``
Expands to ``STR`` (recursively) if the property ``NAME`` is available.
``${!NAME:STR}``
Expands to ``STR`` (recursively) if the property ``NAME`` cannot be
retrieved.
``${?NAME==VALUE:STR}``
Expands to ``STR`` (recursively) if the property ``NAME`` expands to a
string equal to ``VALUE``. You can prefix ``NAME`` with ``=`` in order to
compare the raw value of a property (see section below). If the property
is unavailable, or other errors happen when retrieving it, the value is
never considered equal.
Note that ``VALUE`` can't contain any of the characters ``:`` or ``}``.
Also, it is possible that escaping with ``"`` or ``%`` might be added in
the future, should the need arise.
``${!NAME==VALUE:STR}``
Same as with the ``?`` variant, but ``STR`` is expanded if the value is
not equal. (Using the same semantics as with ``?``.)
``$$``
Expands to ``$``.
``$}``
Expands to ``}``. (To produce this character inside recursive
expansion.)
``$>``
Disable property expansion and special handling of ``$`` for the rest
of the string.
In places where property expansion is allowed, C-style escapes are often
accepted as well. Example:
- ``\n`` becomes a newline character
- ``\\`` expands to ``\``
Raw and Formatted Properties
----------------------------
Normally, properties are formatted as human-readable text, meant to be
displayed on OSD or on the terminal. It is possible to retrieve an unformatted
(raw) value from a property by prefixing its name with ``=``. These raw values
can be parsed by other programs and follow the same conventions as the options
associated with the properties.
.. admonition:: Examples
- ``${time-pos}`` expands to ``00:14:23`` (if playback position is at 14
minutes 23 seconds)
- ``${=time-pos}`` expands to ``863.4`` (same time, plus 400 milliseconds -
milliseconds are normally not shown in the formatted case)
Sometimes, the difference in amount of information carried by raw and formatted
property values can be rather big. In some cases, raw values have more
information, like higher precision than seconds with ``time-pos``. Sometimes
it is the other way around, e.g. ``aid`` shows track title and language in the
formatted case, but only the track number if it is raw.
+18
View File
@@ -0,0 +1,18 @@
LUA SCRIPTING
=============
mpv can load Lua scripts. These scripts can be used to control mpv in a similar
way to slave mode. mpv provides the builtin module ``mp`` (can be loaded
with ``require '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.
.. admonition:: Warning
Lua scripting is work in progress, and it's in a very early stage. When
writing scripts, rely only on the features and functions documented here.
Everything else is subject to change.
.. admonition:: Warning
Nothing is finished and documented yet.
+90 -238
View File
@@ -2,23 +2,44 @@ mpv
###
##############
a media player
a movie player
##############
:Author: wm4
:Copyright: GPLv2+
:Manual section: 1
:Manual group: multimedia
.. raw:: latex
\tableofcontents
\pagebreak
SYNOPSIS
========
| **mpv** [options] [file|URL|PLAYLIST|-]
| **mpv** [options] [file|URL|-]
| **mpv** [options] --playlist=PLAYLIST
| **mpv** [options] files
| **mpv** [options] {group of files and options}
| **mpv** [bd]://[title][/device] [options]
| **mpv** dvd://[title|[start\_title]-end\_title][/device] [options]
| **mpv** dvdnav://[longest|menu|title][/device] [options]
| **mpv** \vcd://[/device]
| **mpv** \tv://[channel][/input_id] [options]
| **mpv** radio://[channel|frequency][/capture] [options]
| **mpv** \pvr:// [options]
| **mpv** \dvb://[card\_number@]channel [options]
| **mpv** \mf://[filemask|\@listfile] [-mf options] [options]
| **mpv** cdda://track[-endtrack][:speed][/device] [options]
| **mpv** [file|mms[t]|http|httpproxy|rt[s]p|ftp|udp|smb]://[user:pass\@]URL[:port] [options]
| **mpv** edl://[edl specification as in edl-mpv.rst]
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
@@ -39,16 +60,15 @@ 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 work always; see ``sub_seek`` command.
PGUP and PGDWN
Seek forward/backward 10 minutes.
[ and ]
Decrease/increase current playback speed by 10%.
@@ -63,32 +83,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.
@@ -98,22 +127,19 @@ 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
o
Toggle OSD states: none / seek / seek + timer / seek + timer + total time.
d
@@ -126,15 +152,12 @@ 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.
Ctrl + and Ctrl -
Adjust audio delay by +/- 0.1 seconds.
V
Toggle subtitle VSFilter aspect compatibility mode. See
``--ass-vsfilter-aspect-compat`` for more info.
@@ -152,18 +175,23 @@ S
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 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``).)
@@ -179,24 +207,22 @@ corresponding adjustment, or the software equalizer (``--vf=eq``).)
7 and 8
Adjust saturation.
(The following keys are valid only on OS X.)
(The following keys are valid only on OSX.)
command + 0
Resize video window to half its original size.
(On other platforms, you can bind keys to change the ``window-scale``
property.)
Resize movie window to half its original size.
command + 1
Resize video window to its original size.
Resize movie window to its original size.
command + 2
Resize video window to double its original size.
Resize movie window to double its original size.
command + f
Toggle fullscreen (see also ``--fs``).
command + [ and command + ]
Set video window alpha.
Set movie window alpha.
(The following keys are valid if you have a keyboard with multimedia keys.)
@@ -215,6 +241,12 @@ support.)
h and k
Select previous/next channel.
n
Change norm.
u
Change channel list.
Mouse Control
-------------
@@ -271,7 +303,7 @@ need to escape special characters. To work this around, the path can be
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.)
@@ -324,7 +356,7 @@ Location and Syntax
You can put all of the options in configuration files which will be read every
time mpv is run. The system-wide configuration file 'mpv.conf' is in your
configuration directory (e.g. ``/etc/mpv`` or ``/usr/local/etc/mpv``), the
user-specific one is ``~/.config/mpv/mpv.conf``.
user-specific one is ``~/.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
@@ -359,13 +391,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.
@@ -420,135 +452,6 @@ 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.)
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 (or ``00:00:00`` 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.
- 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. Also can 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 should almost never
happen, unless decoder-framedropping is enabled with one of the
``--framedrop`` options, the stream contains errors, or a weird codec is in
use. (``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 ``cached-used`` properties.)
PROTOCOLS
=========
``http://...``, ``https://``, ...
Many network protocols are supported, but the protocol prefix must always
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.
``smb://PATH``
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 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. 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.
``dvdread://...:``
Play a DVD using the old libdvdread code. This is what MPlayer and older
mpv versions use for ``dvd://``. Use is discouraged. It's provided only
for compatibility and for transition.
``tv://[channel][/input_id]`` ``--tv-...``
Analogue TV via V4L. Also useful for webcams. (Linux only.)
``pvr://`` ``--pvr-...``
PVR. (Linux only.)
``dvb://[cardnumber@]channel`` ``--dvbin-...``
Digital TV via DVB. (Linux only.)
``mf://[filemask|@listfile]`` ``--mf-...``
Play a series of images as video.
``cdda://track[-endtrack][:speed][/device]`` ``--cdrom-device=PATH`` ``--cdda-...``
Play CD.
``lavf://...``
Access any FFmpeg/Libav libavformat protocol. Basically, this passed the
string after the ``//`` directly to libavformat.
``av://type:options``
This is intended for using libavdevice inputs. ``type`` is the libavdevice
demuxer name, and ``options`` is the (pseudo-)filename passed to the
demuxer.
For example, ``mpv av://lavfi:mandelbrot`` makes use of the libavfilter
wrapper included in libavdevice, and will use the ``mandelbrot`` source
filter to generate input data.
``avdevice://`` is an alias.
``file://PATH``
A local path as URL. Might be useful in some special use-cases. Note that
``PATH`` itself should start with a third ``/`` to make the path an
absolute path.
``edl://[edl specification as in edl-mpv.rst]``
Stitch together parts of multiple files and play them.
``null://``
Simulate an empty file.
``memory://data``
Use the ``data`` part as source data.
.. include:: options.rst
.. include:: ao.rst
@@ -567,8 +470,6 @@ PROTOCOLS
.. include:: lua.rst
.. include:: ipc.rst
.. include:: changes.rst
ENVIRONMENT VARIABLES
@@ -577,28 +478,23 @@ 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/.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.
``HOME``
Used to determine mpv config directory: ``$HOME/.mpv``
``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``)
``MPV_LOCALEDIR``
Directory where mpv looks for gettext translation files (if enabled).
``MPV_VERBOSE`` (see also ``-v`` and ``--msglevel``)
Set the initial verbosity level across all message modules (default: 0).
This is an integer, and the resulting verbosity corresponds to the number
of ``--v`` options passed to the command line.
The resulting verbosity corresponds to that of ``--msglevel=5`` plus the
value of ``MPV_VERBOSE``.
``MPV_LEAK_REPORT``
If set to ``1``, enable internal talloc leak reporting. Note that this can
@@ -706,56 +602,12 @@ FILES
``/usr/local/etc/mpv/mpv.conf``
mpv system-wide settings (depends on ``--prefix`` passed to configure)
``~/.config/mpv/mpv.conf``
``~/.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/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.
Note that the environment variables ``$XDG_CONFIG_HOME`` and ``$MPV_HOME`` can
override the standard directory ``~/.config/mpv/``.
Also, the old config location at ``~/.mpv/`` is still read, and if the XDG
variant does not exist, will still be preferred.
FILES ON WINDOWS
================
On win32 (if compiled with MinGW, but not Cygwin), the default config file
locations are different:
``%APPDATA%/mpv/mpv.conf``
Preferred mpv config file. This maps to a system and user-specific path,
for example ``C:\users\USERNAME\Application Data\mpv\mpv.conf``. You can
find the exact path by running ``echo %APPDATA%\mpv\mpv.conf`` in cmd.exe.
``%APPDATA%/mpv/input.conf``
key bindings (see `INPUT.CONF`_ section)
``%APPDATA%/mpv/lua/``
equivalent of ``~/.config/mpv/lua/`` on Unix.
The environment variable ``$MPV_HOME`` completely overrides these, like on
UNIX.
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.
A third config directory with lowest priority is the directory named ``mpv``
in the same directory as ``mpv.exe``. This used to be the directory with
highest priority, but is now discouraged to use and might be removed in the
future.
Note that mpv likes to mix ``/`` and ``\`` path separators for simplicity.
kernel32.dll accepts this, but cmd.exe does not.
EXAMPLES OF MPV USAGE
=====================
@@ -773,8 +625,8 @@ Play only chapters 5, 6, 7:
Play only titles 5, 6, 7:
``mpv dvd://5-7``
Play a multi-angle DVD:
``mpv dvd://1 --dvd-angle=2``
Play a multiangle DVD:
``mpv dvd://1 --dvdangle=2``
Play from a different DVD device:
``mpv dvd://1 --dvd-device=/dev/dvd2``
File diff suppressed because it is too large. Load diff
+7 -61
View File
@@ -122,24 +122,12 @@ time remaining
left-click toggle between total and remaining time
============= ================================================
Key Bindings
~~~~~~~~~~~~
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 `Script Commands`_ section.
============= ================================================
del Hide the OSC permanently until mpv is restarted.
============= ================================================
Configuration
-------------
The OSC offers limited configuration through a config file
``lua-settings/osc.conf`` placed in mpv's user dir and through the
``--lua-opts`` command-line option. Options provided through the command-line
will override those from the config file.
The OSC offers limited configuration through a config file ``plugin_osc.conf``
placed in mpv's user dir.
Config Syntax
~~~~~~~~~~~~~
@@ -147,25 +135,14 @@ Config Syntax
The config file must exactly follow the following syntax::
# this is a comment
optionA=value1
optionB=value2
parameter1=value1
parameter2=value2
``#`` can only be used at the beginning of a line and there may be no
spaces around the ``=`` or anywhere else.
Command-line Syntax
~~~~~~~~~~~~~~~~~~~
To avoid collisions with other scripts, all options need to be prefixed with
``osc-``.
Example::
--lua-opts=osc-optionA=value1,osc-optionB=value2
Configurable Options
~~~~~~~~~~~~~~~~~~~~
Configurable parameters
~~~~~~~~~~~~~~~~~~~~~~~
``showwindowed``
| Default: yes
@@ -216,41 +193,10 @@ Configurable Options
| 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.
it will hide immediately if the mouse enters it.
``minmousemove``
| Default: 3
| Minimum amount of pixels the mouse has to move between ticks to make
the OSC show up
``seektooltip``
| Default: yes
| Display a tooltip over the seekbar indicating time at mouse position.
``seekbarstyle``
| Default: slider
| Sets the style of the seekbar, slider (diamond marker) or bar (fill)
Script Commands
~~~~~~~~~~~~~~~
The OSC script listens to certain script commands. These commands can bound
in ``input.conf``, or sent by other scripts.
``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.
Example
You could put this into ``input.conf`` to hide the OSC with the ``a`` key and
to unhide it with ``b``::
a script_message disable-osc
b script_message enable-osc
+48 -188
View File
@@ -47,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.
@@ -55,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>``
@@ -88,14 +88,19 @@ Available filters are:
``mirror``
Mirrors the image on the Y axis.
``rotate[=0|90|180|270]``
Rotates the image by a multiple of 90 degrees clock-wise.
``rotate[=<0-7>]``
Rotates the image by 90 degrees and optionally flips it. For values
between 4-7 rotation is only done if the movie geometry is portrait and
not landscape.
``scale[=w:h:param:param2:chr-drop:noup:arnd``
:0: Rotate by 90 degrees clockwise and flip (default).
:1: Rotate by 90 degrees clockwise.
:2: Rotate by 90 degrees counterclockwise.
:3: Rotate by 90 degrees counterclockwise and flip.
``scale[=w:h[:interlaced[:chr_drop[:par[:par2[:noup[:arnd]]]]]]]``
Scales the image with the software scaler (slow) and performs a YUV<->RGB
color space conversion (see also ``--sws``).
All parameters are optional.
colorspace conversion (see also ``--sws``).
``<w>,<h>``
scaled width/height (default: original width/height)
@@ -109,7 +114,15 @@ Available filters are:
:-(n+8): Like -n above, but rounding the dimension to the closest
multiple of 16.
``<param>[:<param2>]`` (see also ``--sws``)
``<chr_drop>``
chroma skipping
:0: Use all available input lines for chroma.
:1: Use only every 2. input line for chroma.
:2: Use only every 4. input line for chroma.
:3: Use only every 8. input line for chroma.
``<par>[:<par2>]`` (see also ``--sws``)
Set some scaling parameters depending on the type of scaler selected
with ``--sws``::
@@ -120,17 +133,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)
``<chr-drop>``
chroma skipping
:0: Use all available input lines for chroma (default).
:1: Use only every 2. input line for chroma.
:2: Use only every 4. input line for chroma.
:3: Use only every 8. input line for chroma.
--sws=9 (lanczos): filter length (1-10)
``<noup>``
Disallow upscaling past the original dimensions.
@@ -222,8 +227,8 @@ Available filters are:
====================== =====================
``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``.
@@ -231,23 +236,12 @@ Available filters are:
``<fmt>``
Format name, e.g. rgb15, bgr24, 420p, etc. (default: 420p).
``pp=[filter string]``
Enables the specified chain of post-processing subfilters. Subfilters must
``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.
.. note::
Unlike in MPlayer or in earlier versions, you must quote the pp string
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
.. admonition:: Warning
This filter is most likely useless on modern HD video. It might be
helpful with old low-resolution files.
All subfilters share common options to determine their scope:
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.
@@ -262,6 +256,11 @@ Available filters are:
``--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]]``
@@ -342,7 +341,7 @@ Available filters are:
filtering every second line with a (-1 4 2 4 -1) filter.
``l5/lowpass5``
Vertically applied FIR low-pass deinterlacing filter that deinterlaces
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]``
@@ -362,7 +361,7 @@ Available filters are:
.. note::
This filter is only available if FFmpeg/Libav has been compiled
This filter is only available if FFmpeg/libav has been compiled
with libpostproc enabled.
.. admonition:: Examples
@@ -449,7 +448,7 @@ Available filters are:
temporal noise (noise pattern changes between frames)
``uniform``
uniform noise (Gaussian otherwise)
uniform noise (gaussian otherwise)
``hq``
high quality (slightly better looking, slightly slower) - not available
@@ -509,7 +508,7 @@ Available filters are:
:1: linear interpolation (default)
``unsharp[=lx:ly:la:cx:cy:ca]``
unsharp mask / Gaussian blur
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.
@@ -623,7 +622,7 @@ Available filters are:
``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 videos that have been captured with the
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``
@@ -713,6 +712,11 @@ Available filters are:
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.
``file=<file>``
You can specify a text file to load the coordinates from. Each line
must have a timestamp (in seconds, and in ascending order) and the
``x:y:w:h:t`` coordinates (``t`` can be omitted).
(Not supported when using libavfilter.)
``show``
Draw a rectangle showing the area defined by x/y/w/h.
@@ -775,8 +779,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
@@ -809,7 +813,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>``
@@ -846,95 +850,6 @@ Available filters are:
``a3=<string>``
Specify the fourth parameter to pass to the library.
``vapoursynth=file:buffered-frames:concurrent-frames``
Loads a VapourSynth filter script. This is intended for streamed
processing: mpv actually provides a source filter, instead of using a
native VapourSynth video source. The mpv source will answer frame
requests only within a small window of frames (the size of this window
is controlled with the ``buffered-frames`` parameter), and requests outside
of that will return errors. As such, you can't use the full power of
VapourSynth, but you can use certain filters.
If you just want to play video generated by a VapourSynth (i.e. using
a native VapourSynth video source), it's better to use ``vspipe`` and a
FIFO to feed the video to mpv. The same applies if the filter script
requires random frame access (see ``buffered-frames`` parameter).
This filter is experimental. If it turns out that it works well and is
used, it will be ported to libavfilter. Otherwise, it will be just removed.
``file``
Filename of the script source. Currently, this is always a python
script. The variable ``video_in`` is set to the mpv video source,
and it is expected that the script reads video from it. (Otherwise,
mpv will decode no video, and the video packet queue will overflow,
eventually leading to audio being stopped.) The script is also
expected to pass through timestamps using the ``_DurationNum`` and
``_DurationDen`` frame properties.
.. admonition:: Example:
::
import vapoursynth as vs
core = vs.get_core()
core.std.AddBorders(video_in, 10, 10, 20, 20).set_output()
.. warning::
The script will be reloaded on every seek. This is done to reset
the filter properly on discontinuities.
``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 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
multiplied to get the final buffer size.
(Normally, VapourSynth source filters must provide random access, but
mpv was made for playback, and does not provide frame-exact random
access. The way this video filter works is a compromise to make simple
filters work anyway.)
``concurrent-frames``
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.
``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 conveniencve 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
@@ -951,58 +866,3 @@ Available filters are:
bob
bob deinterlacing (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
``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
decoding was activated at least once (i.e. vdpau was loaded).
``sharpen=<-1-1>``
For positive values, apply a sharpening algorithm to the video, for
negative values a blurring algorithm (default: 0).
``denoise=<0-1>``
Apply a noise reduction algorithm to the video (default: 0; no noise
reduction).
``deint=<yes|no>``
Whether deinterlacing is enabled (default: no). If enabled, it will use
the mode selected with ``deint-mode``.
``deint-mode=<first-field|bob|temporal|temporal-spatial>``
Select deinterlacing mode (default: temporal).
All modes respect ``--field-dominance``.
Note that there's currently a mechanism that allows the ``vdpau`` VO to
change the ``deint-mode`` of auto-inserted ``vdpaupp`` filters. To avoid
confusion, it's recommended not to use the ``--vo=vdpau`` suboptions
related to filtering.
first-field
Show only first field.
bob
Bob deinterlacing.
temporal
Motion-adaptive temporal deinterlacing. May lead to A/V desync
with slow video hardware and/or high resolution.
temporal-spatial
Motion-adaptive temporal deinterlacing with edge-guided spatial
interpolation. Needs fast video hardware.
``chroma-deint``
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.
``pullup``
Try to apply inverse telecine, needs motion adaptive temporal
deinterlacing.
``hqscaling=<0-9>``
0
Use default VDPAU scaling (default).
1-9
Apply high quality VDPAU scaling (needs capable hardware).
``buffer=<num>``
Buffer ``<num>`` frames in the filter chain. This filter is probably pretty
useless, except for debugging. (Note that this won't help smoothing out
latencies with decoding, because the filter will never output a frame if
the buffer isn't full, except on EOF.)
+65 -194
View File
@@ -20,9 +20,6 @@ normal driver parameters.
See ``--vo=help`` for a list of compiled-in video output drivers.
The recommended output drivers are ``--vo=vdpau`` and ``--vo=opengl-hq``.
All other drivers are just for compatibility or special purposes.
.. admonition:: Example
``--vo=opengl,xv,``
@@ -35,39 +32,37 @@ Available video output drivers are:
the most compatible VO on X, but may be low-quality, and has issues with
OSD and subtitle display.
.. note:: This driver is for compatibility with old systems.
``adaptor=<number>``
Select a specific XVideo adapter (check xvinfo results).
Select a specific XVideo adaptor (check xvinfo results).
``port=<number>``
Select a specific XVideo port.
``ck=<cur|use|set>``
Select the source from which the color key is taken (default: cur).
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.
``ck-method=<man|bg|auto>``
Sets the color key drawing method (default: man).
Sets the colorkey drawing method (default: man).
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.
``colorkey=<number>``
Changes the color key to an RGB value of your choice. ``0x000000`` is
Changes the colorkey to an RGB value of your choice. ``0x000000`` is
black and ``0xffffff`` is white.
``no-colorkey``
Disables color-keying.
Disables colorkeying.
``x11`` (X11 only)
Shared memory video output driver without hardware acceleration that works
@@ -79,36 +74,21 @@ Available video output drivers are:
Uses the VDPAU interface to display and optionally also decode video.
Hardware decoding is used with ``--hwdec=vdpau``.
.. note::
Earlier versions of mpv (and MPlayer, mplayer2) provided sub-options
to tune vdpau post-processing, like ``deint``, ``sharpen``, ``denoise``,
``chroma-deint``, ``pullup``, ``hqscaling``. These sub-options are
deprecated, and you should use the ``vdpaupp`` video filter instead.
``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).
``denoise=<0-1>``
(Deprecated. See note about ``vdpaupp``.)
Apply a noise reduction algorithm to the video (default: 0; no noise
reduction).
``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``),
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.
Select deinterlacing mode (default: -3). Positive values choose mode
and enable deinterlacing. Corresponding negative values select the
same deinterlacing mode, but do not enable deinterlacing on startup
(useful in configuration files to specify which mode will be enabled by
the "D" key). All modes respect ``--field-dominance``.
0
Pick the ``vdpaupp`` video filter default, which corresponds to 3.
Same as -3.
1
Show only first field.
2
@@ -120,19 +100,13 @@ Available video output drivers are:
Motion-adaptive temporal deinterlacing with edge-guided spatial
interpolation. Needs fast video hardware.
``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.
``pullup``
(Deprecated. See note about ``vdpaupp``.)
Try to apply inverse telecine, needs motion adaptive temporal
deinterlacing.
``hqscaling=<0-9>``
(Deprecated. See note about ``vdpaupp``.)
0
Use default VDPAU scaling (default).
1-9
@@ -173,7 +147,7 @@ Available video output drivers are:
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
@@ -198,9 +172,6 @@ Available video output drivers are:
``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.
``prefer-stretchrect``
Use ``IDirect3DDevice9::StretchRect`` over other methods if possible.
@@ -233,29 +204,18 @@ Available video output drivers are:
Always force textures to power of 2, even if the device reports
non-power-of-2 texture sizes as supported.
``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.
``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.
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
``swap-discard``
Use ``D3DSWAPEFFECT_DISCARD``, which might be faster.
@@ -268,7 +228,10 @@ Available video output drivers are:
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``).
``opengl``
OpenGL video output driver. It supports extended scaling methods, dithering
@@ -286,7 +249,7 @@ Available video output drivers are:
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.
``lscale=<filter>``
@@ -297,16 +260,11 @@ Available video output drivers are:
``lanczos2``
Lanczos scaling with radius=2. Provides good quality and speed.
This is the default when using ``opengl-hq``.
``lanczos3``
Lanczos with radius=3.
``lanczos``
Generic Lanczos scaling filter. Set radius with ``lradius``.
``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.
@@ -323,14 +281,6 @@ Available video output drivers are:
Mitchell-Netravali. The ``b`` and ``c`` parameters can be set with
``lparam1`` and ``lparam2``. Both are set to 1/3 by default.
``gaussian``
Gaussian filter with a parameter ``p`` for sharpness control.
``p`` can be set to float number between 1(blurry) and 100(sharp)
and has a default value of about 28.8 (see ``lparam1``).
Note that for extremely small value of ``p``, a large filter radius
might be required to avoid unintended artifacts (see ``lradius``).
There are some more filters. For a complete list, pass ``help`` as
value, e.g.::
@@ -344,16 +294,6 @@ Available video output drivers are:
``lparam2=<value>``
See ``lparam1``.
``lradius=<r>``
Set radius for filters listed below, must be a float number between 1.0
and 8.0. Defaults to be 2.0 if not specified.
``sinc``, ``lanczos``, ``blackman``, ``gaussian``
Note that depending on filter implementation details and video scaling
ratio, the radius that actually being used might be different
(most likely being increased a bit).
``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
@@ -363,9 +303,8 @@ Available video output drivers are:
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.
Select a method for stereo display. You may have to use ``--aspect`` to
fix the aspect value. Experimental, do not expect too much from it.
no
Normal 2D display
@@ -374,24 +313,22 @@ Available video output drivers are:
green-magenta
Convert side by side input to full-color green-magenta stereo.
quadbuffer
Convert side by side input to quad buffered stereo. Only supported
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``.
Enable gamma-correct scaling by working in linear light. This
makes use of sRGB textures and framebuffers.
This option 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::
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.
for YUV colorspaces, gamma 1/0.45 (2.222) is assumed. RGB input is
always assumed to be in sRGB.
This option is not really useful, as gamma-correct scaling has not much
influence on typical video playback. Most visible effect comes from
slightly different gamma.
``pbo``
Enable use of PBOs. This is slightly faster, but can sometimes lead to
@@ -449,22 +386,12 @@ Available video output drivers are:
this options will make rendering a single operation.
Note that chroma scalers are always done as 1-pass filters.
``cscale=<filter>``
``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.
``lscale-down=<filter>``, ``cscale-down=<filter>``
Like ``lscale`` and ``cscale``, but apply these filters on downscaling
instead. If these options are unset, the filter implied by ``lscale``
(and ``cscale``, respectively) will be applied.
``cparam1``, ``cparam2``, ``cradius``
Set filter parameters and radius for ``cscale``.
See ``lparam1``, ``lparam2`` and ``lradius``.
``fancy-downscaling``
When using convolution based filters, extend the filter size
when downscaling. Trades quality for reduced downscaling performance.
@@ -474,16 +401,7 @@ Available video output drivers are:
Borders will be distorted due to filtering.
``glfinish``
Call ``glFinish()`` before and after swapping buffers (default: disabled).
Slower, but might help getting better results when doing framedropping.
The details depend entirely on the OpenGL driver.
``waitvsync``
Call ``glXWaitVideoSyncSGI`` after each buffer swap (default: disabled).
This may or may not help with video timing accuracy and frame drop. It's
possible that this makes video output slower, or has no effect at all.
X11 only.
Call ``glFinish()`` before swapping buffers
``sw``
Continue even if a software renderer is detected.
@@ -496,7 +414,7 @@ Available video output drivers are:
auto
auto-select (default)
cocoa
Cocoa/OS X
Cocoa/OSX
win
Win32/WGL
x11
@@ -521,61 +439,33 @@ Available video output drivers are:
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 key bindings 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.)
``gamma``
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 LittleCMS 2 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.
Needs LittleCMS2 support compiled in.
``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 LittleCMS 2 can take a while
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 color spaces.
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)
relative colorimetric
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 videos and shows to see if things look better that way.
This only affects the output when using either ``icc-profile`` or ``srgb``.
absolute colorimetric (default)
``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.
Sizes must be a power of two, and 256 at most.
``alpha=<blend|yes|no>``
Decides what to do if the input has an alpha component (default: blend).
@@ -606,7 +496,7 @@ Available video output drivers are:
This is equivalent to::
--vo=opengl:lscale=spline36:dither-depth=auto:fbo-format=rgba16
--vo=opengl:lscale=lanczos2: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.
@@ -615,7 +505,7 @@ Available video output drivers are:
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 OS X setups being very slow with ``rgb16``
float texture support, and some OSX setups being very slow with ``rgb16``
but fast with ``rgb32f``.
``opengl-old``
@@ -629,8 +519,6 @@ Available video output drivers are:
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
@@ -739,9 +627,8 @@ Available video output drivers are:
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.
Select a method for stereo display. You may have to use ``--aspect`` to
fix the aspect value. Experimental, do not expect too much from it.
0
Normal 2D display
@@ -750,7 +637,7 @@ Available video output drivers are:
2
Convert side by side input to full-color green-magenta stereo.
3
Convert side by side input to quad buffered stereo. Only supported
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.
@@ -792,7 +679,7 @@ Available video output drivers are:
auto
auto-select (default)
cocoa
Cocoa/OS X
Cocoa/OSX
win
Win32/WGL
x11
@@ -805,9 +692,6 @@ Available video output drivers are:
hardware acceleration. Should work on all platforms supported by SDL 2.0.
For tuning, refer to your copy of the file ``SDL_hints.h``.
.. note:: This driver is for compatibility with systems that don't provide
proper graphics drivers, or which support GLES only.
``sw``
Continue even if a software renderer is detected.
@@ -820,9 +704,6 @@ Available video output drivers are:
hardware decoding to save power on laptops, or possibly preventing video
tearing with some setups.
.. note:: This driver is for compatibility with crappy systems. You can
use vaapi hardware decoding with ``--vo=opengl`` too.
``scaling=<algorithm>``
default
Driver default (mpv default as well).
@@ -863,8 +744,6 @@ Available video output drivers are:
``caca``
Color ASCII art video output driver that works on a text console.
.. note:: This driver is a joke.
``image``
Output each frame into an image file in the current directory. Each file
takes the frame number padded with leading zeros as name.
@@ -910,17 +789,9 @@ Available video output drivers are:
``wayland`` (Wayland only)
Wayland shared memory video output as fallback for ``opengl``.
.. note:: This driver is for compatibility with systems that don't provide
working OpenGL drivers.
``default-format``
Use the default RGB32 format instead of an auto-detected one.
``alpha``
Use a buffer format that supports videos and images with alpha
information
``rgb565``
Use RGB565 as buffer format. This format is implemented on most
platforms, especially on embedded where it is far more efficient then
RGB8888.
``triple-buffering``
Use 3 buffers instead of 2. This can lead to more fluid playback, but
uses more memory.
-1609
View File
File diff suppressed because it is too large. Load diff
-183
View File
@@ -1,183 +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 using the option
``--input-unix-socket``. Clients can connect to this socket and send commands to
the player or receive events from it. You can use the ``socat`` tool to send
commands (and receive reply) from the shell.
.. 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.
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.
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, line starting
with ``#`` and empty lines are ignored.
Currently, embedded 0 bytes terminate the current line, but you should not
rely on this.
Commands
--------
Additionally 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 observe 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.
``suspend``
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``
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. (Also see ``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.
-759
View File
@@ -1,759 +0,0 @@
LUA SCRIPTING
=============
mpv can load Lua scripts. Scripts passed to the ``--lua`` option, or found in
the ``lua`` subdirectory of the mpv configuration directory (usually
``~/.config/mpv/lua/``) will be loaded on program start. mpv also appends the
``lua`` 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 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.
Example
-------
A script which leaves fullscreen mode when the player is paused:
::
function on_pause()
mp.set_property("fullscreen", "no")
end
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.
Mode of operation
-----------------
Your script will be loaded by the player at program start from the ``lua``
configuration subdirectory, from a path specified with the ``--lua`` option, 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
script got into an endless loop, mpv will probably behave fine during playback
(unless the player is suspended, see ``mp.suspend``), but it won't terminate
when quitting, because it's waiting on your script.
Internally, the C code will call the Lua function ``mp_event_loop`` after
loading a Lua script. This function is normally defined by the default prelude
loaded before your script (see ``player/lua/defaults.lua`` in the mpv sources).
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
------------
The ``mp`` module is preloaded, although it can be loaded manually with
``require 'mp'``. It provides the core client API.
``mp.command(string)``
Run the given command. This is similar to the commands used in input.conf.
See `List of Input Commands`_.
Returns ``true`` on success, or ``nil, error`` on error.
``mp.commandv(arg1, arg2, ...)``
Similar to ``mp.command``, but pass each command argument as separate
parameter. This has the advantage that you don't have to care about
quoting and escaping in some cases.
Example:
::
mp.command("loadfile " .. filename .. " append")
mp.commandv("loadfile", filename, "append")
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.
``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
properties. The returned string is formatted similar to ``${=name}``
(see `Property Expansion`_).
Returns the string on success, or ``def, error`` on error. ``def`` is the
second parameter provided to the function, and is nil if it's missing.
``mp.get_property_osd(name [,def])``
Similar to ``mp.get_property``, but return the property value formatted for
OSD. This is the same string as printed with ``${name}`` when used in
input.conf.
Returns the string on success, or ``def, error`` on error. ``def`` is the
second parameter provided to the function, and is an empty string if it's
missing. Unlike ``get_property()``, assigning the return value to a variable
will always result in a string.
``mp.get_property_bool(name [,def])``
Similar to ``mp.get_property``, but return the property value as Boolean.
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.
Note that while Lua does not distinguish between integers and floats,
mpv internals do. This function simply request a double float from mpv,
and mpv will usually convert integer property values to float.
Returns a number on success, or ``def, error`` on error.
``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,
or number. Some properties (for example ``chapter-list``) are returned as
tables.
Returns a value on success, or ``def, error`` on error. Note that ``nil``
might be a possible, valid value too in some corner cases.
``mp.set_property(name, value)``
Set the given property to the given string value. See ``mp.get_property``
and `Properties`_ for more information about properties.
Returns true on success, or ``nil, error`` on error.
``mp.set_property_bool(name, value)``
Similar to ``mp.set_property``, but set the given property to the given
Boolean value.
``mp.set_property_number(name, value)``
Similar to ``mp.set_property``, but set the given property to the given
numeric value.
Note that while Lua does not distinguish between integers and floats,
mpv internals do. This function will test whether the number can be
represented as integer, and if so, it will pass an integer value to mpv,
otherwise a double float.
``mp.set_property_native(name, value)``
Similar to ``mp.set_property``, but set the given property using its native
type.
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
properties for which it makes sense to use this, instead of
``set_property``, ``set_property_bool``, ``set_property_number``.
For these reasons, this function should probably be avoided for now, except
for properties that use tables natively.
``mp.get_time()``
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]])``
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``).
After calling this function, key presses will cause the function ``fn`` to
be called (unless the user remapped 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``
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``.
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
user defined bindings in the central input.conf are preferred over bindings
added with this function (but see ``mp.add_forced_key_binding``).
Example:
::
function something_handler()
print("the key was pressed")
end
mp.add_key_binding("x", "something", something_handler)
This will print the message ``the key was pressed`` when ``x`` was pressed.
The user can remap these key bindings. Then the user has to put the
following into his input.conf to remap the command to the ``y`` key:
::
y script_binding something
This will print the message when the key ``y`` is pressed. (``x`` will
still work, unless the user remaps 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
``mp.add_forced_key_binding(...)``
This works almost the same as ``mp.add_key_binding``, but registers the
key binding in a way that will overwrite the user's custom bindings in his
input.conf. (``mp.add_key_binding`` overwrites default key bindings only,
but not those by the user's input.conf.)
``mp.remove_key_binding(name)``
Remove a key binding added with ``mp.add_key_binding`` or
``mp.add_forced_key_binding``. Use the same name as you used when adding
the bindings. It's not possible to remove bindings for which you omitted
the name.
``mp.register_event(name, fn)``
Call a specific function when an event happens. The event name is a string,
and the function fn is a Lua function value.
Some events have associated data. This is put into a Lua table and passed
as argument to fn. The Lua table by default contains a ``name`` field,
which is a string containing the event name. If the event has an error
associated, the ``error`` field is set to a string describing the error,
on success it's not set.
If multiple functions are registered for the same event, they are run in
registration order, which the first registered function running before all
the other ones.
Returns true if such an event exists, false otherwise.
See `Events`_ and `List of events`_ for details.
``mp.unregister_event(fn)``
Undo ``mp.register_event(..., fn)``. This removes all event handlers that
are equal to the ``fn`` parameter. This uses normal Lua ``==`` comparison,
so be careful when dealing with closures.
``mp.observe_property(name, type, fn)``
Watch a property for changes. If the property ``name`` is changed, then
the function ``fn(name)`` will be called. ``type`` can be ``nil``, or be
set to one of ``none``, ``native``, ``bool``, ``string``, or ``number``.
``none`` is the same as ``nil``. For all other values, the new value of
the property will be passed as second argument to ``fn``, using
``mp.get_property_<type>`` to retrieve it. This means if ``type`` is for
example ``string``, ``fn`` is roughly called as in
``fn(name, mp.get_property_string(name))``.
If possible, change events are coalesced. If a property is changed a bunch
of times in a row, only the last change triggers the change function. (The
exact behavior depends on timing and other things.)
In some cases the function is not called even if the property changes.
Whether this can happen depends on the property.
If the ``type`` is ``none`` or ``nil``, sporadic property change events are
possible. This means the change function ``fn`` can be called even if the
property doesn't actually change.
``mp.unobserve_property(fn)``
Undo ``mp.observe_property(..., fn)``. This removes all property handlers
that are equal to the ``fn`` parameter. This uses normal Lua ``==``
comparison, so be careful when dealing with closures.
``mp.add_timeout(seconds, fn)``
Call the given function fn when the given number of seconds has elapsed.
Note that the number of seconds can be fractional. For now, the timer's
resolution may be as low as 50 ms, although this will be improved in the
future.
This is a one-shot timer: it will be removed when it's fired.
Returns a timer object. See ``mp.add_periodic_timer`` for details.
``mp.add_periodic_timer(seconds, fn)``
Call the given function periodically. This is like ``mp.add_timeout``, but
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
``resume()`` essentially unpauses the timer.
``kill()``
Disable the timer. Resets the elapsed time. ``resume()`` will
restart the timer.
``resume()``
Restart the timer. If the timer was disabled with ``stop()``, this
will resume at the time it was stopped. If the timer was disabled
with ``kill()``, or if it's a previously fired one-shot timer (added
with ``add_timeout()``), this starts the timer from the beginning,
using the initially configured timeout.
``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).
``mp.get_opt(key)``
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 script which would have the same name, it's made unique
by appending a number.
.. admonition:: Example
The script ``/path/to/fooscript.lua`` becomes ``fooscript``.
``mp.osd_message(text [,duration])``
Show an OSD message on the screen. ``duration`` is in seconds, and is
optional (uses ``--osd-duration`` by default).
Advanced mp functions
---------------------
These also live in the ``mp`` module, but are documented separately as they
are useful only in special situations.
``mp.suspend()``
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.
This is automatically called by the event handler.
``mp.resume()``
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 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.)
``mp.get_next_timeout()``
Return the relative time in seconds when the next timer (``mp.add_timeout``
and similar) expires. If there is no timer, return ``nil``.
``mp.dispatch_events([allow_wait])``
This can be used to run custom event loops. If you want to have direct
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.
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
this is the default behavior), it returns as soon as the event loop is
emptied. It's strongly recommended to use ``mp.get_next_timeout()`` and
``mp.get_wakeup_pipe()`` if you're interested in properly working
notification of new events and working timers.
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
messages are normally printed to the terminal. By calling this function,
you can set the minimum log level of messages which should be received with
the ``log-message`` event. See the description of this event for details.
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
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.
Used by ``mp.add_key_binding``, so be careful about name collisions.
``mp.unregister_script_message(name)``
Undo a previous registration with ``mp.register_script_message``. Does
nothing if the ``name`` wasn't registered.
mp.msg functions
----------------
This module allows outputting messages to the terminal, and can be loaded
with ``require 'mp.msg'``.
``msg.log(level, ...)``
The level parameter is the message priority. It's a string and one of
``fatal``, ``error``, ``warn``, ``info``, ``v``, ``debug``. The user's
settings will determine which of these messages will be visible. Normally,
all messages are visible, except ``v`` and ``debug``.
The parameters after that are all converted to strings. Spaces are inserted
to separate multiple parameters.
You don't need to add newlines.
``msg.fatal(...)``, ``msg.error(...)``, ``msg.warn(...)``, ``msg.info(...)``, ``msg.verbose(...)``, ``msg.debug(...)``
All of these are shortcuts and equivalent to the corresponding
``msg.log(level, ...)`` call.
mp.options functions
--------------------
mpv comes with a built-in module to manage options from config-files and the
command-line. All you have to do is to supply a table with default options to
the read_options function. The function will overwrite the default values
with values found in the config-file and the command-line (in that order).
``options.read_options(table [, identifier])``
A ``table`` with key-value pairs. The type of the default values is
important for converting the values read from the config file or
command-line back. Do not use ``nil`` as a default value!
The ``identifier`` is used to identify the config-file and the command-line
options. These needs to unique to avoid collisions with other scripts.
Defaults to ``mp.get_script_name()``.
Example implementation::
require 'mp.options'
local options = {
optionA = "defaultvalueA",
optionB = -0.5,
optionC = true,
}
options.read_options(options, "myscript")
print(option.optionA)
The config file will be stored in ``lua-settings/identifier.conf`` in mpv's user
folder. Comment lines can be started with # and stray spaces are not removed.
Boolean values will be represented with yes/no.
Example config::
# comment
optionA=Hello World
optionB=9999
optionC=no
Command-line options are read from the ``--lua-opts`` parameter. To avoid
collisions, all keys have to be prefixed with ``identifier-``.
Example command-line::
--lua-opts=myscript-optionA=TEST:myscript-optionB=0:myscript-optionC=yes
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).
The list is unsorted (in whatever order the operating system returns it).
If the ``filter`` argument is given, it must be one of the following
strings:
``files``
List regular files only. This excludes directories, special files
(like UNIX device files or FIFOs), and dead symlinks. It includes
UNIX symlinks to regular files.
``dirs``
List directories only, or symlinks to directories. ``.`` and ``..``
are not included.
``normal``
Include the results of both ``files`` and ``dirs``. (This is the
default.)
``all``
List all entries, even device files, dead symlinks, FIFOs, and the
``.`` and ``..`` entries.
On error, ``nil, error`` is returned.
``utils.split_path(path)``
Split a path into directory component and filename component, and return
them. The first return value is always the directory. The second return
value is the trailing part of the path, the directory entry.
``utils.join_path(p1, p2)``
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 paramater ``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``.
In all cases, ``mp.resume_all()`` is implicitly called.
``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.)
Events
------
Events are notifications from player core to scripts. You can register an
event handler with ``mp.register_event``.
Note that all scripts (and other parts of the player) receive events equally,
and there's no such thing as blocking other scripts from receiving events.
Example:
::
function my_fn(event)
print("start of playback!")
end
mp.register_event("playback-start", my_fn)
List of events
--------------
``start-file``
Happens right before a new file is loaded. When you receive this, the
player is loading the file (or possibly already done with it).
``end-file``
Happens after a file was unloaded. Typically, the player will load the
next file right away, or quit if this was the last file.
``file-loaded``
Happens after a file was loaded and begins playback.
``seek``
Happens on seeking (including ordered chapter segment changes).
``playback-restart``
Start of playback after seek or after file was loaded.
``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.
``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
to avoid wasting CPU when the player is paused.
``shutdown``
Sent when the player quits, and the script should terminate. Normally
handled automatically. See `Mode of operation`_.
``log-message``
Receives messages enabled with ``mp.enable_messages``. The message data
is contained in the table passed as first parameter to the event handler.
The table contains, in addition to the default event fields, the following
fields:
``prefix``
The module prefix, identifies the sender of the message. This is what
the terminal player puts in front of the message text when using the
``--v`` option, and is also what is used for ``--msg-level``.
``level``
The log level as string. See ``msg.log`` for possible log level names.
Note that later versions of mpv might add new levels or remove
(undocumented) existing ones.
``text``
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
any time.
``get-property-reply``
Undocumented (not useful for Lua scripts).
``set-property-reply``
Undocumented (not useful for Lua scripts).
``command-reply``
Undocumented (not useful for Lua scripts).
``script-input-dispatch``
Undocumented (used internally).
``client-message``
Undocumented (used internally).
``video-reconfig``
Happens on video output or filter reconfig.
``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.
Extras
------
This documents experimental features, or features that are "too special" and
we don't guarantee a stable interface to it.
``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.
Currently existing hooks:
``on_load``
Called when a file is to be opened, before anything is actually done.
For example, you could read and write the ``stream-open-filename``
property to redirect an URL to something else (consider support for
streaming sites which rarely give the user a direct media URL), or
you could set per-file options with by setting the property
``file-local-options/<option name>``. The player will wait until all
hooks are run.
-71
View File
@@ -1,71 +0,0 @@
Release Policy
==============
Every few months, a new release is cut off of the master branch and is assigned
a 0.X.0 version number.
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 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
-----------------
- 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 ``VERSION`` file.
- Update ``DOCS/client-api-changes.rst`` (on major releases).
- 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.
Release notes template
----------------------
Here is a template that can be used for writing the ``RELEASE_NOTES`` file.
```markdown
Release 0.X.Y
=============
Changes
-------
- List of changes.
Bug fixes
---------
- List of bug fixes.
New features
------------
- 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
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 -47
View File
@@ -1,4 +1,6 @@
This file intends to give a big picture overview of how mpv is structured.
NOTE: DOCS/OUTDATED-tech/* may contain more detailed information, but most of it
is possibly or definitely outdated. 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 +19,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 +33,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".
@@ -95,7 +84,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,
@@ -105,10 +94,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
@@ -116,7 +104,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.
@@ -124,18 +112,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 comming 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
@@ -194,7 +183,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.
@@ -216,12 +205,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.
@@ -229,19 +215,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 -subcp.)
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 -1
View File
@@ -45,7 +45,7 @@ mpv's custom configure step on top of waf
To some extents mpv has a custom build system written on top of waf. This
document will not go over the standard waf behaviour as that is documented in
the `Waf book <http://docs.waf.googlecode.com/git/book_17/single.html>`_.
the ``Waf book``.
All of the configuration process is handled with a declarative approach. Lists
of dictionaries define the checks, and some custom Python code traverses these
+14 -47
View File
@@ -3,8 +3,6 @@ mpv
[![Build Status](https://api.travis-ci.org/mpv-player/mpv.png)](https://travis-ci.org/mpv-player/mpv)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/1232/badge.svg)](https://scan.coverity.com/projects/1232)
Overview
--------
@@ -47,23 +45,13 @@ Essential dependencies (incomplete list):
- gcc or clang
- X development headers (xlib, X extensions, libvdpau, libGL, libXv, ...)
- 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)
- Lua (strictly speaking optional, but required for the OSC pseudo-GUI)
Libass dependencies:
- gcc or clang, yasm on x86 and x86_64
- fribidi, freetype, fontconfig development headers (for libass)
FFmpeg dependencies:
- gcc or clang, yasm on x86 and x86_64
- OpenSSL (has to be explicitly enabled when compiling ffmpeg)
- libass
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libpostproc)
- libjpeg
- libquvi if you want to play Youtube videos directly
- libx264/libmp3lame/libfdk-aac if you want to use encoding (has to be
explicitly enabled when compiling ffmpeg)
- Libav also works, but some features will not work. (See section below.)
Most of the above libraries are available in suitable versions on normal
Linux distributions. However FFmpeg is an exception (distro versions may be
@@ -83,26 +71,6 @@ 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. See the [wiki article][ffmpeg_vs_libav] about the issue.
Release cycle
-------------
Every few months, a new release is cut off of the master branch and is assigned
a 0.X.0 version number.
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 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
-----------
@@ -116,26 +84,25 @@ 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.
Contact
-------
Contacts
--------
Most activity happens on the IRC channel and the github issue tracker. The
mailing lists are mostly unused.
These forms of contact are meant to ask questions about mpv usage, give
feedback on mpv and discuss it's development.
- **Github issue tracker**: [issue tracker][issue-tracker] (report bugs here)
- **User IRC Channel**: `#mpv-player` on `irc.freenode.net`
- **Developer IRC Channel**: `#mpv-player-dev` on `irc.freenode.net`
If possible, please avoid posting bugs here and use the [issue tracker][issue-tracker]
instead.
- **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])
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`. Use
only if discretion is required.
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`.
[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/changes.rst
[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/en/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
+31 -57
View File
@@ -1,67 +1,41 @@
Release 0.7.0
=============
Changes
-------
- Buffer partial log messages in the client API (the client API will now only
pass full log messages to clients).
- Remove ncurses/terminfo/termcap support (it was disabled by default and
replaced by new code since v0.6.0).
- Enable cdda:// support by default again (it was disabled since v0.6.0).
- Cascade-load input.conf (if there are several input.confs in the set of valid
config paths, load them all).
- Draw the OSD twice in 3D mode (this fixes subtitles display in 3D mode).
- Make wasapi the default AO on Windows again since many of its problems have
been solved.
- Use "site-functions" subdir to install the zsh completion script instead of
the Debian-specific "vendor-completions" (also provide the --zshdir waf
configure option for changing this value).
- Improve synchronization between the Cocoa GUI and the player (this fixes some
long standing deadlock issues on Mac OS X).
- Remove --fs-missioncontrol option (only relevant to Mac OS X).
- Build system switches to waf. The old build system is still available by
running ``./old-configure``, but it will be removed some time in the future.
- The "run" input command changes in a not backwards compatible way.
- Some input.conf commands were replaced (such as speed_mult).
- Many audio/video filter have changed sub-options in a not backwards
compatible way. (This is a consequence of unifying audio/video filter
option parsing.)
- Most video filters now use libavfilter internally if available.
- Disable key autorepeat for some key binds, which prevents accidentally
triggering a binding multiple times.
- Encoding: install and include encoding profiles by default.
Bug fixes
---------
- Fix a bug that degraded vdpau playback after ~1 hour of runtime.
- Restrict hardware decoding to codecs where it generally makes sense. This
excludes mpeg4 for example, which often causes hardware decoders to decode to
garbage. Use ``--hwdec-codecs`` to enable hardware decoding for more codecs.
New features
------------
- Enable pitch correction by default when playing at higher speeds (this can be
controlled with the --audio-pitch-correction option).
- Open stream and demuxer asynchronously (this should avoid having the player
get blocked on network streams).
- Add cache-buffering-state property for querying the cache fill status until
the player unpauses.
- Add support for listing and selecting the audio device (note that it is not
implemented for all AOs, see the --audio-device option for more information).
- Add support for a JSON-based IPC mechanism (note that this is not currently
supported on Windows, see the JSON IPC section in the manpage for more
information).
- Add Lua utility function for starting processes (see utils.subprocess() in the
manpage).
- Add Lua utility function for parsing JSON (see utils.parse_json() in the
manpage).
- Add field-dominance property (see --field-dominance option).
- Add video-rotate property (see --video-rotate option).
- Add playback-abort property for querying whether playback is stopped or is to
be stopped.
- Add cursor-autohide property (see --cursor-autohide option).
- Add vo-configured property for querying whether a window is created.
- Add support for dxva2 hardware acceleration on Windows.
- Drop libquvi support (this has been replaced by a built-in Lua script that
invokes the youtube-dl tool, which needs to be installed, see the --ytdl
option).
- Add support for loading chapters from an external file (see the
--chapters-file option).
- Add window-minimized property for querying whether the window is minimized
(works for X11 only).
- Make it possible to configure the OSC seekbar style (see the "seekbarstyle"
OSC option).
- Add support for libmpv on Mac OS X (it used to be broken, now it's fully
functional and also provides support for embedding the mpv window inside a
Cocoa/Qt application).
- Try to use the audio channel map reported by ALSA in the alsa AO.
- Add option to disable text OSD rendering completely (useful for working around
certain fontconfig issues, see the --use-text-osd option).
- Add window-scale property, which allows changing the window size via mpv key
bindings.
- Add revert_seek command, which is meant to undo accidental seeks.
- Hardware decoding (vdpau, vda, vaapi) can now be used with vo_opengl.
- Pulseaudio: set pulse stream name to mpv window title (like MPlayer).
- Support showing 2 subtitles at a time (``--secondary-sid``).
- Re-add some basic ``dvdnav://`` support. This doesn't handle navigation
highlights correctly, but navigation should mostly work. (Note that
``dvdnav://`` by default starts the longest title, instead of the DVD menu.
The menu is available with ``dvdnav://menu``.)
- Win32: you can drop files on the mpv window.
This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log 7759c18..9479daa`` in
complete change log can be viewed by running ``git log f572d2..f06a87`` in
the git repository.
-93
View File
@@ -1,93 +0,0 @@
#!/usr/bin/env python
import re
import os
import sys
import shutil
import subprocess
from functools import partial
sys_re = re.compile("^/System")
usr_re = re.compile("^/usr/lib/")
exe_re = re.compile("@executable_path")
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(objfile) in libname
def otool(objfile):
command = "otool -L %s | grep -e '\t' | awk '{ print $1 }'" % objfile
output = subprocess.check_output(command, shell = True)
return filter(partial(is_user_lib, objfile), output.split())
def install_name_tool_change(old, new, objfile):
subprocess.call(["install_name_tool", "-change", old, new, objfile])
def install_name_tool_id(name, objfile):
subprocess.call(["install_name_tool", "-id", name, objfile])
def libraries(objfile, result = dict()):
libs_list = otool(objfile)
result[objfile] = set(libs_list)
for lib in libs_list:
if lib not in result:
libraries(lib, result)
return result
def leafs(libs_dict, processed = []):
result = []
processed = set(processed)
for objfile, libs in libs_dict.items():
if libs <= processed:
result.append(objfile)
return result
def lib_path(binary):
return os.path.join(os.path.dirname(binary), 'lib')
def lib_name(lib):
return os.path.join("@executable_path", "lib", os.path.basename(lib))
def process_libraries(libs_dict, binary, processed = []):
ls = leafs(libs_dict, processed)
diff = set(ls) - set(processed)
if diff == set([binary]):
return
for src in diff:
name = lib_name(src)
dst = os.path.join(lib_path(binary), os.path.basename(src))
shutil.copy(src, dst)
os.chmod(dst, 0o755)
install_name_tool_id(name, dst)
if src in libs_dict[binary]:
install_name_tool_change(src, name, binary)
for p in processed:
if p in libs_dict[src]:
install_name_tool_change(p, lib_name(p), dst)
process_libraries(libs_dict, binary, ls)
def main():
binary = os.path.abspath(sys.argv[1])
if not os.path.exists(lib_path(binary)):
os.makedirs(lib_path(binary))
libs = libraries(binary)
print(libs)
process_libraries(libs, binary)
if __name__ == "__main__":
main()
+2 -2
View File
@@ -5,8 +5,8 @@
conv() {
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" ;
-158
View File
@@ -1,158 +0,0 @@
#!/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:=}"
# This script uses ffmpeg's "idet" filter for interlace detection. In the
# long run this should replace ildetect.sh+ildetect.so.
# exit status:
# 0 progressive
# 1 telecine
# 2 interlaced
# 8 unknown
# 16 detect fail
# 17+ mpv's status | 16
testfun()
{
$ILDETECT_MPV "$@" \
--vf-add=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: "
}
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 "$@")
EOF
interlaced=$((bff + tff))
determined=$((interlaced + progressive))
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"
else
verdict="interlaced"
fi
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"
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"
fi
else
# Likely progressive
verdict="progressive"
fi
printf '%s\n' "$verdict"
}
judge "$@" --vf-clr
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
[ -n "$ILDETECT_RUN_INTERLACED_ONLY" ] || \
$ILDETECT_MPV "$@"
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 0
;;
interlaced-tff)
judge "$@" --vf-clr --vf-pre=pullup --field-dominance=top
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 2
;;
esac
;;
interlaced-bff)
judge "$@" --vf-clr --vf-pre=pullup --field-dominance=bottom
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 2
;;
esac
;;
interlaced)
judge "$@" --vf-clr --vf-pre=pullup
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 2
;;
esac
;;
*)
echo >&2 "ERROR: Internal error."
exit 16
;;
esac
-6
View File
@@ -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'),
}),
}),
}),
+17 -20
View File
@@ -132,8 +132,7 @@ sub _bin2int($) {
# creates a floating-point number with the given mantissa and exponent
sub _ldexp {
my ($mantissa, $exponent) = @_;
my $r = new Math::BigRat($mantissa);
return $r * Math::BigRat->new(2)**$exponent;
return $mantissa * Math::BigRat->new(2)**$exponent;
}
# NOTE: the read_* functions are hard to read because they're ports
@@ -253,27 +252,25 @@ bytes from the internal filehandle.
Only lengths C<4> and C<8> are supported (C C<float> and C<double>).
=cut
{
my $b1 = new Math::BigInt 1;
sub read_float {
my ($self, $length) = @_;
my $i = $self->read_uint($length);
my $f;
sub read_float {
my ($self, $length) = @_;
my $i = new Math::BigInt $self->read_uint($length)->bstr;
my $f;
use bigrat try => BIGINT_TRY;
# These evil expressions reinterpret an unsigned int as IEEE binary floats
if ($length == 4) {
$f = _ldexp(($i & ((1<<23) - 1)) + (1<<23), ($i>>23 & ((1<<8) - 1)) - 150);
$f = -$f if $i & ($b1<<31);
} elsif ($length == 8) {
$f = _ldexp(($i & (($b1<<52) - 1)) + ($b1<<52), ($i>>52 & ((1<<12) - 1)) - 1075);
$f = -$f if $i & ($b1<<63);
} else {
croak "Matroska Syntax error: unsupported IEEE float byte size $length";
}
return $f;
# These evil expressions reinterpret an unsigned int as IEEE binary floats
if ($length == 4) {
$f = _ldexp(($i & (1<<23 - 1)) + (1<<23), ($i>>23 & (1<<8 - 1)) - 150);
$f = -$f if $i & (1<<31);
} elsif ($length == 8) {
$f = _ldexp(($i & (1<<52 - 1)) + (1<<52), ($i>>52 & (1<<12 - 1)) - 1075);
$f = -$f if $i & (1<<63);
} else {
croak "Matroska Syntax error: unsupported IEEE float byte size $length";
}
return $f;
}
=method read_ebml_id($length)
-12
View File
@@ -1,12 +0,0 @@
mpv lua scripts
===============
The lua scripts in this folder can be loaded on a one-time basis by
adding the option
--lua=/path/to/script.lua
to mpv's command line.
Where appropriate, they may also be placed in ~/.config/mpv/lua from where
they will be automatically loaded when mpv starts.
-113
View File
@@ -1,113 +0,0 @@
-- This script uses the lavfi cropdetect filter to automatically
-- insert a crop filter with appropriate parameters for the currently
-- playing video.
--
-- It registers the key-binding "C" (shift+c), which when pressed,
-- inserts the filter vf=lavfi=cropdetect. After 1 second, it then
-- inserts the filter vf=crop=w:h:x:y, where w,h,x,y are determined
-- from the vf-metadata gathered by cropdetect. The cropdetect filter
-- is removed immediately after the crop filter is inserted as it is
-- no longer needed.
--
-- If the "C" key is pressed again, the crop filter is removed
-- restoring playback to its original state.
--
-- Since the crop parameters are determined from the 1 second of video
-- between inserting the cropdetect and crop filters, the "C" key
-- should be pressed at a position in the video where the crop region
-- is unambiguous (i.e., not a black frame, black background title
-- card, or dark scene).
--
-- The default delay between insertion of the cropdetect and
-- crop filters may be overridden by adding
--
-- --lua-opts=autocrop.detect_seconds=<number of seconds>
--
-- to mpv's arguments. This may be desirable to allow cropdetect more
-- time to collect data.
require "mp.msg"
script_name = mp.get_script_name()
cropdetect_label = string.format("%s-cropdetect", script_name)
crop_label = string.format("%s-crop", 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 = 1
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 autocrop_start()
-- exit if cropdetection is already in progress
if timer then
mp.msg.warn("already cropdetecting!")
return
end
-- if there's a crop filter, remove it and exit
if del_filter_if_present(crop_label) then
return
end
-- insert the cropdetect filter
ret=mp.command(
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)
end
function do_crop()
-- get the metadata
local cropdetect_metadata = mp.get_property_native(
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
mp.command(string.format("vf add @%s:crop=%s:%s:%s:%s",
crop_label,
cropdetect_metadata["lavfi.cropdetect.w"],
cropdetect_metadata["lavfi.cropdetect.h"],
cropdetect_metadata["lavfi.cropdetect.x"],
cropdetect_metadata["lavfi.cropdetect.y"]))
else
mp.msg.error(
"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?"
)
mp.msg.error(
"Does your version of ffmpeg/libav support AVFrame metadata?"
)
end
-- remove the cropdetect filter
del_filter_if_present(cropdetect_label)
timer=nil
end
mp.add_key_binding("C", "auto_crop", autocrop_start)
-164
View File
@@ -1,164 +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 filter vf=lavfi=idet. After 4 second, it examines the results
-- to determine whether the content progressive or interlaced and the
-- interlacing field dominance. It immediately sets the latter within
-- mpv.
--
-- If the content is judged not to be progressive, it may be either
-- interlaced or telecined. To determine which one, the video is
-- seeked back to the detection starting point with the "pullup"
-- filter inserted. After another four seconds, if idet thinks that
-- the pulled up viedo is "progressive", then pullup is the correct
-- filter and this script leaves it in places while removing the idet
-- filter. Otherwise, the content plain interlaced and mpv's deinterlace
-- property is set. This will usually insert the yadif deinterlacing filter.
--
-- The default detection time may be overridden by adding
--
-- --lua-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)
-- 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)
percent_pos = mp.get_property("percent-pos")
-- insert the detection filter
local cmd = string.format('vf add @%s:lavfi=graph="idet"', detect_label)
if not mp.command(cmd) then
mp.msg.error("failed to insert detection filter")
return
end
-- wait to gather data
timer = mp.add_timeout(detect_seconds, judge_field_dominance)
end
function stop_detect()
del_filter_if_present(detect_label)
timer = nil
mp.set_property("playback-pos", percent_pos)
end
progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3, 4
function judge()
-- get the metadata
local result = mp.get_property_native(string.format("vf-metadata/%s", detect_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("progressive = "..num_progressive)
mp.msg.verbose("interlaced-tff = "..num_tff)
mp.msg.verbose("interlaced-bff = "..num_bff)
mp.msg.verbose("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 judge_field_dominance()
verdict = judge()
if verdict == progressive then
stop_detect()
mp.msg.info("progressive: doing nothing")
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
local cmd = string.format("vf pre @%s:pullup", pullup_label)
if not mp.command(cmd) then
mp.msg.error("failed to insert pullup filter")
stop_detect()
return
end
-- redo the detection with the pullup filter to see if it's telecined
mp.set_property("percent-pos", percent_pos)
timer = mp.add_timeout(detect_seconds, judge_ivtc)
end
function judge_ivtc()
verdict = judge()
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
return
end
mp.add_key_binding("ctrl+d", script_name, start_detect)
-75
View File
@@ -1,75 +0,0 @@
-- This script automatically loads playlist entries before and after the
-- the currently played file. It does so by scanning the directory a file is
-- located in when starting playback. It sorts the directory entries
-- 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 5 * 2 files when starting a file (before + after).
MAXENTRIES = 5
mputils = require 'mp.utils'
function add_files_at(index, files)
index = index - 1
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 find_and_add_entries()
local path = mp.get_property("path", "")
local dir, filename = mputils.split_path(path)
if #dir == 0 then
return
end
local files = mputils.readdir(dir, "files")
table.sort(files)
if dir == "." then
dir = ""
end
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
local current
for i = 1, #files do
if files[i] == filename then
current = i
break
end
end
if current == nil then
return
end
local append = {[-1] = {}, [1] = {}}
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
for i = 1, MAXENTRIES do
local file = files[current + i * direction]
local pl_e = pl[pl_current + i * direction]
if file == nil or file[1] == "." then
break
end
local filepath = dir .. file
if pl_e then
-- If there's a playlist entry, and it's the same file, stop.
if pl_e.filename == filepath then
break
end
end
if direction == -1 then
if pl_current == 1 then -- never add additional entries in the middle
mp.msg.info("Prepending " .. file)
table.insert(append[-1], 1, filepath)
end
else
mp.msg.info("Adding " .. file)
table.insert(append[1], filepath)
end
end
end
add_files_at(pl_current + 1, append[1])
add_files_at(pl_current, append[-1])
end
mp.register_event("start-file", find_and_add_entries)
-56
View File
@@ -1,56 +0,0 @@
-- This script cycles between deinterlacing, pullup (inverse
-- telecine), and both filters off. It uses the "deinterlace" property
-- so that a hardware deinterlacer will be used if available.
--
-- It overrides the default deinterlace toggle keybinding "D"
-- (shift+d), so that rather than merely cycling the "deinterlace" property
-- between on and off, it adds a "pullup" step to the cycle.
--
-- It provides OSD feedback as to the actual state of the two filters
-- after each cycle step/keypress.
--
-- Note: if hardware decoding is enabled, pullup filter will likely
-- fail to insert.
--
-- TODO: It might make sense to use hardware assisted vdpaupp=pullup,
-- if available, but I don't have hardware to test it. Patch welcome.
script_name = mp.get_script_name()
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
end
return "no"
end
function do_cycle()
if pullup_on() == "yes" then
-- if pullup is on remove it
mp.command(string.format("vf del @%s:pullup", pullup_label))
return
elseif mp.get_property("deinterlace") == "yes" then
-- if deinterlace is on, turn it off and insert pullup filter
mp.set_property("deinterlace", "no")
mp.command(string.format("vf add @%s:pullup", pullup_label))
return
else
-- if neither is on, turn on deinterlace
mp.set_property("deinterlace", "yes")
return
end
end
function cycle_deinterlace_pullup_handler()
do_cycle()
-- independently determine current state and give user feedback
mp.osd_message(string.format("deinterlace: %s\n"..
"pullup: %s",
mp.get_property("deinterlace"),
pullup_on()))
end
mp.add_key_binding("D", "cycle-deinterlace-pullup", cycle_deinterlace_pullup_handler)
-99
View File
@@ -1,99 +0,0 @@
-- This script enables live control of the dynamic range compression
-- (drc) audio filter while the video is playing back. This can be
-- useful to avoid having to stop and restart mpv to adjust filter
-- 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
--
-- * off
-- * method=1 (single-sample smoothing)
-- * method=2 (multi-sample smoothing)
--
-- It registers the keybindings ctrl+9/ctrl+0 to decrease/increase the
-- target ampltiude. These keys will insert the filter at the default
-- target amplitude of 0.25 if it was not previously present.
--
-- OSD feedback of the current filter state is displayed on pressing
-- each bound key.
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"])
else
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
end
end
function append_drc(afs)
afs[#afs+1] = {
name = "drc",
label = script_name,
params = {
method = "1",
target = "0.25"
}
}
print_state(afs[#afs]["params"])
end
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)
else
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
)
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
)
end
function drc_louder_handler()
drc_scale_target(2.0)
end
function drc_quieter_handler()
drc_scale_target(0.5)
end
-- 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)
mp.add_key_binding("ctrl+0", "drc_louder", drc_louder_handler)
-16
View File
@@ -1,16 +0,0 @@
-- Test script for property change notification mechanism.
function format_property_val(v)
if type(v) == "table" then
return mp.format_table(v) -- undocumented function; might be removed
else
return tostring(v)
end
end
for i,name in ipairs(mp.get_property_native("property-list")) do
mp.observe_property(name, "native", function(name, val)
print("property '" .. name .. "' changed to '" ..
format_property_val(val) .. "'")
end)
end
-69
View File
@@ -1,69 +0,0 @@
-- Rebuild the terminal status line as a lua script
-- Be aware that this will require more cpu power!
-- Add a string to the status line
function atsl(s)
newStatus = newStatus .. s
end
function update_status_line()
-- Reset the status line
newStatus = ""
if mp.get_property_bool("pause") then
atsl("(Paused) ")
elseif mp.get_property_bool("paused-for-cache") then
atsl("(Buffering) ")
end
if mp.get_property("vid") ~= "no" then
atsl("A")
end
if mp.get_property("aid") ~= "no" then
atsl("V")
end
atsl(": ")
atsl(mp.get_property_osd("time-pos"))
atsl(" / ");
atsl(mp.get_property_osd("length"));
atsl(" (")
atsl(mp.get_property_osd("percent-pos", -1))
atsl("%)")
local r = mp.get_property_number("speed", -1)
if r ~= 1 then
atsl(string.format(" x%4.2f", r))
end
r = mp.get_property_number("avsync", nil)
if r ~= nil then
atsl(string.format(" A-V: %7.3f", r))
end
r = mp.get_property("total-avsync-change", 0)
if math.abs(r) > 0.05 then
atsl(string.format(" ct:%7.3f", r))
end
r = mp.get_property_number("drop-frame-count", -1)
if r > 0 then
atsl(" Late: ")
atsl(r)
end
r = mp.get_property_number("cache", 0)
if r > 0 then
atsl(string.format(" Cache: %d%% ", r))
end
-- Set the new status line
mp.set_property("options/term-status-msg", newStatus)
end
-- Register the event
mp.register_event("tick", update_status_line)
+150 -127
View File
@@ -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
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 --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
+66 -1
View File
@@ -1,13 +1,35 @@
#!/usr/bin/env python
import os
import re
import shutil
import sys
from optparse import OptionParser
from textwrap import dedent
def sh(command):
return os.popen(command).read()
def dylib_lst(input_file):
return sh("otool -L %s | grep -e '\t' | awk '{ print $1 }'" % input_file)
sys_re = re.compile("/System")
exe_re = re.compile("@executable_path")
binary_name = sys.argv[1]
def is_user_lib(libname, input_file):
return not sys_re.match(libname) and \
not exe_re.match(libname) and \
not "libobjc" in libname and \
not "libSystem" in libname and \
not "libgcc" in libname and \
not os.path.basename(input_file) in libname and \
not libname == ''
def user_dylib_lst(input_file):
return [lib for lib in dylib_lst(input_file).split("\n") if
is_user_lib(lib, input_file)]
def bundle_path(binary_name):
return "%s.app" % binary_name
@@ -34,9 +56,52 @@ def copy_bundle(binary_name):
def copy_binary(binary_name):
shutil.copy(binary_name, target_binary(binary_name))
def run_install_name_tool(target_file, dylib_path, dest_dir, root=True):
new_dylib_path = os.path.join("@executable_path", "lib",
os.path.basename(dylib_path))
sh("install_name_tool -change %s %s %s" % \
(dylib_path, new_dylib_path, target_file))
if root:
sh("install_name_tool -id %s %s" % \
(new_dylib_path, os.path.join(dest_dir,
os.path.basename(dylib_path))))
def cp_dylibs(target_file, dest_dir):
for dylib_path in user_dylib_lst(target_file):
dylib_dest_path = os.path.join(dest_dir, os.path.basename(dylib_path))
try:
shutil.copy(dylib_path, dylib_dest_path)
except IOError:
if re.match("dylib$", target_file):
reinstall_what = target_file
else:
reinstall_what = dylib_path
sys.exit(dedent("""\
%s uses library %s which is not available anymore.
This is most likely because you uninstalled %s.
Please reinstall %s to fix it's dependencies.""" % \
(target_file, dylib_path, dylib_path, reinstall_what) ))
os.chmod(dylib_dest_path, 0o755)
cp_dylibs(dylib_dest_path, dest_dir)
def fix_dylibs_paths(target_file, dest_dir, root=True):
for dylib_path in user_dylib_lst(target_file):
dylib_dest_path = os.path.join(dest_dir, os.path.basename(dylib_path))
run_install_name_tool(target_file, dylib_path, dest_dir, root)
fix_dylibs_paths(dylib_dest_path, dest_dir, False)
def apply_plist_template(plist_file, version):
sh("sed -i -e 's/${VERSION}/%s/g' %s" % (version, plist_file))
def bundle_dependencies(binary_name):
lib_bundle_directory = os.path.join(target_directory(binary_name), "lib")
cp_dylibs(binary_name, lib_bundle_directory)
fix_dylibs_paths(target_binary(binary_name), lib_bundle_directory)
def main():
version = sh("./version.sh --print").strip()
@@ -63,7 +128,7 @@ def main():
if options.deps:
print("> bundling dependencies")
sh(" ".join(["TOOLS/dylib-unhell.py", target_binary(binary_name)]))
bundle_dependencies(binary_name)
print("done.")
+1 -588
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
@@ -230,592 +230,5 @@
</array>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>AC3 Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ac3</string>
<key>UTTypeReferenceURL</key>
<string>http://wiki.multimedia.cx/index.php?title=AC3</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ac3</string>
<string>a52</string>
<string>eac3</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>DTS Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.dts</string>
<key>UTTypeReferenceURL</key>
<string>http://wiki.multimedia.cx/index.php?title=DTS</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>dts</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>Free Lossless Audio Codec</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.flac</string>
<key>UTTypeReferenceURL</key>
<string>http://flac.sourceforge.net/format.html</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>flac</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>Matroska Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.mka</string>
<key>UTTypeReferenceURL</key>
<string>http://www.matroska.org</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mka</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>Ogg Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ogg-audio</string>
<key>UTTypeReferenceURL</key>
<string>http://xiph.org/ogg</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ogg</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>PCM Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.pcm</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/Pulse-code_modulation</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>pcm</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>Windows Media Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.wma</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/Windows_Media_Audio</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>wma</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Audio Video Interleave</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.avi</string>
<key>UTTypeReferenceURL</key>
<string>http://www.the-labs.com/Video/odmlff2-avidef.pdf</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>avi</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>DIVX Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.divx</string>
<key>UTTypeReferenceURL</key>
<string>http://www.divx.com</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>divx</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>DV Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.dv</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/DV</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>dv</string>
<string>hdv</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Flash Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.flv</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/Flash_Video</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>flv</string>
<string>f4v</string>
<string>f4p</string>
<string>swf</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>MPEG-2 Transport Stream</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.mts</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/.m2ts</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>trp</string>
<string>m2t</string>
<string>m2ts</string>
<string>mts</string>
<string>mtv</string>
<string>ts</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Matroska Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.mkv</string>
<key>UTTypeReferenceURL</key>
<string>http://www.matroska.org</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mkv</string>
<string>webm</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Ogg Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ogv</string>
<key>UTTypeReferenceURL</key>
<string>http://xiph.org/ogg</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ogm</string>
<string>ogv</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Real Media</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.rmvb</string>
<key>UTTypeReferenceURL</key>
<string>http://www.real.com</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>rmvb</string>
<string>rm</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Video Object</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.vob</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/VOB</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>vob</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Windows Media Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.wmv</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/Windows_Media_Video</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>wmv</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>XVID Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.xvid</string>
<key>UTTypeReferenceURL</key>
<string>http://www.xvid.org</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>xvid</string>
</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>
<string>public.plain-text</string>
</array>
<key>UTTypeDescription</key>
<string>SubRip Subtitle</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.subrip</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/SubRip</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>srt</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.plain-text</string>
</array>
<key>UTTypeDescription</key>
<string>MicroDVD Subtitle</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.sub</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/MicroDVD</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>sub</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.plain-text</string>
</array>
<key>UTTypeDescription</key>
<string>SubStation Alpha Subtitle</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ass</string>
<key>UTTypeReferenceURL</key>
<string>https://github.com/libass/libass</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ass</string>
<string>ssa</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>VobSub Subtitle</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.vobsub</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/DirectVobSub</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>idx</string>
<string>sub</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.plain-text</string>
</array>
<key>UTTypeDescription</key>
<string>SAMI Subtitle</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.smi</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/SAMI</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>smi</string>
<string>smil</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
-109
View File
@@ -1,109 +0,0 @@
#!/usr/bin/env python3
import matplotlib.pyplot as plot
import sys
filename = sys.argv[1]
"""
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:
<timestamp in microseconds> <text> '#' <comment>
e.g.:
10474959 start flip #cplayer
<text> is what MP_STATS(log, "...") writes. The rest is added by msg.c.
Currently, the following event types are supported:
'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
<name> singular event
"""
class G:
events = {}
sevents = [] # events, deterministically sorted
start = None
# http://matplotlib.org/api/markers_api.html#module-matplotlib.markers
markers = ["o", "8", "s", "p", "*", "h", "+", "x", "D"]
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):
if event not in G.events:
e = Event()
G.events[event] = e
e.name = event
e.vals = []
e.type = evtype
e.marker = "o"
e.numid = len(G.events)
G.sevents = list(G.events.values())
G.sevents.sort(key=lambda x: x.name)
if e.type == "event-signal":
e.marker = find_marker()
return G.events[event]
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) / 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.vals.append((ts, 0))
e.vals.append((ts, 1))
elif event.startswith("end "):
e = get_event(event[4:], "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.vals.append((ts, val))
elif event.startswith("event-timed "):
_, val, name = event.split(" ", 2)
val = int(val) / 1000 - G.start
e = get_event(name, "event-signal")
e.vals.append((val, 1))
else:
e = get_event(event, "event-signal")
e.vals.append((ts, 1))
for e in G.sevents:
e.vals = [(x, y * e.numid / len(G.events)) for (x, y) in e.vals]
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 = e.marker, linestyle = "None")
legend.append(pl)
plot.subplot(2, 1, 1)
plot.legend(legend, [pl.get_label() for pl in legend])
plot.show()
+35 -41
View File
@@ -3,31 +3,32 @@
"""
This script emulates "unique application" functionality on Linux. When starting
playback with this script, it will try to reuse an already running instance of
mpv (but only if that was started with umpv). Other mpv instances (not started
by umpv) are ignored, and the script doesn't know about them.
mpv (but only if that was started with umpv).
This only takes filenames as arguments. Custom options can't be used; the script
interprets them as filenames. If mpv is already running, the files passed to
umpv are appended to mpv's internal playlist. If a file does not exist or is
otherwise not playable, mpv will skip the playlist entry when attempting to
play it (from the GUI perspective, it's silently ignored).
This script only uses mpv instances started with umpv. Other instances are
ignored, and don't exist for the script.
This only takes filenames as arguments. If mpv is already running, they are
appended to mpv's internal playlist. If the file does not exist or is otherwise
not playable, mpv will skip the playlist entry when attempting to play it (from
the GUI perspective, it's silently ignored).
If mpv isn't running yet, this script will start mpv and let it control the
current terminal. It will not write output to stdout/stderr, because this
will typically just fill ~/.xsession-errors with garbage.
current terminal. If you play an audio-only file, mpv will not open a window
(that is its normal behavior; but it might not be what a user expects if this
script is used in a GUI setting).
mpv will terminate if there are no more files to play, and running the umpv
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.
Warning:
The script attempts to make sure the FIFO is safely created (i.e. not world-
readable, not trying to open a bogus
"""
import sys
@@ -36,28 +37,15 @@ import errno
import subprocess
import fcntl
import stat
import string
if len(sys.argv) < 2:
print("error: needs at least one file as argument.")
sys.exit(1)
files = sys.argv[1:]
# this is the same method mpv uses to decide this
def is_url(filename):
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))
# make them absolute; also makes them safe against interpretation as options
def make_abs(filename):
if not is_url(filename):
return os.path.abspath(filename)
return filename
files = [make_abs(f) for f in files]
files = [os.path.abspath(f) for f in files]
FIFO = os.path.join(os.getenv("HOME"), ".umpv_fifo")
FIFO = "/tmp/umpv-fifo-" + os.getenv("USER")
fifo_fd = -1
try:
@@ -70,6 +58,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 +82,10 @@ 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, 0600)
opts = (os.getenv("MPV") or "mpv").split()
opts.extend(["--no-terminal", "--force-window", "--input-file=" + FIFO,
"--"])
opts.extend(files)
subprocess.check_call(opts)
subprocess.check_call(["mpv", "--input-file=" + FIFO] + files)
+4 -3
View File
@@ -32,11 +32,11 @@
/*
* frame stepping filter
*
* usage: --vf=dlopen=/path/to/framestep.so:5
* usage: -vf dlopen=./framestep.so:5
*
* outputs every 5th frame
*
* usage: --vf=dlopen=/path/to/framestep.so:5:3
* usage: -vf dlopen=./framestep.so:5:3
*
* outputs every 5th frame, starting with frame index 3 (default: 0)
*/
@@ -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;
+3 -2
View File
@@ -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);
@@ -283,7 +284,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
il->tc_decision_threshold = A(10, 0.2);
static struct vf_dlopen_formatpair map[] = {
{ "gray", "gray" },
{ "y8", "y8" },
{ NULL, NULL }
};
ctx->format_mapping = map;
+1
View File
@@ -11,6 +11,7 @@ esac
: ${MPV:=mpv}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
: ${ILDETECT_DRY_RUN:=}
: ${ILDETECT_QUIET:=}
+4 -3
View File
@@ -35,7 +35,7 @@
/*
* rectangle
*
* usage: --vf=dlopen=/path/to/rectangle.so
* usage: -vf dlopen=./rectangle.so
*
* provides an editable rectangle
* NOTE: unix only, and requires xterm to be installed. Don't ask.
@@ -345,10 +345,11 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
(void) argc;
(void) argv;
static struct vf_dlopen_formatpair map[] = {
{ "yuv420p", "yuv420p" },
{ "yv12", "yv12" },
{ 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]);
+2 -2
View File
@@ -29,7 +29,7 @@
/*
* qscale visualizer
*
* usage: --vf=dlopen=/path/to/showqscale.so
* usage: -vf dlopen=./showqscale.so
*
* uses reddish colors for high QPs, and greenish colors for low QPs
*/
@@ -111,7 +111,7 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
(void) argc;
(void) argv;
static struct vf_dlopen_formatpair map[] = {
{ "yuv420p", "yuv420p" },
{ "yv12", "yv12" },
{ NULL, NULL }
};
ctx->format_mapping = map;
+3 -2
View File
@@ -32,7 +32,7 @@
/*
* telecine filter
*
* usage: --vf=dlopen=/path/to/telecine.so:t:23
* usage: -vf dlopen=./telecine.so:t:23
*
* Parameter: first parameter is "t" for top field first, "b" for bottom field first
* then digits (0-9) for how many fields a frame is to be displayed
@@ -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;
+7 -6
View File
@@ -30,17 +30,17 @@
/*
* tile filter
*
* usage: --vf=dlopen=/path/to/tile.so:4:3
* usage: -vf dlopen=./tile.so:4:3
*
* only supports rgb24 and yuv420p for now
* only supports rgb24 and yv12 for now
* in theory can support any format where rows are a multiple of bytes, and the
* multiple is known
*/
#define ALLFORMATS \
/* format bytes xmul ymul */ \
FORMAT("rgb24" , 3, 1, 1) \
FORMAT("yuv420p", 1, 2, 2)
/* format bytes xmul ymul */ \
FORMAT("rgb24", 3, 1, 1) \
FORMAT("yv12", 1, 2, 2)
typedef struct {
int rows, cols;
@@ -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]);
-22
View File
@@ -1,22 +0,0 @@
#!/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 \
"$@")"
set -f
${MPV:-mpv} \
--cookies \
--cookies-file="$cookies_file" \
--user-agent="$user_agent" \
-- $video_url
rm -rf "$cookies_dir"
-202
View File
@@ -1,202 +0,0 @@
#!/usr/bin/perl
# Generate ZSH completion
use strict;
use warnings;
my $mpv = $ARGV[0] || 'mpv';
my @opts = parse_opts("$mpv --list-options", '^ (\-\-[^\s\*]*)\*?\s*(.*)', 1);
my @ao = parse_opts("$mpv --ao=help", '^ ([^\s\:]*)\s*: (.*)');
my @vo = parse_opts("$mpv --vo=help", '^ ([^\s\:]*)\s*: (.*)');
my @af = parse_opts("$mpv --af=help", '^ ([^\s\:]*)\s*: (.*)');
my @vf = parse_opts("$mpv --vf=help", '^ ([^\s\:]*)\s*: (.*)');
my @protos = parse_opts("$mpv --list-protocols", '^ ([^\s]*)');
my ($opts_str, $ao_str, $vo_str, $af_str, $vf_str, $protos_str);
$opts_str .= qq{ '$_' \\\n} foreach (@opts);
chomp $opts_str;
$ao_str .= qq{ '$_' \\\n} foreach (@ao);
chomp $ao_str;
$vo_str .= qq{ '$_' \\\n} foreach (@vo);
chomp $vo_str;
$af_str .= qq{ '$_' \\\n} foreach (@af);
chomp $af_str;
$vf_str .= qq{ '$_' \\\n} foreach (@vf);
chomp $vf_str;
$protos_str .= qq{$_ } foreach (@protos);
chomp $protos_str;
my $profile_comp = <<'EOS';
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 == 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
EOS
chomp $profile_comp;
my $tmpl = <<"EOS";
#compdef mpv
# mpv zsh completion
local curcontext="\$curcontext" state state_descr line
typeset -A opt_args
local rc=1
_arguments -C -S \\
$opts_str
'*:files:->mfiles' && rc=0
case \$state in
ao)
local -a values
values=(
$ao_str
)
_describe -t values 'audio outputs' values && rc=0
;;
vo)
local -a values
values=(
$vo_str
)
_describe -t values 'video outputs' values && rc=0
;;
af)
local -a values
values=(
$af_str
)
_describe -t values 'audio filters' values && rc=0
;;
vf)
local -a values
values=(
$vf_str
)
_describe -t values 'video filters' values && rc=0
;;
profile|profiles)
$profile_comp
;;
files)
compset -P '*,'
compset -S ',*'
_files -r ',/ \\t\\n\\-' && rc=0
;;
mfiles)
local expl
_tags files urls
while _tags; do
_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)(-.)" && rc=0
if _requested urls; then
while _next_label urls expl URL; do
_urls "\$expl[@]" && rc=0
compadd -S '' "\$expl[@]" $protos_str && rc=0
done
fi
(( rc )) || return 0
done
;;
esac
return rc
EOS
print $tmpl;
sub parse_opts {
my ($cmd, $regex, $parsing_main_options) = @_;
my @list;
my @lines = split /\n/, `$cmd`;
foreach my $line (@lines) {
if ($line !~ /^$regex/) {
next;
}
my $entry = $1;
if ($parsing_main_options) {
$entry .= '=-';
}
if (defined $2) {
my $desc = $2;
$desc =~ s/\:/\\:/g;
$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');
$entry .= '->profiles' if ($1 eq '--profile');
$entry .= '->profile' if ($1 eq '--show-profile');
$entry .= '->files' if ($line =~ /\[file\]/);
}
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 -1
View File
@@ -1 +1 @@
0.7.0
0.3.3
+38 -173
View File
@@ -20,13 +20,10 @@
#include <stdlib.h>
#include <assert.h>
#include <libavutil/buffer.h>
#include <libavutil/frame.h>
#include <libavutil/version.h>
#include <libavutil/mem.h>
#include "talloc.h"
#include "common/common.h"
#include "fmt-conversion.h"
#include "audio.h"
static void update_redundant_info(struct mp_audio *mpa)
@@ -34,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_fmt2bps(mpa->format);
mpa->bps = af_fmt2bits(mpa->format) / 8;
if (af_fmt_is_planar(mpa->format)) {
mpa->spf = 1;
mpa->num_planes = mpa->nch;
@@ -91,12 +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)
{
snprintf(buf, buf_sz, "%dHz %s %dch %s", mpa->rate,
mp_chmap_to_str(&mpa->channels), 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)
@@ -113,27 +116,19 @@ 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
@@ -152,33 +147,36 @@ 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
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
mpa->planes[n] = mpa->allocated[n]->data;
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;
}
}
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);
}
// Like mp_audio_realloc(), but only reallocate if the audio grows in size.
// 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)) {
size_t alloc = ta_calc_prealloc_elems(samples);
if (alloc > INT_MAX)
abort(); // oom
mp_audio_realloc(mpa, alloc);
}
if (samples > mp_audio_get_allocated_size(mpa))
mp_audio_realloc(mpa, samples);
}
/* Get the size allocated for the data, in number of samples. If the allocated
@@ -191,7 +189,7 @@ int mp_audio_get_allocated_size(struct mp_audio *mpa)
{
int size = 0;
for (int n = 0; n < mpa->num_planes; n++) {
int s = mpa->allocated[n] ? mpa->allocated[n]->size / mpa->sstride : 0;
int s = mpa->allocated[n] / mpa->sstride;
size = n == 0 ? s : MPMIN(size, s);
}
return size;
@@ -237,136 +235,3 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
data->samples -= samples;
}
// 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)
{
bool ok = true;
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
if (data->allocated[n])
ok &= av_buffer_is_writable(data->allocated[n]);
}
if (!ok) {
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);
// "Transfer" the reference.
mp_audio_destructor(data);
*data = *new;
talloc_set_destructor(new, NULL);
talloc_free(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 special again
if (lavc_chmap.num != avframe->channels)
mp_chmap_from_channels(&lavc_chmap, avframe->channels);
#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) || avframe->nb_extended_buf)
goto fail;
for (int n = 0; n < AV_NUM_DATA_POINTERS; n++) {
if (!avframe->buf[n])
break;
if (n >= MP_NUM_CHANNELS)
goto fail;
new->allocated[n] = av_buffer_ref(avframe->buf[n]);
if (!new->allocated[n])
goto fail;
}
for (int n = 0; n < new->num_planes; n++)
new->planes[n] = avframe->data[n];
new->samples = avframe->nb_samples;
return new;
fail:
talloc_free(new);
av_frame_free(&tmp);
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->avpool = av_buffer_pool_init(alloc, 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;
}
+4 -13
View File
@@ -35,10 +35,10 @@ 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_fmt2bps(format))
int bps; // size of sub-samples (af_fmt2bits(format) / 8)
// private
struct AVBufferRef *allocated[MP_NUM_CHANNELS];
int allocated[MP_NUM_CHANNELS]; // use mp_audio_get_allocated_size()
};
void mp_audio_set_format(struct mp_audio *mpa, int format);
@@ -49,8 +49,8 @@ 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);
@@ -68,13 +68,4 @@ void mp_audio_copy(struct mp_audio *dst, int dst_offset,
struct mp_audio *src, int src_offset, int length);
void mp_audio_skip_samples(struct mp_audio *data, int samples);
int mp_audio_make_writeable(struct mp_audio *data);
struct AVFrame;
struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe);
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);
#endif
+16 -19
View File
@@ -18,13 +18,12 @@
#include <stdlib.h>
#include <assert.h>
#include "common/common.h"
#include "common/msg.h"
#include "chmap.h"
// Names taken from libavutil/channel_layout.c (Not accessible by API.)
// Use of these names is hard-coded in some places (e.g. ao_alsa.c)
static const char *const speaker_names[MP_SPEAKER_ID_COUNT][2] = {
static const char *speaker_names[MP_SPEAKER_ID_COUNT][2] = {
[MP_SPEAKER_ID_FL] = {"fl", "front left"},
[MP_SPEAKER_ID_FR] = {"fr", "front right"},
[MP_SPEAKER_ID_FC] = {"fc", "front center"},
@@ -54,7 +53,7 @@ static const char *const speaker_names[MP_SPEAKER_ID_COUNT][2] = {
// Names taken from libavutil/channel_layout.c (Not accessible by API.)
// Channel order corresponds to lavc/waveex, except for the alsa entries.
static const char *const std_layout_names[][2] = {
static const char *std_layout_names[][2] = {
{"empty", ""}, // not in lavc
{"mono", "fc"},
{"stereo", "fl-fr"},
@@ -87,7 +86,6 @@ static const char *const std_layout_names[][2] = {
{"7.1(wide-side)", "fl-fr-fc-lfe-flc-frc-sl-sr"},
{"octagonal", "fl-fr-fc-bl-br-bc-sl-sr"},
{"downmix", "dl-dr"},
{"auto", ""}, // not in lavc
{0}
};
@@ -107,7 +105,7 @@ static const struct mp_chmap default_layouts[MP_NUM_CHANNELS + 1] = {
// 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] = {
static const char *mplayer_layouts[MP_NUM_CHANNELS + 1] = {
[1] = "mono",
[2] = "stereo",
[4] = "quad",
@@ -377,35 +375,34 @@ void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
// 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()),
@@ -488,5 +485,5 @@ void mp_chmap_print_help(struct mp_log *log)
std_layout_names[n][0], std_layout_names[n][1]);
}
for (int n = 0; n < MP_NUM_CHANNELS; n++)
mp_info(log, " unknown%d\n", n + 1);
mp_info(log, " unknown%d\n", n);
}
+4 -7
View File
@@ -20,14 +20,14 @@
#include <inttypes.h>
#include <stdbool.h>
#include "misc/bstr.h"
#include "bstr/bstr.h"
#define MP_NUM_CHANNELS 8
// Speaker a channel can be assigned to.
// This corresponds to WAVEFORMATEXTENSIBLE channel mask bit indexes.
// E.g. channel_mask = (1 << MP_SPEAKER_ID_FL) | ...
enum mp_speaker_id {
enum {
// Official WAVEFORMATEXTENSIBLE (shortened names)
MP_SPEAKER_ID_FL = 0, // FRONT_LEFT
MP_SPEAKER_ID_FR, // FRONT_RIGHT
@@ -61,8 +61,7 @@ enum mp_speaker_id {
MP_SPEAKER_ID_UNKNOWN0 = 64,
MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1,
// 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,
};
@@ -120,9 +119,7 @@ void mp_chmap_reorder_to_lavc(struct mp_chmap *map);
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
const struct mp_chmap *to);
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(const struct mp_chmap *src);
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
struct mp_log;
+16 -21
View File
@@ -18,21 +18,21 @@
#include <stdlib.h>
#include <assert.h>
#include "common/common.h"
#include "chmap_sel.h"
static const struct mp_chmap speaker_replacements[][2] = {
// 5.1 <-> 5.1 (side)
{ MP_CHMAP2(SL, SR), MP_CHMAP2(BL, BR) },
// 7.1 <-> 7.1 (rear ext)
{ MP_CHMAP2(SL, SR), MP_CHMAP2(SDL, SDR) },
// 5.1 and 5.1(side) are practically the same. It doesn't make much sense to
// reject either of them.
static const int replaceable_speakers[][2] = {
{MP_SPEAKER_ID_SL, MP_SPEAKER_ID_BL},
{MP_SPEAKER_ID_SR, MP_SPEAKER_ID_BR},
{-1},
};
// Try to replace speakers from the left of the list with the ones on the
// right, or the other way around.
static bool replace_speakers(struct mp_chmap *map, struct mp_chmap list[2])
// list[] contains a list of speaker pairs, with each pair indicating how
// a speaker can be swapped for another speaker. Try to replace speakers from
// the left of the list with the ones on the right, or the other way around.
static bool replace_speakers(struct mp_chmap *map, const int list[][2])
{
assert(list[0].num == list[1].num);
if (!mp_chmap_is_valid(map))
return false;
for (int dir = 0; dir < 2; dir++) {
@@ -41,9 +41,9 @@ static bool replace_speakers(struct mp_chmap *map, struct mp_chmap list[2])
bool replaced = false;
struct mp_chmap t = *map;
for (int n = 0; n < t.num; n++) {
for (int i = 0; i < list[0].num; i++) {
if (t.speaker[n] == list[from].speaker[i]) {
t.speaker[n] = list[to].speaker[i];
for (int i = 0; list[i][0] != -1; i++) {
if (t.speaker[n] == list[i][from]) {
t.speaker[n] = list[i][to];
replaced = true;
break;
}
@@ -168,14 +168,9 @@ bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *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];
if (replace_speakers(&t, r) && test_layout(s, &t)) {
*map = t;
return true;
}
}
// 5.1 <-> 5.1(side)
if (replace_speakers(map, replaceable_speakers) && test_layout(s, map))
return true;
// Fallback to mono/stereo as last resort
if (map->num == 1) {
*map = (struct mp_chmap) MP_CHMAP_INIT_MONO;
+1 -1
View File
@@ -36,7 +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 mp_audio **out);
int (*decode_audio)(struct dec_audio *da, struct mp_audio *buffer, int maxlen);
};
enum ad_ctrl {
+217 -89
View File
@@ -25,7 +25,6 @@
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/common.h>
#include <libavutil/intreadwrite.h>
#include "talloc.h"
@@ -34,49 +33,156 @@
#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;
struct demux_packet *packet;
uint32_t skip_samples;
};
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;
#define OPT_BASE_STRUCT struct MPOpts
const m_option_t ad_lavc_decode_opts_conf[] = {
OPT_FLOATRANGE("ac3drc", ad_lavc_param.ac3drc, 0, 0, 2),
OPT_FLAG("downmix", ad_lavc_param.downmix, 0),
OPT_INTRANGE("threads", ad_lavc_param.threads, 0, 1, 16),
OPT_STRING("o", ad_lavc_param.avopt, 0),
{0}
};
const struct m_sub_options ad_lavc_conf = {
.opts = (const m_option_t[]) {
OPT_FLOATRANGE("ac3drc", ac3drc, 0, 0, 2),
OPT_FLAG("downmix", downmix, 0),
OPT_INTRANGE("threads", threads, 0, 1, 16),
OPT_KEYVALUELIST("o", avopts, 0),
{0}
},
.size = sizeof(struct ad_lavc_params),
.defaults = &(const struct ad_lavc_params){
.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) {
avctx->extradata = av_mallocz(wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE);
avctx->extradata_size = wf->cbSize;
memcpy(avctx->extradata, wf + 1, avctx->extradata_size);
}
}
static int init(struct dec_audio *da, const char *decoder)
{
struct MPOpts *mpopts = da->opts;
struct ad_lavc_params *opts = mpopts->ad_lavc_params;
struct ad_lavc_param *opts = &mpopts->ad_lavc_param;
AVCodecContext *lavc_context;
AVCodec *lavc_codec;
struct sh_stream *sh = da->header;
@@ -85,7 +191,13 @@ static int init(struct dec_audio *da, const char *decoder)
struct priv *ctx = talloc_zero(NULL, struct priv);
da->priv = ctx;
ctx->force_channel_map = sh_audio->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) {
@@ -96,41 +208,47 @@ static int init(struct dec_audio *da, const char *decoder)
lavc_context = avcodec_alloc_context3(lavc_codec);
ctx->avctx = lavc_context;
ctx->avframe = av_frame_alloc();
lavc_context->refcounted_frames = 1;
ctx->avframe = avcodec_alloc_frame();
lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
lavc_context->codec_id = lavc_codec->id;
if (opts->downmix) {
lavc_context->request_channel_layout =
mp_chmap_to_lavc(&mpopts->audio_output_channels);
// Compatibility for Libav 9
av_opt_set_int(lavc_context, "request_channels",
mpopts->audio_output_channels.num,
AV_OPT_SEARCH_CHILDREN);
}
// 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
mp_set_avopts(da->log, lavc_context, opts->avopts);
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;
}
}
lavc_context->codec_tag = sh->format;
lavc_context->sample_rate = sh_audio->samplerate;
lavc_context->bit_rate = sh_audio->bitrate;
lavc_context->block_align = sh_audio->block_align;
lavc_context->bits_per_coded_sample = sh_audio->bits_per_coded_sample;
lavc_context->channels = sh_audio->channels.num;
if (!mp_chmap_is_unknown(&sh_audio->channels))
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
lavc_context->bit_rate = sh_audio->i_bps * 8;
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
// demux_mkv
if (sh_audio->wf)
set_from_wf(lavc_context, sh_audio->wf);
// 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);
lavc_context->extradata = av_malloc(sh_audio->codecdata_len +
FF_INPUT_BUFFER_PADDING_SIZE);
lavc_context->extradata_size = sh_audio->codecdata_len;
memcpy(lavc_context->extradata, (char *)sh_audio->codecdata,
lavc_context->extradata_size);
}
if (sh->lav_headers)
@@ -144,9 +262,26 @@ 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);
if (lavc_context->bit_rate != 0)
da->bitrate = lavc_context->bit_rate;
// 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;
}
}
da->i_bps = lavc_context->bit_rate / 8;
if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
da->i_bps = sh_audio->wf->nAvgBytesPerSec;
return 1;
}
@@ -164,7 +299,7 @@ static void uninit(struct dec_audio *da)
av_freep(&lavc_context->extradata);
av_freep(&lavc_context);
}
av_frame_free(&ctx->avframe);
avcodec_free_frame(&ctx->avframe);
}
static int control(struct dec_audio *da, int cmd, void *arg)
@@ -173,24 +308,24 @@ static int control(struct dec_audio *da, int cmd, void *arg)
switch (cmd) {
case ADCTRL_RESET:
avcodec_flush_buffers(ctx->avctx);
ctx->frame.samples = 0;
talloc_free(ctx->packet);
ctx->packet = NULL;
ctx->skip_samples = 0;
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
static int decode_new_packet(struct dec_audio *da)
{
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
priv->frame.samples = 0;
struct demux_packet *mpkt = priv->packet;
if (!mpkt) {
if (demux_read_packet_async(da->header, &mpkt) == 0)
return AD_WAIT;
}
if (!mpkt)
mpkt = demux_read_packet(da->header);
priv->packet = talloc_steal(priv, mpkt);
@@ -206,7 +341,6 @@ static int decode_packet(struct dec_audio *da, struct mp_audio **out)
}
int got_frame = 0;
av_frame_unref(priv->avframe);
int ret = avcodec_decode_audio4(avctx, priv->avframe, &got_frame, &pkt);
if (mpkt) {
// At least "shorten" decodes sub-frames, instead of the whole packet.
@@ -223,14 +357,22 @@ static int decode_packet(struct dec_audio *da, struct mp_audio **out)
}
// LATM may need many packets to find mux info
if (ret == AVERROR(EAGAIN))
return AD_OK;
return 0;
}
if (ret < 0) {
MP_ERR(da, "Error decoding audio.\n");
return AD_ERR;
MP_VERBOSE(da, "lavc_audio: error\n");
return -1;
}
if (!got_frame)
return mpkt ? AD_OK : AD_EOF;
return mpkt ? 0 : -1; // -1: eof
if (setup_format(da) < 0)
return -1;
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];
double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, NULL);
if (out_pts != MP_NOPTS_VALUE) {
@@ -238,49 +380,35 @@ static int decode_packet(struct dec_audio *da, struct mp_audio **out)
da->pts_offset = 0;
}
struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe);
if (!mpframe)
return AD_ERR;
MP_DBG(da, "Decoded %d -> %d samples\n", in_len,
priv->frame.samples);
return 0;
}
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) {
struct sh_audio *sh_audio = da->header->audio;
if (lavc_chmap.num == sh_audio->channels.num)
lavc_chmap = sh_audio->channels;
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;
}
mp_audio_set_channels(mpframe, &lavc_chmap);
#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);
uint32_t pad = AV_RL32(d + 4);
uint32_t skip = MPMIN(priv->skip_samples, mpframe->samples);
if (skip) {
mp_audio_skip_samples(mpframe, skip);
da->pts_offset += skip;
priv->skip_samples -= skip;
}
if (pad <= mpframe->samples)
mpframe->samples -= pad;
}
#endif
if (!mp_audio_config_equals(buffer, &priv->frame))
return 0;
*out = mpframe;
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 = {
@@ -289,5 +417,5 @@ const struct ad_functions ad_lavc = {
.init = init,
.uninit = uninit,
.control = control,
.decode_packet = decode_packet,
.decode_audio = decode_audio,
};
+153 -82
View File
@@ -35,7 +35,9 @@
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;
@@ -43,7 +45,6 @@ struct ad_mpg123_context {
short delay;
/* If the stream is actually VBR. */
char vbr;
struct mp_audio frame;
};
static void uninit(struct dec_audio *da)
@@ -57,7 +58,7 @@ static void uninit(struct dec_audio *da)
/* This initializes libmpg123 and prepares the handle, including funky
* parameters. */
static int init(struct dec_audio *da, const char *decoder)
static int preinit(struct dec_audio *da)
{
int err;
struct ad_mpg123_context *con;
@@ -110,18 +111,15 @@ static int init(struct dec_audio *da, const char *decoder)
* We need at least 1152 samples. dec_audio.c normally guarantees this. */
mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.);
err = mpg123_open_feed(con->handle);
if (err != MPG123_OK)
goto bad_end;
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));
}
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;
@@ -142,6 +140,111 @@ static int mpg123_format_to_af(int mpg123_encoding)
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_fmt2bits(af) / 8);
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)
{
@@ -151,7 +254,7 @@ static int compute_bitrate(struct mpg123_frameinfo *i)
{-1, 384, 1152, 576}, /* MPEG 2.5 */
{-1, -1, -1, -1}, /* Unknown */
};
return (int) ((i->framesize + 4) * 8 * i->rate /
return (int) ((i->framesize + 4) * 8 * i->rate * 0.001 /
samples_per_frame[i->version][i->layer] + 0.5);
}
@@ -164,9 +267,6 @@ static void update_info(struct dec_audio *da)
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)
@@ -174,100 +274,71 @@ static void update_info(struct dec_audio *da)
/* 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);
finfo.bitrate) / con->mean_count;
da->i_bps = (int) (con->mean_rate * 1000 / 8);
con->delay = 10;
}
} else {
da->bitrate = bitrate ? bitrate : compute_bitrate(&finfo);
da->i_bps = (finfo.bitrate ? finfo.bitrate : compute_bitrate(&finfo))
* 1000 / 8;
con->delay = 1;
con->mean_rate = 0.;
con->mean_count = 0;
}
}
/* libmpg123 has a new format ready; query and store, return return value
of mpg123_getformat() */
static int set_format(struct dec_audio *da)
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;
long rate;
int channels;
int encoding;
ret = mpg123_getformat(con->handle, &rate, &channels, &encoding);
if (ret == MPG123_OK) {
mp_audio_set_num_channels(&con->frame, channels);
con->frame.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;
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;
}
mp_audio_set_format(&con->frame, af);
con->sample_size = channels * af_fmt2bps(af);
}
return ret;
}
static int decode_packet(struct dec_audio *da, struct mp_audio **out)
{
struct ad_mpg123_context *con = da->priv;
int ret;
struct demux_packet *pkt;
if (demux_read_packet_async(da->header, &pkt) == 0)
return AD_WAIT;
if (!pkt)
return AD_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 (con->need_data) {
if (feed_new_packet(da) < 0)
return -1;
}
if (ret != MPG123_OK)
goto mpg123_fail;
unsigned char *audio = NULL;
size_t bytes = 0;
ret = mpg123_decode_frame(con->handle, NULL, &audio, &bytes);
if (ret == MPG123_NEED_MORE)
if (!mp_audio_config_equals(&da->decoded, buffer))
return 0;
if (ret != MPG123_OK && ret != MPG123_DONE && ret != MPG123_NEW_FORMAT)
goto mpg123_fail;
ret = set_format(da);
size_t got_now = 0;
ret = mpg123_replace_buffer(con->handle, buf, maxlen * con->sample_size);
if (ret != MPG123_OK)
goto mpg123_fail;
if (con->sample_size < 1) {
MP_ERR(da, "no sample size\n");
return AD_ERR;
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;
}
int got_samples = bytes / con->sample_size;
*out = mp_audio_pool_get(da->pool, &con->frame, got_samples);
if (!*out)
return AD_ERR;
memcpy((*out)->planes[0], audio, bytes);
update_info(da);
return 0;
mpg123_fail:
MP_ERR(da, "mpg123 decoding error: %s\n", mpg123_strerror(con->handle));
return AD_ERR;
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)
@@ -300,5 +371,5 @@ const struct ad_functions ad_mpg123 = {
.init = init,
.uninit = uninit,
.control = control,
.decode_packet = decode_packet,
.decode_audio = decode_audio,
};
+29 -29
View File
@@ -38,16 +38,16 @@ struct spdifContext {
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;
struct mp_audio fmt;
};
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;
@@ -118,13 +118,13 @@ static int init(struct dec_audio *da, const char *decoder)
switch (stream->codec->codec_id) {
case AV_CODEC_ID_AAC:
spdif_ctx->iec61937_packet_size = 16384;
sample_format = AF_FORMAT_S_AAC;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_AC3:
spdif_ctx->iec61937_packet_size = 6144;
sample_format = AF_FORMAT_S_AC3;
sample_format = AF_FORMAT_AC3_LE;
samplerate = 48000;
num_channels = 2;
break;
@@ -132,40 +132,40 @@ static int init(struct dec_audio *da, const char *decoder)
if (da->opts->dtshd) {
av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_S_DTSHD;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 192000;
num_channels = 2*4;
} else {
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_S_DTS;
sample_format = AF_FORMAT_AC3_LE;
samplerate = 48000;
num_channels = 2;
}
break;
case AV_CODEC_ID_EAC3:
spdif_ctx->iec61937_packet_size = 24576;
sample_format = AF_FORMAT_S_EAC3;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 192000;
num_channels = 2;
break;
case AV_CODEC_ID_MP3:
spdif_ctx->iec61937_packet_size = 4608;
sample_format = AF_FORMAT_S_MP3;
sample_format = AF_FORMAT_MPEG2;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_TRUEHD:
spdif_ctx->iec61937_packet_size = 61440;
sample_format = AF_FORMAT_S_TRUEHD;
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");
@@ -183,19 +183,24 @@ fail:
return 0;
}
static int decode_packet(struct dec_audio *da, 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;
int sstride = 2 * da->decoded.channels.num;
assert(sstride == buffer->sstride);
if (maxlen * sstride < spdif_ctx->iec61937_packet_size)
return 0;
spdif_ctx->out_buffer_len = 0;
spdif_ctx->out_buffer_size = maxlen * sstride;
spdif_ctx->out_buffer = buffer->planes[0];
struct demux_packet *mpkt;
if (demux_read_packet_async(da->header, &mpkt) == 0)
return AD_WAIT;
struct demux_packet *mpkt = demux_read_packet(da->header);
if (!mpkt)
return AD_EOF;
return -1;
AVPacket pkt;
mp_set_av_packet(&pkt, mpkt, NULL);
@@ -206,17 +211,12 @@ static int decode_packet(struct dec_audio *da, struct mp_audio **out)
da->pts_offset = 0;
}
int ret = av_write_frame(lavf_ctx, &pkt);
talloc_free(mpkt);
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 AD_ERR;
int samples = spdif_ctx->out_buffer_len / spdif_ctx->fmt.sstride;
*out = mp_audio_pool_get(da->pool, &spdif_ctx->fmt, samples);
if (!*out)
return AD_ERR;
memcpy((*out)->planes[0], spdif_ctx->out_buffer, spdif_ctx->out_buffer_len);
return -1;
return 0;
}
@@ -253,5 +253,5 @@ const struct ad_functions ad_spdif = {
.init = init,
.uninit = uninit,
.control = control,
.decode_packet = decode_packet,
.decode_audio = decode_audio,
};
+177 -61
View File
@@ -28,7 +28,7 @@
#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"
@@ -48,14 +48,35 @@ extern const struct ad_functions ad_lavc;
extern const struct ad_functions ad_spdif;
static const struct ad_functions * const ad_drivers[] = {
&ad_lavc,
#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)
{
if (d_audio->ad_driver) {
@@ -76,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;
}
@@ -136,7 +163,14 @@ int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
d_audio->decoder_desc =
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_INFO(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));
MP_SMODE(d_audio, "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
d_audio->i_bps * 8, d_audio->decoded.rate,
d_audio->decoded.channels.num);
} else {
MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
d_audio->header->codec ? d_audio->header->codec : "<unknown>");
@@ -150,94 +184,176 @@ void audio_uninit(struct dec_audio *d_audio)
{
if (!d_audio)
return;
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
af_destroy(d_audio->afilter);
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);
}
/* Decode packets until we know the audio format. Then reinit the buffer.
* Returns AD_OK on success, negative AD_* code otherwise.
* Also returns AD_OK if already initialized (and does nothing).
*/
int initial_audio_decode(struct dec_audio *da)
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format)
{
while (!da->waiting) {
int ret = da->ad_driver->decode_packet(da, &da->waiting);
if (ret < 0)
return ret;
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);
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 :(
}
talloc_steal(da, da->waiting);
da->decode_format = *da->waiting;
return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR;
*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, or negative AD_* error code.
* 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 *da, struct mp_audio_buffer *outbuf,
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
int minsamples)
{
struct af_stream *afs = da->afilter;
if (afs->initialized < 1)
return AD_ERR;
// 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;
MP_STATS(da, "start audio");
/* 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 res = 0;
while (res >= 0 && minsamples >= 0) {
int prev_buffered = -1;
while (minsamples >= 0) {
int buffered = mp_audio_buffer_samples(outbuf);
if (minsamples < buffered)
if (minsamples < buffered || buffered == prev_buffered)
break;
prev_buffered = buffered;
res = 0;
int decsamples = (minsamples - buffered) / filter_multiplier;
// + some extra for possible filter buffering
decsamples += unitsize << 5;
struct mp_audio *mpa = da->waiting;
if (!mpa)
res = da->ad_driver->decode_packet(da, &mpa);
if (res != AD_EOF) {
if (res < 0)
break;
if (!mpa )
continue;
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 (mpa) {
da->pts_offset += mpa->samples;
da->decode_format = *mpa;
mp_audio_set_null_data(&da->decode_format);
// On format change, make sure to drain the filter chain.
if (!mp_audio_config_equals(&afs->input, mpa)) {
res = AD_NEW_FMT;
da->waiting = talloc_steal(da, mpa);
mpa = NULL;
}
}
/* if this iteration does not fill buffer, we must have lots
* of buffering in filters */
huge_filter_buffer = 1;
if (mpa)
da->waiting = NULL;
if (af_filter(afs, mpa, outbuf) < 0)
return AD_ERR;
int res = filter_n_bytes(d_audio, outbuf, decsamples);
if (res < 0)
return res;
}
MP_STATS(da, "end audio");
return res;
return 0;
}
void audio_reset_decoding(struct dec_audio *d_audio)
{
if (d_audio->ad_driver)
d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
if (d_audio->afilter)
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
d_audio->pts = MP_NOPTS_VALUE;
d_audio->pts_offset = 0;
if (d_audio->waiting) {
talloc_free(d_audio->waiting);
d_audio->waiting = NULL;
}
if (d_audio->decode_buffer)
mp_audio_buffer_clear(d_audio->decode_buffer);
}
+9 -15
View File
@@ -21,7 +21,6 @@
#include "audio/chmap.h"
#include "audio/audio.h"
#include "demux/demux.h"
#include "demux/stheader.h"
struct mp_audio_buffer;
@@ -33,14 +32,14 @@ struct dec_audio {
struct mpv_global *global;
const struct ad_functions *ad_driver;
struct sh_stream *header;
struct mp_audio_buffer *decode_buffer;
struct af_stream *afilter;
char *decoder_desc;
int init_retries;
struct mp_audio_pool *pool;
struct mp_audio decode_format;
struct mp_audio *waiting; // used on format-change
// set by decoder
int bitrate; // input bitrate, can change with VBR sources
struct mp_audio decoded; // format of decoded audio (no data, temporarily
// different from decode_buffer during format
// changes)
int i_bps; // 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
@@ -49,20 +48,15 @@ struct dec_audio {
void *priv;
};
enum {
AD_OK = 0,
AD_ERR = -1,
AD_EOF = -2,
AD_NEW_FMT = -3,
AD_WAIT = -4,
};
struct mp_decoder_list *audio_decoder_list(void);
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);
int initial_audio_decode(struct dec_audio *d_audio);
void audio_reset_decoding(struct dec_audio *d_audio);
void audio_uninit(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 */
+94 -148
View File
@@ -28,39 +28,37 @@
#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_forcespeed;
extern const struct af_info af_info_bs2b;
extern const struct af_info af_info_lavfi;
extern const struct af_info af_info_convert24;
extern const struct af_info af_info_convertsignendian;
extern struct af_info af_info_dummy;
extern struct af_info af_info_delay;
extern struct af_info af_info_channels;
extern struct af_info af_info_format;
extern struct af_info af_info_force;
extern struct af_info af_info_volume;
extern struct af_info af_info_equalizer;
extern struct af_info af_info_pan;
extern struct af_info af_info_surround;
extern struct af_info af_info_sub;
extern struct af_info af_info_export;
extern struct af_info af_info_drc;
extern struct af_info af_info_extrastereo;
extern struct af_info af_info_lavcac3enc;
extern struct af_info af_info_lavrresample;
extern struct af_info af_info_sweep;
extern struct af_info af_info_hrtf;
extern struct af_info af_info_ladspa;
extern struct af_info af_info_center;
extern struct af_info af_info_sinesuppress;
extern struct af_info af_info_karaoke;
extern struct af_info af_info_scaletempo;
extern struct af_info af_info_bs2b;
extern struct af_info af_info_lavfi;
extern struct af_info af_info_convert24;
extern struct af_info af_info_convertsignendian;
static const struct af_info *const filter_list[] = {
static struct af_info* filter_list[] = {
&af_info_dummy,
&af_info_delay,
&af_info_channels,
@@ -85,12 +83,11 @@ static const struct af_info *const filter_list[] = {
&af_info_center,
&af_info_sinesuppress,
&af_info_karaoke,
&af_info_forcespeed,
&af_info_scaletempo,
#if HAVE_LIBBS2B
&af_info_bs2b,
#endif
#if HAVE_LIBAVFILTER
#if HAVE_AF_LAVFI
&af_info_lavfi,
#endif
// Must come last, because they're fallback format conversion filter
@@ -124,6 +121,13 @@ const struct m_obj_list af_obj_list = {
},
};
static bool af_config_equals(struct mp_audio *a, struct mp_audio *b)
{
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)
{
if (dst->format == AF_FORMAT_UNKNOWN)
@@ -158,7 +162,7 @@ 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;
@@ -200,7 +204,6 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
.mul = 1,
.data = talloc_zero(af, struct mp_audio),
.log = mp_log_new(af, s->log, name),
.replaygain_data = s->replaygain_data,
};
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)
@@ -306,18 +309,23 @@ 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->data)
mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data));
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 int af_count_filters(struct af_stream *s)
@@ -337,28 +345,26 @@ static int af_count_filters(struct af_stream *s)
// (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;
#define NUM_FMT 64
#define NUM_FILT 32
#define NUM_NODES (NUM_FMT * NUM_FILT)
for (int n = 0; filter_list[n]; n++)
num_filt = n + 1;
assert(n < NUM_FILT);
for (int n = 0; af_fmtstr_table[n].format; n++)
num_fmt = n + 1;
assert(n < NUM_FMT);
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++) {
bool visited[NUM_NODES] = {0};
unsigned char distance[NUM_NODES];
short previous[NUM_NODES] = {0};
for (int n = 0; n < NUM_NODES; n++) {
distance[n] = 255;
if (af_fmtstr_table[n % num_fmt].format == srcfmt)
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++) {
for (int n = 0; n < NUM_NODES; n++) {
if (!visited[n] && (next < 0 || (distance[n] < distance[next])))
next = n;
}
@@ -366,27 +372,27 @@ static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
return NULL;
visited[next] = true;
int fmt = next % num_fmt;
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;
*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];
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 other = n * NUM_FMT + i;
int ndist = distance[next] + 1;
if (ndist < distance[other]) {
distance[other] = ndist;
@@ -397,7 +403,9 @@ static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
}
}
assert(0);
#undef MAX_NODES
#undef NUM_FMT
#undef NUM_FILT
#undef NODE_N
}
static bool af_is_conversion_filter(struct af_instance *af)
@@ -514,16 +522,11 @@ static int af_reinit(struct af_stream *s)
// Reset just in case...
mp_audio_set_null_data(&in);
if (!mp_audio_config_valid(&in))
goto error;
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:
if (!mp_audio_config_valid(af->data))
goto error;
af = af->next;
break;
case AF_FALSE: { // Configuration filter is needed
@@ -554,27 +557,22 @@ static int af_reinit(struct af_stream *s)
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;
}
@@ -584,13 +582,12 @@ void af_uninit(struct af_stream *s)
{
while (s->first->next && s->first->next != s->last)
af_remove(s, s->first->next);
s->initialized = 0;
}
struct af_stream *af_new(struct mpv_global *global)
{
struct af_stream *s = talloc_zero(NULL, struct af_stream);
static const struct af_info in = { .name = "in" };
static struct af_info in = { .name = "in" };
s->first = talloc(s, struct af_instance);
*s->first = (struct af_instance) {
.info = &in,
@@ -600,7 +597,7 @@ struct af_stream *af_new(struct mpv_global *global)
.data = &s->input,
.mul = 1.0,
};
static const struct af_info out = { .name = "out" };
static struct af_info out = { .name = "out" };
s->last = talloc(s, struct af_instance);
*s->last = (struct af_instance) {
.info = &out,
@@ -634,6 +631,10 @@ void af_destroy(struct af_stream *s)
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);
@@ -643,20 +644,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;
@@ -669,6 +667,9 @@ int af_init(struct af_stream *s)
struct af_instance *af_add(struct af_stream *s, char *name, char **args)
{
struct af_instance *new;
// Sanity check
if (!s || !s->first || !name)
return NULL;
// Insert the filter somewhere nice
if (af_is_conversion_filter(s->first->next))
new = af_append(s, s->first->next, name, args);
@@ -679,85 +680,30 @@ struct af_instance *af_add(struct af_stream *s, char *name, char **args)
// Reinitalize the filter list
if (af_reinit(s) != AF_OK) {
af_remove(s, new);
if (af_reinit(s) != AF_OK) {
af_uninit(s);
af_init(s);
}
af_uninit(s);
af_init(s);
return NULL;
}
return new;
}
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.
/* 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_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);
if (af_reinit(s) != AF_OK) {
af_uninit(s);
af_init(s);
return -1;
}
return 1;
}
/* Feed "data" to the chain, and write results to output. "data" needs to be
* a refcounted frame, although refcounting is not used yet.
* data==NULL means EOF.
*/
int af_filter(struct af_stream *s, struct mp_audio *data,
struct mp_audio_buffer *output)
int af_filter(struct af_stream *s, struct mp_audio *data, int flags)
{
struct af_instance *af = s->first;
assert(s->initialized > 0);
int flags = 0;
int r = 0;
struct mp_audio tmp;
char dummy[MP_NUM_CHANNELS];
if (data) {
assert(mp_audio_config_equals(af->data, data));
r = mp_audio_make_writeable(data);
} else {
data = &tmp;
*data = *(af->data);
mp_audio_set_null_data(data);
flags = AF_FILTER_FLAG_EOF;
for (int n = 0; n < MP_NUM_CHANNELS; n++)
data->planes[n] = &dummy[n];
}
if (r < 0)
goto done;
struct mp_audio frame = *data;
for (int n = 0; n < MP_NUM_CHANNELS; n++)
frame.allocated[n] = NULL;
assert(mp_audio_config_equals(af->data, data));
// Iterate through all filters
while (af) {
r = af->filter(af, &frame, flags);
int r = af->filter(af, data, flags);
if (r < 0)
goto done;
assert(mp_audio_config_equals(af->data, &frame));
return r;
assert(mp_audio_config_equals(af->data, data));
af = af->next;
}
mp_audio_buffer_append(output, &frame);
done:
if (data != &tmp)
talloc_free(data);
return r;
return 0;
}
// Calculate average ratio of filter output samples to input samples.
+1 -11
View File
@@ -59,7 +59,6 @@ struct af_info {
struct af_instance {
const struct af_info *info;
struct mp_log *log;
struct replaygain_data *replaygain_data;
int (*control)(struct af_instance *af, int cmd, void *arg);
void (*uninit)(struct af_instance *af);
/* flags is a bit mask of AF_FILTER_FLAG_* values
@@ -76,13 +75,10 @@ struct af_instance {
* 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;
};
// 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;
@@ -94,7 +90,6 @@ struct af_stream {
struct mp_log *log;
struct MPOpts *opts;
struct replaygain_data *replaygain_data;
};
// Return values
@@ -120,7 +115,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,
};
// Argument for AF_CONTROL_SET_PAN_LEVEL
@@ -134,11 +128,7 @@ 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 **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 mp_audio_buffer;
int af_filter(struct af_stream *s, struct mp_audio *data,
struct mp_audio_buffer *output);
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);
+53 -24
View File
@@ -48,12 +48,20 @@ static int filter_##name(struct af_instance *af, struct mp_audio *data, int f) \
}
FILTER(f, float)
FILTER(s32, int32_t)
FILTER(u32, uint32_t)
FILTER(s24, bs2b_int24_t)
FILTER(u24, bs2b_uint24_t)
FILTER(s16, int16_t)
FILTER(u16, uint16_t)
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)
@@ -77,26 +85,47 @@ static int control(struct af_instance *af, int cmd, void *arg)
/* check for formats supported by libbs2b
and assign corresponding handlers */
switch (format) {
case AF_FORMAT_FLOAT:
af->filter = filter_f;
case AF_FORMAT_FLOAT_BE:
af->filter = filter_fbe;
break;
case AF_FORMAT_S32:
af->filter = filter_s32;
case AF_FORMAT_FLOAT_LE:
af->filter = filter_fle;
break;
case AF_FORMAT_U32:
af->filter = filter_u32;
case AF_FORMAT_S32_BE:
af->filter = filter_s32be;
break;
case AF_FORMAT_S24:
af->filter = filter_s24;
case AF_FORMAT_U32_BE:
af->filter = filter_u32be;
break;
case AF_FORMAT_U24:
af->filter = filter_u24;
case AF_FORMAT_S32_LE:
af->filter = filter_s32le;
break;
case AF_FORMAT_S16:
af->filter = filter_s16;
case AF_FORMAT_U32_LE:
af->filter = filter_u32le;
break;
case AF_FORMAT_U16:
af->filter = filter_u16;
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;
@@ -113,12 +142,12 @@ static int control(struct af_instance *af, int cmd, void *arg)
// 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",
MP_WARN(af, "[bs2b] Requested sample rate %d Hz is out of bounds [%d..%d] Hz.\n"
"[bs2b] 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",
MP_VERBOSE(af, "[bs2b] using format %s\n",
af_fmt_to_str(af->data->format));
return af_test_output(af,(struct mp_audio*)arg);
@@ -160,7 +189,7 @@ static int af_open(struct af_instance *af)
#define OPT_BASE_STRUCT struct af_bs2b
/// Description of this filter
const struct af_info af_info_bs2b = {
struct af_info af_info_bs2b = {
.info = "Bauer stereophonic-to-binaural audio filter",
.name = "bs2b",
.open = af_open,
+7 -7
View File
@@ -35,7 +35,7 @@
// Data for specific instances of this filter
typedef struct af_center_s
{
int ch; // Channel number which to insert the filtered data
int ch; // Channel number which to insert the filtered data
}af_center_t;
// Initialization and runtime control
@@ -61,12 +61,12 @@ static int control(struct af_instance* af, int cmd, void* arg)
// 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* 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
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
@@ -86,7 +86,7 @@ static int af_open(struct af_instance* af){
}
#define OPT_BASE_STRUCT af_center_t
const struct af_info af_info_center = {
struct af_info af_info_center = {
.info = "Audio filter for adding a center channel",
.name = "center",
.flags = AF_FLAGS_NOT_REENTRANT,
+22 -22
View File
@@ -114,7 +114,7 @@ static void copy(struct af_instance *af, void* in, void* out,
}
default:
MP_ERR(af, "Unsupported number of bytes/sample: %i"
" please report this error on the MPlayer mailing list. \n",bps);
" please report this error on the MPlayer mailing list. \n",bps);
}
}
@@ -124,14 +124,14 @@ static int check_routes(struct af_instance *af, int nin, int nout)
af_channels_t* s = af->priv;
int i;
if((s->nr < 1) || (s->nr > AF_NCH)){
MP_ERR(af, "The number of routing pairs must be"
" between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
MP_ERR(af, "[channels] The number of routing pairs must be"
" between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
return AF_ERROR;
}
for(i=0;i<s->nr;i++){
if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){
MP_ERR(af, "Invalid routing in pair nr. %i.\n", i);
MP_ERR(af, "[channels] Invalid routing in pair nr. %i.\n", i);
return AF_ERROR;
}
}
@@ -154,22 +154,22 @@ static int control(struct af_instance* af, int cmd, void* arg)
int i;
// Make sure this filter isn't redundant
if(af->data->nch == ((struct mp_audio*)arg)->nch)
return AF_DETACH;
return AF_DETACH;
// If mono: fake stereo
if(((struct mp_audio*)arg)->nch == 1){
s->nr = MPMIN(af->data->nch,2);
for(i=0;i<s->nr;i++){
s->route[i][FR] = 0;
s->route[i][TO] = i;
}
s->nr = MPMIN(af->data->nch,2);
for(i=0;i<s->nr;i++){
s->route[i][FR] = 0;
s->route[i][TO] = i;
}
}
else{
s->nr = MPMIN(af->data->nch, ((struct mp_audio*)arg)->nch);
for(i=0;i<s->nr;i++){
s->route[i][FR] = i;
s->route[i][TO] = i;
}
s->nr = MPMIN(af->data->nch, ((struct mp_audio*)arg)->nch);
for(i=0;i<s->nr;i++){
s->route[i][FR] = i;
s->route[i][TO] = i;
}
}
}
@@ -184,10 +184,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
// 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
struct mp_audio* c = data; // Current working data
struct mp_audio* l = af->data; // Local data
af_channels_t* s = af->priv;
int i;
int i;
mp_audio_realloc_min(af->data, data->samples);
@@ -197,7 +197,7 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
if(AF_OK == check_routes(af,c->nch,l->nch))
for(i=0;i<s->nr;i++)
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);
l->nch,s->route[i][TO],mp_audio_psize(c),c->bps);
// Set output data
c->planes[0] = l->planes[0];
@@ -220,11 +220,11 @@ static int af_open(struct af_instance* af){
do {
int n = 0;
if (ch >= AF_NCH) {
MP_FATAL(af, "Can't have more than %d routes.\n", AF_NCH);
MP_FATAL(af, "[channels] Can't have more than %d routes.\n", AF_NCH);
return AF_ERROR;
}
sscanf(cp, "%i-%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
MP_VERBOSE(af, "Routing from channel %i to"
MP_VERBOSE(af, "[channels] Routing from channel %i to"
" channel %i\n",s->route[ch][FR],s->route[ch][TO]);
cp = &cp[n];
ch++;
@@ -238,7 +238,7 @@ static int af_open(struct af_instance* af){
}
#define OPT_BASE_STRUCT af_channels_t
const struct af_info af_info_channels = {
struct af_info af_info_channels = {
.info = "Insert or remove channels",
.name = "channels",
.open = af_open,
+1 -2
View File
@@ -20,7 +20,6 @@
#include "audio/format.h"
#include "af.h"
#include "osdep/endian.h"
static bool test_conversion(int src_format, int dst_format)
{
@@ -109,7 +108,7 @@ static int af_open(struct af_instance *af)
return AF_OK;
}
const struct af_info af_info_convert24 = {
struct af_info af_info_convert24 = {
.info = "Convert between 24 and 32 bit sample format",
.name = "convert24",
.open = af_open,
+42 -10
View File
@@ -20,16 +20,21 @@
#include "af.h"
#include "audio/format.h"
#include "osdep/endian.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;
if (((src_format & ~AF_FORMAT_SIGN_MASK) ==
(dst_format & ~AF_FORMAT_SIGN_MASK)) &&
((src_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_I))
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;
}
@@ -58,11 +63,34 @@ static int control(struct af_instance *af, int cmd, void *arg)
return AF_UNKNOWN;
}
static void si2us(void *data, int len, int bps)
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 (BYTE_ORDER == LITTLE_ENDIAN && bps > 1)
if (le && bps > 1)
p += bps - 1;
if (len <= 0)
return;
@@ -77,8 +105,12 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
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);
si2us(data->planes[0], len, data->bps,
(outfmt & AF_FORMAT_END_MASK) == AF_FORMAT_LE);
mp_audio_set_format(data, outfmt);
return 0;
@@ -91,9 +123,9 @@ static int af_open(struct af_instance *af)
return AF_OK;
}
const struct af_info af_info_convertsignendian = {
.info = "Convert between sample format sign",
.name = "convertsign",
struct af_info af_info_convertsignendian = {
.info = "Convert between sample format sign/endian",
.name = "convertsignendian",
.open = af_open,
.test_conversion = test_conversion,
};
+27 -27
View File
@@ -37,10 +37,10 @@
// 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]
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;
@@ -54,7 +54,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
struct mp_audio *in = arg;
if (in->bps != 1 && in->bps != 2 && in->bps != 4) {
MP_FATAL(af, "Sample format not supported\n");
MP_FATAL(af, "[delay] Sample format not supported\n");
return AF_ERROR;
}
@@ -69,16 +69,16 @@ static int control(struct af_instance* af, int cmd, void* arg)
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");
MP_FATAL(af, "[delay] 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",
MP_DBG(af, "[delay] 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",
MP_TRACE(af, "[delay] Channel %i delayed by %i samples\n",
i,s->wi[i]);
}
return AF_OK;
@@ -99,12 +99,12 @@ static void uninit(struct af_instance* af)
// 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;
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:{
@@ -113,10 +113,10 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
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);
q[wi] = a[i];
a[i] = q[ri];
UPDATEQI(wi);
UPDATEQI(ri);
}
s->wi[ch] = wi;
break;
@@ -127,10 +127,10 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
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);
q[wi] = a[i];
a[i] = q[ri];
UPDATEQI(wi);
UPDATEQI(ri);
}
s->wi[ch] = wi;
break;
@@ -141,10 +141,10 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
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);
q[wi] = a[i];
a[i] = q[ri];
UPDATEQI(wi);
UPDATEQI(ri);
}
s->wi[ch] = wi;
break;
@@ -178,7 +178,7 @@ static int af_open(struct af_instance* af){
}
#define OPT_BASE_STRUCT af_delay_t
const struct af_info af_info_delay = {
struct af_info af_info_delay = {
.info = "Delay audio filter",
.name = "delay",
.open = af_open,
+19 -19
View File
@@ -70,8 +70,8 @@ typedef struct af_volume_s
// method 2
int idx;
struct {
float avg; // average level of the sample
int len; // sample size (weight)
float avg; // average level of the sample
int len; // sample size (weight)
} mem[NSAMPLES];
// "Ideal" level
float mid_s16;
@@ -100,8 +100,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
static void method1_int16(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
int16_t *data = (int16_t*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
int16_t *data = (int16_t*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
float curavg = 0.0, newavg, neededmul;
int tmp;
@@ -142,8 +142,8 @@ static void method1_int16(af_drc_t *s, struct mp_audio *c)
static void method1_float(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
float *data = (float*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
float *data = (float*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
float curavg = 0.0, newavg, neededmul, tmp;
for (i = 0; i < len; i++)
@@ -179,8 +179,8 @@ static void method1_float(af_drc_t *s, struct mp_audio *c)
static void method2_int16(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
int16_t *data = (int16_t*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
int16_t *data = (int16_t*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
float curavg = 0.0, newavg, avg = 0.0;
int tmp, totallen = 0;
@@ -204,8 +204,8 @@ static void method2_int16(af_drc_t *s, struct mp_audio *c)
avg /= (float)totallen;
if (avg >= SIL_S16)
{
s->mul = s->mid_s16 / avg;
s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
s->mul = s->mid_s16 / avg;
s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
}
}
@@ -229,8 +229,8 @@ static void method2_int16(af_drc_t *s, struct mp_audio *c)
static void method2_float(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
float *data = (float*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
float *data = (float*)c->planes[0]; // Audio data
int len = c->samples*c->nch; // Number of samples
float curavg = 0.0, newavg, avg = 0.0, tmp;
int totallen = 0;
@@ -254,8 +254,8 @@ static void method2_float(af_drc_t *s, struct mp_audio *c)
avg /= (float)totallen;
if (avg >= SIL_FLOAT)
{
s->mul = s->mid_float / avg;
s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
s->mul = s->mid_float / avg;
s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
}
}
@@ -279,16 +279,16 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
if(af->data->format == (AF_FORMAT_S16))
{
if (s->method == 2)
method2_int16(s, data);
method2_int16(s, data);
else
method1_int16(s, data);
method1_int16(s, data);
}
else if(af->data->format == (AF_FORMAT_FLOAT))
{
if (s->method == 2)
method2_float(s, data);
method2_float(s, data);
else
method1_float(s, data);
method1_float(s, data);
}
return 0;
}
@@ -313,7 +313,7 @@ static int af_open(struct af_instance* af){
}
#define OPT_BASE_STRUCT af_drc_t
const struct af_info af_info_drc = {
struct af_info af_info_drc = {
.info = "Dynamic range compression filter",
.name = "drc",
.flags = AF_FLAGS_NOT_REENTRANT,
+3 -3
View File
@@ -33,8 +33,8 @@ 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));
MP_VERBOSE(af, "[dummy] 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;
@@ -54,7 +54,7 @@ static int af_open(struct af_instance* af){
}
// Description of this filter
const struct af_info af_info_dummy = {
struct af_info af_info_dummy = {
.info = "dummy",
.name = "dummy",
.open = af_open,
+45 -45
View File
@@ -32,41 +32,41 @@
#include "common/common.h"
#include "af.h"
#define L 2 // Storage for filter taps
#define KM 10 // Max number of bands
#define L 2 // Storage for filter taps
#define KM 10 // Max number of bands
#define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2)
gives 4dB suppression @ Fc*2 and Fc/2 */
gives 4dB suppression @ Fc*2 and Fc/2 */
/* Center frequencies for band-pass filters
The different frequency bands are:
nr. center frequency
0 31.25 Hz
1 62.50 Hz
2 125.0 Hz
3 250.0 Hz
4 500.0 Hz
5 1.000 kHz
6 2.000 kHz
7 4.000 kHz
8 8.000 kHz
9 16.00 kHz
nr. center frequency
0 31.25 Hz
1 62.50 Hz
2 125.0 Hz
3 250.0 Hz
4 500.0 Hz
5 1.000 kHz
6 2.000 kHz
7 4.000 kHz
8 8.000 kHz
9 16.00 kHz
*/
#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}
#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}
// Maximum and minimum gain for the bands
#define G_MAX +12.0
#define G_MIN -12.0
#define G_MAX +12.0
#define G_MIN -12.0
// Data for specific instances of this filter
typedef struct af_equalizer_s
{
float a[KM][L]; // A weights
float b[KM][L]; // B weights
float wq[AF_NCH][KM][L]; // Circular buffer for W data
float g[AF_NCH][KM]; // Gain factor for each channel and band
int K; // Number of used eq bands
int channels; // Number of channels
float a[KM][L]; // A weights
float b[KM][L]; // B weights
float wq[AF_NCH][KM][L]; // Circular buffer for W data
float g[AF_NCH][KM]; // Gain factor for each channel and band
int K; // Number of used eq bands
int channels; // Number of channels
float gain_factor; // applied at output to avoid clipping
double p[KM];
} af_equalizer_t;
@@ -107,8 +107,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
s->K--;
if(s->K != KM)
MP_INFO(af, "Limiting the number of filters to"
" %i due to low sample rate.\n",s->K);
MP_INFO(af, "[equalizer] Limiting the number of filters to"
" %i due to low sample rate.\n",s->K);
// Generate filter taps
for(k=0;k<s->K;k++)
@@ -144,33 +144,33 @@ static int control(struct af_instance* af, int cmd, void* arg)
// 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_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
struct mp_audio* c = data; // Current working data
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
while(ci--){
float* g = s->g[ci]; // Gain factor
float* in = ((float*)c->planes[0])+ci;
float* out = ((float*)c->planes[0])+ci;
float* end = in + c->samples*c->nch; // Block loop end
float* g = s->g[ci]; // Gain factor
float* in = ((float*)c->planes[0])+ci;
float* out = ((float*)c->planes[0])+ci;
float* end = in + c->samples*c->nch; // Block loop end
while(in < end){
register int k = 0; // Frequency band index
register float yt = *in; // Current input sample
register int k = 0; // Frequency band index
register float yt = *in; // Current input sample
in+=nch;
// Run the filters
for(;k<s->K;k++){
// Pointer to circular buffer wq
register float* wq = s->wq[ci][k];
// Calculate output from AR part of current filter
register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1];
// Calculate output form MA part of current filter
yt+=(w + wq[1]*s->b[k][1])*g[k];
// Update circular buffer
wq[1] = wq[0];
wq[0] = w;
// Pointer to circular buffer wq
register float* wq = s->wq[ci][k];
// Calculate output from AR part of current filter
register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1];
// Calculate output form MA part of current filter
yt+=(w + wq[1]*s->b[k][1])*g[k];
// Update circular buffer
wq[1] = wq[0];
wq[0] = w;
}
// Calculate output
*out=yt*s->gain_factor;
@@ -194,7 +194,7 @@ static int af_open(struct af_instance* af){
}
#define OPT_BASE_STRUCT af_equalizer_t
const struct af_info af_info_equalizer = {
struct af_info af_info_equalizer = {
.info = "Equalizer audio filter",
.name = "equalizer",
.flags = AF_FLAGS_NOT_REENTRANT,
+34 -35
View File
@@ -47,7 +47,7 @@
#define DEF_SZ 512 // default buffer size (in samples)
#define SHARED_FILE "mpv-af_export" /* default file name
(relative to ~/.mpv/ */
(relative to ~/.mpv/ */
#define SIZE_HEADER (2 * sizeof(int) + sizeof(unsigned long long))
@@ -55,12 +55,12 @@
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
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;
@@ -78,7 +78,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
int mapsize;
// Free previous buffers
free(s->buf[0]);
if (s->buf)
free(s->buf[0]);
// unmap previous area
if(s->mmap_area)
@@ -93,24 +94,22 @@ static int control(struct af_instance* af, int cmd, void* arg)
// 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");
return AF_ERROR;
}
if(NULL == s->buf[0])
MP_FATAL(af, "[export] 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");
MP_FATAL(af, "[export] 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);
MP_INFO(af, "[export] Exporting to file: %s\n", s->filename);
if(s->fd < 0) {
MP_FATAL(af, "Could not open/create file: %s\n",
s->filename);
MP_FATAL(af, "[export] Could not open/create file: %s\n",
s->filename);
return AF_ERROR;
}
@@ -126,9 +125,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
// 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);
MP_FATAL(af, "[export] Could not mmap file %s\n", s->filename);
MP_INFO(af, "[export] Memory mapped to file: %s (%p)\n",
s->filename, s->mmap_area);
// Initialize header
*((int*)s->mmap_area) = af->data->nch;
@@ -148,8 +147,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
static void uninit( struct af_instance* af )
{
af_export_t* s = af->priv;
free(s->buf[0]);
if (s->buf)
free(s->buf[0]);
// Free mmaped area
if(s->mmap_area)
@@ -165,27 +164,27 @@ static void uninit( struct af_instance* af )
*/
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
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;
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
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;
flag = 1;
break;
}
}
s->wi = wi % s->sz;
@@ -197,7 +196,7 @@ static int filter( struct af_instance* af, struct mp_audio* data, int flags)
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));
&(s->count), sizeof(s->count));
}
return 0;
@@ -223,7 +222,7 @@ static int af_open( struct af_instance* af )
}
#define OPT_BASE_STRUCT af_export_t
const struct af_info af_info_export = {
struct af_info af_info_export = {
.info = "Sound export filter",
.name = "export",
.open = af_open,
+7 -7
View File
@@ -51,11 +51,11 @@ static int control(struct af_instance* af, int cmd, void* arg)
mp_audio_set_num_channels(af->data, 2);
if (af->data->format == AF_FORMAT_FLOAT)
{
af->filter = play_float;
af->filter = play_float;
}// else
{
mp_audio_set_format(af->data, AF_FORMAT_S16);
af->filter = play_s16;
af->filter = play_s16;
}
return af_test_output(af,(struct mp_audio*)arg);
@@ -69,8 +69,8 @@ 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
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)
@@ -91,8 +91,8 @@ 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 *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)
@@ -118,7 +118,7 @@ static int af_open(struct af_instance* af){
}
#define OPT_BASE_STRUCT af_extrastereo_t
const struct af_info af_info_extrastereo = {
struct af_info af_info_extrastereo = {
.info = "Increase difference between audio channels",
.name = "extrastereo",
.flags = AF_FLAGS_NOT_REENTRANT,
-69
View File
@@ -1,69 +0,0 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 "af.h"
struct priv {
double speed;
};
static int control(struct af_instance *af, int cmd, void *arg)
{
struct priv *priv = af->priv;
switch (cmd) {
case AF_CONTROL_REINIT: {
struct mp_audio *in = arg;
struct mp_audio orig_in = *in;
struct mp_audio *out = af->data;
mp_audio_copy_config(out, in);
out->rate = in->rate * priv->speed;
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
}
case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
priv->speed = *(double *)arg;
return AF_OK;
}
}
return AF_UNKNOWN;
}
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
{
mp_audio_copy_config(data, af->data);
return 0;
}
static int af_open(struct af_instance *af)
{
struct priv *priv = af->priv;
af->control = control;
af->filter = filter;
priv->speed = 1.0;
return AF_OK;
}
#define OPT_BASE_STRUCT struct priv
const struct af_info af_info_forcespeed = {
.info = "Force audio speed",
.name = "forcespeed",
.open = af_open,
.priv_size = sizeof(struct priv),
};
+3 -3
View File
@@ -80,12 +80,12 @@ static int control(struct af_instance *af, int cmd, void *arg)
force_out_params(af, out);
if (in->nch != out->nch || in->bps != out->bps) {
MP_ERR(af, "Forced input/output formats are incompatible.\n");
MP_ERR(af, "[af_format] Forced input/output formats are incompatible.\n");
return AF_ERROR;
}
if (priv->fail) {
MP_ERR(af, "Failing on purpose.\n");
MP_ERR(af, "[af_format] Failing on purpose.\n");
return AF_ERROR;
}
@@ -114,7 +114,7 @@ static int af_open(struct af_instance *af)
#define OPT_BASE_STRUCT struct priv
const struct af_info af_info_format = {
struct af_info af_info_format = {
.info = "Force audio format",
.name = "format",
.open = af_open,
+219 -237
View File
@@ -75,23 +75,23 @@ typedef struct af_hrtf_s {
} af_hrtf_t;
/* Convolution on a ring buffer
* nx: length of the ring buffer
* nk: length of the convolution kernel
* sx: ring buffer
* sk: convolution kernel
* offset: offset on the ring buffer, can be
* nx: length of the ring buffer
* nk: length of the convolution kernel
* sx: ring buffer
* sk: convolution kernel
* offset: offset on the ring buffer, can be
*/
static float conv(const int nx, const int nk, const float *sx, const float *sk,
const int offset)
const int offset)
{
/* k = reminder of offset / nx */
int k = offset >= 0 ? offset % nx : nx + (offset % nx);
if(nk + k <= nx)
return af_filter_fir(nk, sx + k, sk);
return af_filter_fir(nk, sx + k, sk);
else
return af_filter_fir(nk + k - nx, sx, sk + nx - k) +
af_filter_fir(nx - k, sx + k, sk);
return af_filter_fir(nk + k - nx, sx, sk + nx - k) +
af_filter_fir(nx - k, sx + k, sk);
}
/* Detect when the impulse response starts (significantly) */
@@ -104,8 +104,8 @@ static int pulse_detect(const float *sx)
int i;
for(i = 0; i < nmax; i++)
if(fabs(sx[i]) > thresh)
return i;
if(fabs(sx[i]) > thresh)
return i;
return 0;
}
@@ -122,14 +122,14 @@ static inline float passive_lock(float x)
/* Unified active matrix decoder for 2 channel matrix encoded surround
sources */
static inline void matrix_decode(short *in, const int k, const int il,
const int ir, const int decode_rear,
const int dlbuflen,
float l_fwr, float r_fwr,
float lpr_fwr, float lmr_fwr,
float *adapt_l_gain, float *adapt_r_gain,
float *adapt_lpr_gain, float *adapt_lmr_gain,
float *lf, float *rf, float *lr,
float *rr, float *cf)
const int ir, const int decode_rear,
const int dlbuflen,
float l_fwr, float r_fwr,
float lpr_fwr, float lmr_fwr,
float *adapt_l_gain, float *adapt_r_gain,
float *adapt_lpr_gain, float *adapt_lmr_gain,
float *lf, float *rf, float *lr,
float *rr, float *cf)
{
const int kr = (k + MATREARDELAY) % dlbuflen;
float l_gain = (l_fwr + r_fwr) /
@@ -161,13 +161,13 @@ static inline void matrix_decode(short *in, const int k, const int il,
fp_out = fopen("af_hrtf.log", "w");
if(counter % 240 == 0)
fprintf(fp_out, "%g %g %g %g %g ", counter * (1.0 / 48000),
l_gain, r_gain, lpr_gain, lmr_gain);
l_gain, r_gain, lpr_gain, lmr_gain);
#endif
/*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
/* AGC adaption */
d_gain = (fabs(l_gain - *adapt_l_gain) +
fabs(r_gain - *adapt_r_gain)) * 0.5;
fabs(r_gain - *adapt_r_gain)) * 0.5;
f = d_gain * (1.0 / MATAGCTRIG);
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
*adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
@@ -179,12 +179,12 @@ static inline void matrix_decode(short *in, const int k, const int il,
if(decode_rear) {
lr[kr] = rr[kr] = (l_agc - r_agc) * M_SQRT1_2;
/* Stereo rear channel is steered with the same AGC steering as
the decoding matrix. Note this requires a fast updating AGC
at the order of 20 ms (which is the case here). */
the decoding matrix. Note this requires a fast updating AGC
at the order of 20 ms (which is the case here). */
lr[kr] *= (l_fwr + l_fwr) /
(1 + l_fwr + r_fwr);
(1 + l_fwr + r_fwr);
rr[kr] *= (r_fwr + r_fwr) /
(1 + l_fwr + r_fwr);
(1 + l_fwr + r_fwr);
}
/*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
@@ -221,9 +221,9 @@ static inline void matrix_decode(short *in, const int k, const int il,
#if 0
if(counter % 240 == 0)
fprintf(fp_out, "%g %g %g %g %g\n",
*adapt_l_gain, *adapt_r_gain,
*adapt_lpr_gain, *adapt_lmr_gain,
c_gain);
*adapt_l_gain, *adapt_r_gain,
*adapt_lpr_gain, *adapt_lmr_gain,
c_gain);
counter++;
#endif
}
@@ -237,18 +237,18 @@ static inline void update_ch(af_hrtf_t *s, short *in, const int k)
s->l_fwr += abs(in[0]) - fabs(s->fwrbuf_l[fwr_pos]);
s->r_fwr += abs(in[1]) - fabs(s->fwrbuf_r[fwr_pos]);
s->lpr_fwr += abs(in[0] + in[1]) -
fabs(s->fwrbuf_l[fwr_pos] + s->fwrbuf_r[fwr_pos]);
fabs(s->fwrbuf_l[fwr_pos] + s->fwrbuf_r[fwr_pos]);
s->lmr_fwr += abs(in[0] - in[1]) -
fabs(s->fwrbuf_l[fwr_pos] - s->fwrbuf_r[fwr_pos]);
fabs(s->fwrbuf_l[fwr_pos] - s->fwrbuf_r[fwr_pos]);
}
/* Rear matrix decoder */
if(s->matrix_mode) {
s->lr_fwr += abs(in[2]) - fabs(s->fwrbuf_lr[fwr_pos]);
s->rr_fwr += abs(in[3]) - fabs(s->fwrbuf_rr[fwr_pos]);
s->lrprr_fwr += abs(in[2] + in[3]) -
fabs(s->fwrbuf_lr[fwr_pos] + s->fwrbuf_rr[fwr_pos]);
fabs(s->fwrbuf_lr[fwr_pos] + s->fwrbuf_rr[fwr_pos]);
s->lrmrr_fwr += abs(in[2] - in[3]) -
fabs(s->fwrbuf_lr[fwr_pos] - s->fwrbuf_rr[fwr_pos]);
fabs(s->fwrbuf_lr[fwr_pos] - s->fwrbuf_rr[fwr_pos]);
}
switch (s->decode_mode) {
@@ -265,11 +265,11 @@ static inline void update_ch(af_hrtf_t *s, short *in, const int k)
s->fwrbuf_l[k] = in[0];
s->fwrbuf_r[k] = in[1];
matrix_decode(in, k, 0, 1, 1, s->dlbuflen,
s->l_fwr, s->r_fwr,
s->lpr_fwr, s->lmr_fwr,
&(s->adapt_l_gain), &(s->adapt_r_gain),
&(s->adapt_lpr_gain), &(s->adapt_lmr_gain),
s->lf, s->rf, s->lr, s->rr, s->cf);
s->l_fwr, s->r_fwr,
s->lpr_fwr, s->lmr_fwr,
&(s->adapt_l_gain), &(s->adapt_r_gain),
&(s->adapt_lpr_gain), &(s->adapt_lmr_gain),
s->lf, s->rf, s->lr, s->rr, s->cf);
break;
case HRTF_MIX_STEREO:
/* Stereo sources */
@@ -284,27 +284,6 @@ static inline void update_ch(af_hrtf_t *s, short *in, const int k)
s->ba_r[k] = in[4] + in[1] + in[3];
}
static void clear_coeff(af_hrtf_t *s, float *c)
{
memset(c, 0, s->dlbuflen * sizeof(float));
}
static void reset(af_hrtf_t *s)
{
clear_coeff(s, s->lf);
clear_coeff(s, s->rf);
clear_coeff(s, s->lr);
clear_coeff(s, s->rr);
clear_coeff(s, s->cf);
clear_coeff(s, s->cr);
clear_coeff(s, s->ba_l);
clear_coeff(s, s->ba_r);
clear_coeff(s, s->fwrbuf_l);
clear_coeff(s, s->fwrbuf_r);
clear_coeff(s, s->fwrbuf_lr);
clear_coeff(s, s->fwrbuf_rr);
}
/* Initialization and runtime control */
static int control(struct af_instance *af, int cmd, void* arg)
{
@@ -313,27 +292,30 @@ static int control(struct af_instance *af, int cmd, void* arg)
switch(cmd) {
case AF_CONTROL_REINIT:
reset(s);
af->data->rate = 48000;
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
/* Default behavior is stereo mixing. */
s->decode_mode = HRTF_MIX_STEREO;
}
} else if (af->data->nch < 5) {
mp_audio_set_channels_old(af->data, 5);
}
af->data->rate = ((struct mp_audio*)arg)->rate;
if(af->data->rate != 48000) {
// automatic samplerate adjustment in the filter chain
// is not yet supported.
MP_ERR(af, "[hrtf] ERROR: Sampling rate is not 48000 Hz (%d)!\n",
af->data->rate);
return AF_ERROR;
}
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
/* Default behavior is stereo mixing. */
s->decode_mode = HRTF_MIX_STEREO;
}
}
else if (af->data->nch < 5)
mp_audio_set_channels_old(af->data, 5);
mp_audio_set_format(af->data, AF_FORMAT_S16);
test_output_res = af_test_output(af, (struct mp_audio*)arg);
// after testing input set the real output format
test_output_res = af_test_output(af, (struct mp_audio*)arg);
// after testing input set the real output format
mp_audio_set_num_channels(af->data, 2);
s->print_flag = 1;
return test_output_res;
case AF_CONTROL_RESET:
reset(s);
return AF_OK;
s->print_flag = 1;
return test_output_res;
}
return AF_UNKNOWN;
@@ -342,21 +324,21 @@ static int control(struct af_instance *af, int cmd, void* arg)
/* Deallocate memory */
static void uninit(struct af_instance *af)
{
af_hrtf_t *s = af->priv;
af_hrtf_t *s = af->priv;
free(s->lf);
free(s->rf);
free(s->lr);
free(s->rr);
free(s->cf);
free(s->cr);
free(s->ba_l);
free(s->ba_r);
free(s->ba_ir);
free(s->fwrbuf_l);
free(s->fwrbuf_r);
free(s->fwrbuf_lr);
free(s->fwrbuf_rr);
free(s->lf);
free(s->rf);
free(s->lr);
free(s->rr);
free(s->cf);
free(s->cr);
free(s->ba_l);
free(s->ba_r);
free(s->ba_ir);
free(s->fwrbuf_l);
free(s->fwrbuf_r);
free(s->fwrbuf_lr);
free(s->fwrbuf_rr);
}
/* Filter data through filter
@@ -382,29 +364,29 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
mp_audio_realloc_min(af->data, data->samples);
if(s->print_flag) {
s->print_flag = 0;
switch (s->decode_mode) {
case HRTF_MIX_51:
MP_INFO(af, "Using HRTF to mix %s discrete surround into "
"L, R channels\n", s->matrix_mode ? "5+1" : "5");
break;
case HRTF_MIX_STEREO:
MP_INFO(af, "Using HRTF to mix stereo into "
"L, R channels\n");
break;
case HRTF_MIX_MATRIX2CH:
MP_INFO(af, "Using active matrix to decode 2 channel "
"input, HRTF to mix %s matrix surround into "
"L, R channels\n", "3/2");
break;
default:
MP_WARN(af, "bogus decode_mode: %d\n", s->decode_mode);
break;
}
s->print_flag = 0;
switch (s->decode_mode) {
case HRTF_MIX_51:
MP_INFO(af, "[hrtf] Using HRTF to mix %s discrete surround into "
"L, R channels\n", s->matrix_mode ? "5+1" : "5");
break;
case HRTF_MIX_STEREO:
MP_INFO(af, "[hrtf] Using HRTF to mix stereo into "
"L, R channels\n");
break;
case HRTF_MIX_MATRIX2CH:
MP_INFO(af, "[hrtf] Using active matrix to decode 2 channel "
"input, HRTF to mix %s matrix surround into "
"L, R channels\n", "3/2");
break;
default:
MP_WARN(af, "[hrtf] bogus decode_mode: %d\n", s->decode_mode);
break;
}
if(s->matrix_mode)
MP_INFO(af, "Using active matrix to decode rear center "
"channel\n");
MP_INFO(af, "[hrtf] Using active matrix to decode rear center "
"channel\n");
}
out = af->data->planes[0];
@@ -428,122 +410,122 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
*/
while(in < end) {
const int k = s->cyc_pos;
const int k = s->cyc_pos;
update_ch(s, in, k);
update_ch(s, in, k);
/* Simulate a 7.5 ms -20 dB echo of the center channel in the
front channels (like reflection from a room wall) - a kind of
psycho-acoustically "cheating" to focus the center front
channel, which is normally hard to be perceived as front */
s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
/* Simulate a 7.5 ms -20 dB echo of the center channel in the
front channels (like reflection from a room wall) - a kind of
psycho-acoustically "cheating" to focus the center front
channel, which is normally hard to be perceived as front */
s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
switch (s->decode_mode) {
case HRTF_MIX_51:
case HRTF_MIX_MATRIX2CH:
/* Mixer filter matrix */
common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
if(s->matrix_mode) {
/* In matrix decoding mode, the rear channel gain must be
renormalized, as there is an additional channel. */
matrix_decode(in, k, 2, 3, 0, s->dlbuflen,
s->lr_fwr, s->rr_fwr,
s->lrprr_fwr, s->lrmrr_fwr,
&(s->adapt_lr_gain), &(s->adapt_rr_gain),
&(s->adapt_lrprr_gain), &(s->adapt_lrmrr_gain),
s->lr, s->rr, NULL, NULL, s->cr);
common +=
conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
M1_76DB;
left =
( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
(conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
M1_76DB + common);
right =
( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
(conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
M1_76DB + common);
} else {
left =
( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
common);
right =
( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
common);
}
break;
case HRTF_MIX_STEREO:
left =
( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o));
right =
( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o));
break;
default:
/* make gcc happy */
left = 0.0;
right = 0.0;
break;
}
switch (s->decode_mode) {
case HRTF_MIX_51:
case HRTF_MIX_MATRIX2CH:
/* Mixer filter matrix */
common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
if(s->matrix_mode) {
/* In matrix decoding mode, the rear channel gain must be
renormalized, as there is an additional channel. */
matrix_decode(in, k, 2, 3, 0, s->dlbuflen,
s->lr_fwr, s->rr_fwr,
s->lrprr_fwr, s->lrmrr_fwr,
&(s->adapt_lr_gain), &(s->adapt_rr_gain),
&(s->adapt_lrprr_gain), &(s->adapt_lrmrr_gain),
s->lr, s->rr, NULL, NULL, s->cr);
common +=
conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
M1_76DB;
left =
( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
(conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
M1_76DB + common);
right =
( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
(conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
M1_76DB + common);
} else {
left =
( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
common);
right =
( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
common);
}
break;
case HRTF_MIX_STEREO:
left =
( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o));
right =
( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o));
break;
default:
/* make gcc happy */
left = 0.0;
right = 0.0;
break;
}
/* Bass compensation for the lower frequency cut of the HRTF. A
cross talk of the left and right channel is introduced to
match the directional characteristics of higher frequencies.
The bass will not have any real 3D perception, but that is
OK (note at 180 Hz, the wavelength is about 2 m, and any
spatial perception is impossible). */
left_b = conv(dblen, blen, s->ba_l, s->ba_ir, k);
right_b = conv(dblen, blen, s->ba_r, s->ba_ir, k);
left += (1 - BASSCROSS) * left_b + BASSCROSS * right_b;
right += (1 - BASSCROSS) * right_b + BASSCROSS * left_b;
/* Also mix the LFE channel (if available) */
if(data->nch >= 6) {
left += in[5] * M3_01DB;
right += in[5] * M3_01DB;
}
/* Bass compensation for the lower frequency cut of the HRTF. A
cross talk of the left and right channel is introduced to
match the directional characteristics of higher frequencies.
The bass will not have any real 3D perception, but that is
OK (note at 180 Hz, the wavelength is about 2 m, and any
spatial perception is impossible). */
left_b = conv(dblen, blen, s->ba_l, s->ba_ir, k);
right_b = conv(dblen, blen, s->ba_r, s->ba_ir, k);
left += (1 - BASSCROSS) * left_b + BASSCROSS * right_b;
right += (1 - BASSCROSS) * right_b + BASSCROSS * left_b;
/* Also mix the LFE channel (if available) */
if(data->nch >= 6) {
left += in[5] * M3_01DB;
right += in[5] * M3_01DB;
}
/* Amplitude renormalization. */
left *= AMPLNORM;
right *= AMPLNORM;
/* Amplitude renormalization. */
left *= AMPLNORM;
right *= AMPLNORM;
switch (s->decode_mode) {
case HRTF_MIX_51:
case HRTF_MIX_STEREO:
/* "Cheating": linear stereo expansion to amplify the 3D
perception. Note: Too much will destroy the acoustic space
and may even result in headaches. */
diff = STEXPAND2 * (left - right);
out[0] = av_clip_int16(left + diff);
out[1] = av_clip_int16(right - diff);
break;
case HRTF_MIX_MATRIX2CH:
/* Do attempt any stereo expansion with matrix encoded
sources. The L, R channels are already stereo expanded
by the steering, any further stereo expansion will sound
very unnatural. */
out[0] = av_clip_int16(left);
out[1] = av_clip_int16(right);
break;
}
switch (s->decode_mode) {
case HRTF_MIX_51:
case HRTF_MIX_STEREO:
/* "Cheating": linear stereo expansion to amplify the 3D
perception. Note: Too much will destroy the acoustic space
and may even result in headaches. */
diff = STEXPAND2 * (left - right);
out[0] = av_clip_int16(left + diff);
out[1] = av_clip_int16(right - diff);
break;
case HRTF_MIX_MATRIX2CH:
/* Do attempt any stereo expansion with matrix encoded
sources. The L, R channels are already stereo expanded
by the steering, any further stereo expansion will sound
very unnatural. */
out[0] = av_clip_int16(left);
out[1] = av_clip_int16(right);
break;
}
/* Next sample... */
in = &in[data->nch];
out = &out[af->data->nch];
(s->cyc_pos)--;
if(s->cyc_pos < 0)
s->cyc_pos += dblen;
/* Next sample... */
in = &in[data->nch];
out = &out[af->data->nch];
(s->cyc_pos)--;
if(s->cyc_pos < 0)
s->cyc_pos += dblen;
}
/* Set output data */
@@ -564,13 +546,13 @@ static int allocate(af_hrtf_t *s)
if ((s->ba_l = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
if ((s->ba_r = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
if ((s->fwrbuf_l =
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
if ((s->fwrbuf_r =
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
if ((s->fwrbuf_lr =
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
if ((s->fwrbuf_rr =
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
return 0;
}
@@ -613,16 +595,16 @@ static int af_open(struct af_instance* af)
s->print_flag = 1;
if (allocate(s) != 0) {
MP_ERR(af, "Memory allocation error.\n");
return AF_ERROR;
MP_ERR(af, "[hrtf] Memory allocation error.\n");
return AF_ERROR;
}
for(i = 0; i < s->dlbuflen; i++)
s->lf[i] = s->rf[i] = s->lr[i] = s->rr[i] = s->cf[i] =
s->cr[i] = 0;
s->lf[i] = s->rf[i] = s->lr[i] = s->rr[i] = s->cf[i] =
s->cr[i] = 0;
s->lr_fwr =
s->rr_fwr = 0;
s->rr_fwr = 0;
s->cf_ir = cf_filt + (s->cf_o = pulse_detect(cf_filt));
s->af_ir = af_filt + (s->af_o = pulse_detect(af_filt));
@@ -632,24 +614,24 @@ static int af_open(struct af_instance* af)
s->cr_ir = cr_filt + (s->cr_o = pulse_detect(cr_filt));
if((s->ba_ir = malloc(s->basslen * sizeof(float))) == NULL) {
MP_ERR(af, "Memory allocation error.\n");
return AF_ERROR;
MP_ERR(af, "[hrtf] Memory allocation error.\n");
return AF_ERROR;
}
fc = 2.0 * BASSFILTFREQ / (float)af->data->rate;
if(af_filter_design_fir(s->basslen, s->ba_ir, &fc, LP | KAISER, 4 * M_PI) ==
-1) {
MP_ERR(af, "Unable to design low-pass "
"filter.\n");
return AF_ERROR;
MP_ERR(af, "[hrtf] Unable to design low-pass "
"filter.\n");
return AF_ERROR;
}
for(i = 0; i < s->basslen; i++)
s->ba_ir[i] *= BASSGAIN;
s->ba_ir[i] *= BASSGAIN;
return AF_OK;
}
#define OPT_BASE_STRUCT af_hrtf_t
const struct af_info af_info_hrtf = {
struct af_info af_info_hrtf = {
.info = "HRTF Headphone",
.name = "hrtf",
.open = af_open,
+25 -25
View File
@@ -24,38 +24,38 @@
#define HRTF_MIX_MATRIX2CH 2
/* Amplitude scaling factors */
#define M17_0DB 0.1414213562
#define M9_03DB 0.3535533906
#define M6_99DB 0.4472135955
#define M4_77DB 0.5773502692
#define M3_01DB 0.7071067812
#define M1_76DB 0.8164965809
#define M17_0DB 0.1414213562
#define M9_03DB 0.3535533906
#define M6_99DB 0.4472135955
#define M4_77DB 0.5773502692
#define M3_01DB 0.7071067812
#define M1_76DB 0.8164965809
#define DELAYBUFLEN 1024 /* Length of the delay buffer */
#define HRTFFILTLEN 64 /* HRTF filter length */
#define IRTHRESH 0.001 /* Impulse response pruning thresh. */
#define DELAYBUFLEN 1024 /* Length of the delay buffer */
#define HRTFFILTLEN 64 /* HRTF filter length */
#define IRTHRESH 0.001 /* Impulse response pruning thresh. */
#define AMPLNORM M6_99DB /* Overall amplitude renormalization */
#define AMPLNORM M6_99DB /* Overall amplitude renormalization */
#define BASSFILTFREQ 180 /* Bass compensation filter cut (Hz) */
#define BASSFILTLEN 193 /* Bass compensation filter length */
#define BASSGAIN M_SQRT2 /* Bass compensation gain */
#define BASSCROSS 0.35 /* Bass cross talk */
#define BASSFILTFREQ 180 /* Bass compensation filter cut (Hz) */
#define BASSFILTLEN 193 /* Bass compensation filter length */
#define BASSGAIN M_SQRT2 /* Bass compensation gain */
#define BASSCROSS 0.35 /* Bass cross talk */
#define FWRDURATION 240 /* FWR average duration (samples) */
#define MATREARDELAY 720 /* Matrix mode rear delay (samples) */
#define FWRDURATION 240 /* FWR average duration (samples) */
#define MATREARDELAY 720 /* Matrix mode rear delay (samples) */
#define MATAGCTRIG 8.0 /* (Fuzzy) AGC trigger */
#define MATAGCDECAY 1.0 /* AGC baseline decay rate (1/samp.) */
#define MATAGCLOCK 0.2 /* AGC range (around 1) where the
matrix behaves passively */
#define MATCOMPGAIN 0.37 /* Cross talk compensation gain,
0.50 - 0.55 is full cancellation. */
#define MATAGCTRIG 8.0 /* (Fuzzy) AGC trigger */
#define MATAGCDECAY 1.0 /* AGC baseline decay rate (1/samp.) */
#define MATAGCLOCK 0.2 /* AGC range (around 1) where the
matrix behaves passively */
#define MATCOMPGAIN 0.37 /* Cross talk compensation gain,
0.50 - 0.55 is full cancellation. */
#define CFECHODELAY 360 /* Center front echo delay (samples) */
#define CFECHOAMPL M17_0DB /* Center front echo amplitude */
#define CFECHODELAY 360 /* Center front echo delay (samples) */
#define CFECHOAMPL M17_0DB /* Center front echo amplitude */
#define STEXPAND2 0.07 /* Stereo expansion / 2 */
#define STEXPAND2 0.07 /* Stereo expansion / 2 */
/* Head related impulse response (HRIR) derived from KEMAR measurement
data by Bill Gardner <billg@media.mit.edu> and Keith Martin
+29 -29
View File
@@ -32,50 +32,50 @@
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:
switch(cmd){
case AF_CONTROL_REINIT:
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
return af_test_output(af,(struct mp_audio*)arg);
}
return AF_UNKNOWN;
return af_test_output(af,(struct mp_audio*)arg);
}
return AF_UNKNOWN;
}
// Filter data through filter
static int play(struct af_instance* af, struct mp_audio* data, int flags)
{
struct mp_audio* c = data; // Current working data
float* a = c->planes[0]; // Audio data
int nch = c->nch; // Number of channels
int len = c->samples*nch; // Number of samples in current audio block
register int i;
struct mp_audio* c = data; // Current working data
float* a = c->planes[0]; // Audio data
int nch = c->nch; // Number of channels
int len = c->samples*nch; // Number of samples in current audio block
register int i;
/*
FIXME1 add a low band pass filter to avoid suppressing
centered bass/drums
FIXME2 better calculated* attenuation factor
*/
/*
FIXME1 add a low band pass filter to avoid suppressing
centered bass/drums
FIXME2 better calculated* attenuation factor
*/
for(i=0;i<len;i+=nch)
{
a[i] = (a[i] - a[i+1]) * 0.7;
a[i+1]=a[i];
}
for(i=0;i<len;i+=nch)
{
a[i] = (a[i] - a[i+1]) * 0.7;
a[i+1]=a[i];
}
return 0;
return 0;
}
// Allocate memory and set function pointers
static int af_open(struct af_instance* af){
af->control = control;
af->filter = play;
return AF_OK;
af->control = control;
af->filter = play;
return AF_OK;
}
// Description of this filter
const struct af_info af_info_karaoke = {
.info = "Simple karaoke/voice-removal audio filter",
.name = "karaoke",
.flags = AF_FLAGS_NOT_REENTRANT,
.open = af_open,
struct af_info af_info_karaoke = {
.info = "Simple karaoke/voice-removal audio filter",
.name = "karaoke",
.flags = AF_FLAGS_NOT_REENTRANT,
.open = af_open,
};
Loaded 100 of 554 files, more files were not shown because too many files have changed in this diff. Show more