Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
463b877ec0 | ||
|
|
72c81aa111 | ||
|
|
9f7c014930 | ||
|
|
97eddff865 | ||
|
|
cf880b9070 | ||
|
|
3478575419 | ||
|
|
88a53309cd | ||
|
|
da76eb9f14 | ||
|
|
df6901b653 | ||
|
|
53e4ba26b5 | ||
|
|
f10a3cac0f | ||
|
|
7370ad2120 | ||
|
|
ed2d819ea5 | ||
|
|
4f728cfb99 |
No files matched your search
+3
-17
@@ -2,7 +2,6 @@
|
||||
*.a
|
||||
*.d
|
||||
*.exe
|
||||
*.pyc
|
||||
.depend
|
||||
|
||||
/config.h
|
||||
@@ -11,26 +10,13 @@
|
||||
/mpv
|
||||
/mpv.app
|
||||
/version.h
|
||||
/input/input_conf.h
|
||||
/mpvcore/input/input_conf.h
|
||||
/tags
|
||||
/TAGS
|
||||
/video/out/gl_video_shaders.h
|
||||
/video/out/x11_icon.inc
|
||||
/video/out/vdpau_template.c
|
||||
/demux/ebml_defs.c
|
||||
/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
|
||||
|
||||
/waf
|
||||
/build
|
||||
/.waf*
|
||||
/.lock-waf_*
|
||||
|
||||
/old_build
|
||||
/Makefile
|
||||
+10
-20
@@ -1,8 +1,5 @@
|
||||
language: c
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
env:
|
||||
- LIBAV=libav-stable
|
||||
- LIBAV=libav-git
|
||||
@@ -10,31 +7,24 @@ env:
|
||||
- LIBAV=ffmpeg-git
|
||||
compiler:
|
||||
- clang
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- ci
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: LIBAV=libav-stable
|
||||
- os: osx
|
||||
env: LIBAV=libav-git
|
||||
- os: osx
|
||||
env: LIBAV=ffmpeg-git
|
||||
|
||||
before_install: ./travis-deps libass-stable $LIBAV
|
||||
script:
|
||||
- ./bootstrap.py
|
||||
- ./waf configure
|
||||
- ./waf build
|
||||
script: ./configure && make
|
||||
|
||||
notifications-policy: ¬ifications-policy
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
email:
|
||||
recipients:
|
||||
- mpv-team@googlegroups.com
|
||||
<<: *notifications-policy
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#mpv-player-dev"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
<<: *notifications-policy
|
||||
@@ -1,19 +1,35 @@
|
||||
mpv is a fork of mplayer2, which is a fork of MPlayer.
|
||||
Original MPlayer Copyright file follows below.
|
||||
|
||||
mpv as a whole is licensed as GPL version 2 or later (see LICENSE). Most source
|
||||
files are GPLv2+, but some files are available under a more liberal license,
|
||||
such as LGPLv2+, BSD, MIT, ISC, and possibly others. Look at the copyright
|
||||
header of each source file, and grep the sources for "Copyright" if you need
|
||||
to know details. Files without Copyright notice are licensed as LGPLv2+.
|
||||
MPlayer was originally written by Árpád Gereöffy and has been extended and
|
||||
worked on by many more since then, see the AUTHORS file for an (incomplete)
|
||||
list. MPlayer as a whole is copyrighted by the MPlayer team. Individual
|
||||
copyright notices can be found in file headers.
|
||||
|
||||
For information about authors and contributors, consult the git log, which
|
||||
contains the complete SVN and CVS history as well.
|
||||
Most files in MPlayer are licensed under the GNU General Public License,
|
||||
version 2 with an explicit "or later" clause or a compatible license
|
||||
(LGPL 2.1+, MIT/BSD). An exception are the files talloc.c and talloc.h,
|
||||
which are LGPL 3+.
|
||||
Thus MPlayer as a whole can be redistributed under terms compatible with
|
||||
the GNU General Public License, version 3; see the LICENSE file for details.
|
||||
|
||||
Note that mplayer2 as a whole is licensed under GPLv3+. This is because it uses
|
||||
a copy of talloc (part of Samba), which is LGPLv3+, and the next compatible
|
||||
license for this mix is GPLv3+.
|
||||
MPlayer includes code from several external sources. General information and
|
||||
license details are listed below:
|
||||
|
||||
MPlayer as a whole is licensed under GPLv2 (incompatible to GPLv3!), because
|
||||
some files are licensed to GPLv2 (and _not_ any later version of the license).
|
||||
In particular, this affects the file libmpdemux/demux_ty_osd.c. It is disabled
|
||||
under mplayer2, and has been removed from mpv.
|
||||
Name: a couple of files copied from FFmpeg
|
||||
Version: updated to different versions
|
||||
URL: http://www.ffmpeg.org
|
||||
Directory: compat/x86_cpu.h
|
||||
Copyright: Many, see individual files for copyright notices.
|
||||
License: GNU Lesser General Public License
|
||||
|
||||
|
||||
Name: dvbstream
|
||||
Version: 0.4.3-pre3 (CVS checkout)
|
||||
URL: http://sourceforge.net/projects/dvbtools/
|
||||
Directory: stream/dvbin.h stream/stream_dvb.c
|
||||
Copyright: 2001-2002 Dave Chapman <dave@dchapman.com>
|
||||
License: GNU General Public License
|
||||
|
||||
|
||||
This is not a complete list. grep the sources for "Copyright".
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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().
|
||||
@@ -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.
|
||||
@@ -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!
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,42 +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.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
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
// License: pick one of: public domain, WTFPL, ISC, Ms-PL, AGPLv3
|
||||
|
||||
// This example can be built with: qmake && make
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QStatusBar>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
#include <QGridLayout>
|
||||
#include <QApplication>
|
||||
|
||||
#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)
|
||||
{
|
||||
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();
|
||||
|
||||
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. This doesn't work on OSX,
|
||||
// because Cocoa doesn't support this form of embedding.
|
||||
mpv_container = new QWidget(this);
|
||||
setCentralWidget(mpv_container);
|
||||
mpv_container->setAttribute(Qt::WA_NativeWindow);
|
||||
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");
|
||||
|
||||
// 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);
|
||||
|
||||
// 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("");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
if (mpv)
|
||||
mpv_terminate_destroy(mpv);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef QTEXAMPLE_H
|
||||
#define QTEXAMPLE_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <mpv/client.h>
|
||||
|
||||
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;
|
||||
|
||||
void create_player();
|
||||
void handle_mpv_event(mpv_event *event);
|
||||
};
|
||||
|
||||
#endif // QTEXAMPLE_H
|
||||
@@ -1,12 +0,0 @@
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = qtexample
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG = mpv
|
||||
|
||||
SOURCES += qtexample.cpp
|
||||
HEADERS += qtexample.h
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +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"));
|
||||
int val = 1;
|
||||
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
|
||||
|
||||
// Done setting up options.
|
||||
check_error(mpv_initialize(ctx));
|
||||
|
||||
// Play this file.
|
||||
const char *cmd[] = {"loadfile", argv[1], NULL};
|
||||
check_error(mpv_command(ctx, cmd));
|
||||
|
||||
// Let it play, and wait until the user quits.
|
||||
while (1) {
|
||||
mpv_event *event = mpv_wait_event(ctx, 10000);
|
||||
printf("event: %s\n", mpv_event_name(event->event_id));
|
||||
if (event->event_id == MPV_EVENT_SHUTDOWN)
|
||||
break;
|
||||
}
|
||||
|
||||
mpv_terminate_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,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.
|
||||
@@ -1,74 +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.
|
||||
|
||||
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
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
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:
|
||||
./configure --enable-cross-compile --target=i686-w64-mingw32
|
||||
|
||||
Using MXE to setup a MinGW-w64 environment is recommended: http://mxe.cc
|
||||
Currently, using an experimental branch of MXE is required:
|
||||
https://github.com/tonytheodore/mxe.git
|
||||
|
||||
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! We are using an experimental repository, which supports MinGW-w64.
|
||||
# The official MXE supports classic MinGW only, which doesn't work with mpv.
|
||||
|
||||
cd /opt
|
||||
git clone https://github.com/tonytheodore/mxe.git 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
|
||||
|
||||
# Older MXE and MinGW-w64 snapshots don't provide up-to-date OpenGL headers.
|
||||
|
||||
wget http://www.opengl.org/registry/api/glext.h
|
||||
mv glext.h usr/i686-w64-mingw32/include/GL/
|
||||
|
||||
# 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
|
||||
./configure --enable-cross-compile --target=i686-w64-mingw32
|
||||
make
|
||||
|
||||
# This should work. For some reason, the resulting .exe will depend on the DLL
|
||||
# /opt/mingw/usr/i686-w64-mingw32/bin/libwinpthread-1.dll because pthreads-w32
|
||||
# folks don't like static linking. How to enable static linking is left as
|
||||
# exercise to the reader. Passsing --disable-pthreads to mpv's configure will
|
||||
# get rid of the dependency, but may disable some features (such as the stream
|
||||
# cache).
|
||||
@@ -1,121 +0,0 @@
|
||||
EDL files
|
||||
=========
|
||||
|
||||
EDL files basically concatenate ranges of video/audio from multiple source
|
||||
files into a single continuous virtual file. Each such range is called a
|
||||
segment, and consists of source file, source offset, and segment length.
|
||||
|
||||
For example::
|
||||
|
||||
# mpv EDL v0
|
||||
f1.mkv,10,20
|
||||
f2.mkv
|
||||
f1.mkv,40,10
|
||||
|
||||
This would skip the first 10 seconds of the file f1.mkv, then play the next
|
||||
20 seconds, then switch to the file f2.mkv and play all of it, then switch
|
||||
back to f1.mkv, skip to the 40 second mark, and play 10 seconds, and then
|
||||
stop playback. The difference to specifying the files directly on command
|
||||
line (and using ``--{ --start=10 --length=20 f1.mkv --}`` etc.) is that the
|
||||
virtual EDL file appears as a virtual timeline (like a single file), instead
|
||||
as a playlist.
|
||||
|
||||
The general simplified syntax is::
|
||||
|
||||
# mpv EDL v0
|
||||
<filename>
|
||||
<filename>,<start in seconds>,<length in seconds>
|
||||
|
||||
If the start time is omitted, 0 is used. If the length is omitted, the
|
||||
estimated duration of the source file is used.
|
||||
|
||||
Note::
|
||||
|
||||
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
|
||||
=======================
|
||||
|
||||
Generally, the format is relatively strict. No superfluous whitespace (except
|
||||
empty lines and commented lines) are allowed. You must use UNIX line breaks.
|
||||
|
||||
The first line in the file must be ``# mpv EDL v0``. This designates that the
|
||||
file uses format version 0, which is not frozen yet and may change any time.
|
||||
(If you need a stable EDL file format, make a feature request. Likewise, if
|
||||
you have suggestions for improvements, it's not too late yet.)
|
||||
|
||||
The rest of the lines belong to one of these classes:
|
||||
|
||||
1) An empty or commented line. A comment starts with ``#``, which must be the
|
||||
first character in the line. The rest of the line (up until the next line
|
||||
break) is ignored. An empty line has 0 bytes between two line feed bytes.
|
||||
2) A segment entry in all other cases.
|
||||
|
||||
Each segment entry consists of a list of named or unnamed parameters.
|
||||
Parameters are separated with ``,``. Named parameters consist of a name,
|
||||
followed by ``=``, followed by the value. Unnamed parameters have only a
|
||||
value, and the name is implicit from the parameter position.
|
||||
|
||||
Syntax::
|
||||
|
||||
segment_entry ::= <param> ( <param> ',' )*
|
||||
param ::= [ <name> '=' ] ( <value> | '%' <number> '%' <valuebytes> )
|
||||
|
||||
The ``name`` string can consist of any characters, except ``=%,;\n``. The
|
||||
``value`` string can consist of any characters except of ``,;\n``.
|
||||
|
||||
The construct starting with ``%`` allows defining any value with arbitrary
|
||||
contents inline, where ``number`` is an integer giving the number of bytes in
|
||||
``valuebytes``. If a parameter value contains disallowed characters, it has to
|
||||
be guarded by a length specifier using this syntax.
|
||||
|
||||
The parameter name defines the meaning of the parameter:
|
||||
|
||||
1) ``file``, the source file to use for this segment.
|
||||
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.
|
||||
|
||||
Unnamed parameters carry implicit names. The parameter position determines
|
||||
which of the parameters listed above is set. For example, the second parameter
|
||||
implicitly uses the name ``start``.
|
||||
|
||||
Example::
|
||||
|
||||
# mpv EDL v0
|
||||
%18%filename,with,.mkv,10,length=20,param3=%13%value,escaped,param4=value2
|
||||
|
||||
this sets ``file`` to ``filename,with,.mkv``, ``start`` to ``10``, ``length``
|
||||
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
|
||||
==================
|
||||
|
||||
mpv accepts inline EDL data in form of ``edl://`` URIs. Other than the
|
||||
header, the syntax is exactly the same. It's far more convenient to use ``;``
|
||||
instead of line breaks, but that is orthogonal.
|
||||
|
||||
Example: ``edl://f1.mkv,length=5,start=10;f2.mkv,30,20;f3.mkv``
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
Format of mplayer2 EDL files
|
||||
============================
|
||||
|
||||
The first line in the file must be ``mplayer EDL file, version 2``.
|
||||
The rest of the lines belong to one of these classes:
|
||||
|
||||
1) lines specifying source files
|
||||
2) empty lines
|
||||
3) lines specifying timeline segments.
|
||||
|
||||
Lines beginning with ``<`` specify source files. These lines first
|
||||
contain an identifier used to refer to the source file later, then the
|
||||
filename separated by whitespace. The identifier must start with a
|
||||
letter. Filenames that start or end with whitespace or contain
|
||||
newlines are not supported.
|
||||
|
||||
On other lines ``#`` characters delimit comments. Lines that contain
|
||||
only whitespace after comments have been removed are ignored.
|
||||
|
||||
Timeline segments must appear in the file in chronological order. Each
|
||||
segment has the following information associated with it:
|
||||
|
||||
- duration
|
||||
- output start time
|
||||
- output end time (= output start time + duration)
|
||||
- source id (specifies the file the content of the segment comes from)
|
||||
- source start time (timestamp in the source file)
|
||||
- source end time (= source start time + duration)
|
||||
|
||||
The output timestamps must form a continuous timeline from 0 to the
|
||||
end of the last segment, such that each new segment starts from the
|
||||
time the previous one ends at. Source files and times may change
|
||||
arbitrarily between segments.
|
||||
|
||||
The general format for lines specifying timeline segments is
|
||||
[output time info] source_id [source time info]
|
||||
source_id must be an identifier defined on a ``<`` line. Both the time
|
||||
info parts consists of zero or more of the following elements:
|
||||
|
||||
1) ``timestamp``
|
||||
2) ``-timestamp``
|
||||
3) ``+duration``
|
||||
4) ``*``
|
||||
5) ``-*``
|
||||
|
||||
, where ``timestamp`` and ``duration`` are decimal numbers (computations
|
||||
are done with nanosecond precision). Whitespace around ``+`` and ``-`` is
|
||||
optional. 1) and 2) specify start and end time of the segment on
|
||||
output or source side. 3) specifies duration; the semantics are the
|
||||
same whether this appears on output or source side. 4) and 5) are
|
||||
ignored on the output side (they're always implicitly assumed). On the
|
||||
source side 4) specifies that the segment starts where the previous
|
||||
segment *using this source* ended; if there was no previous segment
|
||||
time 0 is used. 5) specifies that the segment ends where the next
|
||||
segment using this source starts.
|
||||
|
||||
Redundant information may be omitted. It will be filled in using the
|
||||
following rules:
|
||||
|
||||
- output start for first segment is 0
|
||||
- two of [output start, output end, duration] imply third
|
||||
- two of [source start, source end, duration] imply third
|
||||
- output start = output end of previous segment
|
||||
- output end = output start of next segment
|
||||
- if ``*``, source start = source end of earlier segment
|
||||
- if ``-*``, source end = source start of a later segment
|
||||
|
||||
As a special rule, a last zero-duration segment without a source
|
||||
specification may appear. This will produce no corresponding segment
|
||||
in the resulting timeline, but can be used as syntax to specify the
|
||||
end time of the timeline (with effect equal to adding -time on the
|
||||
previous line).
|
||||
|
||||
Examples::
|
||||
|
||||
mplayer EDL file, version 2
|
||||
< id1 filename
|
||||
|
||||
0 id1 123
|
||||
100 id1 456
|
||||
200 id1 789
|
||||
300
|
||||
|
||||
All segments come from the source file ``filename``. First segment
|
||||
(output time 0-100) comes from time 123-223, second 456-556, third
|
||||
789-889.
|
||||
|
||||
::
|
||||
|
||||
mplayer EDL file, version 2
|
||||
< f filename
|
||||
f 60-120
|
||||
f 600-660
|
||||
f 30- 90
|
||||
|
||||
Play first seconds 60-120 from the file, then 600-660, then 30-90.
|
||||
|
||||
::
|
||||
|
||||
mplayer EDL file, version 2
|
||||
< id1 filename1
|
||||
< id2 filename2
|
||||
|
||||
+10 id1 *
|
||||
+10 id2 *
|
||||
+10 id1 *
|
||||
+10 id2 *
|
||||
+10 id1 *
|
||||
+10 id2 *
|
||||
|
||||
This plays time 0-10 from filename1, then 0-10 from filename1, then
|
||||
10-20 from filename1, then 10-20 from filename2, then 20-30 from
|
||||
filename1, then 20-30 from filename2.
|
||||
|
||||
::
|
||||
|
||||
mplayer EDL file, version 2
|
||||
< t1 filename1
|
||||
< t2 filename2
|
||||
|
||||
t1 * +2 # segment 1
|
||||
+2 t2 100 # segment 2
|
||||
t1 * # segment 3
|
||||
t2 *-* # segment 4
|
||||
t1 3 -* # segment 5
|
||||
+0.111111 t2 102.5 # segment 6
|
||||
7.37 t1 5 +1 # segment 7
|
||||
|
||||
This rather pathological example illustrates the rules for filling in
|
||||
implied data. All the values can be determined by recursively applying
|
||||
the rules given above, and the full end result is this::
|
||||
|
||||
+2 0-2 t1 0-2 # segment 1
|
||||
+2 2-4 t2 100-102 # segment 2
|
||||
+0.758889 4-4.758889 t1 2-2.758889 # segment 3
|
||||
+0.5 4.4758889-5.258889 t2 102-102.5 # segment 4
|
||||
+2 5.258889-7.258889 t1 3-5 # segment 5
|
||||
+0.111111 7.258889-7.37 t2 102.5-102.611111 # segment 6
|
||||
+1 7.37-8.37 t1 5-6 # segment 7
|
||||
+8
-12
@@ -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,17 +38,12 @@ 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
|
||||
|
||||
Some example profiles are provided in a file
|
||||
etc/encoding-profiles.conf; as for this, see below.
|
||||
etc/encoding-example-profiles.conf; as for this, see below.
|
||||
|
||||
|
||||
Encoding examples
|
||||
@@ -94,12 +89,13 @@ Device targets
|
||||
As the options for various devices can get complex, profiles can be used.
|
||||
|
||||
An example profile file for encoding is provided in
|
||||
etc/encoding-profiles.conf in the source tree. This file is installed and loaded
|
||||
by default (if libavfilter is enabled at compilation). If you want to modify
|
||||
it, you can replace and it with your own copy by doing::
|
||||
etc/encoding-example-profiles.conf in the source tree. You can include it into
|
||||
your configuration by doing::
|
||||
|
||||
mkdir -p ~/.mpv
|
||||
cp /etc/mpv/encoding-profiles.conf ~/.mpv/encoding-profiles.conf
|
||||
curl https://raw.github.com/mpv-player/mpv/master/etc/encoding-example-profiles.conf \
|
||||
> ~/.mpv/encoding-profiles.conf
|
||||
echo "include = $HOME/.mpv/encoding-profiles.conf" >> ~/.mpv/config
|
||||
|
||||
Refer to the top of that file for more comments - in a nutshell, the following
|
||||
options are added by it::
|
||||
@@ -139,9 +135,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")
|
||||
|
||||
@@ -11,12 +11,6 @@ syntax is:
|
||||
|
||||
To get a full list of available audio filters, see ``--af=help``.
|
||||
|
||||
You can also set defaults for each filter. The defaults are applied before the
|
||||
normal filter parameters.
|
||||
|
||||
``--af-defaults=<filter1[=parameter1:parameter2:...],filter2,...>``
|
||||
Set defaults for each filter.
|
||||
|
||||
Audio filters are managed in lists. There are a few commands to manage the
|
||||
filter list:
|
||||
|
||||
@@ -41,7 +35,7 @@ Available filters are:
|
||||
This filter is automatically enabled if the audio output does not support
|
||||
the audio configuration of the file being played.
|
||||
|
||||
It supports only the following sample formats: u8, s16, s32, float.
|
||||
It supports only the following sample formats: u8, s16ne, s32ne, floatne.
|
||||
|
||||
``filter-size=<length>``
|
||||
Length of the filter with respect to the lower sampling rate. (default:
|
||||
@@ -56,9 +50,9 @@ Available filters are:
|
||||
entries. (default: no)
|
||||
``no-detach``
|
||||
Do not detach if input and output audio format/rate/channels match.
|
||||
(If you just want to set defaults for this filter that will be used
|
||||
even by automatically inserted lavrresample instances, you should
|
||||
prefer setting them with ``--af-defaults=lavrresample:...``.)
|
||||
You should add this option if you specify additional parameters, as
|
||||
automatically inserted lavrresample instances will use the default
|
||||
settings.
|
||||
``o=<string>``
|
||||
Set AVOptions on the SwrContext or AVAudioResampleContext. These should
|
||||
be documented by FFmpeg or Libav.
|
||||
@@ -70,18 +64,17 @@ Available filters are:
|
||||
outputting to S/PDIF. If the input sample rate is not 48 kHz, 44.1 kHz or
|
||||
32 kHz, it will be resampled to 48 kHz.
|
||||
|
||||
``tospdif=<yes|no>``
|
||||
Output raw AC-3 stream if ``no``, output to S/PDIF for
|
||||
passthrough if ``yes`` (default).
|
||||
|
||||
``bitrate=<rate>``
|
||||
The bitrate use for the AC-3 stream. Set it to 384 to get 384 kbps.
|
||||
``<tospdif>``
|
||||
Output raw AC-3 stream if zero or not set, output to S/PDIF for
|
||||
passthrough when ``<tospdif>`` is set non-zero.
|
||||
``<bitrate>``
|
||||
The bitrate use for the AC-3 stream. Set it to either 384 or 384000
|
||||
to get 384 kbps.
|
||||
|
||||
Valid values: 32, 40, 48, 56, 64, 80, 96, 112, 128,
|
||||
160, 192, 224, 256, 320, 384, 448, 512, 576, 640.
|
||||
|
||||
The special value ``default`` selects a default bitrate based on the
|
||||
input channel number:
|
||||
Default bitrate is based on the input channel number:
|
||||
|
||||
:1ch: 96
|
||||
:2ch: 192
|
||||
@@ -90,7 +83,7 @@ Available filters are:
|
||||
:5ch: 448
|
||||
:6ch: 448
|
||||
|
||||
``minchn=<n>``
|
||||
``<minchn>``
|
||||
If the input channel number is less than ``<minchn>``, the filter will
|
||||
detach itself (default: 5).
|
||||
|
||||
@@ -147,7 +140,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 +177,7 @@ Available filters are:
|
||||
Would amplify the sound in the upper and lower frequency region
|
||||
while canceling it almost completely around 1kHz.
|
||||
|
||||
``channels=nch[:routes]``
|
||||
``channels=nch[:nr:from1:to1:from2:to2:from3:to3:...]``
|
||||
Can be used for adding, removing, routing and copying audio channels. If
|
||||
only ``<nch>`` is given, the default routing is used. It works as follows:
|
||||
If the number of output channels is greater than the number of input
|
||||
@@ -195,53 +188,46 @@ Available filters are:
|
||||
|
||||
``<nch>``
|
||||
number of output channels (1-8)
|
||||
``<routes>``
|
||||
List of ``,`` separated routes, in the form ``from1-to1,from2-to2,...``.
|
||||
Each pair defines where to route each channel. There can be at most
|
||||
8 routes. Without this argument, the default routing is used. Since
|
||||
``,`` is also used to separate filters, you must quote this argument
|
||||
with ``[...]`` or similar.
|
||||
``<nr>``
|
||||
number of routes (1-8)
|
||||
``<from1:to1:from2:to2:from3:to3:...>``
|
||||
Pairs of numbers between 0 and 7 that define where to route each
|
||||
channel.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``mpv --af=channels=4:[0-1,1-0,0-2,1-3] media.avi``
|
||||
``mpv --af=channels=4:4:0:1:1:0:2:2:3:3 media.avi``
|
||||
Would change the number of channels to 4 and set up 4 routes that
|
||||
swap channel 0 and channel 1 and leave channel 2 and 3 intact.
|
||||
Observe that if media containing two channels were played back,
|
||||
channels 2 and 3 would contain silence but 0 and 1 would still be
|
||||
swapped.
|
||||
|
||||
``mpv --af=channels=6:[0-0,0-1,0-2,0-3] media.avi``
|
||||
``mpv --af=channels=6:4:0:0:0:1:0:2:0:3 media.avi``
|
||||
Would change the number of channels to 6 and set up 4 routes that
|
||||
copy channel 0 to channels 0 to 3. Channel 4 and 5 will contain
|
||||
silence.
|
||||
|
||||
.. note::
|
||||
|
||||
You should probably not use this filter. If you want to change the
|
||||
output channel layout, try the ``format`` filter, which can make mpv
|
||||
automatically up- and downmix standard channel layouts.
|
||||
|
||||
``format=format:srate:channels:out-format:out-srate:out-channels``
|
||||
``force=in-format:in-srate:in-channels:out-format:out-srate:out-channels``
|
||||
Force a specific audio format/configuration without actually changing the
|
||||
audio data. Keep in mind that the filter system might auto-insert actual
|
||||
conversion filters before or after this filter if needed.
|
||||
|
||||
All parameters are optional. The first 3 parameters restrict what the filter
|
||||
accepts as input. The ``out-`` parameters change the audio format, without
|
||||
All parameters are optional. The ``in-`` variants restrict what the filter
|
||||
accepts as input. The ``out-`` variants change the audio format, without
|
||||
actually doing a conversion. The data will be 'reinterpreted' by the
|
||||
filters or audio outputs following this filter.
|
||||
|
||||
``<format>``
|
||||
Force conversion to this format. Use ``--af=format=format=help`` to get
|
||||
a list of valid formats.
|
||||
``<in-format>``
|
||||
Force conversion to this format. See ``format`` filter for valid audio
|
||||
format values.
|
||||
|
||||
``<srate>``
|
||||
``<in-srate>``
|
||||
Force conversion to a specific sample rate. The rate is an integer,
|
||||
48000 for example.
|
||||
|
||||
``<channels>``
|
||||
Force mixing to a specific channel layout. See ``--audio-channels`` option
|
||||
``<in-channels>``
|
||||
Force mixing to a specific channel layout. See ``--channels`` option
|
||||
for possible values.
|
||||
|
||||
``<out-format>``
|
||||
@@ -250,71 +236,55 @@ 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
|
||||
channels in most cases, while this filter can do this.
|
||||
``format[=format]``
|
||||
Convert between different sample formats. Automatically enabled when
|
||||
needed by the audio output or another filter. See also ``--format``.
|
||||
|
||||
*NOTE*: this filter used to be named ``force``. Also, unlike the old
|
||||
``format`` filter, this does not do any actual conversion anymore.
|
||||
Conversion is done by other, automatically inserted filters.
|
||||
``<format>``
|
||||
Sets the desired format. The general form is 'sbe', where 's' denotes
|
||||
the sign (either 's' for signed or 'u' for unsigned), 'b' denotes the
|
||||
number of bits per sample (16, 24 or 32) and 'e' denotes the
|
||||
endianness ('le' means little-endian, 'be' big-endian and 'ne' the
|
||||
endianness of the computer mpv is running on). Valid values (amongst
|
||||
others) are: 's16le', 'u32be' and 'u24ne'. Exceptions to this rule that
|
||||
are also valid format specifiers: u8, s8, floatle, floatbe, floatne,
|
||||
mpeg2, and ac3.
|
||||
|
||||
``convert24``
|
||||
Filter for internal use only. Converts between 24-bit and 32-bit sample
|
||||
formats.
|
||||
|
||||
``convertsignendian``
|
||||
Filter for internal use only. Converts between signed/unsigned formats
|
||||
and formats with different endian.
|
||||
|
||||
``volume[=<volumedb>[:...]]``
|
||||
``volume[=v[:sc[:fast]]]``
|
||||
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
|
||||
knob on your amplifier.
|
||||
|
||||
This filter has a second feature: It measures the overall maximum sound
|
||||
level and prints out that level when mpv exits. This feature currently
|
||||
only works with floating-point data.
|
||||
|
||||
*NOTE*: This filter is not reentrant and can therefore only be enabled
|
||||
once for every audio stream.
|
||||
|
||||
``<volumedb>``
|
||||
``<v>``
|
||||
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``
|
||||
Turns soft clipping on. Soft-clipping can make the
|
||||
``<sc>``
|
||||
Turns soft clipping on (1) or off (0). 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``
|
||||
Force S16 sample format if set. Lower quality, but might be faster
|
||||
``<fast>``
|
||||
Force S16 sample format if set to 1. 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``
|
||||
``mpv --af=volume=10.1:0 media.avi``
|
||||
Would amplify the sound by 10.1dB and hard-clip if the sound level
|
||||
is too high.
|
||||
|
||||
``pan=n:[<matrix>]``
|
||||
``pan=n[:L00:L01:L02:...L10:L11:L12:...Ln0:Ln1:Ln2:...]``
|
||||
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
|
||||
@@ -326,33 +296,29 @@ Available filters are:
|
||||
|
||||
``<n>``
|
||||
Number of output channels (1-8).
|
||||
``<matrix>``
|
||||
A list of values ``[L00,L01,L02,...,L10,L11,L12,...,Ln0,Ln1,Ln2,...]``,
|
||||
where each element ``Lij`` means how much of input channel i is mixed
|
||||
into output channel j (range 0-1). So in principle you first have n
|
||||
numbers saying what to do with the first input channel, then n numbers
|
||||
that act on the second input channel etc. If you do not specify any
|
||||
numbers for some input channels, 0 is assumed.
|
||||
Note that the values are separated by ``,``, which is already used
|
||||
by the option parser to separate filters. This is why you must quote
|
||||
the value list with ``[...]`` or similar.
|
||||
``<Lij>``
|
||||
How much of input channel i is mixed into output channel j (0-1). So
|
||||
in principle you first have n numbers saying what to do with the first
|
||||
input channel, then n numbers that act on the second input channel
|
||||
etc. If you do not specify any numbers for some input channels, 0 is
|
||||
assumed.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``mpv --af=pan=1:[0.5,0.5] media.avi``
|
||||
``mpv --af=pan=1:0.5:0.5 media.avi``
|
||||
Would downmix from stereo to mono.
|
||||
|
||||
``mpv --af=pan=3:[1,0,0.5,0,1,0.5] media.avi``
|
||||
``mpv --af=pan=3:1:0:0.5:0:1:0.5 media.avi``
|
||||
Would give 3 channel output leaving channels 0 and 1 intact, and mix
|
||||
channels 0 and 1 into output channel 2 (which could be sent to a
|
||||
subwoofer for example).
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
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
|
||||
remixing audio to 5.1 and output it like this.
|
||||
If you just want to force remixing to a certain output channel
|
||||
layout, it is easier to use the ``force`` filter. For example,
|
||||
``mpv '--af=force=channels=5.1' '--channels=5.1'`` would always
|
||||
force remixing audio to 5.1 and output it like this.
|
||||
|
||||
``sub[=fc:ch]``
|
||||
Adds a subwoofer channel to the audio stream. The audio data used for
|
||||
@@ -380,7 +346,7 @@ Available filters are:
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=sub=100:4 --audio-channels=5 media.avi``
|
||||
``mpv --af=sub=100:4 --channels=5 media.avi``
|
||||
Would add a subwoofer channel with a cutoff frequency of 100Hz to
|
||||
output channel 4.
|
||||
|
||||
@@ -408,16 +374,16 @@ Available filters are:
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=surround=15 --audio-channels=4 media.avi``
|
||||
``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,...]]``
|
||||
``delay[=ch1:ch2:...]``
|
||||
Delays the sound to the loudspeakers such that the sound from the
|
||||
different channels arrives at the listening position simultaneously. It is
|
||||
only useful if you have more than 2 loudspeakers.
|
||||
|
||||
``[ch1,ch2,...]``
|
||||
``ch1,ch2,...``
|
||||
The delay in ms that should be imposed on each channel (floating point
|
||||
number between 0 and 1000).
|
||||
|
||||
@@ -436,11 +402,11 @@ Available filters are:
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=delay=[10.5,10.5,0,0,7,0] media.avi``
|
||||
``mpv --af=delay=10.5:10.5:0:0:7:0 media.avi``
|
||||
Would delay front left and right by 10.5ms, the two rear channels
|
||||
and the subwoofer by 0ms and the center channel by 7ms.
|
||||
|
||||
``export=mmapped_file:nsamples]``
|
||||
``export[=mmapped_file[:nsamples]]``
|
||||
Exports the incoming signal to other processes using memory mapping
|
||||
(``mmap()``). Memory mapped areas contain a header::
|
||||
|
||||
@@ -452,7 +418,7 @@ Available filters are:
|
||||
The rest is payload (non-interleaved) 16-bit data.
|
||||
|
||||
``<mmapped_file>``
|
||||
File to map data to (required)
|
||||
File to map data to (default: ``~/.mpv/mpv-af_export``).
|
||||
``<nsamples>``
|
||||
number of samples per channel (default: 512).
|
||||
|
||||
@@ -472,7 +438,7 @@ Available filters are:
|
||||
|
||||
``drc[=method:target]``
|
||||
Applies dynamic range compression. This maximizes the volume by compressing
|
||||
the audio signal's dynamic range. (Formerly called ``volnorm``.)
|
||||
the audio signal's dynamic range.
|
||||
|
||||
``<method>``
|
||||
Sets the used method.
|
||||
@@ -493,7 +459,7 @@ Available filters are:
|
||||
This filter can cause distortion with audio signals that have a very
|
||||
large dynamic range.
|
||||
|
||||
``ladspa=file:label:[<control0>,<control1>,...]``
|
||||
``ladspa=file:label[:controls...]``
|
||||
Load a LADSPA (Linux Audio Developer's Simple Plugin API) plugin. This
|
||||
filter is reentrant, so multiple LADSPA plugins can be used at once.
|
||||
|
||||
@@ -509,21 +475,12 @@ Available filters are:
|
||||
one filter, but others contain many of them. Entering 'help' here
|
||||
will list all available filters within the specified library, which
|
||||
eliminates the use of 'listplugins' from the LADSPA SDK.
|
||||
``[<control0>,<control1>,...]``
|
||||
Controls are zero or more ``,`` separated floating point values that
|
||||
determine the behavior of the loaded plugin (for example delay,
|
||||
threshold or gain).
|
||||
``<controls>``
|
||||
Controls are zero or more floating point values that determine the
|
||||
behavior of the loaded plugin (for example delay, threshold or gain).
|
||||
In verbose mode (add ``-v`` to the mpv command line), all
|
||||
available controls and their valid ranges are printed. This eliminates
|
||||
the use of 'analyseplugin' from the LADSPA SDK.
|
||||
Note that ``,`` is already used by the option parser to separate
|
||||
filters, so you must quote the list of values with ``[...]`` or
|
||||
similar.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``mpv --af=ladspa='/usr/lib/ladspa/delay.so':delay_5s:[0.5,0.2] media.avi``
|
||||
Does something.
|
||||
|
||||
``karaoke``
|
||||
Simple voice removal filter exploiting the fact that voice is usually
|
||||
@@ -590,7 +547,7 @@ Available filters are:
|
||||
``mpv --af=scaletempo=stride=30:overlap=.50:search=10 media.ogg``
|
||||
Would tweak the quality and performace parameters.
|
||||
|
||||
``mpv --af=format=float,scaletempo media.ogg``
|
||||
``mpv --af=format=floatne,scaletempo media.ogg``
|
||||
Would make scaletempo use float code. Maybe faster on some
|
||||
platforms.
|
||||
|
||||
@@ -10,53 +10,35 @@ syntax is:
|
||||
If the list has a trailing ',', mpv will fall back on drivers not contained
|
||||
in the list. Suboptions are optional and can mostly be omitted.
|
||||
|
||||
You can also set defaults for each driver. The defaults are applied before the
|
||||
normal driver parameters.
|
||||
|
||||
``--ao-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
|
||||
Set defaults for each driver.
|
||||
|
||||
.. 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 OSX systems, use ``--ao=coreaudio``.
|
||||
See ``--ao=help`` for a list of compiled-in audio output drivers.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
- ``--ao=alsa,oss,`` Try the ALSA driver, then the OSS driver, then others.
|
||||
- ``--ao=alsa:no-block:device=[hw:0,3]`` Sets noblock-mode and the
|
||||
- ``--ao=alsa:noblock:device=[hw:0,3]`` Sets noblock-mode and the
|
||||
device-name as first card, fourth device.
|
||||
|
||||
Available audio output drivers are:
|
||||
|
||||
``alsa`` (Linux only)
|
||||
ALSA audio output driver
|
||||
ALSA 0.9/1.x audio output driver
|
||||
|
||||
``no-block``
|
||||
Sets noblock-mode.
|
||||
``device=<device>``
|
||||
Sets the device name. For ac3 output via S/PDIF, use an "iec958" or
|
||||
"spdif" device, unless you really know how to set it correctly.
|
||||
``no-block``
|
||||
Sets noblock-mode.
|
||||
``resample=yes``
|
||||
Enable ALSA resampling plugin. (This is disabled by default, because
|
||||
some drivers report incorrect audio delay in some cases.)
|
||||
``mixer-device=<device>``
|
||||
Set the mixer device used with ``--no-softvol`` (default: ``default``).
|
||||
``mixer-name=<name>``
|
||||
Set the name of the mixer element (default: ``Master``). This is for
|
||||
example ``PCM`` or ``Master``.
|
||||
``mixer-index=<number>``
|
||||
Set the index of the mixer channel (default: 0). Consider the output of
|
||||
Set the index of the mixer channel (default: 0). Consider the output
|
||||
"``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 +72,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,19 +99,7 @@ Available audio output drivers are:
|
||||
with fixed setups.
|
||||
|
||||
``coreaudio`` (Mac OS X only)
|
||||
Native Mac OS X audio output driver using the AudioUnits and the CoreAudio
|
||||
sound server.
|
||||
|
||||
``device_id=<id>``
|
||||
ID of output device to use (0 = default device)
|
||||
``help``
|
||||
List all available output devices with their IDs.
|
||||
|
||||
``coreaudio_device`` (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).
|
||||
Native Mac OS X audio output driver
|
||||
|
||||
``device_id=<id>``
|
||||
ID of output device to use (0 = default device)
|
||||
@@ -136,9 +109,6 @@ Available audio output drivers are:
|
||||
``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
|
||||
|
||||
@@ -147,26 +117,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,
|
||||
@@ -175,8 +129,6 @@ 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.
|
||||
@@ -186,10 +138,6 @@ Available audio output drivers are:
|
||||
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
|
||||
@@ -202,30 +150,7 @@ Available audio output drivers are:
|
||||
|
||||
``null``
|
||||
Produces no audio output but maintains video playback speed. Use
|
||||
``--ao=null:untimed`` for benchmarking.
|
||||
|
||||
``untimed``
|
||||
Do not simulate timing of a perfect audio device. This means audio
|
||||
decoding will go as fast as possible, instead of timing it to the
|
||||
system clock.
|
||||
|
||||
``buffer``
|
||||
Simulated buffer length in seconds.
|
||||
|
||||
``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.
|
||||
``--no-audio`` for benchmarking.
|
||||
|
||||
``pcm``
|
||||
Raw PCM/WAVE file writer audio output
|
||||
@@ -241,10 +166,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
|
||||
@@ -253,17 +174,6 @@ Available audio output drivers are:
|
||||
Set the TCP port used for connecting to the server (default: 12345).
|
||||
Not used if connecting to a Unix domain socket.
|
||||
|
||||
``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.)
|
||||
|
||||
``device=<device>``
|
||||
sndio device to use (default: ``$AUDIODEVICE``, resp. ``snd0``).
|
||||
|
||||
``wasapi``
|
||||
Audio output to the Windows Audio Session API.
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
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.
|
||||
**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.
|
||||
|
||||
.. note::
|
||||
These lists are incomplete.
|
||||
General Changes for MPlayer to mplayer2
|
||||
---------------------------------------
|
||||
|
||||
General Changes for MPlayer to mpv
|
||||
----------------------------------
|
||||
|
||||
* Switch to GPLv2+. (Technically speaking, MPlayer as a whole seems to be
|
||||
GPLv2-only, while mplayer2 is GPLv3+ - see ``Copyright`` file for details.)
|
||||
* Removal of the internal GUI, MEncoder, OSD menu, video kernel drivers for
|
||||
Linux 2.4 (including VIDIX)
|
||||
* Large internal cleanups
|
||||
* Removal of support for dead platforms
|
||||
* New buildsystem
|
||||
* No embedded copy of ffmpeg and other libraries
|
||||
* 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
|
||||
@@ -40,6 +30,17 @@ General Changes for MPlayer to mpv
|
||||
* 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
|
||||
-----------------------------------
|
||||
|
||||
* 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
|
||||
@@ -98,13 +99,6 @@ General Changes for MPlayer to mpv
|
||||
* Support mapping multiple commands to one key.
|
||||
* Allow changing/adjusting video filters at runtime. (This is also used to make
|
||||
the ``D`` key insert vf_yadif if deinterlacing is not supported otherwise.)
|
||||
* Native VAAPI support
|
||||
* OSX: VDA support using libavcodec hwaccel API insted of FFmpeg's decoder. Up
|
||||
to 2-2.5x reduction in CPU usage.
|
||||
* Make hardware decoding in general work with the ``opengl`` video output.
|
||||
* Lua scripting (see `LUA SCRIPTING`_)
|
||||
* A client API, that allows embedding **mpv** into applications
|
||||
(see ``libmpv/client.h`` in the sources)
|
||||
* General bug fixes and removal of long-standing issues
|
||||
* General code cleanups (including refactoring or rewrites of many parts)
|
||||
* Many more changes
|
||||
@@ -121,114 +115,66 @@ 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.
|
||||
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 ``--no-opt``.
|
||||
``-no-opt``, or better ``--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``
|
||||
``-use-filename-title`` ``--title="${filename}"``
|
||||
``-loop 0`` ``--loop=inf``
|
||||
``-hardframedrop`` ``--framedrop=hard``
|
||||
``-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``
|
||||
``-delay`` ``--audio-delay``
|
||||
``-subdelay`` ``--sub-delay``
|
||||
``-subfile`` ``--sub-file``
|
||||
``-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``
|
||||
``-subfont`` ``--sub-text-font``
|
||||
``-subfps`` ``--sub-fps``
|
||||
``-subpos`` ``--sub-pos``
|
||||
``-sws`` ``--sws-scaler``
|
||||
``-tvscan`` ``--tv-scan``
|
||||
``-use-filename-title`` ``--title='${filename}'``
|
||||
``-spugauss`` ``--sub-gauss``
|
||||
``-vobsub`` ``--sub`` (pass the .idx file)
|
||||
``-ass-bottom-margin`` ``--vf=sub=bottom:top``
|
||||
``-vc ffh264vdpau`` (etc.) ``--hwdec=vdpau``
|
||||
``-vobsub`` ``--sub-file`` (pass the .idx file)
|
||||
``-ac spdifac3`` ``--ad=spdif:ac3`` (see ``--ad=help``)
|
||||
``-afm hwac3`` ``--ad=spdif:ac3,spdif:dts``
|
||||
``-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)
|
||||
``-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]``
|
||||
=========================== ========================================
|
||||
|
||||
.. 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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -236,8 +182,8 @@ input.conf and Slave 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.
|
||||
commands, they will be displayed with ``-v`` when it is loaded, and show
|
||||
and the replacement commands.
|
||||
|
||||
Properties containing ``_`` to separate words use ``-`` instead.
|
||||
|
||||
@@ -250,9 +196,9 @@ input.conf and Slave Commands
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``pt_step -1 [0|1]`` | ``playlist_prev [weak|force] (same)`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``switch_ratio [<ratio>]`` | ``set video-aspect <ratio>`` |
|
||||
| ``switch_ratio [<ratio>]`` | ``set aspect <ratio>`` |
|
||||
| | |
|
||||
| | ``set video-aspect 0`` (reset aspect) |
|
||||
| | ``set aspect 0`` (to reset aspect) |
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``step_property_osd <prop>`` | ``cycle <prop> <step>`` (wraps), |
|
||||
| ``<step> <dir>`` | ``add <prop> <step>`` (clamps). |
|
||||
@@ -276,108 +222,52 @@ input.conf and Slave Commands
|
||||
+--------------------------------+----------------------------------------+
|
||||
| ``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`` |
|
||||
| ``af_switch``, ``af_add``, ... | ``af [set|add|...]`` |
|
||||
+--------------------------------+----------------------------------------+
|
||||
|
||||
.. note::
|
||||
Other
|
||||
~~~~~
|
||||
|
||||
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
|
||||
* 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 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 planned, but nothing
|
||||
has emerged yet.
|
||||
|
||||
* **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.
|
||||
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
|
||||
---------------------------
|
||||
|
||||
**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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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?
|
||||
--------------
|
||||
|
||||
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.
|
||||
* 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>``
|
||||
@@ -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).
|
||||
@@ -0,0 +1,547 @@
|
||||
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>]``
|
||||
|
||||
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 symbol name.
|
||||
|
||||
``<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.
|
||||
|
||||
Optional arguments can be skipped with ``-``.
|
||||
|
||||
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).
|
||||
|
||||
``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``.
|
||||
|
||||
``speed_mult <value>``
|
||||
Multiply the ``speed`` property by the given value.
|
||||
|
||||
``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 <index>``
|
||||
Remove the playlist entry at the given index. Index values start counting
|
||||
with 0. You cannot remove the entry for the currently played file.
|
||||
|
||||
``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>"``
|
||||
Run the given command with ``/bin/sh -c``. The string is expanded like in
|
||||
`Property Expansion`_.
|
||||
|
||||
``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.
|
||||
|
||||
``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``
|
||||
|
||||
``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``.
|
||||
|
||||
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``, ``radio_step_channel``,
|
||||
``radio_set_channel``, ``radio_set_freq``, ``radio_step_freq`` (all of these
|
||||
should be replaced by properties), ``stop`` (questionable use), ``get_property``
|
||||
(?), ``vo_cmdline`` (experimental).
|
||||
|
||||
Input Command Prefixes
|
||||
----------------------
|
||||
|
||||
``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 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
|
||||
``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>``
|
||||
``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 deinterlacing, if available (bool)
|
||||
``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
|
||||
``aspect`` x video aspect
|
||||
``vid`` x current video track (similar to ``--vid``)
|
||||
``video`` x alias for ``vid``
|
||||
``program`` x switch TS program (write-only)
|
||||
``sid`` x current subtitle track (similar to ``--sid``)
|
||||
``sub`` x alias for ``sid``
|
||||
``sub-delay`` x see ``--sub-delay``
|
||||
``sub-pos`` x see ``--sub-pos``
|
||||
``sub-visibility`` x whether current subtitle is rendered
|
||||
``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, cur. entr. 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 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`` cannot be
|
||||
retrieved.
|
||||
``${?NAME:STR}``
|
||||
Expands to ``STR`` (recursively) if the property ``NAME`` is available.
|
||||
``$$``
|
||||
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.
|
||||
@@ -1,11 +1,20 @@
|
||||
..
|
||||
Hint: To generate a nicely formatted XeLaTeX document from this file, use
|
||||
rst2xetex --use-latex-docinfo --use-latex-toc --hyperlink-color=MidnightBlue --latex-preamble="\usepackage[usenames,dvipsnames]{xcolor}\usepackage{fullpage}\setmainfont{Droid Sans}\setsansfont{Linux Biolinum O}\setmonofont[HyphenChar=None]{DejaVu Sans Mono}" mpv.rst
|
||||
|
||||
You might want to put the .. contents:: directive below to generate a TOC.
|
||||
|
||||
mpv
|
||||
###
|
||||
|
||||
##############
|
||||
a media player
|
||||
a movie player
|
||||
##############
|
||||
|
||||
:Copyright: GPLv2+
|
||||
:Author: wm4
|
||||
:Date: 2013-07-08
|
||||
:Copyright: GPLv3
|
||||
:Version: git
|
||||
:Manual section: 1
|
||||
:Manual group: multimedia
|
||||
|
||||
@@ -15,11 +24,23 @@ SYNOPSIS
|
||||
| **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** \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]
|
||||
|
||||
|
||||
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
|
||||
@@ -40,13 +61,16 @@ 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``).
|
||||
|
||||
PGUP and PGDWN
|
||||
Seek forward/backward 10 minutes.
|
||||
|
||||
[ and ]
|
||||
Decrease/increase current playback speed by 10%.
|
||||
|
||||
@@ -66,13 +90,9 @@ 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
|
||||
play one frame in reverse and then go into pause mode again.
|
||||
|
||||
q / ESC
|
||||
Stop playing and quit.
|
||||
|
||||
@@ -80,12 +100,21 @@ 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.
|
||||
|
||||
@@ -95,6 +124,9 @@ m
|
||||
\#
|
||||
Cycle through the available audio tracks.
|
||||
|
||||
TAB (MPEG-TS and libavformat only)
|
||||
Cycle through the available programs.
|
||||
|
||||
f
|
||||
Toggle fullscreen (see also ``--fs``).
|
||||
|
||||
@@ -104,10 +136,7 @@ T
|
||||
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
|
||||
@@ -120,6 +149,9 @@ v
|
||||
j and J
|
||||
Cycle through the available subtitles.
|
||||
|
||||
F
|
||||
Toggle displaying "forced subtitles".
|
||||
|
||||
x and z
|
||||
Adjust subtitle delay by +/- 0.1 seconds.
|
||||
|
||||
@@ -140,14 +172,21 @@ S
|
||||
I
|
||||
Show filename on the OSD.
|
||||
|
||||
PGUP and PGDWN
|
||||
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``.
|
||||
P
|
||||
Show progression bar, elapsed time and total duration on the OSD.
|
||||
|
||||
D
|
||||
! and @
|
||||
Seek to the beginning of the previous/next chapter.
|
||||
|
||||
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``).)
|
||||
|
||||
@@ -163,24 +202,23 @@ corresponding adjustment, or the software equalizer (``--vf=eq``).)
|
||||
7 and 8
|
||||
Adjust saturation.
|
||||
|
||||
(The following keys are valid only on OSX.)
|
||||
(The following keys are valid only when using the corevideo video output
|
||||
driver.)
|
||||
|
||||
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.)
|
||||
|
||||
@@ -194,11 +232,17 @@ PREVIOUS and NEXT
|
||||
Seek backward/forward 1 minute.
|
||||
|
||||
(The following keys are only valid if you compiled with TV or DVB input
|
||||
support.)
|
||||
support and will take precedence over the keys defined above.)
|
||||
|
||||
h and k
|
||||
Select previous/next channel.
|
||||
|
||||
n
|
||||
Change norm.
|
||||
|
||||
u
|
||||
Change channel list.
|
||||
|
||||
Mouse Control
|
||||
-------------
|
||||
|
||||
@@ -208,6 +252,24 @@ button 3 and button 4
|
||||
button 5 and button 6
|
||||
Decrease/increase volume.
|
||||
|
||||
Joystick Control
|
||||
----------------
|
||||
|
||||
left and right
|
||||
Seek backward/forward 10 seconds.
|
||||
|
||||
up and down
|
||||
Seek forward/backward 1 minute.
|
||||
|
||||
button 1
|
||||
Pause.
|
||||
|
||||
button 2
|
||||
Toggle OSD states: none / seek / seek + timer / seek + timer + total time.
|
||||
|
||||
button 3 and button 4
|
||||
Decrease/increase volume.
|
||||
|
||||
|
||||
USAGE
|
||||
=====
|
||||
@@ -237,28 +299,6 @@ It has the following format::
|
||||
|
||||
``mpv --ao=pcm:file=%`expr length "$NAME"`%"$NAME" test.avi``
|
||||
|
||||
Paths
|
||||
-----
|
||||
|
||||
Some care must be taken when passing arbitrary paths and filenames to mpv. For
|
||||
example, paths starting with ``-`` will be interpreted as options. Likewise,
|
||||
if a path contains the sequence ``://``, the string before that might be
|
||||
interpreted as protocol prefix, even though ``://`` can be part of a legal
|
||||
UNIX path. To avoid problems with arbitrary paths, you should be sure that
|
||||
absolute paths passed to mpv start with ``/``, and relative paths with ``./``.
|
||||
|
||||
The name ``-`` itself is interpreted as stdin, and will cause mpv to disable
|
||||
console controls. (Which makes it suitable for playing data piped to stdin.)
|
||||
|
||||
For paths passed to suboptions, the situation is further complicated by the
|
||||
need to escape special characters. To work this around, the path can be
|
||||
additionally wrapped in the ``%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 ``~/.mpv/``).
|
||||
``~/`` expands to the user's home directory. (The trailing ``/`` is always
|
||||
required.)
|
||||
|
||||
Per-File Options
|
||||
----------------
|
||||
|
||||
@@ -274,8 +314,6 @@ file1.mkv ``--a --b --c``
|
||||
file2.mkv ``--a --b --c``
|
||||
=============== ===========================
|
||||
|
||||
(This is different from MPlayer and mplayer2.)
|
||||
|
||||
Also, if any option is changed at runtime (via input commands), they are not
|
||||
reset when a new file is played.
|
||||
|
||||
@@ -308,7 +346,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
|
||||
@@ -343,8 +381,8 @@ 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
|
||||
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
|
||||
@@ -370,7 +408,7 @@ profile name ``default`` to continue with normal options.
|
||||
::
|
||||
|
||||
[vo.vdpau]
|
||||
# Use hardware decoding (might break playback of some h264 files)
|
||||
# Use hardware decoding (this might break playback of some h264 files)
|
||||
hwdec=vdpau
|
||||
|
||||
[protocol.dvd]
|
||||
@@ -380,7 +418,7 @@ profile name ``default`` to continue with normal options.
|
||||
|
||||
[extension.flv]
|
||||
profile-desc="profile for .flv files"
|
||||
vf=flip
|
||||
flip=yes
|
||||
|
||||
[ao.alsa]
|
||||
device=spdif
|
||||
@@ -404,84 +442,8 @@ taking screenshots is handled by the VOs, and adding the screenshot filter will
|
||||
break hardware decoding. (The filter may still be useful for taking screenshots
|
||||
at a certain point within the video chain when using multiple video filters.)
|
||||
|
||||
PROTOCOLS
|
||||
=========
|
||||
|
||||
``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.
|
||||
|
||||
``-``
|
||||
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.
|
||||
OPTIONS
|
||||
=======
|
||||
|
||||
.. include:: options.rst
|
||||
|
||||
@@ -497,10 +459,6 @@ PROTOCOLS
|
||||
|
||||
.. include:: input.rst
|
||||
|
||||
.. include:: osc.rst
|
||||
|
||||
.. include:: lua.rst
|
||||
|
||||
.. include:: changes.rst
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
@@ -509,28 +467,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
|
||||
@@ -545,7 +498,7 @@ behavior of mpv.
|
||||
|
||||
FFmpeg/Libav:
|
||||
This library accesses various environment variables. However, they are not
|
||||
centrally documented, and documenting them is not our job. Therefore, this
|
||||
centrally documented, and documenting them is not our job. Therefore, the
|
||||
list is incomplete.
|
||||
|
||||
Notable environment variables:
|
||||
@@ -638,31 +591,23 @@ 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.
|
||||
|
||||
EXAMPLES OF MPV USAGE
|
||||
=====================
|
||||
|
||||
Blu-ray playback:
|
||||
Quickstart Blu-ray playing:
|
||||
- ``mpv bd:////path/to/disc``
|
||||
- ``mpv bd:// --bluray-device=/path/to/disc``
|
||||
|
||||
Quickstart DVD playing:
|
||||
``mpv dvd://1``
|
||||
|
||||
Play in Japanese with English subtitles:
|
||||
``mpv dvd://1 --alang=ja --slang=en``
|
||||
|
||||
@@ -673,7 +618,7 @@ Play only titles 5, 6, 7:
|
||||
``mpv dvd://5-7``
|
||||
|
||||
Play a multiangle DVD:
|
||||
``mpv dvd://1 --dvd-angle=2``
|
||||
``mpv dvd://1 --dvdangle=2``
|
||||
|
||||
Play from a different DVD device:
|
||||
``mpv dvd://1 --dvd-device=/dev/dvd2``
|
||||
@@ -698,6 +643,6 @@ mpv is a MPlayer fork based on mplayer2, which in turn is a fork of MPlayer.
|
||||
MPlayer was initially written by Arpad Gereoffy. See the ``AUTHORS`` file for
|
||||
a list of some of the many other contributors.
|
||||
|
||||
MPlayer is (C) 2000-2013 The MPlayer Team
|
||||
MPlayer is (C) 2000-2012 The MPlayer Team
|
||||
|
||||
This man page was written mainly by Gabucino, Jonas Jermann and Diego Biurrun.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -7,11 +7,10 @@ syntax is:
|
||||
``--vf=<filter1[=parameter1:parameter2:...],filter2,...>``
|
||||
Setup a chain of video filters.
|
||||
|
||||
You can also set defaults for each filter. The defaults are applied before the
|
||||
normal filter parameters.
|
||||
|
||||
``--vf-defaults=<filter1[=parameter1:parameter2:...],filter2,...>``
|
||||
Set defaults for each filter.
|
||||
Many parameters are optional and set to default values if omitted. To
|
||||
explicitly use a default value, set a parameter to '-1'. Parameters ``w:h``
|
||||
means width x height in pixels, ``x:y`` means x;y position counted from the
|
||||
upper left corner of the bigger image.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -47,7 +46,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 +54,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>``
|
||||
@@ -75,7 +74,7 @@ Available filters are:
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``expand=800::::4/3``
|
||||
``expand=800:::::4/3``
|
||||
Expands to 800x600, unless the source is higher resolution, in
|
||||
which case it expands to fill a 4/3 aspect.
|
||||
|
||||
@@ -83,20 +82,25 @@ Available filters are:
|
||||
Rounds up to make both width and height divisible by <r> (default: 1).
|
||||
|
||||
``flip``
|
||||
Flips the image upside down.
|
||||
Flips the image upside down. See also ``--flip``.
|
||||
|
||||
``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
|
||||
colorspace conversion (see also ``--sws``).
|
||||
|
||||
All parameters are optional.
|
||||
|
||||
``<w>,<h>``
|
||||
scaled width/height (default: original width/height)
|
||||
|
||||
@@ -109,7 +113,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``::
|
||||
|
||||
@@ -124,14 +136,6 @@ Available filters are:
|
||||
|
||||
--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.
|
||||
|
||||
``<noup>``
|
||||
Disallow upscaling past the original dimensions.
|
||||
|
||||
@@ -146,7 +150,7 @@ Available filters are:
|
||||
:0: Disable accurate rounding (default).
|
||||
:1: Enable accurate rounding.
|
||||
|
||||
``dsize[=w:h:aspect-method:r:aspect]``
|
||||
``dsize[=aspect|w:h:aspect-method:r]``
|
||||
Changes the intended display size/aspect at an arbitrary point in the
|
||||
filter chain. Aspect can be given as a fraction (4/3) or floating point
|
||||
number (1.33). Alternatively, you may specify the exact display width and
|
||||
@@ -195,9 +199,6 @@ Available filters are:
|
||||
Rounds up to make both width and height divisible by ``<r>``
|
||||
(default: 1).
|
||||
|
||||
``<aspect>``
|
||||
Force an aspect ratio.
|
||||
|
||||
``format[=fmt[:outfmt]]``
|
||||
Restricts the color space for the next filter without doing any conversion.
|
||||
Use together with the scale filter for a real conversion.
|
||||
@@ -231,7 +232,7 @@ Available filters are:
|
||||
``<fmt>``
|
||||
Format name, e.g. rgb15, bgr24, 420p, etc. (default: 420p).
|
||||
|
||||
``pp[=[filter1[:option1[:option2...]]/[-]filter2...]]``
|
||||
``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
|
||||
@@ -249,12 +250,7 @@ Available filters are:
|
||||
|
||||
.. note::
|
||||
|
||||
``--vf=pp:help`` shows a list of available subfilters.
|
||||
|
||||
.. note::
|
||||
|
||||
Unlike in MPlayer or in earlier versions, you must quote the pp string
|
||||
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
|
||||
``--pphelp`` shows a list of available subfilters.
|
||||
|
||||
Available subfilters are:
|
||||
|
||||
@@ -368,14 +364,14 @@ Available filters are:
|
||||
``--vf=pp=de/-al``
|
||||
default filters without brightness/contrast correction
|
||||
|
||||
``--vf=pp=[default/tmpnoise:1:2:3]``
|
||||
``--vf=pp=default/tmpnoise:1:2:3``
|
||||
Enable default filters & temporal denoiser.
|
||||
|
||||
``--vf=pp=[hb:y/vb:a]``
|
||||
``--vf=pp=hb:y/vb:a``
|
||||
Horizontal deblocking on luminance only, and switch vertical
|
||||
deblocking on or off automatically depending on available CPU time.
|
||||
|
||||
``lavfi=graph[:sws-flags[:o=opts]]``
|
||||
``lavfi=graph[:sws_flags[:o=opts]]``
|
||||
Filter video using FFmpeg's libavfilter.
|
||||
|
||||
``<graph>``
|
||||
@@ -409,7 +405,7 @@ Available filters are:
|
||||
``'--vf=lavfi=graph="gradfun=radius=30:strength=20,vflip"'``
|
||||
Same as before, but uses named parameters for everything.
|
||||
|
||||
``<sws-flags>``
|
||||
``<sws_flags>``
|
||||
If libavfilter inserts filters for pixel format conversion, this
|
||||
option gives the flags which should be passed to libswscale. This
|
||||
option is numeric and takes a bit-wise combination of ``SWS_`` flags.
|
||||
@@ -424,30 +420,21 @@ Available filters are:
|
||||
``'--vf=lavfi=yadif:o="threads=2,thread_type=slice"'``
|
||||
forces a specific threading configuration.
|
||||
|
||||
``noise[=<strength>[:averaged][:pattern][:temporal][:uniform][:hq]``
|
||||
``noise[=luma[u][t|a][h][p]:chroma[u][t|a][h][p]]``
|
||||
Adds noise.
|
||||
|
||||
``strength``
|
||||
Set the noise for all components. If you want different strength
|
||||
values for luma and chroma, use libavfilter's noise filter directly
|
||||
(using ``--vf=lavfi=[noise=...]``), or tell the libavfilter developers
|
||||
to stop being stupid.
|
||||
:<0-100>: luma noise
|
||||
:<0-100>: chroma noise
|
||||
:u: uniform noise (gaussian otherwise)
|
||||
:t: temporal noise (noise pattern changes between frames)
|
||||
:a: averaged temporal noise (smoother, but a lot slower)
|
||||
:h: high quality (slightly better looking, slightly slower)
|
||||
:p: mix random noise with a (semi)regular pattern
|
||||
|
||||
``averaged``
|
||||
averaged temporal noise (smoother, but a lot slower)
|
||||
.. note::
|
||||
|
||||
``pattern``
|
||||
mix random noise with a (semi)regular pattern
|
||||
|
||||
``temporal``
|
||||
temporal noise (noise pattern changes between frames)
|
||||
|
||||
``uniform``
|
||||
uniform noise (gaussian otherwise)
|
||||
|
||||
``hq``
|
||||
high quality (slightly better looking, slightly slower) - not available
|
||||
when using libavfilter
|
||||
Deprecated. Use libavfilter's ``noise`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
``hqdn3d[=luma_spatial:chroma_spatial:luma_tmp:chroma_tmp]``
|
||||
This filter aims to reduce image noise producing smooth images and making
|
||||
@@ -463,6 +450,11 @@ Available filters are:
|
||||
chroma temporal strength (default:
|
||||
``luma_tmp*chroma_spatial/luma_spatial``)
|
||||
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``hqdn3d`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
``eq[=gamma:contrast:brightness:saturation:rg:gg:bg:weight]``
|
||||
Software equalizer that uses lookup tables (slow), allowing gamma correction
|
||||
in addition to simple brightness and contrast adjustment. The parameters are
|
||||
@@ -502,26 +494,39 @@ Available filters are:
|
||||
:0: nearest-neighbor sampling, fast but incorrect
|
||||
:1: linear interpolation (default)
|
||||
|
||||
``unsharp[=lx:ly:la:cx:cy:ca]``
|
||||
``unsharp[=l|cWxH:amount[:l|cWxH:amount]]``
|
||||
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.
|
||||
``l``
|
||||
Apply effect on luma component.
|
||||
|
||||
``lx``, ``ly``, ``cx``, ``cy``
|
||||
``c``
|
||||
Apply effect on chroma components.
|
||||
|
||||
``<width>x<height>``
|
||||
width and height of the matrix, odd sized in both directions (min =
|
||||
3:3, max = 13:11 or 11:13, usually something between 3:3 and 7:7)
|
||||
3x3, max = 13x11 or 11x13, usually something between 3x3 and 7x7)
|
||||
|
||||
``la``, ``ca``
|
||||
``amount``
|
||||
Relative amount of sharpness/blur to add to the image (a sane range
|
||||
should be -1.5-1.5).
|
||||
|
||||
:<0: blur
|
||||
:>0: sharpen
|
||||
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``unsharp`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
``swapuv``
|
||||
Swap U & V plane.
|
||||
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``swapuv`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
``pullup[=jl:jr:jt:jb:sb:mp]``
|
||||
Pulldown reversal (inverse telecine) filter, capable of handling mixed
|
||||
hard-telecine, 24000/1001 fps progressive, and 30000/1001 fps progressive
|
||||
@@ -546,7 +551,7 @@ Available filters are:
|
||||
frames in the output.
|
||||
|
||||
``mp`` (metric plane)
|
||||
This option may be set to ``u`` or ``v`` to use a chroma plane instead of the
|
||||
This option may be set to 1 or 2 to use a chroma plane instead of the
|
||||
luma plane for doing ``pullup``'s computations. This may improve accuracy
|
||||
on very clean source material, but more likely will decrease accuracy,
|
||||
especially if there is chroma noise (rainbow effect) or any grayscale
|
||||
@@ -617,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``
|
||||
@@ -665,36 +670,41 @@ Available filters are:
|
||||
``v``
|
||||
Verbose operation. Prints the selected mode for each frame and the
|
||||
average squared difference between fields for ``t``, ``b``, and ``p``
|
||||
alternatives. (Ignored when libavfilter is used.)
|
||||
alternatives.
|
||||
|
||||
``yadif=[mode[:enabled=yes|no]]``
|
||||
Yet another deinterlacing filter
|
||||
|
||||
``<mode>``
|
||||
:frame: Output 1 frame for each frame.
|
||||
:field: Output 1 frame for each field.
|
||||
:frame-nospatial: Like ``frame`` but skips spatial interlacing check.
|
||||
:field-nospatial: Like ``field`` but skips spatial interlacing check.
|
||||
:0: Output 1 frame for each frame.
|
||||
:1: Output 1 frame for each field.
|
||||
:2: Like 0 but skips spatial interlacing check.
|
||||
:3: Like 1 but skips spatial interlacing check.
|
||||
|
||||
``<enabled>``
|
||||
:yes: Filter is active (default).
|
||||
:no: Filter is not active, but can be activated with the ``D`` key
|
||||
(or any other key that toggles the ``deinterlace`` property).
|
||||
|
||||
This filter, is automatically inserted when using the ``D`` key (or any
|
||||
other key that toggles the ``deinterlace`` property or when using the
|
||||
``--deinterlace`` switch), assuming the video output does not have native
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``yadif`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
This filter, or libavfilter's implementation if available, is automatically
|
||||
inserted when using the ``D`` key (or any other key that toggles the
|
||||
``deinterlace`` property), assuming the video output does not have native
|
||||
deinterlacing support.
|
||||
|
||||
If you just want to set the default mode, put this filter and its options
|
||||
into ``--vf-defaults`` instead, and enable deinterlacing with ``D`` or
|
||||
``--deinterlace``.
|
||||
``down3dright[=lines]``
|
||||
Reposition and resize stereoscopic images. Extracts both stereo fields and
|
||||
places them side by side, resizing them to maintain the original movie
|
||||
aspect.
|
||||
|
||||
Also note that the ``D`` key is stupid enough to insert an interlacer twice
|
||||
when inserting yadif with ``--vf``, so using the above methods is
|
||||
recommended.
|
||||
``<lines>``
|
||||
number of lines to select from the middle of the image (default: 12)
|
||||
|
||||
``delogo[=x:y:w:h:t:show]``
|
||||
``delogo[=x:y:w:h:t]``
|
||||
Suppresses a TV station logo by a simple interpolation of the surrounding
|
||||
pixels. Just set a rectangle covering the logo and watch it disappear (and
|
||||
sometimes something even uglier appear - your mileage may vary).
|
||||
@@ -707,8 +717,15 @@ 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.
|
||||
``show``
|
||||
Draw a rectangle showing the area defined by x/y/w/h.
|
||||
``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).
|
||||
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``delogo`` or ``removelogo`` filters
|
||||
through ``--vf=lavfi`` instead.
|
||||
|
||||
``screenshot``
|
||||
Optional filter for screenshot support. This is only needed if the video
|
||||
@@ -801,24 +818,29 @@ Available filters are:
|
||||
``mr`` or ``mono_right``
|
||||
mono output (right eye only)
|
||||
|
||||
``gradfun[=strength[:radius|:size=<size>]]``
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``stereo3d`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
``gradfun[=strength[:radius]]``
|
||||
Fix the banding artifacts that are sometimes introduced into nearly flat
|
||||
regions by truncation to 8bit color depth. Interpolates the gradients that
|
||||
should go where the bands are, and dithers them.
|
||||
|
||||
``<strength>``
|
||||
Maximum amount by which the filter will change any one pixel. Also the
|
||||
threshold for detecting nearly flat regions (default: 1.5).
|
||||
threshold for detecting nearly flat regions (default: 1.2).
|
||||
|
||||
``<radius>``
|
||||
Neighborhood to fit the gradient to. Larger radius makes for smoother
|
||||
gradients, but also prevents the filter from modifying pixels near
|
||||
detailed regions (default: disabled).
|
||||
detailed regions (default: 16).
|
||||
|
||||
``<size>``
|
||||
size of the filter in percent of the image diagonal size. This is
|
||||
used to calculate the final radius size (default: 1).
|
||||
.. note::
|
||||
|
||||
Deprecated. Use libavfilter's ``gradfun`` filter through ``--vf=lavfi``
|
||||
instead.
|
||||
|
||||
``dlopen=dll[:a0[:a1[:a2[:a3]]]]``
|
||||
Loads an external library to filter the image. The library interface
|
||||
@@ -839,139 +861,3 @@ 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.
|
||||
|
||||
``vavpp``
|
||||
VA-AP-API video post processing. Works with ``--vo=vaapi`` and ``--vo=opengl``
|
||||
only. Currently deinterlaces. This filter is automatically inserted if
|
||||
deinterlacing is requested (either using the ``D`` key, by default mapped to
|
||||
the command ``cycle deinterlace``, or the ``--deinterlace`` option).
|
||||
|
||||
``deint=<method>``
|
||||
Select the deinterlacing algorithm.
|
||||
|
||||
no
|
||||
Don't perform deinterlacing.
|
||||
first-field
|
||||
Show only first field (going by ``--field-dominance``).
|
||||
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.)
|
||||
@@ -10,19 +10,10 @@ syntax is:
|
||||
If the list has a trailing ',', mpv will fall back on drivers not contained
|
||||
in the list. Suboptions are optional and can mostly be omitted.
|
||||
|
||||
You can also set defaults for each driver. The defaults are applied before the
|
||||
normal driver parameters.
|
||||
|
||||
``--vo-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
|
||||
Set defaults for each driver.
|
||||
|
||||
.. note::
|
||||
|
||||
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,``
|
||||
@@ -31,11 +22,12 @@ normal driver parameters.
|
||||
Available video output drivers are:
|
||||
|
||||
``xv`` (X11 only)
|
||||
Uses the XVideo extension to enable hardware-accelerated display. This is
|
||||
Uses the XVideo extension to enable hardware-accelerated playback. This is
|
||||
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.
|
||||
For information about what colorkey is used and how it is drawn, run
|
||||
mpv with the ``-v`` option and look out for the lines tagged with ``[xv
|
||||
common]`` at the beginning.
|
||||
|
||||
``adaptor=<number>``
|
||||
Select a specific XVideo adaptor (check xvinfo results).
|
||||
@@ -79,36 +71,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 postprocessing, 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 +97,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
|
||||
@@ -162,16 +133,6 @@ Available video output drivers are:
|
||||
``output_surfaces=<2-15>``
|
||||
Allocate this many output surfaces to display video frames (default:
|
||||
3). See below for additional information.
|
||||
``colorkey=<#RRGGBB|#AARRGGBB>``
|
||||
Set the VDPAU presentation queue background color, which in practice
|
||||
is the colorkey used if VDPAU operates in overlay mode (default:
|
||||
``#020507``, some shade of black). If the alpha component of this value
|
||||
is 0, the default VDPAU colorkey will be used instead (which is usually
|
||||
green).
|
||||
``force-yuv``
|
||||
Never accept RGBA input. This means mpv will insert a filter to convert
|
||||
to a YUV format before the VO. Sometimes useful to force availability
|
||||
of certain YUV-only features, like video equalizer or deinterlacing.
|
||||
|
||||
Using the VDPAU frame queueing functionality controlled by the queuetime
|
||||
options makes mpv's frame flip timing less sensitive to system CPU load and
|
||||
@@ -198,9 +159,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.
|
||||
|
||||
@@ -257,15 +215,11 @@ 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``).
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``opengl``
|
||||
OpenGL video output driver. It supports extended scaling methods, dithering
|
||||
and color management.
|
||||
@@ -280,11 +234,6 @@ Available video output drivers are:
|
||||
Some features are available with OpenGL 3 capable graphics drivers only
|
||||
(or if the necessary extensions are available).
|
||||
|
||||
Hardware decoding over OpenGL-interop is supported to some degree. Note
|
||||
that in this mode, some corner case might not be gracefully handled, and
|
||||
colorspace conversion and chroma upsampling is generally in the hand of
|
||||
the hardware decoder APIs.
|
||||
|
||||
``lscale=<filter>``
|
||||
|
||||
``bilinear``
|
||||
@@ -293,13 +242,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.
|
||||
|
||||
``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.
|
||||
@@ -318,9 +265,7 @@ Available video output drivers are:
|
||||
|
||||
|
||||
There are some more filters. For a complete list, pass ``help`` as
|
||||
value, e.g.::
|
||||
|
||||
mpv --vo=opengl:lscale=help
|
||||
value, e.g.: ``mpv --vo=opengl:lscale=help``
|
||||
|
||||
``lparam1=<value>``
|
||||
Set filter parameters. Ignored if the filter is not tunable. These are
|
||||
@@ -338,9 +283,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
|
||||
@@ -353,26 +297,22 @@ Available video output drivers are:
|
||||
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
|
||||
sporadic and temporary image corruption (in theory, because reupload
|
||||
is not retried when it fails), and perhaps actually triggers slower
|
||||
paths with drivers that don't support PBOs properly.
|
||||
Enable use of PBOs. This is faster, but can sometimes lead to sporadic
|
||||
and temporary image corruption.
|
||||
|
||||
``dither-depth=<N|no|auto>``
|
||||
Set dither target depth to N. Default: no.
|
||||
@@ -473,30 +413,16 @@ Available video output drivers are:
|
||||
Selects the internal format of textures used for FBOs. The format can
|
||||
influence performance and quality of the video output. (FBOs are not
|
||||
always used, and typically only when using extended scalers.)
|
||||
``fmt`` can be one of: rgb, rgba, rgb8, rgb10, rgb10_a2, rgb16, rgb16f,
|
||||
rgb32f, rgba12, rgba16, rgba16f, rgba32f.
|
||||
``fmt`` can be one of: rgb, rgba, rgb8, rgb10, rgb16, rgb16f, rgb32f,
|
||||
rgba12, rgba16, rgba16f, rgba32f.
|
||||
Default: rgb.
|
||||
|
||||
``gamma=<0.0..10.0>``
|
||||
Set a gamma value. If gamma is adjusted in other ways (like with
|
||||
the ``--gamma`` option or keybindings and the ``gamma`` property), the
|
||||
value is multiplied with the other gamma value.
|
||||
|
||||
Setting this value to 1.0 can be used to always enable gamma control.
|
||||
(Disables delayed enabling.)
|
||||
``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 LittleCMS2 support compiled in. This option overrides the ``srgb``
|
||||
property, as using both is somewhat redundant. It also enables linear
|
||||
light scaling.
|
||||
|
||||
|
||||
``icc-profile-auto``
|
||||
Automatically select the ICC display profile currently specified by
|
||||
the display settings of the operating system.
|
||||
|
||||
NOTE: Only implemented on OS X with Cocoa.
|
||||
Needs LittleCMS2 support compiled in.
|
||||
|
||||
``icc-cache=<file>``
|
||||
Store and load the 3D LUT created from the ICC profile in this file.
|
||||
@@ -505,64 +431,38 @@ Available video output drivers are:
|
||||
Its size depends on the ``3dlut-size``, and can be very big.
|
||||
|
||||
``icc-intent=<value>``
|
||||
Specifies the ICC Intent used for transformations between colorspaces.
|
||||
This affects the rendering when using ``icc-profile`` or ``srgb`` and
|
||||
also affects the way DCP XYZ content gets converted to RGB.
|
||||
|
||||
0
|
||||
perceptual
|
||||
1
|
||||
relative colorimetric (default)
|
||||
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).
|
||||
|
||||
blend
|
||||
Blend the frame against a black background.
|
||||
yes
|
||||
Try to create a framebuffer with alpha component. This only makes sense
|
||||
if the video contains alpha information (which is extremely rare). May
|
||||
not be supported on all platforms. If alpha framebuffers are
|
||||
unavailable, it silently falls back on a normal framebuffer. Note
|
||||
that when using FBO indirections (such as with ``opengl-hq``), an FBO
|
||||
format with alpha must be specified with the ``fbo-format`` option.
|
||||
no
|
||||
Ignore alpha component.
|
||||
``alpha``
|
||||
Try to create a framebuffer with alpha component. This only makes sense
|
||||
if the video contains alpha information (which is extremely rare). May
|
||||
not be supported on all platforms. If alpha framebuffers are
|
||||
unavailable, it silently falls back on a normal framebuffer. Note
|
||||
that when using FBO indirections (such as with ``opengl-hq``), an FBO
|
||||
format with alpha must be specified with the ``fbo-format`` option.
|
||||
|
||||
``chroma-location=<auto|center|left>``
|
||||
Set the YUV chroma sample location. auto means use the bitstream
|
||||
flags (default: auto).
|
||||
|
||||
``rectangle-textures``
|
||||
Force use of rectangle textures (default: no). Normally this shouldn't
|
||||
have any advantages over normal textures. Note that hardware decoding
|
||||
overrides this flag.
|
||||
|
||||
``opengl-hq``
|
||||
Same as ``opengl``, but with default settings for high quality rendering.
|
||||
|
||||
This is equivalent to::
|
||||
|
||||
--vo=opengl:lscale=spline36:dither-depth=auto:fbo-format=rgba16
|
||||
--vo=opengl:lscale=lanczos2:dither-depth=auto:pbo:fbo-format=rgb16
|
||||
|
||||
Note that some cheaper LCDs do dithering that gravely interferes with
|
||||
``opengl``'s dithering. Disabling dithering with ``dither-depth=no`` helps.
|
||||
@@ -585,8 +485,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
|
||||
@@ -695,9 +593,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
|
||||
@@ -712,7 +609,8 @@ Available video output drivers are:
|
||||
The following options are only useful if writing your own fragment programs.
|
||||
|
||||
``customprog=<filename>``
|
||||
Load a custom fragment program from ``<filename>``.
|
||||
Load a custom fragment program from ``<filename>``. See
|
||||
``TOOLS/edgedect.fp`` for an example.
|
||||
``customtex=<filename>``
|
||||
Load a custom "gamma ramp" texture from ``<filename>``. This can be used
|
||||
in combination with ``yuv=4`` or with the ``customprog`` option.
|
||||
@@ -761,66 +659,18 @@ 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.
|
||||
|
||||
``switch-mode``
|
||||
Instruct SDL to switch the monitor video mode when going fullscreen.
|
||||
|
||||
``vaapi``
|
||||
Intel VA API video output driver with support for hardware decoding. Note
|
||||
that there is absolutely no reason to use this, other than wanting to use
|
||||
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).
|
||||
fast
|
||||
Fast, but low quality.
|
||||
hq
|
||||
Unspecified driver dependent high-quality scaling, slow.
|
||||
nla
|
||||
``non-linear anamorphic scaling``
|
||||
|
||||
``deint-mode=<mode>``
|
||||
Select deinterlacing algorithm. Note that by default deinterlacing is
|
||||
initially always off, and needs to be enabled with the ``D`` key
|
||||
(default key binding for ``cycle deinterlace``).
|
||||
|
||||
This option doesn't apply if libva supports video post processing (vpp).
|
||||
In this case, the default for ``deint-mode`` is ``no``, and enabling
|
||||
deinterlacing via user interaction using the methods mentioned above
|
||||
actually inserts the ``vavpp`` video filter. If vpp is not actually
|
||||
supported with the libva backend in use, you can use this option to
|
||||
forcibly enable VO based deinterlacing.
|
||||
|
||||
no
|
||||
Don't allow deinterlacing (default for newer libva).
|
||||
first-field
|
||||
Show only first field (going by ``--field-dominance``).
|
||||
bob
|
||||
bob deinterlacing (default for older libva).
|
||||
|
||||
``scaled-osd=<yes|no>``
|
||||
If enabled, then the OSD is rendered at video resolution and scaled to
|
||||
display resolution. By default, this is disabled, and the OSD is
|
||||
rendered at display resolution if the driver supports it.
|
||||
|
||||
``null``
|
||||
Produces no video output. Useful for benchmarking.
|
||||
|
||||
``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.
|
||||
@@ -862,21 +712,3 @@ Available video output drivers are:
|
||||
JPEG DPI (default: 72)
|
||||
``outdir=<dirname>``
|
||||
Specify the directory to save the image files to (default: ``./``).
|
||||
|
||||
``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.
|
||||
|
||||
``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.
|
||||
|
||||
-1353
File diff suppressed because it is too large.
Load diff
@@ -1,651 +0,0 @@
|
||||
LUA SCRIPTING
|
||||
=============
|
||||
|
||||
mpv can load Lua scripts. Scripts in ``~/.mpv/lua/`` will be loaded on program
|
||||
start, or if passed to ``--lua``. mpv provides the builtin module ``mp``, which
|
||||
provides functions to send commands to the mpv core and to retrieve information
|
||||
about playback state, user settings, file information, and so on.
|
||||
|
||||
These scripts can be used to control mpv in a similar way to slave mode.
|
||||
Technically, the Lua code uses the client API internally.
|
||||
|
||||
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 ``~/.mpv/lua/``,
|
||||
or ``--lua``, or in some cases, internally (like ``--osc``). Each script runs
|
||||
in its own thread. Your script is first run "as is", and once that is done,
|
||||
the event loop is entered. This event loop will dispatch events received by mpv
|
||||
and call your own event handlers which you have registered with
|
||||
``mp.register_event``, or timers added with ``mp.add_timeout`` or similar.
|
||||
|
||||
When the player quits, all scripts will be asked to terminate. This happens via
|
||||
a ``shutdown`` event, which by default will make the event loop return. If your
|
||||
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).
|
||||
|
||||
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.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])``
|
||||
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 overmapped the key with another binding).
|
||||
|
||||
The ``name`` argument should be a short symbolic string. It allows the user
|
||||
to remap the key binding via input.conf using the ``script_message``
|
||||
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.
|
||||
|
||||
Internally, key bindings are dispatched via the ``script_message_to`` input
|
||||
command and ``mp.register_script_message``.
|
||||
|
||||
Trying to map multiple commands to a key will essentially prefer a random
|
||||
binding, while the other bindings are not called. It is guaranteed that
|
||||
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_message something
|
||||
|
||||
|
||||
This will print the message when the key ``y`` is pressed. (``x`` will
|
||||
still work, unless the user overmaps it.)
|
||||
|
||||
You can also explicitly send a message to a named script only. Assume the
|
||||
above script was using the filename ``fooscript.lua``:
|
||||
|
||||
::
|
||||
|
||||
y script_message_to 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 calback 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 unqueue and dispatch mpv events.
|
||||
|
||||
If the ``allow_wait`` parameter is set to ``true``, the function will block
|
||||
until the next event is received or the next timer expires. Otherwise (and
|
||||
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.
|
||||
|
||||
``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.
|
||||
|
||||
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.
|
||||
|
||||
``tracks-changed``
|
||||
The list of video/audio/sub tracks was updated. (This happens on playback
|
||||
start, and very rarely during playback.)
|
||||
|
||||
``track-switched``
|
||||
A video/audio/subtitle track was switched on or off. This usually happens
|
||||
when the user (or a script) changes the subtitle track and so on.
|
||||
|
||||
``idle``
|
||||
Idle mode is entered. This happens when playback ended, and the player was
|
||||
started with ``--idle`` or ``--force-window``. This mode is implicitly ended
|
||||
when the ``start-file`` or ``shutdown`` events happen.
|
||||
|
||||
``pause``
|
||||
Playback was paused. This also happens when for example the player is
|
||||
paused on low network cache. Then the event type indicates the pause state
|
||||
(like the property "pause" as opposed to the "core-idle" property), and you
|
||||
might receive multiple ``pause`` events in a row.
|
||||
|
||||
``unpause``
|
||||
Playback was unpaused. See above for details.
|
||||
|
||||
``tick``
|
||||
Called after a video frame was displayed. This is a hack, and you should
|
||||
avoid using it. Use timers instead and maybe watch pausing/unpausing events
|
||||
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.
|
||||
|
||||
``metadata-update``
|
||||
Metadata (like file tags) was updated.
|
||||
|
||||
``chapter-change``
|
||||
The current chapter possibly changed.
|
||||
@@ -1,252 +0,0 @@
|
||||
ON SCREEN CONTROLLER
|
||||
====================
|
||||
|
||||
The On Screen Controller (short: OSC) is a minimal GUI integrated with mpv to
|
||||
offer basic mouse-controllability. It is intended to make interaction easier
|
||||
for new users and to enable precise and direct seeking.
|
||||
|
||||
The OSC is enabled by default if mpv was compiled with lua support. It can be
|
||||
disabled entirely using the ``--osc=no`` option.
|
||||
|
||||
Using the OSC
|
||||
-------------
|
||||
|
||||
By default, the OSC will show up whenever the mouse is moved inside the
|
||||
player window and will hide if the mouse is not moved outside the OSC for
|
||||
0.5 seconds or if the mouse leaves the window.
|
||||
|
||||
The Interface
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
+------------------+-----------+--------------------+
|
||||
| playlist prev | title | playlist next |
|
||||
+-------+------+---+--+------+-+----+------+--------+
|
||||
| audio | skip | seek | | seek | skip | full |
|
||||
+-------+ back | back | play | frwd | frwd | screen |
|
||||
| sub | | | | | | |
|
||||
+-------+------+------+------+------+------+--------+
|
||||
| seekbar |
|
||||
+----------------+--------------+-------------------+
|
||||
| time passed | cache status | time remaining |
|
||||
+----------------+--------------+-------------------+
|
||||
|
||||
|
||||
playlist prev
|
||||
============= ================================================
|
||||
left-click play previous file in playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
title
|
||||
| Displays current media-title or filename
|
||||
|
||||
============= ================================================
|
||||
left-click show playlist position and length and full title
|
||||
right-click show filename
|
||||
============= ================================================
|
||||
|
||||
playlist next
|
||||
============= ================================================
|
||||
left-click play next file in playlist
|
||||
shift+L-click show playlist
|
||||
============= ================================================
|
||||
|
||||
audio and sub
|
||||
| Displays selected track and amount of available tracks
|
||||
|
||||
============= ================================================
|
||||
left-click cycle audio/sub tracks forward
|
||||
right-click cycle audio/sub tracks backwards
|
||||
shift+L-click show available audio/sub tracks
|
||||
============= ================================================
|
||||
|
||||
skip back
|
||||
============= ================================================
|
||||
left-click go to beginning of chapter / previous chapter
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
seek back
|
||||
============= ================================================
|
||||
left-click skip back 5 seconds
|
||||
right-click skip back 30 seconds
|
||||
shift-L-click skip back 1 frame
|
||||
============= ================================================
|
||||
|
||||
play
|
||||
============= ================================================
|
||||
left-click toggle play/pause
|
||||
============= ================================================
|
||||
|
||||
seek frwd
|
||||
============= ================================================
|
||||
left-click skip forward 10 seconds
|
||||
right-click skip forward 60 seconds
|
||||
shift-L-click skip forward 1 frame
|
||||
============= ================================================
|
||||
|
||||
skip frwd
|
||||
============= ================================================
|
||||
left-click go to next chapter
|
||||
shift+L-click show chapters
|
||||
============= ================================================
|
||||
|
||||
fullscreen
|
||||
============= ================================================
|
||||
left-click toggle fullscreen
|
||||
============= ================================================
|
||||
|
||||
seekbar
|
||||
| Indicates current playback position and position of chapters
|
||||
|
||||
============= ================================================
|
||||
left-click seek to position
|
||||
============= ================================================
|
||||
|
||||
time passed
|
||||
| Shows current playback position timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle displaying timecodes with milliseconds
|
||||
============= ================================================
|
||||
|
||||
cache status
|
||||
| Shows current cache fill status (only visible when below 45%)
|
||||
|
||||
time remaining
|
||||
| Shows remaining playback time timestamp
|
||||
|
||||
============= ================================================
|
||||
left-click toggle between total and remaining time
|
||||
============= ================================================
|
||||
|
||||
Keybindings
|
||||
~~~~~~~~~~~
|
||||
|
||||
These keybindings are active by default if nothing else is already bound to
|
||||
these keys. In case of collosision, the function needs to be bound to a
|
||||
different key. See `Script Commands`_ section.
|
||||
|
||||
============= ================================================
|
||||
del 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.
|
||||
|
||||
Config Syntax
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The config file must exactly follow the following syntax::
|
||||
|
||||
# this is a comment
|
||||
optionA=value1
|
||||
optionB=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
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``showwindowed``
|
||||
| Default: yes
|
||||
| Show OSC when windowed?
|
||||
|
||||
``showfullscreen``
|
||||
| Default: yes
|
||||
| Show OSC when fullscreen?
|
||||
|
||||
``scalewindowed``
|
||||
| Default: 1
|
||||
| Scaling of the controller when windowed
|
||||
|
||||
``scalefullscreen``
|
||||
| Default: 1
|
||||
| Scaling of the controller when fullscreen
|
||||
|
||||
``scaleforcedwindow``
|
||||
| Default: 2
|
||||
| Scaling of the controller when rendered on a forced (dummy) window
|
||||
|
||||
``vidscale``
|
||||
| Default: yes
|
||||
| Scale the controller with the video?
|
||||
|
||||
``valign``
|
||||
| Default: 0.8
|
||||
| Vertical alignment, -1 (top) to 1 (bottom)
|
||||
|
||||
``halign``
|
||||
| Default: 0
|
||||
| Horizontal alignment, -1 (left) to 1 (right)
|
||||
|
||||
``boxalpha``
|
||||
| Default: 80
|
||||
| Alpha of the background box, 0 (opaque) to 255 (fully transparent)
|
||||
|
||||
``hidetimeout``
|
||||
| Default: 500
|
||||
| Duration in ms until the OSC hides if no mouse movement, negative value
|
||||
disables auto-hide
|
||||
|
||||
``fadeduration``
|
||||
| Default: 200
|
||||
| Duration of fade out in ms, 0 = no fade
|
||||
|
||||
``deadzonesize``
|
||||
| Default: 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.
|
||||
|
||||
``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.
|
||||
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
+40
-55
@@ -1,11 +1,12 @@
|
||||
This file intends to give a big picture 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
|
||||
and the playback loop.
|
||||
|
||||
Generally, it accesses all other subsystems, initializes them, and pushes
|
||||
data between them during playback.
|
||||
mpvcore/mplayer.c:
|
||||
This contains the main play loop, anything related to mpv and playback
|
||||
related initializations. It also contains the main function. Generally, it
|
||||
accesses all other subsystems, initializes them, and pushes data between
|
||||
them during playback.
|
||||
|
||||
The structure is as follows (as of commit e13c05366557cb):
|
||||
* main():
|
||||
@@ -17,12 +18,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.)
|
||||
@@ -41,7 +42,7 @@ player/*.c:
|
||||
- the other subsystems rarely call back into the frontend, and the frontend
|
||||
polls them instead (probably a good thing)
|
||||
|
||||
I like to call the player/*.c files the "frontend".
|
||||
I like to call mplayer.c (and some other files) the "frontend".
|
||||
|
||||
talloc.h & talloc.c:
|
||||
Hierarchical memory manager copied from Samba. It's like a malloc() with
|
||||
@@ -75,53 +76,37 @@ talloc.h & talloc.c:
|
||||
replacement. It works on top of system malloc and provides additional
|
||||
features that are supposed to make memory management easier.
|
||||
|
||||
Warning: actually, we're not using talloc anymore. talloc in mpv has been
|
||||
replaced by a custom re-implementation (TA in ta/). It provides
|
||||
some talloc emulation (just the parts needed by mpv). We will get
|
||||
rid of the talloc emulation later and use TA natively.
|
||||
(See ta/README for details.)
|
||||
mpvcore/mp_core.h:
|
||||
Data structures for mplayer.c and command.c. They are usually not accessed
|
||||
by other parts of mpv for the sake of modularization.
|
||||
|
||||
player/command.c:
|
||||
This contains the implementation for client API 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,
|
||||
where most of the work is done, but also calls other parts of mpv.
|
||||
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.
|
||||
|
||||
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.
|
||||
options.h contains the global option struct MPOpts, and its default values
|
||||
are in defaultopts.c for some reason.
|
||||
|
||||
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.
|
||||
|
||||
options/options.h, options/options.c
|
||||
options.h contains the global option struct MPOpts. The option declarations
|
||||
(option names, types, and MPOpts offsets for the option parser) are in
|
||||
options.c. Most default values for options and MPOpts are in
|
||||
mp_default_opts at the end of options.c.
|
||||
|
||||
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.
|
||||
|
||||
The actual option parser is spread over m_option.c, m_config.c, and
|
||||
parser-mpcmd.c, and uses the option table in options.c.
|
||||
|
||||
input/input.c:
|
||||
mpvcore/input/input.c:
|
||||
This translates keyboard input comming from libvo and other sources (such
|
||||
as remote control devices like Apple IR or client API commands) to the
|
||||
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.
|
||||
by mplayer.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:
|
||||
mpvcore/command.c:
|
||||
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 mplayer.c, where most of the
|
||||
work is done, but also into other parts of mpv.
|
||||
|
||||
mpvcore/mp_msg.h:
|
||||
All terminal output should go through mp_msg().
|
||||
|
||||
stream/*:
|
||||
@@ -197,8 +182,8 @@ audio/decode/:
|
||||
|
||||
audio/filter/:
|
||||
Audio filter chain. af_lavrresample is inserted if any form of conversion
|
||||
between audio formats is needed. (af_convert24.c and af_convertsignendian.c
|
||||
are also used for some formats not directly supported by FFmpeg.)
|
||||
between audio formats is needed. (af_format.c is also used for some corner
|
||||
cases.)
|
||||
|
||||
audio/out/:
|
||||
Audio outputs.
|
||||
@@ -213,7 +198,7 @@ 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).
|
||||
@@ -222,7 +207,7 @@ sub/:
|
||||
.ass subtitles via libass. demux_lavf.c loads most subtitle types via
|
||||
FFmpeg. demux_subreader.c is the old MPlayer code. It's used as last
|
||||
fallback, or to handle some text subtitle types on Libav. (It also can
|
||||
load UTF-16 encoded subtitles without requiring the use of -sub-codepage.)
|
||||
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
|
||||
@@ -238,8 +223,8 @@ sub/:
|
||||
detection as well as timing postprocessing work. (Timing postprocessing
|
||||
removes tiny gaps or overlaps between subtitle events.)
|
||||
|
||||
player/timeline/:
|
||||
A timeline is the abstraction used by loadfile.c to combine several files
|
||||
mpvcore/timeline/:
|
||||
A timeline is the abstraction used by mplayer.c to combine several files
|
||||
into one seemingly linear video. It's mainly used for ordered chapters
|
||||
playback. The high level code to find and load other files containing the
|
||||
segments for playing an ordered chapters file is in tl_matroska.c.
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
waf build system overview
|
||||
=========================
|
||||
|
||||
mpv's new build system is based on waf and it should completly replace the
|
||||
custom ./configure + Makefile based system inherited from MPlayer.
|
||||
|
||||
Goals and the choice of waf
|
||||
===========================
|
||||
|
||||
The new system comes with some goals, which can be summed up as: be as good as
|
||||
the old one at what it did well (customizability) and fix some of it's major
|
||||
shortcomings:
|
||||
|
||||
1) The build system must be uniform in how it handles any single feature check.
|
||||
Repetition and boilerplate have to be avoided.
|
||||
|
||||
When adding a new feature using the old configure, one had to add a fair
|
||||
amount of code to the shell script to do option parsing, detection of the
|
||||
feature and declaration of variables for the Makefile to pickup. The worst
|
||||
part is this pieces are spread apart in the configure and copy pasted for
|
||||
any single case. That brings us to..
|
||||
|
||||
2) --enable-feature has to override the user and help him understand that he
|
||||
has libraries missing and should install them for the feature to be enabled.
|
||||
|
||||
3) Must be customizable, hackable, pleasant to the developer eyes and to work
|
||||
with in general.
|
||||
|
||||
4) Must have separate configuration and build steps.
|
||||
|
||||
Goal 2 comes as a given on pretty much any build system, since autotools made
|
||||
this behaviour very popular among users (and rightly so).
|
||||
|
||||
Goal 1+3 were somewhat harder to accomplish as it looks like all of the build
|
||||
systems we evaluated (waf included!) had problems with them. For reference we
|
||||
had proof of concept build systems with waf, CMake and autotools.
|
||||
|
||||
What puts waf apart from CMake and autotools, is that projects using it use
|
||||
Python to program their build system. Also while the Waf Book shows really
|
||||
simple API usages, you can write your own build system on top of waf that is
|
||||
tailored to the project's specific needs.
|
||||
|
||||
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>`_.
|
||||
|
||||
All of the configuration process is handled with a declarative approach. Lists
|
||||
of dictionaries define the checks, and some custom Python code traverses these
|
||||
lists and depending on the check definition it calls into the actual waf API.
|
||||
|
||||
A simple example using pkg-config would be::
|
||||
|
||||
{
|
||||
'name': '--vdpau',
|
||||
'desc': 'VDPAU acceleration',
|
||||
'deps': [ 'x11' ],
|
||||
'func': check_pkg_config('vdpau', '>= 0.2'),
|
||||
}
|
||||
|
||||
This defines a feature called ``vdpau`` which can be enabled or disabled by
|
||||
the users with configure flags (that's the meaning of ``--``). This feature
|
||||
depends on another feature whose name is ``x11``, and the autodetection check
|
||||
consists of running ``pkg-config`` and looking for ``vdpau`` with version
|
||||
``>= 0.2``. If the check succeds a ``#define HAVE_VDPAU 1`` will be added to
|
||||
``config.h``, if not ``#define HAVE_VDPAU 0`` will be added.
|
||||
|
||||
The defines names are automatically prepended with ``HAVE_``, capitalized and
|
||||
special characters are replaced with underscores. This happens in
|
||||
``waftools/inflectors.py``.
|
||||
|
||||
Mandatory fields:
|
||||
-----------------
|
||||
|
||||
``name``: indicates the unique identifier used by the custom dependency code
|
||||
to refer to a feature. If the unique identifier is prepended with ``--``
|
||||
the build system will also generate options for ``./waf configure`` so that
|
||||
the feature can be enabled and disabled.
|
||||
|
||||
``desc``: this is the textual representation of the feature used in the
|
||||
interactions with the users.
|
||||
|
||||
``func``: function that will perform the check. These functions are defined in
|
||||
``waftools/checks``. The reusable checks are all functions that return
|
||||
functions. The return functions will then be applied using waf's configuration
|
||||
context.
|
||||
|
||||
The source code for the reusable checks is a bit convoluted, but it should be
|
||||
easy to pick up their usage from the ``wscript``. Their signature mirrors
|
||||
the semantics of some of the shell functions used in mplayer.
|
||||
|
||||
If someone expresses some interest, I will extend this document with official
|
||||
documentation for each check function.
|
||||
|
||||
Optional fields
|
||||
---------------
|
||||
|
||||
``deps``: list of dependencies of this feature. It is a list of names of
|
||||
other features as defined in the ``name`` field (minus the eventual leading
|
||||
``--``). All of the dependencies must be satisfied. If they are not the check
|
||||
will be skipped without even running ``func``.
|
||||
|
||||
``deps_any``: like deps but it is satisfied even if only one of the dependencies
|
||||
is satisfied. You can think of ``deps`` as a 'and' condition and ``deps_any``
|
||||
as a 'or' condition.
|
||||
|
||||
``deps_neg``: like deps but it is satisfied when none of the dependencies is
|
||||
satisfied.
|
||||
|
||||
``req``: defaults to False. If set to True makes this feature a hard
|
||||
dependency of mpv (configuration will fail if autodetection fails). If set to
|
||||
True you must also provide ``fmsg``.
|
||||
|
||||
``fmsg``: string with the failure message in case a required dependency is not
|
||||
satisfied.
|
||||
|
||||
``os_specific_checks``: this takes a dictionary that has ``os-`` dependencies
|
||||
as keys (such as ``os-win32``), and by values has another dictionary that is
|
||||
merged on top of the current feature definition only for that specific OS.
|
||||
For example::
|
||||
|
||||
{
|
||||
'name': '--pthreads',
|
||||
'desc': 'POSIX threads',
|
||||
'func': check_pthreads,
|
||||
'os_specific_checks': {
|
||||
'os-win32': {
|
||||
'func': check_pthreads_w32_static.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
will override the value of ``func`` with ``check_pthreads_w32_static`` only
|
||||
if the target OS of the build is Windows.
|
||||
|
||||
``groups``: groups a dependency with another one. This can be used to disabled
|
||||
all the grouped dependencies with one ``--disable-``. At the moment this is
|
||||
only used for OpenGL backends, where you want to disable them when
|
||||
``--disable-gl`` is passed to the configure.
|
||||
|
||||
mpv's custom build step on top of waf
|
||||
=====================================
|
||||
|
||||
Build step is pretty much vanilla waf. The only difference being that the list
|
||||
of source files can contain both strings or tuples. If a tuple is found,
|
||||
the second element in the tuple will the used to match the features detected
|
||||
in the configure step (the ``name`` field described above). If this feature
|
||||
was not enabled during configure, the source file will not be compiled in.
|
||||
|
||||
All of the custom Python for this is inside the function ``filtered_sources``
|
||||
contained in the file ``waftools/dependencies.py``.
|
||||
|
||||
Also ``dependencies_use`` and ``dependencies_includes`` collect cflags and
|
||||
ldflags that were generated from the features checks in the configure step.
|
||||
@@ -1,284 +1,625 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
0. Definitions.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
1. Source Code.
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
14. Revised Versions of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
NO WARRANTY
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
@@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
This program 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
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
@@ -304,37 +645,30 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
+152
-188
@@ -19,22 +19,21 @@
|
||||
# with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
include old_build/config.mak
|
||||
include config.mak
|
||||
|
||||
###### variable declarations #######
|
||||
|
||||
SOURCES_AUDIO_INPUT-$(ALSA) += stream/ai_alsa1x.c
|
||||
SOURCES_AUDIO_INPUT-$(OSS_AUDIO)+= stream/ai_oss.c
|
||||
SOURCES_AUDIO_INPUT-$(SNDIO) += stream/ai_sndio.c
|
||||
SOURCES_AUDIO_INPUT-$(OSS) += stream/ai_oss.c
|
||||
SOURCES-$(AUDIO_INPUT) += $(SOURCES_AUDIO_INPUT-yes)
|
||||
SOURCES-$(CDDA) += stream/stream_cdda.c
|
||||
SOURCES-$(CDDA) += stream/stream_cdda.c \
|
||||
stream/cdinfo.c
|
||||
SOURCES-$(DVBIN) += stream/dvb_tune.c \
|
||||
stream/stream_dvb.c
|
||||
SOURCES-$(DVDREAD) += stream/stream_dvd.c \
|
||||
stream/stream_dvd_common.c
|
||||
SOURCES-$(DVDNAV) += stream/stream_dvdnav.c \
|
||||
stream/stream_dvd_common.c
|
||||
|
||||
SOURCES-$(HAVE_SYS_MMAN_H) += audio/filter/af_export.c
|
||||
SOURCES-$(LADSPA) += audio/filter/af_ladspa.c
|
||||
SOURCES-$(LIBASS) += sub/ass_mp.c sub/sd_ass.c \
|
||||
demux/demux_libass.c
|
||||
@@ -45,21 +44,43 @@ SOURCES-$(LIBBS2B) += audio/filter/af_bs2b.c
|
||||
SOURCES-$(LIBPOSTPROC) += video/filter/vf_pp.c
|
||||
SOURCES-$(LIBSMBCLIENT) += stream/stream_smb.c
|
||||
|
||||
SOURCES-$(MACOSX_BUNDLE) += osdep/macosx_bundle.m
|
||||
SOURCES-$(COCOA) += video/out/cocoa_common.m \
|
||||
osdep/macosx_application.m \
|
||||
osdep/macosx_events.m \
|
||||
osdep/ar/HIDRemote.m
|
||||
SOURCES-$(MNG) += demux/demux_mng.c
|
||||
SOURCES-$(MPG123) += audio/decode/ad_mpg123.c
|
||||
|
||||
SOURCES-$(NEED_GETTIMEOFDAY) += osdep/gettimeofday.c
|
||||
SOURCES-$(NEED_GLOB) += osdep/glob-win.c
|
||||
|
||||
SOURCES-$(PRIORITY) += osdep/priority.c
|
||||
SOURCES-$(PVR) += stream/stream_pvr.c
|
||||
SOURCES-$(RADIO) += stream/stream_radio.c
|
||||
SOURCES-$(RADIO_CAPTURE) += stream/audio_in.c
|
||||
SOURCES-$(STREAM_CACHE) += stream/cache.c
|
||||
|
||||
SOURCES-$(TV) += stream/stream_tv.c stream/tv.c \
|
||||
stream/frequencies.c stream/tvi_dummy.c \
|
||||
demux/demux_tv.c
|
||||
stream/frequencies.c stream/tvi_dummy.c
|
||||
|
||||
SOURCES-$(TV_V4L2) += stream/tvi_v4l2.c stream/audio_in.c
|
||||
SOURCES-$(VCD) += stream/stream_vcd.c
|
||||
SOURCES-$(DUMMY_OSD) += sub/osd_dummy.c
|
||||
SOURCES-$(LIBASS_OSD) += sub/osd_libass.c
|
||||
|
||||
SOURCES-$(ALSA) += audio/out/ao_alsa.c
|
||||
SOURCES-$(CACA) += video/out/vo_caca.c
|
||||
SOURCES-$(SDL2) += audio/out/ao_sdl.c video/out/vo_sdl.c
|
||||
SOURCES-$(SDL) += audio/out/ao_sdl.c
|
||||
SOURCES-$(SDL2) += video/out/vo_sdl.c
|
||||
SOURCES-$(COREAUDIO) += audio/out/ao_coreaudio.c \
|
||||
audio/out/ao_coreaudio_utils.c \
|
||||
audio/out/ao_coreaudio_properties.c
|
||||
SOURCES-$(COREVIDEO) += video/out/vo_corevideo.c
|
||||
SOURCES-$(DIRECT3D) += video/out/vo_direct3d.c \
|
||||
video/out/w32_common.c
|
||||
SOURCES-$(DSOUND) += audio/out/ao_dsound.c
|
||||
SOURCES-$(WASAPI) += audio/out/ao_wasapi.c
|
||||
SOURCES-$(GL) += video/out/gl_common.c video/out/gl_osd.c \
|
||||
video/out/vo_opengl.c video/out/gl_lcms.c \
|
||||
video/out/gl_video.c video/out/dither.c \
|
||||
@@ -67,64 +88,59 @@ SOURCES-$(GL) += video/out/gl_common.c video/out/gl_osd.c \
|
||||
video/out/pnm_loader.c
|
||||
|
||||
SOURCES-$(ENCODING) += video/out/vo_lavc.c audio/out/ao_lavc.c \
|
||||
common/encode_lavc.c
|
||||
mpvcore/encode_lavc.c
|
||||
|
||||
SOURCES-$(GL_WIN32) += video/out/w32_common.c video/out/gl_w32.c
|
||||
SOURCES-$(GL_X11) += video/out/x11_common.c video/out/gl_x11.c
|
||||
SOURCES-$(GL_COCOA) += video/out/gl_cocoa.c
|
||||
SOURCES-$(GL_WAYLAND) += video/out/wayland_common.c \
|
||||
video/out/gl_wayland.c
|
||||
|
||||
SOURCES-$(JACK) += audio/out/ao_jack.c
|
||||
SOURCES-$(JOYSTICK) += input/joystick.c
|
||||
SOURCES-$(LIBQUVI4) += stream/resolve/resolve_quvi.c
|
||||
SOURCES-$(LIBQUVI9) += stream/resolve/resolve_quvi9.c
|
||||
SOURCES-$(LIRC) += input/lirc.c
|
||||
SOURCES-$(JOYSTICK) += mpvcore/input/joystick.c
|
||||
SOURCES-$(LIBQUVI) += mpvcore/resolve_quvi.c
|
||||
SOURCES-$(LIBQUVI9) += mpvcore/resolve_quvi9.c
|
||||
SOURCES-$(LIRC) += mpvcore/input/lirc.c
|
||||
SOURCES-$(OPENAL) += audio/out/ao_openal.c
|
||||
SOURCES-$(OSS_AUDIO) += audio/out/ao_oss.c
|
||||
SOURCES-$(OSS) += audio/out/ao_oss.c
|
||||
SOURCES-$(PULSE) += audio/out/ao_pulse.c
|
||||
SOURCES-$(PORTAUDIO) += audio/out/ao_portaudio.c
|
||||
SOURCES-$(RSOUND) += audio/out/ao_rsound.c
|
||||
SOURCES-$(SNDIO) += audio/out/ao_sndio.c
|
||||
SOURCES-$(VDPAU) += video/vdpau.c video/vdpau_mixer.c \
|
||||
video/out/vo_vdpau.c video/decode/vdpau.c \
|
||||
video/filter/vf_vdpaupp.c
|
||||
SOURCES-$(VDPAU_GL_X11) += video/out/gl_hwdec_vdpau.c
|
||||
SOURCES-$(VAAPI) += video/out/vo_vaapi.c \
|
||||
video/decode/vaapi.c \
|
||||
video/vaapi.c
|
||||
SOURCES-$(VAAPI_VPP) += video/filter/vf_vavpp.c
|
||||
SOURCES-$(VAAPI_GLX) += video/out/gl_hwdec_vaglx.c
|
||||
SOURCES-$(VDPAU) += video/vdpau.c video/out/vo_vdpau.c
|
||||
SOURCES-$(VDPAU_DEC) += video/decode/vdpau.c
|
||||
SOURCES-$(VDPAU_DEC_OLD) += video/decode/vdpau_old.c
|
||||
|
||||
SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c
|
||||
SOURCES-$(XV) += video/out/vo_xv.c
|
||||
SOURCES-$(WAYLAND) += video/out/vo_wayland.c video/out/wayland_common.c
|
||||
|
||||
SOURCES-$(LIBAVFILTER) += video/filter/vf_lavfi.c \
|
||||
audio/filter/af_lavfi.c
|
||||
SOURCES-$(VF_LAVFI) += video/filter/vf_lavfi.c
|
||||
SOURCES-$(AF_LAVFI) += audio/filter/af_lavfi.c
|
||||
|
||||
ifeq ($(HAVE_AVUTIL_REFCOUNTING),no)
|
||||
SOURCES-yes += video/decode/lavc_dr1.c
|
||||
endif
|
||||
|
||||
SOURCES-$(LUA) += player/lua.c
|
||||
SOURCES-$(VAPOURSYNTH) += video/filter/vf_vapoursynth.c
|
||||
SOURCES-$(DLOPEN) += video/filter/vf_dlopen.c
|
||||
|
||||
SOURCES = audio/audio.c \
|
||||
audio/audio_buffer.c \
|
||||
SOURCES = talloc.c \
|
||||
audio/audio.c \
|
||||
audio/chmap.c \
|
||||
audio/chmap_sel.c \
|
||||
audio/fmt-conversion.c \
|
||||
audio/format.c \
|
||||
audio/mixer.c \
|
||||
audio/reorder_ch.c \
|
||||
audio/decode/ad_lavc.c \
|
||||
audio/decode/ad_spdif.c \
|
||||
audio/decode/dec_audio.c \
|
||||
audio/filter/af.c \
|
||||
audio/filter/af_center.c \
|
||||
audio/filter/af_channels.c \
|
||||
audio/filter/af_convert24.c \
|
||||
audio/filter/af_convertsignendian.c \
|
||||
audio/filter/af_delay.c \
|
||||
audio/filter/af_dummy.c \
|
||||
audio/filter/af_equalizer.c \
|
||||
audio/filter/af_export.c \
|
||||
audio/filter/af_extrastereo.c \
|
||||
audio/filter/af_force.c \
|
||||
audio/filter/af_format.c \
|
||||
audio/filter/af_hrtf.c \
|
||||
audio/filter/af_karaoke.c \
|
||||
@@ -136,105 +152,77 @@ SOURCES = audio/audio.c \
|
||||
audio/filter/af_sub.c \
|
||||
audio/filter/af_surround.c \
|
||||
audio/filter/af_sweep.c \
|
||||
audio/filter/af_tools.c \
|
||||
audio/filter/af_drc.c \
|
||||
audio/filter/af_volume.c \
|
||||
audio/filter/filter.c \
|
||||
audio/filter/tools.c \
|
||||
audio/filter/window.c \
|
||||
audio/out/ao.c \
|
||||
audio/out/ao_null.c \
|
||||
audio/out/ao_pcm.c \
|
||||
audio/out/pull.c \
|
||||
audio/out/push.c \
|
||||
bstr/bstr.c \
|
||||
common/av_common.c \
|
||||
common/av_log.c \
|
||||
common/codecs.c \
|
||||
common/common.c \
|
||||
common/msg.c \
|
||||
common/playlist.c \
|
||||
common/tags.c \
|
||||
common/version.c \
|
||||
demux/codec_tags.c \
|
||||
demux/demux.c \
|
||||
demux/demux_edl.c \
|
||||
demux/demux_cue.c \
|
||||
demux/demux_disc.c \
|
||||
demux/demux_lavf.c \
|
||||
demux/demux_mf.c \
|
||||
demux/demux_mkv.c \
|
||||
demux/demux_playlist.c \
|
||||
demux/demux_raw.c \
|
||||
demux/demux_subreader.c \
|
||||
demux/demux_raw.c \
|
||||
demux/ebml.c \
|
||||
demux/mf.c \
|
||||
demux/packet.c \
|
||||
input/cmd_list.c \
|
||||
input/cmd_parse.c \
|
||||
input/event.c \
|
||||
input/input.c \
|
||||
input/keycodes.c \
|
||||
misc/charset_conv.c \
|
||||
misc/dispatch.c \
|
||||
misc/rendezvous.c \
|
||||
misc/ring.c \
|
||||
options/m_config.c \
|
||||
options/m_option.c \
|
||||
options/m_property.c \
|
||||
options/options.c \
|
||||
options/parse_commandline.c \
|
||||
options/parse_configfile.c \
|
||||
options/path.c \
|
||||
mpvcore/asxparser.c \
|
||||
mpvcore/av_common.c \
|
||||
mpvcore/av_log.c \
|
||||
mpvcore/av_opts.c \
|
||||
mpvcore/bstr.c \
|
||||
mpvcore/charset_conv.c \
|
||||
mpvcore/codecs.c \
|
||||
mpvcore/command.c \
|
||||
mpvcore/cpudetect.c \
|
||||
mpvcore/m_config.c \
|
||||
mpvcore/m_option.c \
|
||||
mpvcore/m_property.c \
|
||||
mpvcore/mp_common.c \
|
||||
mpvcore/mp_msg.c \
|
||||
mpvcore/mp_ring.c \
|
||||
mpvcore/mplayer.c \
|
||||
mpvcore/options.c \
|
||||
mpvcore/parser-cfg.c \
|
||||
mpvcore/parser-mpcmd.c \
|
||||
mpvcore/path.c \
|
||||
mpvcore/playlist.c \
|
||||
mpvcore/playlist_parser.c \
|
||||
mpvcore/screenshot.c \
|
||||
mpvcore/version.c \
|
||||
mpvcore/input/input.c \
|
||||
mpvcore/timeline/tl_edl.c \
|
||||
mpvcore/timeline/tl_matroska.c \
|
||||
mpvcore/timeline/tl_cue.c \
|
||||
osdep/io.c \
|
||||
osdep/numcores.c \
|
||||
osdep/terminal-unix.c \
|
||||
osdep/timer.c \
|
||||
osdep/timer-linux.c \
|
||||
osdep/threads.c \
|
||||
player/audio.c \
|
||||
player/client.c \
|
||||
player/configfiles.c \
|
||||
player/command.c \
|
||||
player/discnav.c \
|
||||
player/loadfile.c \
|
||||
player/main.c \
|
||||
player/misc.c \
|
||||
player/osd.c \
|
||||
player/playloop.c \
|
||||
player/screenshot.c \
|
||||
player/scripting.c \
|
||||
player/sub.c \
|
||||
player/video.c \
|
||||
player/timeline/tl_matroska.c \
|
||||
player/timeline/tl_mpv_edl.c \
|
||||
player/timeline/tl_cue.c \
|
||||
stream/cache.c \
|
||||
stream/cache_file.c \
|
||||
stream/cookies.c \
|
||||
stream/rar.c \
|
||||
stream/stream.c \
|
||||
stream/stream_avdevice.c \
|
||||
stream/stream_edl.c \
|
||||
stream/stream_file.c \
|
||||
stream/stream_lavf.c \
|
||||
stream/stream_memory.c \
|
||||
stream/stream_mf.c \
|
||||
stream/stream_null.c \
|
||||
stream/stream_rar.c \
|
||||
sub/dec_sub.c \
|
||||
sub/draw_bmp.c \
|
||||
sub/find_subfiles.c \
|
||||
sub/img_convert.c \
|
||||
sub/osd.c \
|
||||
sub/sd_lavc.c \
|
||||
sub/sd_lavc_conv.c \
|
||||
sub/sd_lavf_srt.c \
|
||||
sub/sd_microdvd.c \
|
||||
sub/sd_movtext.c \
|
||||
sub/sd_spu.c \
|
||||
sub/sd_srt.c \
|
||||
ta/ta.c \
|
||||
ta/ta_utils.c \
|
||||
ta/ta_talloc.c \
|
||||
sub/spudec.c \
|
||||
sub/sub.c \
|
||||
video/csputils.c \
|
||||
video/fmt-conversion.c \
|
||||
video/image_writer.c \
|
||||
@@ -243,13 +231,14 @@ SOURCES = audio/audio.c \
|
||||
video/mp_image_pool.c \
|
||||
video/sws_utils.c \
|
||||
video/decode/dec_video.c \
|
||||
video/decode/vd.c \
|
||||
video/decode/vd_lavc.c \
|
||||
video/filter/vf.c \
|
||||
video/filter/pullup.c \
|
||||
video/filter/vf_buffer.c \
|
||||
video/filter/vf_crop.c \
|
||||
video/filter/vf_delogo.c \
|
||||
video/filter/vf_divtc.c \
|
||||
video/filter/vf_down3dright.c \
|
||||
video/filter/vf_dsize.c \
|
||||
video/filter/vf_eq.c \
|
||||
video/filter/vf_expand.c \
|
||||
@@ -271,6 +260,7 @@ SOURCES = audio/audio.c \
|
||||
video/filter/vf_sub.c \
|
||||
video/filter/vf_swapuv.c \
|
||||
video/filter/vf_unsharp.c \
|
||||
video/filter/vf_vo.c \
|
||||
video/filter/vf_yadif.c \
|
||||
video/out/bitmap_packer.c \
|
||||
video/out/aspect.c \
|
||||
@@ -278,15 +268,17 @@ SOURCES = audio/audio.c \
|
||||
video/out/vo.c \
|
||||
video/out/vo_null.c \
|
||||
video/out/vo_image.c \
|
||||
video/out/win_state.c \
|
||||
osdep/$(GETCH) \
|
||||
osdep/$(TIMER) \
|
||||
$(SOURCES-yes)
|
||||
|
||||
OBJECTS += $(addsuffix .o, $(basename $(SOURCES)))
|
||||
OBJECTS-$(PE_EXECUTABLE) += osdep/mpv-rc.o
|
||||
OBJECTS += $(OBJECTS-yes)
|
||||
|
||||
DEP_FILES = $(patsubst %.S,%.d,$(patsubst %.cpp,%.d,$(patsubst %.c,%.d,$(SOURCES:.m=.d) $(SOURCES:.m=.d))))
|
||||
|
||||
ALL_TARGETS += mpv
|
||||
ALL_TARGETS += mpv$(EXESUF)
|
||||
|
||||
INSTALL_BIN += install-mpv
|
||||
INSTALL_BIN_STRIP += install-mpv-strip
|
||||
@@ -294,7 +286,7 @@ INSTALL_MAN =
|
||||
|
||||
ifeq ($(BUILD_MAN),yes)
|
||||
INSTALL_MAN += install-mpv-man
|
||||
ALL_TARGETS += DOCS/man/mpv.1
|
||||
ALL_TARGETS += DOCS/man/en/mpv.1
|
||||
endif
|
||||
|
||||
DIRS = . \
|
||||
@@ -302,21 +294,13 @@ DIRS = . \
|
||||
audio/decode \
|
||||
audio/filter \
|
||||
audio/out \
|
||||
bstr \
|
||||
common \
|
||||
compat \
|
||||
input \
|
||||
player/timeline \
|
||||
core \
|
||||
mpvcore/input \
|
||||
mpvcore/timeline \
|
||||
demux \
|
||||
misc \
|
||||
options \
|
||||
osdep \
|
||||
osdep/ar \
|
||||
player \
|
||||
stream \
|
||||
stream/resolve \
|
||||
sub \
|
||||
ta \
|
||||
video \
|
||||
video/decode \
|
||||
video/filter \
|
||||
@@ -325,6 +309,7 @@ DIRS = . \
|
||||
|
||||
ADDSUFFIXES = $(foreach suf,$(1),$(addsuffix $(suf),$(2)))
|
||||
ADD_ALL_DIRS = $(call ADDSUFFIXES,$(1),$(DIRS))
|
||||
ADD_ALL_EXESUFS = $(1) $(call ADDSUFFIXES,$(EXESUFS_ALL),$(1))
|
||||
|
||||
###### brief build output #######
|
||||
|
||||
@@ -340,14 +325,27 @@ all: $(ALL_TARGETS)
|
||||
%.1: %.rst
|
||||
$(RST2MAN) $< $@
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
mpv: $(OBJECTS) player/main_fn.o
|
||||
%.o: %.cpp
|
||||
$(CC) $(DEPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.m
|
||||
$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
%-rc.o: %.rc
|
||||
$(WINDRES) -I. $< $@
|
||||
|
||||
mpv$(EXESUF): $(OBJECTS)
|
||||
mpv$(EXESUF):
|
||||
$(CC) -o $@ $^ $(EXTRALIBS)
|
||||
|
||||
input/input.c: input/input_conf.h
|
||||
input/input_conf.h: TOOLS/file2string.pl etc/input.conf
|
||||
mpvcore/input/input.c: mpvcore/input/input_conf.h
|
||||
mpvcore/input/input_conf.h: TOOLS/file2string.pl etc/input.conf
|
||||
./$^ >$@
|
||||
|
||||
MKVLIB_DEPS = TOOLS/lib/Parse/Matroska.pm \
|
||||
@@ -368,25 +366,10 @@ video/out/gl_video.c: video/out/gl_video_shaders.h
|
||||
video/out/gl_video_shaders.h: TOOLS/file2string.pl video/out/gl_video_shaders.glsl
|
||||
./$^ >$@
|
||||
|
||||
video/out/x11_common.c: video/out/x11_icon.inc
|
||||
video/out/x11_icon.inc: TOOLS/file2string.pl video/out/x11_icon.bin
|
||||
./$^ >$@
|
||||
|
||||
sub/osd_libass.c: sub/osd_font.h
|
||||
sub/osd_font.h: TOOLS/file2string.pl sub/osd_font.otf
|
||||
./$^ >$@
|
||||
|
||||
player/lua/%.inc: TOOLS/file2string.pl player/lua/%.lua
|
||||
./$^ >$@
|
||||
|
||||
player/lua.c: player/lua/defaults.inc \
|
||||
player/lua/assdraw.inc \
|
||||
player/lua/osc.inc \
|
||||
player/lua/options.inc
|
||||
|
||||
etc/_mpv: TOOLS/zsh.pl ./mpv
|
||||
./$< > $@
|
||||
|
||||
# ./configure must be rerun if it changed
|
||||
config.mak: configure
|
||||
@echo "############################################################"
|
||||
@@ -399,98 +382,79 @@ version.h .version: version.sh
|
||||
# Force version.sh to run to potentially regenerate version.h
|
||||
-include .version
|
||||
|
||||
%: %.c
|
||||
%$(EXESUF): %.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
###### dependency declarations / specific CFLAGS ######
|
||||
|
||||
common/version.c: version.h
|
||||
mpvcore/version.c osdep/mpv-rc.o: version.h
|
||||
|
||||
osdep/mpv-rc.o: osdep/mpv.exe.manifest etc/mpv-icon.ico
|
||||
|
||||
DOCS/man/en/mpv.1: DOCS/man/en/af.rst \
|
||||
DOCS/man/en/ao.rst \
|
||||
DOCS/man/en/changes.rst \
|
||||
DOCS/man/en/encode.rst \
|
||||
DOCS/man/en/input.rst \
|
||||
DOCS/man/en/options.rst \
|
||||
DOCS/man/en/vf.rst \
|
||||
DOCS/man/en/vo.rst
|
||||
|
||||
DOCS/man/mpv.1: DOCS/man/af.rst \
|
||||
DOCS/man/ao.rst \
|
||||
DOCS/man/changes.rst \
|
||||
DOCS/man/encode.rst \
|
||||
DOCS/man/input.rst \
|
||||
DOCS/man/options.rst \
|
||||
DOCS/man/vf.rst \
|
||||
DOCS/man/vo.rst
|
||||
|
||||
###### installation / clean / generic rules #######
|
||||
|
||||
install: $(INSTALL_BIN) install-data $(INSTALL_MAN)
|
||||
install-no-man: $(INSTALL_BIN) install-data
|
||||
install-strip: $(INSTALL_BIN_STRIP) install-data $(INSTALL_MAN)
|
||||
install-strip-no-man: $(INSTALL_BIN_STRIP) install-data
|
||||
install: $(INSTALL_BIN) $(INSTALL_MAN)
|
||||
install-no-man: $(INSTALL_BIN)
|
||||
install-strip: $(INSTALL_BIN_STRIP) $(INSTALL_MAN)
|
||||
install-strip-no-man: $(INSTALL_BIN_STRIP)
|
||||
|
||||
install-dirs:
|
||||
if test ! -d $(BINDIR) ; then $(INSTALL) -d $(BINDIR) ; fi
|
||||
|
||||
install-%: % install-dirs
|
||||
install-%: %$(EXESUF) install-dirs
|
||||
$(INSTALL) -m 755 $< $(BINDIR)
|
||||
|
||||
install-%-strip: % install-dirs
|
||||
install-%-strip: %$(EXESUF) install-dirs
|
||||
$(INSTALL) -m 755 -s $< $(BINDIR)
|
||||
|
||||
install-mpv-man: install-mpv-man-en
|
||||
|
||||
install-mpv-man-en: DOCS/man/mpv.1
|
||||
install-mpv-man-en: DOCS/man/en/mpv.1
|
||||
if test ! -d $(MANDIR)/man1 ; then $(INSTALL) -d $(MANDIR)/man1 ; fi
|
||||
$(INSTALL) -m 644 DOCS/man/mpv.1 $(MANDIR)/man1/
|
||||
|
||||
ICONSIZES = 16x16 32x32 64x64
|
||||
|
||||
define ICON_INSTALL_RULE
|
||||
install-mpv-icon-$(size): etc/mpv-icon-8bit-$(size).png
|
||||
$(INSTALL) -d $(prefix)/share/icons/hicolor/$(size)/apps
|
||||
$(INSTALL) -m 644 etc/mpv-icon-8bit-$(size).png $(prefix)/share/icons/hicolor/$(size)/apps/mpv.png
|
||||
endef
|
||||
|
||||
$(foreach size,$(ICONSIZES),$(eval $(ICON_INSTALL_RULE)))
|
||||
|
||||
install-mpv-icons: $(foreach size,$(ICONSIZES),install-mpv-icon-$(size))
|
||||
|
||||
install-mpv-desktop: etc/mpv.desktop
|
||||
$(INSTALL) -d $(prefix)/share/applications
|
||||
$(INSTALL) -m 644 etc/mpv.desktop $(prefix)/share/applications/
|
||||
|
||||
install-mpv-config: etc/encoding-profiles.conf
|
||||
$(INSTALL) -d $(CONFDIR)
|
||||
$(INSTALL) -m 644 etc/encoding-profiles.conf $(CONFDIR)
|
||||
|
||||
install-mpv-zsh: etc/_mpv
|
||||
$(INSTALL) -d $(prefix)/share/zsh/vendor-completions
|
||||
$(INSTALL) -m 644 etc/_mpv $(prefix)/share/zsh/vendor-completions/
|
||||
|
||||
install-data: install-mpv-icons install-mpv-desktop install-mpv-config install-mpv-zsh
|
||||
$(INSTALL) -m 644 DOCS/man/en/mpv.1 $(MANDIR)/man1/
|
||||
|
||||
uninstall:
|
||||
$(RM) $(BINDIR)/mpv
|
||||
$(RM) $(MANDIR)/man1/mpv.1 $(MANDIR)/man1/mpv.1
|
||||
$(RM) $(prefix)/share/applications/mpv.desktop
|
||||
$(RM) $(prefix)/share/zsh/vendor-completions/_mpv
|
||||
$(RM) $(foreach size,$(ICONSIZES),$(prefix)/share/icons/hicolor/$(size)/apps/mpv.png)
|
||||
$(RM) $(BINDIR)/mpv$(EXESUF)
|
||||
$(RM) $(MANDIR)/man1/mpv.1
|
||||
$(RM) $(MANDIR)/en/man1/mpv.1
|
||||
|
||||
clean:
|
||||
-$(RM) $(call ADD_ALL_DIRS,/*.o /*.d /*.a /*.ho /*~)
|
||||
-$(RM) $(call ADD_ALL_DIRS,/*.o /*.a /*.ho /*~)
|
||||
-$(RM) mpv
|
||||
-$(RM) DOCS/man/*/mpv.1
|
||||
-$(RM) $(call ADD_ALL_EXESUFS,mpv)
|
||||
-$(RM) DOCS/man/en/mpv.1
|
||||
-$(RM) version.h
|
||||
-$(RM) input/input_conf.h
|
||||
-$(RM) mpvcore/input/input_conf.h
|
||||
-$(RM) video/out/vdpau_template.c
|
||||
-$(RM) demux/ebml_types.h demux/ebml_defs.c
|
||||
-$(RM) video/out/gl_video_shaders.h
|
||||
-$(RM) video/out/x11_icon.inc
|
||||
-$(RM) sub/osd_font.h
|
||||
-$(RM) player/lua/defaults.inc
|
||||
-$(RM) player/lua/assdraw.inc
|
||||
-$(RM) player/lua/osc.inc
|
||||
-$(RM) player/lua/options.inc
|
||||
|
||||
distclean: clean
|
||||
-$(RM) config.log old_build/config.h old_build/config.mak Makefile
|
||||
-rmdir old_build/
|
||||
-$(RM) config.log config.mak config.h TAGS tags
|
||||
|
||||
TAGS:
|
||||
$(RM) $@; find . -name '*.[chS]' -o -name '*.asm' | xargs etags -a
|
||||
|
||||
tags:
|
||||
$(RM) $@; find . -name '*.[chS]' -o -name '*.asm' | xargs ctags -a
|
||||
|
||||
osxbundle:
|
||||
@TOOLS/osxbundle.py mpv
|
||||
|
||||
osxbundle-skip-deps:
|
||||
@TOOLS/osxbundle.py --skip-deps mpv
|
||||
|
||||
-include $(DEP_FILES)
|
||||
|
||||
@@ -16,52 +16,25 @@ Compilation
|
||||
-----------
|
||||
|
||||
Compiling with full features requires development files for several
|
||||
external libraries. Below is a list of some important requirements.
|
||||
|
||||
The mpv build system uses *waf* but we don't store it in your source tree. The
|
||||
script './bootstrap.py' will download the latest version of waf that was tested
|
||||
with the build system.
|
||||
|
||||
For a list of the available build options use `./waf configure --help`. If
|
||||
you think you have support for some feature installed but configure fails to
|
||||
detect it, the file `build/config.log` may contain information about the
|
||||
reasons for the failure.
|
||||
|
||||
NOTE: To avoid cluttering the output with unreadable spam, `--help` only shows
|
||||
one of the two switches for each option. If the option is autodetected by
|
||||
default, the `--disable-***` switch is printed; if the option is disabled by
|
||||
default, the `--enable-***` switch is printed. Either way, you can use
|
||||
`--enable-***` or `--disable-**` regardless of what is printed by `--help`.
|
||||
|
||||
To build the software you can use `./waf build`: the result of the compilation
|
||||
will be located in `build/mpv`. You can use `./waf install` to install mpv
|
||||
to the *prefix* after it is compiled.
|
||||
|
||||
NOTE: Using the old build system (with `./old-configure`) should still work,
|
||||
but will be removed in a future version of mpv.
|
||||
external libraries. Below is a list of some important requirements. For
|
||||
more information see the output of `./configure --help` for a list of options,
|
||||
or look at the list of enabled and disabled features printed after running
|
||||
`./configure`. If you think you have support for some feature installed
|
||||
but configure fails to detect it, the file `config.log` may contain
|
||||
information about the reasons for the failure.
|
||||
|
||||
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)
|
||||
- libquvi if you want to play Youtube videos directly
|
||||
|
||||
Libass dependencies:
|
||||
|
||||
- gcc or clang, yasm on x86 and x86_64
|
||||
- fribidi, freetype, fontconfig development headers (for libass)
|
||||
|
||||
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
|
||||
@@ -74,37 +47,22 @@ If you are running Mac OSX and using homebrew we provide [homebrew-mpv][homebrew
|
||||
to date formula that compiles mpv with sensible dependencies and defaults for
|
||||
OSX.
|
||||
|
||||
FFmpeg vs. Libav
|
||||
----------------
|
||||
configure --enable-* parameters
|
||||
-------------------------------
|
||||
|
||||
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.
|
||||
The --enable-* parameters unconditionally force options on, completely
|
||||
skipping autodetection. This behavior is unlike what you may be used to from
|
||||
autoconf-based configure scripts that can decide to override you. This greater
|
||||
level of control comes at a price. You may have to provide the correct compiler
|
||||
and linker flags yourself.
|
||||
If you used one of these options and experience a compilation or
|
||||
linking failure, make sure you have passed the necessary compiler/linker flags
|
||||
to configure.
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
|
||||
Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug
|
||||
Please use the [issue tracker][issue tracker] provided by GitHub to send us bug
|
||||
reports or feature requests.
|
||||
|
||||
Contributing
|
||||
@@ -114,26 +72,12 @@ 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
|
||||
--------
|
||||
|
||||
These forms of contact are meant to ask questions about mpv usage, give
|
||||
feedback on mpv and discuss it's development.
|
||||
You can find us on IRC in `#mpv-player` 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`.
|
||||
|
||||
[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
|
||||
[issue tracker]: https://github.com/mpv-player/mpv/issues
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
Release 0.5.1
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Add audio/flac to the MIME type list in mpv.desktop.
|
||||
- The --slave-broken option has been reintroduced and is equivalent to using
|
||||
--input-file=/dev/stdin and --input-terminal=no.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix screenshots with anamorphic videos in the vdpau vo.
|
||||
- Fix a crash happening when mpv fails to create a vdpau mixer in the vdpau vo.
|
||||
- Don't quit when the --loop-file option is used.
|
||||
- Always load the cursor theme in the wayland vo (this fixes a crash caused by
|
||||
moving the mouse cursor over the video).
|
||||
- Properly return non-zero from the zsh completion script when no matches are
|
||||
found (this fixes the use of user-defined zsh completion matchers).
|
||||
- Fix the description of the opengl-hq vo default options in the manpage.
|
||||
- Remove duplicated content from the manpage that was accidentally added in the
|
||||
manpage reorganization from the previous release.
|
||||
- Avoid clobbering playback position on video end (when both audio and video
|
||||
streams reached the end, the playback poisition was briefly set at 0).
|
||||
- Avoid overwriting user input in the coreaudio_device ao.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log 6729e39..fdd648b`` in
|
||||
the git repository.
|
||||
|
||||
Release 0.5.0
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Support setting the start time relative to the start PTS with --start.
|
||||
- Use /dev/sr0 as default cdrom/dvd device on Linux.
|
||||
- Change "cache" property representation to float.
|
||||
- Split the ao_coreaudio audio output into ao_coreaudio (which uses the
|
||||
AudioUnits and the CoreAudio sound server) and ao_coreaudio_device (which uses
|
||||
direct device access).
|
||||
- Complete supported URL schemes in the zsh completion script.
|
||||
- Enable compiler optimizations (-O2) during build.
|
||||
- Allow precise seeking with percent-based seeks too.
|
||||
- Do precise seeks when clicking on the OSC seekbar.
|
||||
- Remove support for older VDA hwaccel versions on Mac OS X (requires recent
|
||||
versions of ffmpeg/libav).
|
||||
- Remove the last remains of slave mode (--slave-broken option). Support for
|
||||
reading input commands from stdin can be emulated using: --input-terminal=no
|
||||
--input-file=/dev/stdin.
|
||||
- Some key binding were remapped or removed:
|
||||
+ "LEFT" and "RIGHT" have been remapped to seek 5 seconds instead of 10.
|
||||
+ "c" for changing the YUV color space was unmapped.
|
||||
+ OSD level cycling has been remapped from "o" to "O".
|
||||
+ "o" is now mapped to the show_progress command (like "P").
|
||||
+ "PGUP" and "PGDWN" have been remapped to chapter-based seeks (the old
|
||||
bindings "@" and "!" are still available). The old behvaiour has been
|
||||
remapped to "Shift+PGUP" and "Shift+PGDWM".
|
||||
+ Increasing/decreasing audio delay have been remapped from "+" and "-" to
|
||||
"Ctrl++" and "Ctrl+-".
|
||||
+ "(" and ")" for adjusting audio balance have been unmapped.
|
||||
+ "F" for toggling the "sub-forced-only" option has been unmapped.
|
||||
+ "TAB" for cycling TS programs has been unmapped.
|
||||
+ "A" for cycling DVD angle has been unmapped.
|
||||
+ "U" for stopping playback has been unmapped.
|
||||
+ "l" and "L" for cycling quvi format have been unmapped.
|
||||
- Make it possible to build the client API (libmpv) on Mac OS X.
|
||||
- Do necessary checks for nested Wayland compositors which only have limited
|
||||
interfaces.
|
||||
- The options in the manpage have been re-organized into sections and ordered by
|
||||
usage to make it easier to navigate.
|
||||
- The "hard" framedrop mode has been removed (this behaviour is still available
|
||||
via the --vd-lavc-framedrop option).
|
||||
- Show the basename of a subtitle file only (without the directory part).
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Use a default color space for files with no video (this fixes color managed
|
||||
OSD messages when no video channel is present).
|
||||
- Fix key equivalent dispatching for Cocoa on Mac OS X.
|
||||
- Disable non-interleaved audio formats by default with ao_alsa, since some
|
||||
ALSA plugins don't cope well with them (non-interleaved formats can still be
|
||||
enabled using the "non-interleaved" ao_alsa option).
|
||||
- Fix deadlock in the client API when calling mpv_terminate_destroy() before
|
||||
mpv_initialize().
|
||||
- Fix flushing of filter chain (this fixes a bug where the last frames would get
|
||||
dropped on EOF, if buffered by filters).
|
||||
- Actually use the channels.conf configuration file for DVB.
|
||||
- Restore the --dvbin-file option.
|
||||
- Fix off by one error in the command parser which caused a segfault when using
|
||||
the mp.commandv() Lua function with 10 or more arguments.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Search for config files in $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS in addition
|
||||
to ~/.mpv. The config file has also been renamed to mpv.conf (although the
|
||||
old file still works and will be loaded even if the new one exists).
|
||||
- Add "playback-time" property that returns the current playback time always
|
||||
starting at 0. This is now used to show the playback time in the OSD and the
|
||||
status line, fixing the shown playback time for transport streams that start
|
||||
at a completely random timestamp.
|
||||
- Add cache-related "cache-free", "cache-used" and "cache-idle" properties.
|
||||
- Add option to list supported protocols (--list-protocols).
|
||||
- Allow setting libavformat stream options with the --stream-lavf-o option.
|
||||
- Support running the demuxer in a separate thread and prefetch packets (this
|
||||
can be enabled using the --demuxer-thread option).
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log cb250d4..52f2f67`` in
|
||||
the git repository.
|
||||
@@ -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()
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script is expected to be called as TOOLS/gen-x11-icon.sh (it will access
|
||||
# etc/mpv-icon...), and it will write video/out/x11_icon.bin.
|
||||
|
||||
conv() {
|
||||
echo
|
||||
identify -format "icon: %w %h" $1
|
||||
convert $1 -depth 8 rgba:-
|
||||
}
|
||||
|
||||
(echo "# File generated by gen-x11-icon.sh" ;
|
||||
conv etc/mpv-icon-8bit-16x16.png ;
|
||||
conv etc/mpv-icon-8bit-32x32.png ;
|
||||
conv etc/mpv-icon-8bit-64x64.png) | gzip -c > video/out/x11_icon.bin
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
case "$0" in
|
||||
*/*)
|
||||
MYDIR=${0%/*}
|
||||
;;
|
||||
*)
|
||||
MYDIR=.
|
||||
;;
|
||||
esac
|
||||
|
||||
: ${MPV:=mpv}
|
||||
: ${ILDETECT_MPV:=$MPV}
|
||||
: ${ILDETECT_MPV:=$MPV}
|
||||
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
|
||||
: ${ILDETECT_DRY_RUN:=}
|
||||
: ${ILDETECT_QUIET:=}
|
||||
: ${ILDETECT_RUN_INTERLACED_ONLY:=}
|
||||
: ${ILDETECT_FORCE_RUN:=}
|
||||
: ${MAKE:=make}
|
||||
|
||||
# exit status:
|
||||
# 0 progressive
|
||||
# 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: " | tail -n 1
|
||||
}
|
||||
|
||||
judge()
|
||||
{
|
||||
out=`testfun "$@"`
|
||||
|
||||
tff=${out##* TFF:}; tff=${tff%% *}
|
||||
bff=${out##* BFF:}; bff=${bff%% *}
|
||||
progressive=${out##* Progressive:}; progressive=${progressive%% *}
|
||||
undetermined=${out##* Undetermined:}; undetermined=${undetermined%% *}
|
||||
|
||||
case "$tff$bff$progressive$undetermined" in
|
||||
*[!0-9]*)
|
||||
echo >&2 "ERROR: Unrecognized idet output: $out"
|
||||
exit 16
|
||||
;;
|
||||
esac
|
||||
|
||||
interlaced=$((bff + tff))
|
||||
determined=$((interlaced + progressive))
|
||||
|
||||
if [ $undetermined -gt $determined ] || [ $determined -lt 250 ]; then
|
||||
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 progrssive.
|
||||
verdict=progressive
|
||||
fi
|
||||
|
||||
echo "$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
|
||||
@@ -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)
|
||||
|
||||
@@ -1,19 +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.
|
||||
|
||||
Unless otherwise specified, they are also suitable for inclusion in
|
||||
the `~/.mpv/lua` directory where they will be loaded every time mpv
|
||||
starts, obviating the need to load them with the above `--lua=...`
|
||||
argument. This is acceptable as they do only basic argument parsing
|
||||
and key-binding registration, until those bound keys are actually
|
||||
pressed. They should therefore not interfere with normal playback
|
||||
(unless you have a conflicting user-defined key-binding, in which
|
||||
case, you may want to modify either the `mp.add_key_binding()` calls
|
||||
in the scripts, or your keybinding).
|
||||
@@ -1,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)
|
||||
@@ -1,71 +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)
|
||||
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 dir = -1, 1, 2 do -- 2 iterations, with dir = -1 and +1
|
||||
for i = 1, MAXENTRIES do
|
||||
local file = files[current + i * dir]
|
||||
local pl_e = pl[pl_current + i * dir]
|
||||
if file == nil or file[1] == "." then
|
||||
break
|
||||
end
|
||||
if pl_e then
|
||||
-- If there's a playlist entry, and it's the same file, stop.
|
||||
if pl_e.filename == file then
|
||||
break
|
||||
end
|
||||
end
|
||||
if dir == -1 then
|
||||
if pl_current == 1 then -- never add additional entries in the middle
|
||||
mp.msg.info("Prepending " .. file)
|
||||
table.insert(append[-1], 1, file)
|
||||
end
|
||||
else
|
||||
mp.msg.info("Adding " .. file)
|
||||
table.insert(append[1], file)
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
+3
-3
@@ -56,7 +56,7 @@ sub generate_c_header {
|
||||
my $l = max(map { length $_->{valname} } values %{$el->{subelements}});
|
||||
|
||||
# Output each variable, with pointers for array (multiple) elements
|
||||
for my $subel (sort { $a->{definename} cmp $b->{definename} } values %{$el->{subelements}}) {
|
||||
for my $subel (values %{$el->{subelements}}) {
|
||||
printf " %-${l}s %s%s;\n",
|
||||
$subel->{valname}, $subel->{multiple}?'*':' ', $subel->{fieldname};
|
||||
}
|
||||
@@ -101,7 +101,7 @@ sub generate_c_definitions {
|
||||
|
||||
# define a field for each subelement
|
||||
# also does lots of macro magic, but doesn't open a scope
|
||||
for my $subel (sort { $a->{definename} cmp $b->{definename} } values %{$el->{subelements}}) {
|
||||
for my $subel (values %{$el->{subelements}}) {
|
||||
print "F($subel->{definename}, $subel->{fieldname}, ".
|
||||
($subel->{multiple}?'1':'0').")\n";
|
||||
}
|
||||
@@ -166,4 +166,4 @@ sub process_elem {
|
||||
} else {
|
||||
print "$elem->{type} ". $elem->get_value ."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ __midentify__allprops="
|
||||
video-bitrate
|
||||
video-codec
|
||||
video-format
|
||||
video-aspect
|
||||
aspect
|
||||
fps
|
||||
width
|
||||
height
|
||||
@@ -104,7 +104,7 @@ for __midentify__key in $__midentify__allprops; do
|
||||
eval unset $__midentify__nextprefix$__midentify__key
|
||||
done
|
||||
|
||||
__midentify__output=`$MPV --term-playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet --no-cache --no-config "$@"`
|
||||
__midentify__output=`$MPV --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet "$@"`
|
||||
__midentify__fileindex=0
|
||||
__midentify__prefix=
|
||||
while :; do
|
||||
|
||||
+74
-13
@@ -1,44 +1,105 @@
|
||||
#!/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 bundle_path(binary_name):
|
||||
return "%s.app" % binary_name
|
||||
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_name(binary_name):
|
||||
return os.path.basename(bundle_path(binary_name))
|
||||
return "%s.app" % binary_name
|
||||
|
||||
def target_plist(binary_name):
|
||||
return os.path.join(bundle_path(binary_name), 'Contents', 'Info.plist')
|
||||
return os.path.join(bundle_name(binary_name), 'Contents', 'Info.plist')
|
||||
|
||||
def target_directory(binary_name):
|
||||
return os.path.join(bundle_path(binary_name), 'Contents', 'MacOS')
|
||||
return os.path.join(bundle_name(binary_name), 'Contents', 'MacOS')
|
||||
|
||||
def target_binary(binary_name):
|
||||
return os.path.join(target_directory(binary_name),
|
||||
os.path.basename(binary_name))
|
||||
return os.path.join(target_directory(binary_name), binary_name)
|
||||
|
||||
def copy_bundle(binary_name):
|
||||
if os.path.isdir(bundle_path(binary_name)):
|
||||
shutil.rmtree(bundle_path(binary_name))
|
||||
if os.path.isdir(bundle_name(binary_name)):
|
||||
shutil.rmtree(bundle_name(binary_name))
|
||||
shutil.copytree(
|
||||
os.path.join('TOOLS', 'osxbundle', bundle_name(binary_name)),
|
||||
bundle_path(binary_name))
|
||||
bundle_name(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))
|
||||
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()
|
||||
version = sh("TOOLS/osxbundle/version.sh").strip()
|
||||
|
||||
usage = "usage: %prog [options] arg"
|
||||
parser = OptionParser(usage)
|
||||
@@ -63,7 +124,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,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>
|
||||
@@ -35,7 +35,7 @@
|
||||
<string>wma</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<string>audio.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Audio file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
@@ -86,7 +86,6 @@
|
||||
<string>VCD</string>
|
||||
<string>VFW</string>
|
||||
<string>VOB</string>
|
||||
<string>WEBM</string>
|
||||
<string>WMV</string>
|
||||
<string>asf</string>
|
||||
<string>avi</string>
|
||||
@@ -120,11 +119,10 @@
|
||||
<string>vcd</string>
|
||||
<string>vfw</string>
|
||||
<string>vob</string>
|
||||
<string>webm</string>
|
||||
<string>wmv</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<string>movie.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Movie file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
@@ -159,7 +157,7 @@
|
||||
<string>utf</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<string>subtitles.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Subtitles file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
@@ -183,7 +181,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${VERSION}</string>
|
||||
<string>{{VERSION}}</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@@ -192,630 +190,59 @@
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>mpv Custom Protocol</string>
|
||||
<string>Real Time (Streaming) Protocol</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>mpv</string>
|
||||
<string>rtp</string>
|
||||
<string>rtsp</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Streaming Protocol</string>
|
||||
<string>File over HTTP/FTP/UDP</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>icyx</string>
|
||||
<string>udp</string>
|
||||
<string>ftp</string>
|
||||
<string>http_proxy</string>
|
||||
<string>http</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Microsoft Media Services</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>mms</string>
|
||||
<string>mmst</string>
|
||||
<string>http</string>
|
||||
<string>httpproxy</string>
|
||||
<string>rtp</string>
|
||||
<string>rtsp</string>
|
||||
<string>ftp</string>
|
||||
<string>udp</string>
|
||||
<string>smb</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>CD/DVD/Bluray Media</string>
|
||||
<string>Cuesheet</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>cdda</string>
|
||||
<string>cue</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>CD/DVD Media</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>dvdnav</string>
|
||||
<string>dvd</string>
|
||||
<string>vcd</string>
|
||||
<string>bd</string>
|
||||
</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>
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<dir>/System/Library/Fonts</dir>
|
||||
<dir>/Library/Fonts</dir>
|
||||
<dir>~/Library/Fonts</dir>
|
||||
<dir>/Network/Library/Fonts</dir>
|
||||
<cachedir>~/.fontconfig</cachedir>
|
||||
|
||||
<!--
|
||||
Accept deprecated 'mono' alias, replacing it with 'monospace'
|
||||
-->
|
||||
<match target="pattern">
|
||||
<test qual="any" name="family">
|
||||
<string>mono</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="same">
|
||||
<string>monospace</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<!--
|
||||
Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
|
||||
-->
|
||||
<match target="pattern">
|
||||
<test qual="any" name="family">
|
||||
<string>sans serif</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="same">
|
||||
<string>sans-serif</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<!--
|
||||
Accept deprecated 'sans' alias, replacing it with 'sans-serif'
|
||||
-->
|
||||
<match target="pattern">
|
||||
<test qual="any" name="family">
|
||||
<string>sans</string>
|
||||
</test>
|
||||
<edit name="family" mode="assign" binding="same">
|
||||
<string>sans-serif</string>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
<config>
|
||||
<!--
|
||||
These are the default Unicode chars that are expected to be blank
|
||||
in fonts. All other blank chars are assumed to be broken and
|
||||
won't appear in the resulting charsets
|
||||
-->
|
||||
<blank>
|
||||
<int>0x0020</int> <!-- SPACE -->
|
||||
<int>0x00A0</int> <!-- NO-BREAK SPACE -->
|
||||
<int>0x00AD</int> <!-- SOFT HYPHEN -->
|
||||
<int>0x034F</int> <!-- COMBINING GRAPHEME JOINER -->
|
||||
<int>0x0600</int> <!-- ARABIC NUMBER SIGN -->
|
||||
<int>0x0601</int> <!-- ARABIC SIGN SANAH -->
|
||||
<int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER -->
|
||||
<int>0x0603</int> <!-- ARABIC SIGN SAFHA -->
|
||||
<int>0x06DD</int> <!-- ARABIC END OF AYAH -->
|
||||
<int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK -->
|
||||
<int>0x115F</int> <!-- HANGUL CHOSEONG FILLER -->
|
||||
<int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER -->
|
||||
<int>0x1680</int> <!-- OGHAM SPACE MARK -->
|
||||
<int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ -->
|
||||
<int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA -->
|
||||
<int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR -->
|
||||
<int>0x2000</int> <!-- EN QUAD -->
|
||||
<int>0x2001</int> <!-- EM QUAD -->
|
||||
<int>0x2002</int> <!-- EN SPACE -->
|
||||
<int>0x2003</int> <!-- EM SPACE -->
|
||||
<int>0x2004</int> <!-- THREE-PER-EM SPACE -->
|
||||
<int>0x2005</int> <!-- FOUR-PER-EM SPACE -->
|
||||
<int>0x2006</int> <!-- SIX-PER-EM SPACE -->
|
||||
<int>0x2007</int> <!-- FIGURE SPACE -->
|
||||
<int>0x2008</int> <!-- PUNCTUATION SPACE -->
|
||||
<int>0x2009</int> <!-- THIN SPACE -->
|
||||
<int>0x200A</int> <!-- HAIR SPACE -->
|
||||
<int>0x200B</int> <!-- ZERO WIDTH SPACE -->
|
||||
<int>0x200C</int> <!-- ZERO WIDTH NON-JOINER -->
|
||||
<int>0x200D</int> <!-- ZERO WIDTH JOINER -->
|
||||
<int>0x200E</int> <!-- LEFT-TO-RIGHT MARK -->
|
||||
<int>0x200F</int> <!-- RIGHT-TO-LEFT MARK -->
|
||||
<int>0x2028</int> <!-- LINE SEPARATOR -->
|
||||
<int>0x2029</int> <!-- PARAGRAPH SEPARATOR -->
|
||||
<int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING -->
|
||||
<int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING -->
|
||||
<int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING -->
|
||||
<int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE -->
|
||||
<int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE -->
|
||||
<int>0x202F</int> <!-- NARROW NO-BREAK SPACE -->
|
||||
<int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE -->
|
||||
<int>0x2060</int> <!-- WORD JOINER -->
|
||||
<int>0x2061</int> <!-- FUNCTION APPLICATION -->
|
||||
<int>0x2062</int> <!-- INVISIBLE TIMES -->
|
||||
<int>0x2063</int> <!-- INVISIBLE SEPARATOR -->
|
||||
<int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING -->
|
||||
<int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING -->
|
||||
<int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING -->
|
||||
<int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING -->
|
||||
<int>0x206E</int> <!-- NATIONAL DIGIT SHAPES -->
|
||||
<int>0x206F</int> <!-- NOMINAL DIGIT SHAPES -->
|
||||
<int>0x2800</int> <!-- BRAILLE PATTERN BLANK -->
|
||||
<int>0x3000</int> <!-- IDEOGRAPHIC SPACE -->
|
||||
<int>0x3164</int> <!-- HANGUL FILLER -->
|
||||
<int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE -->
|
||||
<int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER -->
|
||||
<int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR -->
|
||||
<int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR -->
|
||||
<int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR -->
|
||||
</blank>
|
||||
<!--
|
||||
Rescan configuration every 30 seconds when FcFontSetList is called
|
||||
-->
|
||||
<rescan>
|
||||
<int>30</int>
|
||||
</rescan>
|
||||
</config>
|
||||
</fontconfig>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Extract revision number from file used by daily tarball snapshots
|
||||
# or from "git describe" output
|
||||
git_revision=$(cat snapshot_version 2> /dev/null)
|
||||
test $git_revision || test ! -d .git || \
|
||||
git_revision=`git describe --match "v[0-9]*" --always`
|
||||
git_revision=$(expr "$git_revision" : v*'\(.*\)')
|
||||
test $git_revision || git_revision=UNKNOWN
|
||||
|
||||
# releases extract the version number from the VERSION file
|
||||
version=$(cat VERSION 2> /dev/null)
|
||||
test $version || version=$git_revision
|
||||
|
||||
echo $version
|
||||
@@ -1,96 +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> singular event
|
||||
|
||||
"""
|
||||
|
||||
class G:
|
||||
events = {}
|
||||
sevents = [] # events, deterministically sorted
|
||||
start = None
|
||||
|
||||
class Event:
|
||||
pass
|
||||
|
||||
def get_event(event):
|
||||
if event not in G.events:
|
||||
e = Event()
|
||||
G.events[event] = e
|
||||
e.name = event
|
||||
e.vals = []
|
||||
e.type = "unknown"
|
||||
G.sevents = list(G.events.values())
|
||||
G.sevents.sort(key=lambda x: x.name)
|
||||
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:])
|
||||
e.type = "event"
|
||||
e.vals.append((ts, 0))
|
||||
e.vals.append((ts, 1))
|
||||
elif event.startswith("end "):
|
||||
e = get_event(event[4:])
|
||||
e.type = "event"
|
||||
e.vals.append((ts, 1))
|
||||
e.vals.append((ts, 0))
|
||||
elif event.startswith("value "):
|
||||
_, val, name = event.split(" ", 2)
|
||||
val = float(val)
|
||||
e = get_event(name)
|
||||
e.type = "value"
|
||||
e.vals.append((ts, val))
|
||||
else:
|
||||
e = get_event(event)
|
||||
e.type = "event-signal"
|
||||
e.vals.append((ts, 1))
|
||||
|
||||
ao_events = ["ao fill", "audio wait"]
|
||||
for e in G.sevents:
|
||||
if e.name in ao_events:
|
||||
e.vals = [(x, y * 0.5) 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 = "o", linestyle = "None")
|
||||
legend.append(pl)
|
||||
plot.subplot(2, 1, 1)
|
||||
plot.legend(legend, [pl.get_label() for pl in legend])
|
||||
plot.show()
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo >&2 "Usage: $0 input.svg output.ico"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# For smooth rendering on high-DPI displays, the standard three app icon sizes
|
||||
# (16x16, 32x32 and 48x48) have to be scaled to the four Windows DPI settings
|
||||
# as in the table below:
|
||||
|
||||
# Small Regular Tiles
|
||||
# 96 DPI (100%) 16x16 32x32 48x48
|
||||
# 120 DPI (125%) 20x20 40x40 60x60
|
||||
# 144 DPI (150%) 24x24 48x48 72x72
|
||||
# 196 DPI (200%) 32x32 64x64 96x96
|
||||
|
||||
# Also, there should also be an extra large 256x256 icon and some low colour
|
||||
# 8-bit and 4-bit variants, which are still used in Remote Desktop.
|
||||
|
||||
# Note: Windows Vista has a bug in its icon scaling that makes no sense.
|
||||
# Instead of following the DPI setting, small icons are always a bit larger
|
||||
# than they should be at 22x22, 26x26 and 36x36 for 120, 144 and 196 DPI. This
|
||||
# script doesn't generate icons with those sizes, since computers with Vista
|
||||
# and a high-DPI display are probably fairly rare these days.
|
||||
|
||||
temppng=".$(basename "$1" .svg)-temp.png"
|
||||
|
||||
inkscape --without-gui --export-png="$temppng" --export-dpi=72 \
|
||||
--export-background-opacity=0 --export-width=512 --export-height=512 \
|
||||
"$1" >/dev/null 2>&1
|
||||
|
||||
# Old versions of ImageMagick (like the one in Cygwin) use the wrong gamma when
|
||||
# exporting icon files. To fix, add -gamma 2.2 after the input file.
|
||||
|
||||
convert png:"$temppng" -filter lanczos2 \
|
||||
\( -clone 0 -resize 96x96 \) \
|
||||
\( -clone 0 -resize 72x72 \) \
|
||||
\( -clone 0 -resize 64x64 \) \
|
||||
\( -clone 0 -resize 60x60 \) \
|
||||
\( -clone 0 -resize 48x48 \) \
|
||||
\( -clone 0 -resize 40x40 \) \
|
||||
\( -clone 0 -resize 32x32 \) \
|
||||
\( -clone 0 -resize 24x24 \) \
|
||||
\( -clone 0 -resize 20x20 \) \
|
||||
\( -clone 0 -resize 16x16 \) \
|
||||
\( -clone 0 -resize 256x256 \) \
|
||||
\( -clone 0 -resize 32x32 \( -clone 0 -alpha opaque -colors 255 \) \
|
||||
\( -clone 0 -channel A -threshold 50% \) \
|
||||
-delete 0 -compose CopyOpacity -composite -colors 256 \) \
|
||||
\( -clone 0 -resize 16x16 \( -clone 0 -alpha opaque -colors 255 \) \
|
||||
\( -clone 0 -channel A -threshold 50% \) \
|
||||
-delete 0 -compose CopyOpacity -composite -colors 256 \) \
|
||||
\( -clone 0 -resize 32x32 \( -clone 0 -alpha opaque -colors 15 \) \
|
||||
\( -clone 0 -channel A -threshold 50% \) \
|
||||
-delete 0 -compose CopyOpacity -composite -colors 16 \) \
|
||||
\( -clone 0 -resize 16x16 \( -clone 0 -alpha opaque -colors 15 \) \
|
||||
\( -clone 0 -channel A -threshold 50% \) \
|
||||
-delete 0 -compose CopyOpacity -composite -colors 16 \) \
|
||||
-delete 0 \
|
||||
-define png:compression-level=9 -define png:include-chunk=none ico:"$2"
|
||||
|
||||
rm "$temppng"
|
||||
+17
-48
@@ -3,18 +3,20 @@
|
||||
"""
|
||||
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.
|
||||
@@ -23,18 +25,10 @@ Note that you can control the mpv instance by writing to the command fifo:
|
||||
|
||||
echo "cycle fullscreen" > /tmp/umpv-fifo-*
|
||||
|
||||
Note: you can supply custom options with the UMPV_OPTIONS environment variable.
|
||||
The environment variable will be split on whitespace, and each item is
|
||||
passed as option to mpv _if_ the script starts mpv. If mpv is not started
|
||||
by the script (i.e. mpv is already running), the options will be ignored.
|
||||
|
||||
Warning:
|
||||
|
||||
The script attempts to make sure the FIFO is safely created (i.e. not world-
|
||||
writable), and checks that it's really a FIFO. This is important for security,
|
||||
because the FIFO allows anyone with write access to run arbitrary commands
|
||||
in mpv's context using the "run" input command. If you are worried about
|
||||
security, you should verify that the code handles these concerns correctly.
|
||||
readable, not trying to open a bogus
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -43,33 +37,13 @@ import errno
|
||||
import subprocess
|
||||
import fcntl
|
||||
import stat
|
||||
import string
|
||||
|
||||
if len(sys.argv) < 1:
|
||||
if len(sys.argv) < 2:
|
||||
print("error: needs at least one file as argument.")
|
||||
sys.exit(1)
|
||||
files = sys.argv[1:]
|
||||
|
||||
# this is about 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
|
||||
prefix = parts[0]
|
||||
for c in prefix:
|
||||
if string.ascii_letters.find(c) < 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
# make them absolute; also makes them safe against interpretation as options
|
||||
def make_abs(filename):
|
||||
if not is_url(filename):
|
||||
return os.path.abspath(filename)
|
||||
return filename
|
||||
files = [make_abs(f) for f in files]
|
||||
|
||||
opts_env = os.getenv("UMPV_OPTIONS")
|
||||
opts_env = opts_env.split() if opts_env else []
|
||||
files = [os.path.abspath(f) for f in files]
|
||||
|
||||
FIFO = "/tmp/umpv-fifo-" + os.getenv("USER")
|
||||
|
||||
@@ -112,11 +86,6 @@ else:
|
||||
pass
|
||||
else:
|
||||
raise e
|
||||
os.mkfifo(FIFO, int("0600", 8))
|
||||
os.mkfifo(FIFO, 0600)
|
||||
|
||||
opts = ["mpv", "--no-terminal", "--force-window", "--input-file=" + FIFO]
|
||||
opts.extend(opts_env)
|
||||
opts.append("--")
|
||||
opts.extend(files)
|
||||
|
||||
subprocess.check_call(opts)
|
||||
subprocess.check_call(["mpv", "--input-file=" + FIFO] + files)
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -284,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;
|
||||
|
||||
@@ -16,7 +16,6 @@ esac
|
||||
: ${ILDETECT_DRY_RUN:=}
|
||||
: ${ILDETECT_QUIET:=}
|
||||
: ${ILDETECT_RUN_INTERLACED_ONLY:=}
|
||||
: ${ILDETECT_FORCE_RUN:=}
|
||||
: ${MAKE:=make}
|
||||
|
||||
# exit status:
|
||||
@@ -77,12 +76,7 @@ case "$out" in
|
||||
exit 2
|
||||
;;
|
||||
*"probably: "*)
|
||||
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
|
||||
[ -n "$ILDETECT_DRY_RUN" ] || \
|
||||
$ILDETECT_MPV "$@" -vf-pre yadif
|
||||
r=$?
|
||||
[ $r -eq 0 ] || exit $(($r | 16))
|
||||
exit 0
|
||||
exit 8
|
||||
;;
|
||||
*)
|
||||
exit 16
|
||||
|
||||
@@ -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,7 +345,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 }
|
||||
};
|
||||
privdata *priv = malloc(sizeof(privdata));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,23 +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 \
|
||||
"$1")"
|
||||
|
||||
shift
|
||||
|
||||
mpv \
|
||||
--cookies \
|
||||
--cookies-file="$cookies_file" \
|
||||
--user-agent="$user_agent" \
|
||||
"$@" -- $video_url
|
||||
|
||||
rm -rf "$cookies_dir"
|
||||
-159
@@ -1,159 +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 $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
|
||||
;;
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
push @list, $entry
|
||||
}
|
||||
|
||||
if ($parsing_main_options) {
|
||||
@list = sort {
|
||||
$a =~ /(.*?)\:/; my $ma = $1;
|
||||
$b =~ /(.*?)\:/; my $mb = $1;
|
||||
|
||||
length($mb) <=> length($ma)
|
||||
} @list;
|
||||
}
|
||||
|
||||
return @list;
|
||||
}
|
||||
+13
-179
@@ -15,65 +15,44 @@
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/mem.h>
|
||||
|
||||
#include "talloc.h"
|
||||
#include "common/common.h"
|
||||
#include "mpvcore/mp_talloc.h"
|
||||
#include "audio.h"
|
||||
|
||||
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);
|
||||
if (af_fmt_is_planar(mpa->format)) {
|
||||
mpa->spf = 1;
|
||||
mpa->num_planes = mpa->nch;
|
||||
mpa->sstride = mpa->bps;
|
||||
} else {
|
||||
mpa->spf = mpa->nch;
|
||||
mpa->num_planes = 1;
|
||||
mpa->sstride = mpa->bps * mpa->nch;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_audio_set_format(struct mp_audio *mpa, int format)
|
||||
{
|
||||
mpa->format = format;
|
||||
update_redundant_info(mpa);
|
||||
mpa->bps = af_fmt2bits(format) / 8;
|
||||
}
|
||||
|
||||
void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels)
|
||||
{
|
||||
mp_chmap_from_channels(&mpa->channels, num_channels);
|
||||
update_redundant_info(mpa);
|
||||
struct mp_chmap map;
|
||||
mp_chmap_from_channels(&map, num_channels);
|
||||
mp_audio_set_channels(mpa, &map);
|
||||
}
|
||||
|
||||
// Use old MPlayer/ALSA channel layout.
|
||||
void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels)
|
||||
{
|
||||
mp_chmap_from_channels_alsa(&mpa->channels, num_channels);
|
||||
update_redundant_info(mpa);
|
||||
struct mp_chmap map;
|
||||
mp_chmap_from_channels_alsa(&map, num_channels);
|
||||
mp_audio_set_channels(mpa, &map);
|
||||
}
|
||||
|
||||
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap)
|
||||
{
|
||||
assert(mp_chmap_is_empty(chmap) || mp_chmap_is_valid(chmap));
|
||||
mpa->channels = *chmap;
|
||||
update_redundant_info(mpa);
|
||||
mpa->nch = mpa->channels.num;
|
||||
}
|
||||
|
||||
void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src)
|
||||
{
|
||||
dst->format = src->format;
|
||||
dst->channels = src->channels;
|
||||
mp_audio_set_format(dst, src->format);
|
||||
mp_audio_set_channels(dst, &src->channels);
|
||||
dst->rate = src->rate;
|
||||
update_redundant_info(dst);
|
||||
}
|
||||
|
||||
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b)
|
||||
@@ -82,17 +61,11 @@ bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b)
|
||||
mp_chmap_equals(&a->channels, &b->channels);
|
||||
}
|
||||
|
||||
bool mp_audio_config_valid(const struct mp_audio *mpa)
|
||||
{
|
||||
return mp_chmap_is_valid(&mpa->channels) && af_fmt_is_valid(mpa->format)
|
||||
&& mpa->rate >= 1 && mpa->rate < 10000000;
|
||||
}
|
||||
|
||||
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format)
|
||||
{
|
||||
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));
|
||||
chmap->num, af_fmt2str_short(format));
|
||||
talloc_free(chstr);
|
||||
return res;
|
||||
}
|
||||
@@ -101,142 +74,3 @@ 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)
|
||||
{
|
||||
if (af_fmt_is_planar(mpa->format))
|
||||
mp_audio_set_format(mpa, af_fmt_from_planar(mpa->format));
|
||||
}
|
||||
|
||||
// Return used size of a plane. (The size is the same for all planes.)
|
||||
int mp_audio_psize(struct mp_audio *mpa)
|
||||
{
|
||||
return mpa->samples * mpa->sstride;
|
||||
}
|
||||
|
||||
void mp_audio_set_null_data(struct mp_audio *mpa)
|
||||
{
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
mpa->planes[n] = NULL;
|
||||
mpa->samples = 0;
|
||||
}
|
||||
|
||||
static void mp_audio_destructor(void *ptr)
|
||||
{
|
||||
struct mp_audio *mpa = ptr;
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
// Note: don't free if not allocated by mp_audio_realloc
|
||||
if (mpa->allocated[n])
|
||||
av_free(mpa->planes[n]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reallocate the data stored in mpa->planes[n] so that enough samples are
|
||||
* available on every plane. The previous data is kept (for the smallest
|
||||
* common number of samples before/after resize).
|
||||
*
|
||||
* mpa->samples is not set or used.
|
||||
*
|
||||
* This function is flexible enough to handle format and channel layout
|
||||
* changes. In these cases, all planes are reallocated as needed. Unused
|
||||
* planes are freed.
|
||||
*
|
||||
* mp_audio_realloc(mpa, 0) will still yield non-NULL for mpa->data[n].
|
||||
*
|
||||
* Allocated data is implicitly freed on talloc_free(mpa).
|
||||
*/
|
||||
void mp_audio_realloc(struct mp_audio *mpa, int samples)
|
||||
{
|
||||
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 (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_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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the size allocated for the data, in number of samples. If the allocated
|
||||
* size isn't on sample boundaries (e.g. after format changes), the returned
|
||||
* sample number is a rounded down value.
|
||||
*
|
||||
* Note that this only works in situations where mp_audio_realloc() also works!
|
||||
*/
|
||||
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->sstride;
|
||||
size = n == 0 ? s : MPMIN(size, s);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// Clear the samples [start, start + length) with silence.
|
||||
void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length)
|
||||
{
|
||||
assert(start >= 0 && length >= 0 && start + length <= mpa->samples);
|
||||
int offset = start * mpa->sstride;
|
||||
int size = length * mpa->sstride;
|
||||
for (int n = 0; n < mpa->num_planes; n++) {
|
||||
if (n > 0 && mpa->planes[n] == mpa->planes[0])
|
||||
continue; // silly optimization for special cases
|
||||
af_fill_silence((char *)mpa->planes[n] + offset, size, mpa->format);
|
||||
}
|
||||
}
|
||||
|
||||
// All integer parameters are in samples.
|
||||
// dst and src can overlap.
|
||||
void mp_audio_copy(struct mp_audio *dst, int dst_offset,
|
||||
struct mp_audio *src, int src_offset, int length)
|
||||
{
|
||||
assert(mp_audio_config_equals(dst, src));
|
||||
assert(length >= 0);
|
||||
assert(dst_offset >= 0 && dst_offset + length <= dst->samples);
|
||||
assert(src_offset >= 0 && src_offset + length <= src->samples);
|
||||
|
||||
for (int n = 0; n < dst->num_planes; n++) {
|
||||
memmove((char *)dst->planes[n] + dst_offset * dst->sstride,
|
||||
(char *)src->planes[n] + src_offset * src->sstride,
|
||||
length * dst->sstride);
|
||||
}
|
||||
}
|
||||
|
||||
// Set data to the audio after the given number of samples (i.e. slice it).
|
||||
void mp_audio_skip_samples(struct mp_audio *data, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= data->samples);
|
||||
|
||||
for (int n = 0; n < data->num_planes; n++)
|
||||
data->planes[n] = (uint8_t *)data->planes[n] + samples * data->sstride;
|
||||
|
||||
data->samples -= samples;
|
||||
}
|
||||
+5
-30
@@ -23,22 +23,14 @@
|
||||
|
||||
// Audio data chunk
|
||||
struct mp_audio {
|
||||
int samples; // number of samples in data (per channel)
|
||||
void *planes[MP_NUM_CHANNELS]; // data buffer (one per plane)
|
||||
int rate; // sample rate
|
||||
void *audio; // data buffer
|
||||
int len; // buffer length (in bytes)
|
||||
int rate; // sample rate
|
||||
struct mp_chmap channels; // channel layout, use mp_audio_set_*() to set
|
||||
int format; // format (AF_FORMAT_...), use mp_audio_set_format() to set
|
||||
// Redundant fields, for convenience
|
||||
int sstride; // distance between 2 samples in bytes on a plane
|
||||
// interleaved: bps * nch
|
||||
// planar: bps
|
||||
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))
|
||||
|
||||
// private
|
||||
int allocated[MP_NUM_CHANNELS]; // use mp_audio_get_allocated_size()
|
||||
int nch; // number of channels (redundant with chmap)
|
||||
int bps; // bytes per sample (redundant with format)
|
||||
};
|
||||
|
||||
void mp_audio_set_format(struct mp_audio *mpa, int format);
|
||||
@@ -47,25 +39,8 @@ void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels);
|
||||
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap);
|
||||
void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src);
|
||||
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b);
|
||||
bool mp_audio_config_valid(const struct mp_audio *mpa);
|
||||
|
||||
char *mp_audio_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);
|
||||
|
||||
int mp_audio_psize(struct mp_audio *mpa);
|
||||
|
||||
void mp_audio_set_null_data(struct mp_audio *mpa);
|
||||
|
||||
void mp_audio_realloc(struct mp_audio *mpa, int samples);
|
||||
void mp_audio_realloc_min(struct mp_audio *mpa, int samples);
|
||||
int mp_audio_get_allocated_size(struct mp_audio *mpa);
|
||||
|
||||
void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length);
|
||||
|
||||
void mp_audio_copy(struct mp_audio *dst, int dst_offset,
|
||||
struct mp_audio *src, int src_offset, int length);
|
||||
void mp_audio_skip_samples(struct mp_audio *data, int samples);
|
||||
|
||||
#endif
|
||||
@@ -1,152 +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 <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "audio_buffer.h"
|
||||
#include "audio.h"
|
||||
#include "format.h"
|
||||
|
||||
struct mp_audio_buffer {
|
||||
struct mp_audio *buffer;
|
||||
};
|
||||
|
||||
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx)
|
||||
{
|
||||
struct mp_audio_buffer *ab = talloc(talloc_ctx, struct mp_audio_buffer);
|
||||
*ab = (struct mp_audio_buffer) {
|
||||
.buffer = talloc_zero(ab, struct mp_audio),
|
||||
};
|
||||
return ab;
|
||||
}
|
||||
|
||||
// Reinitialize the buffer, set a new format, drop old data.
|
||||
// The audio data in fmt is not used, only the format.
|
||||
void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt)
|
||||
{
|
||||
mp_audio_copy_config(ab->buffer, fmt);
|
||||
mp_audio_realloc(ab->buffer, 1);
|
||||
ab->buffer->samples = 0;
|
||||
}
|
||||
|
||||
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
|
||||
const struct mp_chmap *channels, int srate)
|
||||
{
|
||||
struct mp_audio mpa = {0};
|
||||
mp_audio_set_format(&mpa, format);
|
||||
mp_audio_set_channels(&mpa, channels);
|
||||
mpa.rate = srate;
|
||||
mp_audio_buffer_reinit(ab, &mpa);
|
||||
}
|
||||
|
||||
void mp_audio_buffer_get_format(struct mp_audio_buffer *ab,
|
||||
struct mp_audio *out_fmt)
|
||||
{
|
||||
*out_fmt = (struct mp_audio){0};
|
||||
mp_audio_copy_config(out_fmt, ab->buffer);
|
||||
}
|
||||
|
||||
// Make the total size of the internal buffer at least this number of samples.
|
||||
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
mp_audio_realloc_min(ab->buffer, samples);
|
||||
}
|
||||
|
||||
// Get number of samples that can be written without forcing a resize of the
|
||||
// internal buffer.
|
||||
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab)
|
||||
{
|
||||
return mp_audio_get_allocated_size(ab->buffer) - ab->buffer->samples;
|
||||
}
|
||||
|
||||
// Get a pointer to the end of the buffer (where writing would append). If the
|
||||
// internal buffer is too small for the given number of samples, it's resized.
|
||||
// After writing to the buffer, mp_audio_buffer_finish_write() has to be used
|
||||
// to make the written data part of the readable buffer.
|
||||
void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int samples,
|
||||
struct mp_audio *out_buffer)
|
||||
{
|
||||
assert(samples >= 0);
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples + samples);
|
||||
*out_buffer = *ab->buffer;
|
||||
out_buffer->samples = ab->buffer->samples + samples;
|
||||
mp_audio_skip_samples(out_buffer, ab->buffer->samples);
|
||||
}
|
||||
|
||||
void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= mp_audio_buffer_get_write_available(ab));
|
||||
ab->buffer->samples += samples;
|
||||
}
|
||||
|
||||
// Append data to the end of the buffer.
|
||||
// If the buffer is not large enough, it is transparently resized.
|
||||
// For now always copies the data.
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa)
|
||||
{
|
||||
int offset = ab->buffer->samples;
|
||||
ab->buffer->samples += mpa->samples;
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, offset, mpa, 0, mpa->samples);
|
||||
}
|
||||
|
||||
// Prepend silence to the start of the buffer.
|
||||
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0);
|
||||
int oldlen = ab->buffer->samples;
|
||||
ab->buffer->samples += samples;
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, samples, ab->buffer, 0, oldlen);
|
||||
mp_audio_fill_silence(ab->buffer, 0, samples);
|
||||
}
|
||||
|
||||
// Get the start of the current readable buffer.
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa)
|
||||
{
|
||||
*out_mpa = *ab->buffer;
|
||||
}
|
||||
|
||||
// Skip leading samples. (Used with mp_audio_buffer_peek() to read data.)
|
||||
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, 0, ab->buffer, samples,
|
||||
ab->buffer->samples - samples);
|
||||
ab->buffer->samples -= samples;
|
||||
}
|
||||
|
||||
void mp_audio_buffer_clear(struct mp_audio_buffer *ab)
|
||||
{
|
||||
ab->buffer->samples = 0;
|
||||
}
|
||||
|
||||
// Return number of buffered audio samples
|
||||
int mp_audio_buffer_samples(struct mp_audio_buffer *ab)
|
||||
{
|
||||
return ab->buffer->samples;
|
||||
}
|
||||
|
||||
// Return amount of buffered audio in seconds.
|
||||
double mp_audio_buffer_seconds(struct mp_audio_buffer *ab)
|
||||
{
|
||||
return ab->buffer->samples / (double)ab->buffer->rate;
|
||||
}
|
||||
@@ -1,44 +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/>.
|
||||
*/
|
||||
|
||||
#ifndef MP_AUDIO_BUFFER_H
|
||||
#define MP_AUDIO_BUFFER_H
|
||||
|
||||
struct mp_audio_buffer;
|
||||
struct mp_audio;
|
||||
struct mp_chmap;
|
||||
|
||||
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx);
|
||||
void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt);
|
||||
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
|
||||
const struct mp_chmap *channels, int srate);
|
||||
void mp_audio_buffer_get_format(struct mp_audio_buffer *ab,
|
||||
struct mp_audio *out_fmt);
|
||||
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples);
|
||||
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab);
|
||||
void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples,
|
||||
struct mp_audio *out_buffer);
|
||||
void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa);
|
||||
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa);
|
||||
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_clear(struct mp_audio_buffer *ab);
|
||||
int mp_audio_buffer_samples(struct mp_audio_buffer *ab);
|
||||
double mp_audio_buffer_seconds(struct mp_audio_buffer *ab);
|
||||
|
||||
#endif
|
||||
+12
-12
@@ -18,12 +18,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "mpvcore/mp_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"},
|
||||
@@ -53,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"},
|
||||
@@ -105,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",
|
||||
@@ -471,19 +471,19 @@ bool mp_chmap_from_str(struct mp_chmap *dst, bstr src)
|
||||
return true;
|
||||
}
|
||||
|
||||
void mp_chmap_print_help(struct mp_log *log)
|
||||
void mp_chmap_print_help(int msgt, int msgl)
|
||||
{
|
||||
mp_info(log, "Speakers:\n");
|
||||
mp_msg(msgt, msgl, "Speakers:\n");
|
||||
for (int n = 0; n < MP_SPEAKER_ID_COUNT; n++) {
|
||||
if (speaker_names[n][0])
|
||||
mp_info(log, " %-16s (%s)\n",
|
||||
speaker_names[n][0], speaker_names[n][1]);
|
||||
mp_msg(msgt, msgl, " %-16s (%s)\n",
|
||||
speaker_names[n][0], speaker_names[n][1]);
|
||||
}
|
||||
mp_info(log, "Standard layouts:\n");
|
||||
mp_msg(msgt, msgl, "Standard layouts:\n");
|
||||
for (int n = 0; std_layout_names[n][0]; n++) {
|
||||
mp_info(log, " %-16s (%s)\n",
|
||||
std_layout_names[n][0], std_layout_names[n][1]);
|
||||
mp_msg(msgt, msgl, " %-16s (%s)\n",
|
||||
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_msg(msgt, msgl, " unknown%d\n", n);
|
||||
}
|
||||
+3
-5
@@ -20,14 +20,14 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include "bstr/bstr.h"
|
||||
#include "mpvcore/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
|
||||
@@ -121,9 +121,7 @@ void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
|
||||
|
||||
char *mp_chmap_to_str(const struct mp_chmap *src);
|
||||
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
|
||||
|
||||
struct mp_log;
|
||||
void mp_chmap_print_help(struct mp_log *log);
|
||||
void mp_chmap_print_help(int msgt, int msgl);
|
||||
|
||||
// Use these to avoid chaos in case lavc's definition should diverge from MS.
|
||||
#define mp_chmap_to_waveext mp_chmap_to_lavc
|
||||
|
||||
+16
-21
@@ -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;
|
||||
|
||||
+8
-10
@@ -19,13 +19,11 @@
|
||||
#ifndef MPLAYER_AD_H
|
||||
#define MPLAYER_AD_H
|
||||
|
||||
#include "common/codecs.h"
|
||||
#include "mpvcore/codecs.h"
|
||||
#include "demux/stheader.h"
|
||||
#include "demux/demux.h"
|
||||
|
||||
#include "audio/format.h"
|
||||
#include "audio/audio.h"
|
||||
#include "dec_audio.h"
|
||||
|
||||
struct mp_decoder_list;
|
||||
|
||||
@@ -33,14 +31,14 @@ struct mp_decoder_list;
|
||||
struct ad_functions {
|
||||
const char *name;
|
||||
void (*add_decoders)(struct mp_decoder_list *list);
|
||||
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);
|
||||
int (*preinit)(sh_audio_t *sh);
|
||||
int (*init)(sh_audio_t *sh, const char *decoder);
|
||||
void (*uninit)(sh_audio_t *sh);
|
||||
int (*control)(sh_audio_t *sh, int cmd, void *arg);
|
||||
int (*decode_audio)(sh_audio_t *sh, unsigned char *buffer, int minlen,
|
||||
int maxlen);
|
||||
};
|
||||
|
||||
enum ad_ctrl {
|
||||
ADCTRL_RESET = 1, // flush and reset state, e.g. after seeking
|
||||
};
|
||||
#define ADCTRL_RESYNC_STREAM 1 // resync, called after seeking
|
||||
|
||||
#endif /* MPLAYER_AD_H */
|
||||
+242
-138
@@ -29,57 +29,51 @@
|
||||
#include "talloc.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "common/av_common.h"
|
||||
#include "common/codecs.h"
|
||||
#include "common/msg.h"
|
||||
#include "options/options.h"
|
||||
#include "mpvcore/av_common.h"
|
||||
#include "mpvcore/codecs.h"
|
||||
#include "mpvcore/mp_msg.h"
|
||||
#include "mpvcore/options.h"
|
||||
#include "mpvcore/av_opts.h"
|
||||
|
||||
#include "ad.h"
|
||||
#include "audio/reorder_ch.h"
|
||||
#include "audio/fmt-conversion.h"
|
||||
|
||||
#include "compat/mpbswap.h"
|
||||
#include "compat/libav.h"
|
||||
|
||||
struct priv {
|
||||
AVCodecContext *avctx;
|
||||
AVFrame *avframe;
|
||||
struct mp_audio frame;
|
||||
uint8_t *output;
|
||||
uint8_t *output_packed; // used by deplanarize to store packed audio samples
|
||||
int output_left;
|
||||
int unitsize;
|
||||
bool force_channel_map;
|
||||
struct demux_packet *packet;
|
||||
};
|
||||
|
||||
static void uninit(struct dec_audio *da);
|
||||
static void uninit(sh_audio_t *sh);
|
||||
static int decode_audio(sh_audio_t *sh,unsigned char *buffer,int minlen,int maxlen);
|
||||
|
||||
#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 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,
|
||||
},
|
||||
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_STRING("o", ad_lavc_param.avopt, 0),
|
||||
{0}
|
||||
};
|
||||
|
||||
struct pcm_map
|
||||
{
|
||||
int tag;
|
||||
const char *codecs[6]; // {any, 1byte, 2bytes, 3bytes, 4bytes, 8bytes}
|
||||
const char *codecs[5]; // {any, 1byte, 2bytes, 3bytes, 4bytes}
|
||||
};
|
||||
|
||||
// NOTE: these are needed to make rawaudio with demux_mkv work.
|
||||
// NOTE: some of these are needed to make rawaudio with demux_mkv and others
|
||||
// work. ffmpeg does similar mapping internally, not part of the public
|
||||
// API. Some of these might be dead leftovers for demux_mov support.
|
||||
static const struct pcm_map tag_map[] = {
|
||||
// Microsoft PCM
|
||||
{0x0, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
|
||||
@@ -87,12 +81,26 @@ static const struct pcm_map tag_map[] = {
|
||||
// MS PCM, Extended
|
||||
{0xfffe, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
|
||||
// IEEE float
|
||||
{0x3, {"pcm_f32le", [5] = "pcm_f64le"}},
|
||||
{0x3, {"pcm_f32le"}},
|
||||
// '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"}},
|
||||
// 'twos'/'sowt'
|
||||
{0x736F7774, {"pcm_s16be", [1] = "pcm_s8"}},
|
||||
{0x74776F73, {"pcm_s16be", [1] = "pcm_s8"}},
|
||||
// 'fl32'/'FL32'
|
||||
{0x32336c66, {"pcm_f32be"}},
|
||||
{0x32334C46, {"pcm_f32be"}},
|
||||
// '23lf'/'lpcm'
|
||||
{0x666c3332, {"pcm_f32le"}},
|
||||
{0x6D63706C, {"pcm_f32le"}},
|
||||
// 'in24', bigendian int24
|
||||
{0x34326e69, {"pcm_s24be"}},
|
||||
// '42ni', little endian int24, MPlayer internal fourCC
|
||||
{0x696e3234, {"pcm_s24le"}},
|
||||
// 'in32', bigendian int32
|
||||
{0x32336e69, {"pcm_s32be"}},
|
||||
// '23ni', little endian int32, MPlayer internal fourCC
|
||||
{0x696e3332, {"pcm_s32le"}},
|
||||
{-1},
|
||||
};
|
||||
|
||||
@@ -115,8 +123,6 @@ static const struct pcm_map af_map[] = {
|
||||
{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},
|
||||
};
|
||||
|
||||
@@ -124,13 +130,11 @@ 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)
|
||||
if (bytes >= 1 && bytes <= 4)
|
||||
dec = entry->codecs[bytes];
|
||||
if (!dec)
|
||||
dec = entry->codecs[0];
|
||||
@@ -141,19 +145,28 @@ static const char *find_pcm_decoder(const struct pcm_map *map, int format,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_data_from_avframe(struct dec_audio *da)
|
||||
static int preinit(sh_audio_t *sh)
|
||||
{
|
||||
struct priv *priv = da->priv;
|
||||
AVCodecContext *lavc_context = priv->avctx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
/* Prefer playing audio with the samplerate given in container data
|
||||
* if available, but take number the number of channels and sample format
|
||||
* from the codec, since if the codec isn't using the correct values for
|
||||
* those everything breaks anyway.
|
||||
*/
|
||||
static int setup_format(sh_audio_t *sh_audio,
|
||||
const AVCodecContext *lavc_context)
|
||||
{
|
||||
struct priv *priv = sh_audio->context;
|
||||
int sample_format =
|
||||
af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt));
|
||||
int samplerate = lavc_context->sample_rate;
|
||||
// If not set, try container samplerate
|
||||
if (!samplerate && sh_audio->wf) {
|
||||
samplerate = sh_audio->wf->nSamplesPerSec;
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_V, "ad_lavc: using container rate.\n");
|
||||
}
|
||||
|
||||
struct mp_chmap lavc_chmap;
|
||||
mp_chmap_from_lavc(&lavc_chmap, lavc_context->channel_layout);
|
||||
@@ -161,18 +174,23 @@ static void set_data_from_avframe(struct dec_audio *da)
|
||||
if (lavc_chmap.num != lavc_context->channels)
|
||||
mp_chmap_from_channels(&lavc_chmap, lavc_context->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;
|
||||
}
|
||||
mp_audio_set_channels(&da->decoded, &lavc_chmap);
|
||||
|
||||
da->decoded.samples = priv->avframe->nb_samples;
|
||||
for (int n = 0; n < da->decoded.num_planes; n++)
|
||||
da->decoded.planes[n] = priv->avframe->data[n];
|
||||
if (!mp_chmap_equals(&lavc_chmap, &sh_audio->channels) ||
|
||||
samplerate != sh_audio->samplerate ||
|
||||
sample_format != sh_audio->sample_format) {
|
||||
sh_audio->channels = lavc_chmap;
|
||||
sh_audio->samplerate = samplerate;
|
||||
sh_audio->sample_format = sample_format;
|
||||
sh_audio->samplesize = af_fmt2bits(sh_audio->sample_format) / 8;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_from_wf(AVCodecContext *avctx, MP_WAVEFORMATEX *wf)
|
||||
static void set_from_wf(AVCodecContext *avctx, WAVEFORMATEX *wf)
|
||||
{
|
||||
avctx->channels = wf->nChannels;
|
||||
avctx->sample_rate = wf->nSamplesPerSec;
|
||||
@@ -180,45 +198,47 @@ static void set_from_wf(AVCodecContext *avctx, MP_WAVEFORMATEX *wf)
|
||||
avctx->block_align = wf->nBlockAlign;
|
||||
avctx->bits_per_coded_sample = wf->wBitsPerSample;
|
||||
|
||||
if (wf->cbSize > 0)
|
||||
mp_lavc_set_extradata(avctx, wf + 1, wf->cbSize);
|
||||
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)
|
||||
static int init(sh_audio_t *sh_audio, const char *decoder)
|
||||
{
|
||||
struct MPOpts *mpopts = da->opts;
|
||||
struct ad_lavc_params *opts = mpopts->ad_lavc_params;
|
||||
struct MPOpts *mpopts = sh_audio->opts;
|
||||
struct ad_lavc_param *opts = &mpopts->ad_lavc_param;
|
||||
AVCodecContext *lavc_context;
|
||||
AVCodec *lavc_codec;
|
||||
struct sh_stream *sh = da->header;
|
||||
struct sh_audio *sh_audio = sh->audio;
|
||||
|
||||
struct priv *ctx = talloc_zero(NULL, struct priv);
|
||||
da->priv = ctx;
|
||||
sh_audio->context = ctx;
|
||||
|
||||
if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
|
||||
decoder = find_pcm_decoder(tag_map, sh->format,
|
||||
decoder = find_pcm_decoder(tag_map, sh_audio->format,
|
||||
sh_audio->wf->wBitsPerSample);
|
||||
} else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
|
||||
decoder = find_pcm_decoder(af_map, sh->format, 0);
|
||||
decoder = find_pcm_decoder(af_map, sh_audio->format, 0);
|
||||
ctx->force_channel_map = true;
|
||||
}
|
||||
|
||||
lavc_codec = avcodec_find_decoder_by_name(decoder);
|
||||
if (!lavc_codec) {
|
||||
MP_ERR(da, "Cannot find codec '%s' in libavcodec...\n", decoder);
|
||||
uninit(da);
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR,
|
||||
"Cannot find codec '%s' in libavcodec...\n", decoder);
|
||||
uninit(sh_audio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_channels = mpopts->audio_output_channels.num;
|
||||
lavc_context->request_channel_layout =
|
||||
mp_chmap_to_lavc(&mpopts->audio_output_channels);
|
||||
}
|
||||
@@ -227,11 +247,18 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc,
|
||||
AV_OPT_SEARCH_CHILDREN);
|
||||
|
||||
mp_set_avopts(da->log, lavc_context, opts->avopts);
|
||||
if (opts->avopt) {
|
||||
if (parse_avopts(lavc_context, opts->avopt) < 0) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_ERR,
|
||||
"ad_lavc: setting AVOptions '%s' failed.\n", opts->avopt);
|
||||
uninit(sh_audio);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
lavc_context->codec_tag = sh->format;
|
||||
lavc_context->codec_tag = sh_audio->format;
|
||||
lavc_context->sample_rate = sh_audio->samplerate;
|
||||
lavc_context->bit_rate = sh_audio->bitrate;
|
||||
lavc_context->bit_rate = sh_audio->i_bps * 8;
|
||||
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
|
||||
|
||||
if (sh_audio->wf)
|
||||
@@ -240,53 +267,79 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
// 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)
|
||||
mp_copy_lav_codec_headers(lavc_context, sh->lav_headers);
|
||||
|
||||
mp_set_avcodec_threads(lavc_context, opts->threads);
|
||||
if (sh_audio->gsh->lav_headers)
|
||||
mp_copy_lav_codec_headers(lavc_context, sh_audio->gsh->lav_headers);
|
||||
|
||||
/* open it */
|
||||
if (avcodec_open2(lavc_context, lavc_codec, NULL) < 0) {
|
||||
MP_ERR(da, "Could not open codec.\n");
|
||||
uninit(da);
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Could not open codec.\n");
|
||||
uninit(sh_audio);
|
||||
return 0;
|
||||
}
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "INFO: libavcodec \"%s\" init OK!\n",
|
||||
lavc_codec->name);
|
||||
|
||||
if (lavc_context->bit_rate != 0)
|
||||
da->bitrate = lavc_context->bit_rate;
|
||||
else if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
|
||||
da->bitrate = sh_audio->wf->nAvgBytesPerSec * 8;
|
||||
// Decode at least 1 byte: (to get header filled)
|
||||
for (int tries = 0;;) {
|
||||
int x = decode_audio(sh_audio, sh_audio->a_buffer, 1,
|
||||
sh_audio->a_buffer_size);
|
||||
if (x > 0) {
|
||||
sh_audio->a_buffer_len = x;
|
||||
break;
|
||||
}
|
||||
if (++tries >= 5) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR,
|
||||
"ad_lavc: initial decode failed\n");
|
||||
uninit(sh_audio);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sh_audio->i_bps = lavc_context->bit_rate / 8;
|
||||
if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
|
||||
sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;
|
||||
|
||||
int af_sample_fmt =
|
||||
af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt));
|
||||
if (af_sample_fmt == AF_FORMAT_UNKNOWN) {
|
||||
uninit(sh_audio);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uninit(struct dec_audio *da)
|
||||
static void uninit(sh_audio_t *sh)
|
||||
{
|
||||
struct priv *ctx = da->priv;
|
||||
struct priv *ctx = sh->context;
|
||||
if (!ctx)
|
||||
return;
|
||||
AVCodecContext *lavc_context = ctx->avctx;
|
||||
|
||||
if (lavc_context) {
|
||||
if (avcodec_close(lavc_context) < 0)
|
||||
MP_ERR(da, "Could not close codec.\n");
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not close codec.\n");
|
||||
av_freep(&lavc_context->extradata);
|
||||
av_freep(&lavc_context);
|
||||
}
|
||||
av_frame_free(&ctx->avframe);
|
||||
avcodec_free_frame(&ctx->avframe);
|
||||
talloc_free(ctx);
|
||||
sh->context = NULL;
|
||||
}
|
||||
|
||||
static int control(struct dec_audio *da, int cmd, void *arg)
|
||||
static int control(sh_audio_t *sh, int cmd, void *arg)
|
||||
{
|
||||
struct priv *ctx = da->priv;
|
||||
struct priv *ctx = sh->context;
|
||||
switch (cmd) {
|
||||
case ADCTRL_RESET:
|
||||
case ADCTRL_RESYNC_STREAM:
|
||||
avcodec_flush_buffers(ctx->avctx);
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
ctx->output_left = 0;
|
||||
talloc_free(ctx->packet);
|
||||
ctx->packet = NULL;
|
||||
return CONTROL_TRUE;
|
||||
@@ -294,71 +347,121 @@ static int control(struct dec_audio *da, int cmd, void *arg)
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
static int decode_packet(struct dec_audio *da)
|
||||
static av_always_inline void deplanarize(struct sh_audio *sh)
|
||||
{
|
||||
struct priv *priv = da->priv;
|
||||
struct priv *priv = sh->context;
|
||||
|
||||
uint8_t **planes = priv->avframe->extended_data;
|
||||
size_t bps = av_get_bytes_per_sample(priv->avctx->sample_fmt);
|
||||
size_t nb_samples = priv->avframe->nb_samples;
|
||||
size_t channels = priv->avctx->channels;
|
||||
size_t size = bps * nb_samples * channels;
|
||||
|
||||
if (talloc_get_size(priv->output_packed) != size)
|
||||
priv->output_packed =
|
||||
talloc_realloc_size(priv, priv->output_packed, size);
|
||||
|
||||
reorder_to_packed(priv->output_packed, planes, bps, channels, nb_samples);
|
||||
|
||||
priv->output = priv->output_packed;
|
||||
}
|
||||
|
||||
static int decode_new_packet(struct sh_audio *sh)
|
||||
{
|
||||
struct priv *priv = sh->context;
|
||||
AVCodecContext *avctx = priv->avctx;
|
||||
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
|
||||
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(sh->gsh);
|
||||
if (!mpkt)
|
||||
return -1; // error or EOF
|
||||
|
||||
priv->packet = talloc_steal(priv, mpkt);
|
||||
|
||||
int in_len = mpkt ? mpkt->len : 0;
|
||||
int in_len = mpkt->len;
|
||||
|
||||
AVPacket pkt;
|
||||
mp_set_av_packet(&pkt, mpkt, NULL);
|
||||
mp_set_av_packet(&pkt, mpkt);
|
||||
|
||||
// If we don't have a PTS yet, use the first packet PTS we can get.
|
||||
if (da->pts == MP_NOPTS_VALUE && mpkt && mpkt->pts != MP_NOPTS_VALUE) {
|
||||
da->pts = mpkt->pts;
|
||||
da->pts_offset = 0;
|
||||
if (mpkt->pts != MP_NOPTS_VALUE) {
|
||||
sh->pts = mpkt->pts;
|
||||
sh->pts_bytes = 0;
|
||||
}
|
||||
|
||||
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.
|
||||
// At least "mpc8" can return 0 and wants the packet again next time.
|
||||
if (ret >= 0) {
|
||||
ret = FFMIN(ret, mpkt->len); // sanity check against decoder overreads
|
||||
mpkt->buffer += ret;
|
||||
mpkt->len -= ret;
|
||||
mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time
|
||||
}
|
||||
if (mpkt->len == 0 || ret < 0) {
|
||||
talloc_free(mpkt);
|
||||
priv->packet = NULL;
|
||||
}
|
||||
// LATM may need many packets to find mux info
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
return AD_OK;
|
||||
if (ret > 0) {
|
||||
ret = FFMIN(ret, mpkt->len); // sanity check against decoder overreads
|
||||
mpkt->buffer += ret;
|
||||
mpkt->len -= ret;
|
||||
mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time
|
||||
}
|
||||
if (mpkt->len == 0 || ret <= 0) {
|
||||
talloc_free(mpkt);
|
||||
priv->packet = NULL;
|
||||
}
|
||||
// LATM may need many packets to find mux info
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
return 0;
|
||||
if (ret < 0) {
|
||||
MP_ERR(da, "Error decoding audio.\n");
|
||||
return AD_ERR;
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "lavc_audio: error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!got_frame)
|
||||
return mpkt ? AD_OK : AD_EOF;
|
||||
|
||||
set_data_from_avframe(da);
|
||||
|
||||
double out_pts = mp_pts_from_av(priv->avframe->pkt_pts, NULL);
|
||||
if (out_pts != MP_NOPTS_VALUE) {
|
||||
da->pts = out_pts;
|
||||
da->pts_offset = 0;
|
||||
return 0;
|
||||
uint64_t unitsize = (uint64_t)av_get_bytes_per_sample(avctx->sample_fmt) *
|
||||
avctx->channels;
|
||||
if (unitsize > 100000)
|
||||
abort();
|
||||
priv->unitsize = unitsize;
|
||||
uint64_t output_left = unitsize * priv->avframe->nb_samples;
|
||||
if (output_left > 500000000)
|
||||
abort();
|
||||
priv->output_left = output_left;
|
||||
if (av_sample_fmt_is_planar(avctx->sample_fmt) && avctx->channels > 1) {
|
||||
deplanarize(sh);
|
||||
} else {
|
||||
priv->output = priv->avframe->data[0];
|
||||
}
|
||||
|
||||
MP_DBG(da, "Decoded %d -> %d samples\n", in_len, da->decoded.samples);
|
||||
mp_dbg(MSGT_DECAUDIO, MSGL_DBG2, "Decoded %d -> %d \n", in_len,
|
||||
priv->output_left);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen,
|
||||
int maxlen)
|
||||
{
|
||||
struct priv *priv = sh_audio->context;
|
||||
AVCodecContext *avctx = priv->avctx;
|
||||
|
||||
int len = -1;
|
||||
while (len < minlen) {
|
||||
if (!priv->output_left) {
|
||||
if (decode_new_packet(sh_audio) < 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (setup_format(sh_audio, avctx))
|
||||
return len;
|
||||
int size = (minlen - len + priv->unitsize - 1);
|
||||
size -= size % priv->unitsize;
|
||||
size = FFMIN(size, priv->output_left);
|
||||
if (size > maxlen)
|
||||
abort();
|
||||
memcpy(buf, priv->output, size);
|
||||
priv->output += size;
|
||||
priv->output_left -= size;
|
||||
if (len < 0)
|
||||
len = size;
|
||||
else
|
||||
len += size;
|
||||
buf += size;
|
||||
maxlen -= size;
|
||||
sh_audio->pts_bytes += size;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void add_decoders(struct mp_decoder_list *list)
|
||||
{
|
||||
mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
|
||||
@@ -369,8 +472,9 @@ static void add_decoders(struct mp_decoder_list *list)
|
||||
const struct ad_functions ad_lavc = {
|
||||
.name = "lavc",
|
||||
.add_decoders = add_decoders,
|
||||
.preinit = preinit,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode_packet = decode_packet,
|
||||
.decode_audio = decode_audio,
|
||||
};
|
||||
+341
-161
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MPEG 1.0/2.0/2.5 audio layer I, II, III decoding with libmpg123
|
||||
*
|
||||
* Copyright (C) 2010-2013 Thomas Orgis <thomas@orgis.org>
|
||||
* Copyright (C) 2010-2012 Thomas Orgis <thomas@orgis.org>
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,38 +25,42 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "ad.h"
|
||||
#include "common/msg.h"
|
||||
#include "mpvcore/mp_msg.h"
|
||||
|
||||
/* Reducing the ifdeffery to two main variants:
|
||||
* 1. most compatible to any libmpg123 version
|
||||
* 2. fastest variant with recent libmpg123 (>=1.14)
|
||||
* Running variant 2 on older libmpg123 versions may work in
|
||||
* principle, but is not supported.
|
||||
* So, please leave the check for MPG123_API_VERSION there, m-kay?
|
||||
*/
|
||||
#include <mpg123.h>
|
||||
|
||||
#if (defined MPG123_API_VERSION) && (MPG123_API_VERSION < 33)
|
||||
#error "This should not happen"
|
||||
/* Enable faster mode of operation with newer libmpg123, avoiding
|
||||
* unnecessary memcpy() calls. */
|
||||
#if (defined MPG123_API_VERSION) && (MPG123_API_VERSION >= 33)
|
||||
#define AD_MPG123_FRAMEWISE
|
||||
#endif
|
||||
|
||||
/* Switch for updating bitrate info of VBR files. Not essential. */
|
||||
#define AD_MPG123_MEAN_BITRATE
|
||||
|
||||
struct ad_mpg123_context {
|
||||
mpg123_handle *handle;
|
||||
int sample_size;
|
||||
#ifdef AD_MPG123_MEAN_BITRATE
|
||||
/* Running mean for bit rate, stream length estimation. */
|
||||
float mean_rate;
|
||||
unsigned int mean_count;
|
||||
/* Time delay for updates. */
|
||||
short delay;
|
||||
#endif
|
||||
/* If the stream is actually VBR. */
|
||||
char vbr;
|
||||
};
|
||||
|
||||
static void uninit(struct dec_audio *da)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
|
||||
mpg123_close(con->handle);
|
||||
mpg123_delete(con->handle);
|
||||
mpg123_exit();
|
||||
}
|
||||
|
||||
/* This initializes libmpg123 and prepares the handle, including funky
|
||||
* parameters. */
|
||||
static int init(struct dec_audio *da, const char *decoder)
|
||||
static int preinit(sh_audio_t *sh)
|
||||
{
|
||||
int err;
|
||||
struct ad_mpg123_context *con;
|
||||
@@ -67,8 +71,8 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
if (mpg123_init() != MPG123_OK)
|
||||
return 0;
|
||||
|
||||
da->priv = talloc_zero(NULL, struct ad_mpg123_context);
|
||||
con = da->priv;
|
||||
sh->context = malloc(sizeof(struct ad_mpg123_context));
|
||||
con = sh->context;
|
||||
/* Auto-choice of optimized decoder (first argument NULL). */
|
||||
con->handle = mpg123_new(NULL, &err);
|
||||
if (!con->handle)
|
||||
@@ -91,53 +95,39 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
* Let's try to run with the default for now. */
|
||||
|
||||
/* That would produce floating point output.
|
||||
* You can get 32 and 24 bit ints, even 8 bit via format matrix.
|
||||
* If wanting a specific encoding here, configure format matrix and
|
||||
* make sure it is in set_format(). */
|
||||
* You can get 32 and 24 bit ints, even 8 bit via format matrix. */
|
||||
/* mpg123_param(con->handle, MPG123_ADD_FLAGS, MPG123_FORCE_FLOAT, 0.); */
|
||||
|
||||
/* Example for RVA choice (available since libmpg123 1.0.0):
|
||||
mpg123_param(con->handle, MPG123_RVA, MPG123_RVA_MIX, 0.0) */
|
||||
|
||||
#ifdef AD_MPG123_FRAMEWISE
|
||||
/* Prevent funky automatic resampling.
|
||||
* This way, we can be sure that one frame will never produce
|
||||
* more than 1152 stereo samples.
|
||||
* Background:
|
||||
* Going to decode directly to the output buffer. It is important to have
|
||||
* MPG123_AUTO_RESAMPLE disabled for the buffer size being an all-time
|
||||
* limit.
|
||||
* We need at least 1152 samples. dec_audio.c normally guarantees this. */
|
||||
* more than 1152 stereo samples. */
|
||||
mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.);
|
||||
|
||||
err = mpg123_open_feed(con->handle);
|
||||
if (err != MPG123_OK)
|
||||
goto bad_end;
|
||||
#else
|
||||
/* Older mpg123 is vulnerable to concatenated streams when gapless cutting
|
||||
* is enabled (will only play the jingle of a badly constructed radio
|
||||
* stream). The versions using framewise decoding are fine with that. */
|
||||
mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0.);
|
||||
#endif
|
||||
|
||||
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_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 preinit error: %s\n",
|
||||
mpg123_plain_strerror(err));
|
||||
else
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 preinit error: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpg123_format_to_af(int mpg123_encoding)
|
||||
{
|
||||
/* Without external force, mpg123 will always choose signed encoding,
|
||||
* and non-16-bit only on builds that don't support it.
|
||||
* Be reminded that it doesn't matter to the MPEG file what encoding
|
||||
* is produced from it. */
|
||||
switch (mpg123_encoding) {
|
||||
case MPG123_ENC_SIGNED_8: return AF_FORMAT_S8;
|
||||
case MPG123_ENC_SIGNED_16: return AF_FORMAT_S16;
|
||||
case MPG123_ENC_SIGNED_32: return AF_FORMAT_S32;
|
||||
case MPG123_ENC_FLOAT_32: return AF_FORMAT_FLOAT;
|
||||
}
|
||||
if (con->handle)
|
||||
mpg123_delete(con->handle);
|
||||
mpg123_exit();
|
||||
free(sh->context);
|
||||
sh->context = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -150,139 +140,328 @@ 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);
|
||||
}
|
||||
|
||||
/* Opted against the header printout from old mp3lib, too much
|
||||
* irrelevant info. This is modelled after the mpg123 app's
|
||||
* standard output line.
|
||||
* If more verbosity is demanded, one can add more detail and
|
||||
* also throw in ID3v2 info which libmpg123 collects anyway. */
|
||||
static void print_header_compact(struct mpg123_frameinfo *i)
|
||||
{
|
||||
static const char *smodes[5] = {
|
||||
"stereo", "joint-stereo", "dual-channel", "mono", "invalid"
|
||||
};
|
||||
static const char *layers[4] = {
|
||||
"Unknown", "I", "II", "III"
|
||||
};
|
||||
static const char *versions[4] = {
|
||||
"1.0", "2.0", "2.5", "x.x"
|
||||
};
|
||||
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "MPEG %s layer %s, ",
|
||||
versions[i->version], layers[i->layer]);
|
||||
switch (i->vbr) {
|
||||
case MPG123_CBR:
|
||||
if (i->bitrate)
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "%d kbit/s", i->bitrate);
|
||||
else
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "%d kbit/s (free format)",
|
||||
compute_bitrate(i));
|
||||
break;
|
||||
case MPG123_VBR:
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "VBR");
|
||||
break;
|
||||
case MPG123_ABR:
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "%d kbit/s ABR", i->abr_rate);
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "???");
|
||||
}
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, ", %ld Hz %s\n", i->rate,
|
||||
smodes[i->mode]);
|
||||
}
|
||||
|
||||
/* This tries to extract a requested amount of decoded data.
|
||||
* Even when you request 0 bytes, it will feed enough input so that
|
||||
* the decoder _could_ have delivered something.
|
||||
* Returns byte count >= 0, -1 on error.
|
||||
*
|
||||
* Thoughts on exact pts keeping:
|
||||
* We have to assume that MPEG frames are cut in pieces by packet boundaries.
|
||||
* Also, it might be possible that the first packet does not contain enough
|
||||
* data to ensure initial stream sync... or re-sync on erroneous streams.
|
||||
* So we need something robust to relate the decoded byte count to the correct
|
||||
* time stamp. This is tricky, though. From the outside, you cannot tell if,
|
||||
* after having fed two packets until the first output arrives, one should
|
||||
* start counting from the first packet's pts or the second packet's.
|
||||
* So, let's just count from the last fed package's pts. If the packets are
|
||||
* exactly cut to MPEG frames, this will cause one frame mismatch in the
|
||||
* beginning (when mpg123 peeks ahead for the following header), but will
|
||||
* be corrected with the third frame already. One might add special code to
|
||||
* not increment the base pts past the first packet's after a resync before
|
||||
* the first decoded bytes arrived. */
|
||||
static int decode_a_bit(sh_audio_t *sh, unsigned char *buf, int count)
|
||||
{
|
||||
int ret = MPG123_OK;
|
||||
int got = 0;
|
||||
struct ad_mpg123_context *con = sh->context;
|
||||
|
||||
/* There will be one MPG123_NEW_FORMAT message on first open.
|
||||
* This will be handled in init(). */
|
||||
do {
|
||||
size_t got_now = 0;
|
||||
|
||||
/* Feed the decoder. This will only fire from the second round on. */
|
||||
if (ret == MPG123_NEED_MORE) {
|
||||
/* Feed more input data. */
|
||||
struct demux_packet *pkt = demux_read_packet(sh->gsh);
|
||||
if (!pkt)
|
||||
break; /* Apparently that's it. EOF. */
|
||||
|
||||
/* Next bytes from that presentation time. */
|
||||
if (pkt->pts != MP_NOPTS_VALUE) {
|
||||
sh->pts = pkt->pts;
|
||||
sh->pts_bytes = 0;
|
||||
}
|
||||
|
||||
#ifdef AD_MPG123_FRAMEWISE
|
||||
/* Have to use mpg123_feed() to avoid decoding here. */
|
||||
ret = mpg123_feed(con->handle, pkt->buffer, pkt->len);
|
||||
#else
|
||||
/* Do not use mpg123_feed(), added in later libmpg123 versions. */
|
||||
ret = mpg123_decode(con->handle, pkt->buffer, pkt->len, NULL, 0, NULL);
|
||||
#endif
|
||||
talloc_free(pkt);
|
||||
if (ret == MPG123_ERR)
|
||||
break;
|
||||
}
|
||||
/* Theoretically, mpg123 could return MPG123_DONE, so be prepared.
|
||||
* Should not happen in our usage, but it is a valid return code. */
|
||||
else if (ret == MPG123_ERR || ret == MPG123_DONE)
|
||||
break;
|
||||
|
||||
/* Try to decode a bit. This is the return value that counts
|
||||
* for the loop condition. */
|
||||
#ifdef AD_MPG123_FRAMEWISE
|
||||
if (!buf) { /* fake call just for feeding to get format */
|
||||
ret = mpg123_getformat(con->handle, NULL, NULL, NULL);
|
||||
} else { /* This is the decoding. One frame at a time. */
|
||||
ret = mpg123_replace_buffer(con->handle, buf, count);
|
||||
if (ret == MPG123_OK)
|
||||
ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now);
|
||||
}
|
||||
#else
|
||||
ret = mpg123_decode(con->handle, NULL, 0, buf + got, count - got,
|
||||
&got_now);
|
||||
#endif
|
||||
|
||||
got += got_now;
|
||||
sh->pts_bytes += got_now;
|
||||
|
||||
#ifdef AD_MPG123_FRAMEWISE
|
||||
} while (ret == MPG123_NEED_MORE || (got == 0 && count != 0));
|
||||
#else
|
||||
} while (ret == MPG123_NEED_MORE || got < count);
|
||||
#endif
|
||||
|
||||
if (ret == MPG123_ERR) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 decoding failed: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
mpg123_close(con->handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return got;
|
||||
}
|
||||
|
||||
/* Close, reopen stream. Feed data until we know the format of the stream.
|
||||
* 1 on success, 0 on error */
|
||||
static int reopen_stream(sh_audio_t *sh)
|
||||
{
|
||||
struct ad_mpg123_context *con = (struct ad_mpg123_context*) sh->context;
|
||||
|
||||
mpg123_close(con->handle);
|
||||
/* No resetting of the context:
|
||||
* We do not want to loose the mean bitrate data. */
|
||||
|
||||
/* Open and make sure we have fed enough data to get stream properties. */
|
||||
if (MPG123_OK == mpg123_open_feed(con->handle) &&
|
||||
/* Feed data until mpg123 is ready (has found stream beginning). */
|
||||
!decode_a_bit(sh, NULL, 0)) {
|
||||
return 1;
|
||||
} else {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR,
|
||||
"mpg123 failed to reopen stream: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
mpg123_close(con->handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we really start accessing some data and determining file format.
|
||||
* Paranoia note: The mpg123_close() on errors is not really necessary,
|
||||
* But it ensures that we don't accidentally continue decoding with a
|
||||
* bad state (possibly interpreting the format badly or whatnot). */
|
||||
static int init(sh_audio_t *sh, const char *decoder)
|
||||
{
|
||||
long rate = 0;
|
||||
int channels = 0;
|
||||
int encoding = 0;
|
||||
mpg123_id3v2 *v2;
|
||||
struct mpg123_frameinfo finfo;
|
||||
struct ad_mpg123_context *con = sh->context;
|
||||
|
||||
/* We're open about any output format that libmpg123 will suggest.
|
||||
* Note that a standard build will always default to 16 bit signed and
|
||||
* the native sample rate of the file. */
|
||||
if (MPG123_OK == mpg123_format_all(con->handle) &&
|
||||
reopen_stream(sh) &&
|
||||
MPG123_OK == mpg123_getformat(con->handle, &rate, &channels, &encoding) &&
|
||||
/* Forbid the format to change later on. */
|
||||
MPG123_OK == mpg123_format_none(con->handle) &&
|
||||
MPG123_OK == mpg123_format(con->handle, rate, channels, encoding) &&
|
||||
/* Get MPEG header info. */
|
||||
MPG123_OK == mpg123_info(con->handle, &finfo) &&
|
||||
/* Since we queried format, mpg123 should have read past ID3v2 tags.
|
||||
* We need to decide if printing of UTF-8 encoded text info is wanted. */
|
||||
MPG123_OK == mpg123_id3(con->handle, NULL, &v2)) {
|
||||
/* If we are here, we passed all hurdles. Yay! Extract the info. */
|
||||
print_header_compact(&finfo);
|
||||
/* Do we want to print out the UTF-8 Id3v2 info?
|
||||
if (v2)
|
||||
print_id3v2(v2); */
|
||||
|
||||
/* Have kb/s, want B/s
|
||||
* For VBR, the first frame will be a bad estimate. */
|
||||
sh->i_bps = (finfo.bitrate ? finfo.bitrate : compute_bitrate(&finfo))
|
||||
* 1000 / 8;
|
||||
#ifdef AD_MPG123_MEAN_BITRATE
|
||||
con->delay = 1;
|
||||
con->mean_rate = 0.;
|
||||
con->mean_count = 0;
|
||||
#endif
|
||||
con->vbr = (finfo.vbr != MPG123_CBR);
|
||||
mp_chmap_from_channels(&sh->channels, channels);
|
||||
sh->samplerate = rate;
|
||||
/* Without external force, mpg123 will always choose signed encoding,
|
||||
* and non-16-bit only on builds that don't support it.
|
||||
* Be reminded that it doesn't matter to the MPEG file what encoding
|
||||
* is produced from it. */
|
||||
switch (encoding) {
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
sh->sample_format = AF_FORMAT_S8;
|
||||
sh->samplesize = 1;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
sh->sample_format = AF_FORMAT_S16_NE;
|
||||
sh->samplesize = 2;
|
||||
break;
|
||||
/* To stay compatible with the oldest libmpg123 headers, do not rely
|
||||
* on float and 32 bit encoding symbols being defined.
|
||||
* Those formats came later */
|
||||
case 0x1180: /* MPG123_ENC_SIGNED_32 */
|
||||
sh->sample_format = AF_FORMAT_S32_NE;
|
||||
sh->samplesize = 4;
|
||||
break;
|
||||
case 0x200: /* MPG123_ENC_FLOAT_32 */
|
||||
sh->sample_format = AF_FORMAT_FLOAT_NE;
|
||||
sh->samplesize = 4;
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR,
|
||||
"Bad encoding from mpg123: %i.\n", encoding);
|
||||
mpg123_close(con->handle);
|
||||
return 0;
|
||||
}
|
||||
#ifdef AD_MPG123_FRAMEWISE
|
||||
/* Going to decode directly to MPlayer's memory. It is important
|
||||
* to have MPG123_AUTO_RESAMPLE disabled for the buffer size
|
||||
* being an all-time limit. */
|
||||
sh->audio_out_minsize = 1152 * 2 * sh->samplesize;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 init error: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
mpg123_close(con->handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void uninit(sh_audio_t *sh)
|
||||
{
|
||||
struct ad_mpg123_context *con = (struct ad_mpg123_context*) sh->context;
|
||||
|
||||
mpg123_close(con->handle);
|
||||
mpg123_delete(con->handle);
|
||||
free(sh->context);
|
||||
sh->context = NULL;
|
||||
mpg123_exit();
|
||||
}
|
||||
|
||||
#ifdef AD_MPG123_MEAN_BITRATE
|
||||
/* Update mean bitrate. This could be dropped if accurate time display
|
||||
* on audio file playback is not desired. */
|
||||
static void update_info(struct dec_audio *da)
|
||||
static void update_info(sh_audio_t *sh)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
struct mpg123_frameinfo finfo;
|
||||
if (mpg123_info(con->handle, &finfo) != MPG123_OK)
|
||||
return;
|
||||
|
||||
/* finfo.bitrate is expressed in kilobits */
|
||||
const int bitrate = finfo.bitrate * 1000;
|
||||
|
||||
if (finfo.vbr != MPG123_CBR) {
|
||||
if (--con->delay < 1) {
|
||||
struct ad_mpg123_context *con = sh->context;
|
||||
if (con->vbr && --con->delay < 1) {
|
||||
struct mpg123_frameinfo finfo;
|
||||
if (MPG123_OK == mpg123_info(con->handle, &finfo)) {
|
||||
if (++con->mean_count > ((unsigned int) -1) / 2)
|
||||
con->mean_count = ((unsigned int) -1) / 4;
|
||||
|
||||
/* Might not be numerically optimal, but works fine enough. */
|
||||
con->mean_rate = ((con->mean_count - 1) * con->mean_rate +
|
||||
bitrate) / con->mean_count;
|
||||
da->bitrate = (int) (con->mean_rate + 0.5);
|
||||
finfo.bitrate) / con->mean_count;
|
||||
sh->i_bps = (int) (con->mean_rate * 1000 / 8);
|
||||
|
||||
con->delay = 10;
|
||||
}
|
||||
} else {
|
||||
da->bitrate = bitrate ? bitrate : compute_bitrate(&finfo);
|
||||
con->delay = 1;
|
||||
con->mean_rate = 0.;
|
||||
con->mean_count = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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(sh_audio_t *sh, unsigned char *buf, int minlen,
|
||||
int maxlen)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
int ret;
|
||||
long rate;
|
||||
int channels;
|
||||
int encoding;
|
||||
ret = mpg123_getformat(con->handle, &rate, &channels, &encoding);
|
||||
if (ret == MPG123_OK) {
|
||||
mp_audio_set_num_channels(&da->decoded, channels);
|
||||
da->decoded.rate = rate;
|
||||
int af = mpg123_format_to_af(encoding);
|
||||
if (!af) {
|
||||
/* This means we got a funny custom build of libmpg123 that only supports an unknown format. */
|
||||
MP_ERR(da, "Bad encoding from mpg123: %i.\n", encoding);
|
||||
return MPG123_ERR;
|
||||
}
|
||||
mp_audio_set_format(&da->decoded, af);
|
||||
con->sample_size = channels * af_fmt2bps(af);
|
||||
}
|
||||
return ret;
|
||||
int bytes;
|
||||
|
||||
bytes = decode_a_bit(sh, buf, maxlen);
|
||||
if (bytes == 0)
|
||||
return -1; /* EOF */
|
||||
|
||||
#ifdef AD_MPG123_MEAN_BITRATE
|
||||
update_info(sh);
|
||||
#endif
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static int decode_packet(struct dec_audio *da)
|
||||
static int control(sh_audio_t *sh, int cmd, void *arg)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
int ret;
|
||||
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
|
||||
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 (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)
|
||||
return 0;
|
||||
|
||||
if (ret != MPG123_OK && ret != MPG123_DONE && ret != MPG123_NEW_FORMAT)
|
||||
goto mpg123_fail;
|
||||
|
||||
ret = set_format(da);
|
||||
if (ret != MPG123_OK)
|
||||
goto mpg123_fail;
|
||||
|
||||
if (con->sample_size < 1) {
|
||||
MP_ERR(da, "no sample size\n");
|
||||
return AD_ERR;
|
||||
}
|
||||
|
||||
int got_samples = bytes / con->sample_size;
|
||||
da->decoded.planes[0] = audio;
|
||||
da->decoded.samples = got_samples;
|
||||
|
||||
update_info(da);
|
||||
return 0;
|
||||
|
||||
mpg123_fail:
|
||||
MP_ERR(da, "mpg123 decoding error: %s\n", mpg123_strerror(con->handle));
|
||||
return AD_ERR;
|
||||
}
|
||||
|
||||
static int control(struct dec_audio *da, int cmd, void *arg)
|
||||
{
|
||||
struct ad_mpg123_context *con = da->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case ADCTRL_RESET:
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
mpg123_close(con->handle);
|
||||
|
||||
if (mpg123_open_feed(con->handle) != MPG123_OK) {
|
||||
MP_ERR(da, "mpg123 failed to reopen stream: %s\n",
|
||||
mpg123_strerror(con->handle));
|
||||
case ADCTRL_RESYNC_STREAM:
|
||||
/* Close/reopen the stream for mpg123 to make sure it doesn't
|
||||
* think that it still knows the exact stream position.
|
||||
* Otherwise, we would have funny effects from the gapless code.
|
||||
* Oh, and it helps to minimize artifacts from jumping in the stream. */
|
||||
if (reopen_stream(sh)) {
|
||||
#ifdef AD_MPG123_MEAN_BITRATE
|
||||
update_info(sh);
|
||||
#endif
|
||||
return CONTROL_TRUE;
|
||||
} else {
|
||||
/* MPlayer ignores this case! It just keeps on decoding.
|
||||
* So we have to make sure resync never fails ... */
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR,
|
||||
"mpg123 cannot reopen stream for resync.\n");
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
return CONTROL_TRUE;
|
||||
break;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
@@ -296,8 +475,9 @@ static void add_decoders(struct mp_decoder_list *list)
|
||||
const struct ad_functions ad_mpg123 = {
|
||||
.name = "mpg123",
|
||||
.add_decoders = add_decoders,
|
||||
.preinit = preinit,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode_packet = decode_packet,
|
||||
.decode_audio = decode_audio,
|
||||
};
|
||||
+203
-178
@@ -19,211 +19,60 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/opt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/av_common.h"
|
||||
#include "options/options.h"
|
||||
#include "mpvcore/mp_msg.h"
|
||||
#include "mpvcore/av_common.h"
|
||||
#include "mpvcore/options.h"
|
||||
#include "ad.h"
|
||||
|
||||
#define FILENAME_SPDIFENC "spdif"
|
||||
#define OUTBUF_SIZE 65536
|
||||
|
||||
struct spdifContext {
|
||||
struct mp_log *log;
|
||||
AVFormatContext *lavf_ctx;
|
||||
int iec61937_packet_size;
|
||||
int out_buffer_len;
|
||||
uint8_t out_buffer[OUTBUF_SIZE];
|
||||
bool need_close;
|
||||
int out_buffer_size;
|
||||
uint8_t *out_buffer;
|
||||
uint8_t pb_buffer[OUTBUF_SIZE];
|
||||
};
|
||||
|
||||
static void uninit(sh_audio_t *sh);
|
||||
|
||||
static int read_packet(void *p, uint8_t *buf, int buf_size)
|
||||
{
|
||||
// spdifenc does not use read callback.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_packet(void *p, uint8_t *buf, int buf_size)
|
||||
{
|
||||
int len;
|
||||
struct spdifContext *ctx = p;
|
||||
|
||||
int buffer_left = OUTBUF_SIZE - ctx->out_buffer_len;
|
||||
if (buf_size > buffer_left) {
|
||||
MP_ERR(ctx, "spdif packet too large.\n");
|
||||
buf_size = buffer_left;
|
||||
}
|
||||
|
||||
memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, buf_size);
|
||||
ctx->out_buffer_len += buf_size;
|
||||
return buf_size;
|
||||
len = FFMIN(buf_size, ctx->out_buffer_size -ctx->out_buffer_len);
|
||||
memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, len);
|
||||
ctx->out_buffer_len += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void uninit(struct dec_audio *da)
|
||||
static int64_t seek(void *p, int64_t offset, int whence)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = da->priv;
|
||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
||||
|
||||
if (lavf_ctx) {
|
||||
if (spdif_ctx->need_close)
|
||||
av_write_trailer(lavf_ctx);
|
||||
if (lavf_ctx->pb)
|
||||
av_freep(&lavf_ctx->pb->buffer);
|
||||
av_freep(&lavf_ctx->pb);
|
||||
avformat_free_context(lavf_ctx);
|
||||
}
|
||||
// spdifenc does not use seek callback.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(struct dec_audio *da, const char *decoder)
|
||||
static int preinit(sh_audio_t *sh)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = talloc_zero(NULL, struct spdifContext);
|
||||
da->priv = spdif_ctx;
|
||||
spdif_ctx->log = da->log;
|
||||
|
||||
AVFormatContext *lavf_ctx = avformat_alloc_context();
|
||||
if (!lavf_ctx)
|
||||
goto fail;
|
||||
|
||||
lavf_ctx->oformat = av_guess_format("spdif", NULL, NULL);
|
||||
if (!lavf_ctx->oformat)
|
||||
goto fail;
|
||||
|
||||
spdif_ctx->lavf_ctx = lavf_ctx;
|
||||
|
||||
void *buffer = av_mallocz(OUTBUF_SIZE);
|
||||
if (!buffer)
|
||||
abort();
|
||||
lavf_ctx->pb = avio_alloc_context(buffer, OUTBUF_SIZE, 1, spdif_ctx, NULL,
|
||||
write_packet, NULL);
|
||||
if (!lavf_ctx->pb) {
|
||||
av_free(buffer);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Request minimal buffering (not available on Libav)
|
||||
#if LIBAVFORMAT_VERSION_MICRO >= 100
|
||||
lavf_ctx->pb->direct = 1;
|
||||
#endif
|
||||
|
||||
AVStream *stream = avformat_new_stream(lavf_ctx, 0);
|
||||
if (!stream)
|
||||
goto fail;
|
||||
|
||||
stream->codec->codec_id = mp_codec_to_av_codec_id(decoder);
|
||||
|
||||
AVDictionary *format_opts = NULL;
|
||||
|
||||
int num_channels = 0;
|
||||
int sample_format = 0;
|
||||
int samplerate = 0;
|
||||
switch (stream->codec->codec_id) {
|
||||
case AV_CODEC_ID_AAC:
|
||||
spdif_ctx->iec61937_packet_size = 16384;
|
||||
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_AC3_LE;
|
||||
samplerate = 48000;
|
||||
num_channels = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_DTS:
|
||||
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_IEC61937_LE;
|
||||
samplerate = 192000;
|
||||
num_channels = 2*4;
|
||||
} else {
|
||||
spdif_ctx->iec61937_packet_size = 32768;
|
||||
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_IEC61937_LE;
|
||||
samplerate = 192000;
|
||||
num_channels = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_MP3:
|
||||
spdif_ctx->iec61937_packet_size = 4608;
|
||||
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_IEC61937_LE;
|
||||
samplerate = 192000;
|
||||
num_channels = 8;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
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");
|
||||
av_dict_free(&format_opts);
|
||||
goto fail;
|
||||
}
|
||||
av_dict_free(&format_opts);
|
||||
|
||||
spdif_ctx->need_close = true;
|
||||
|
||||
sh->samplesize = 2;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
uninit(da);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_packet(struct dec_audio *da)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = da->priv;
|
||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
||||
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
|
||||
spdif_ctx->out_buffer_len = 0;
|
||||
|
||||
struct demux_packet *mpkt;
|
||||
if (demux_read_packet_async(da->header, &mpkt) == 0)
|
||||
return AD_WAIT;
|
||||
|
||||
if (!mpkt)
|
||||
return AD_EOF;
|
||||
|
||||
AVPacket pkt;
|
||||
mp_set_av_packet(&pkt, mpkt, NULL);
|
||||
pkt.pts = pkt.dts = 0;
|
||||
MP_VERBOSE(da, "spdif packet, size=%d\n", pkt.size);
|
||||
if (mpkt->pts != MP_NOPTS_VALUE) {
|
||||
da->pts = mpkt->pts;
|
||||
da->pts_offset = 0;
|
||||
}
|
||||
int ret = av_write_frame(lavf_ctx, &pkt);
|
||||
talloc_free(mpkt);
|
||||
avio_flush(lavf_ctx->pb);
|
||||
if (ret < 0)
|
||||
return AD_ERR;
|
||||
|
||||
da->decoded.planes[0] = spdif_ctx->out_buffer;
|
||||
da->decoded.samples = spdif_ctx->out_buffer_len / da->decoded.sstride;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int control(struct dec_audio *da, int cmd, void *arg)
|
||||
{
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
static const int codecs[] = {
|
||||
static int codecs[] = {
|
||||
AV_CODEC_ID_AAC,
|
||||
AV_CODEC_ID_AC3,
|
||||
AV_CODEC_ID_DTS,
|
||||
@@ -233,6 +82,181 @@ static const int codecs[] = {
|
||||
AV_CODEC_ID_NONE
|
||||
};
|
||||
|
||||
static int init(sh_audio_t *sh, const char *decoder)
|
||||
{
|
||||
int srate, bps, *dtshd_rate;
|
||||
AVFormatContext *lavf_ctx = NULL;
|
||||
AVStream *stream = NULL;
|
||||
const AVOption *opt = NULL;
|
||||
struct spdifContext *spdif_ctx = NULL;
|
||||
|
||||
spdif_ctx = av_mallocz(sizeof(*spdif_ctx));
|
||||
if (!spdif_ctx)
|
||||
goto fail;
|
||||
spdif_ctx->lavf_ctx = avformat_alloc_context();
|
||||
if (!spdif_ctx->lavf_ctx)
|
||||
goto fail;
|
||||
|
||||
sh->context = spdif_ctx;
|
||||
lavf_ctx = spdif_ctx->lavf_ctx;
|
||||
|
||||
lavf_ctx->oformat = av_guess_format(FILENAME_SPDIFENC, NULL, NULL);
|
||||
if (!lavf_ctx->oformat)
|
||||
goto fail;
|
||||
lavf_ctx->priv_data = av_mallocz(lavf_ctx->oformat->priv_data_size);
|
||||
if (!lavf_ctx->priv_data)
|
||||
goto fail;
|
||||
lavf_ctx->pb = avio_alloc_context(spdif_ctx->pb_buffer, OUTBUF_SIZE, 1, spdif_ctx,
|
||||
read_packet, write_packet, seek);
|
||||
if (!lavf_ctx->pb)
|
||||
goto fail;
|
||||
stream = avformat_new_stream(lavf_ctx, 0);
|
||||
if (!stream)
|
||||
goto fail;
|
||||
lavf_ctx->duration = AV_NOPTS_VALUE;
|
||||
lavf_ctx->start_time = AV_NOPTS_VALUE;
|
||||
lavf_ctx->streams[0]->codec->codec_id = mp_codec_to_av_codec_id(decoder);
|
||||
lavf_ctx->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
|
||||
if (AVERROR_PATCHWELCOME == lavf_ctx->oformat->write_header(lavf_ctx)) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_INFO,
|
||||
"This codec is not supported by spdifenc.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
srate = 48000; //fake value
|
||||
bps = 768000/8; //fake value
|
||||
|
||||
int num_channels = 0;
|
||||
switch (lavf_ctx->streams[0]->codec->codec_id) {
|
||||
case AV_CODEC_ID_AAC:
|
||||
spdif_ctx->iec61937_packet_size = 16384;
|
||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||
sh->samplerate = srate;
|
||||
num_channels = 2;
|
||||
sh->i_bps = bps;
|
||||
break;
|
||||
case AV_CODEC_ID_AC3:
|
||||
spdif_ctx->iec61937_packet_size = 6144;
|
||||
sh->sample_format = AF_FORMAT_AC3_LE;
|
||||
sh->samplerate = srate;
|
||||
num_channels = 2;
|
||||
sh->i_bps = bps;
|
||||
break;
|
||||
case AV_CODEC_ID_DTS:
|
||||
if(sh->opts->dtshd) {
|
||||
opt = av_opt_find(&lavf_ctx->oformat->priv_class,
|
||||
"dtshd_rate", NULL, 0, 0);
|
||||
if (!opt)
|
||||
goto fail;
|
||||
dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) +
|
||||
opt->offset);
|
||||
*dtshd_rate = 192000*4;
|
||||
spdif_ctx->iec61937_packet_size = 32768;
|
||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||
sh->samplerate = 192000; // DTS core require 48000
|
||||
num_channels = 2*4;
|
||||
sh->i_bps = bps;
|
||||
} else {
|
||||
spdif_ctx->iec61937_packet_size = 32768;
|
||||
sh->sample_format = AF_FORMAT_AC3_LE;
|
||||
sh->samplerate = srate;
|
||||
num_channels = 2;
|
||||
sh->i_bps = bps;
|
||||
}
|
||||
break;
|
||||
case AV_CODEC_ID_EAC3:
|
||||
spdif_ctx->iec61937_packet_size = 24576;
|
||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||
sh->samplerate = 192000;
|
||||
num_channels = 2;
|
||||
sh->i_bps = bps;
|
||||
break;
|
||||
case AV_CODEC_ID_MP3:
|
||||
spdif_ctx->iec61937_packet_size = 4608;
|
||||
sh->sample_format = AF_FORMAT_MPEG2;
|
||||
sh->samplerate = srate;
|
||||
num_channels = 2;
|
||||
sh->i_bps = bps;
|
||||
break;
|
||||
case AV_CODEC_ID_TRUEHD:
|
||||
spdif_ctx->iec61937_packet_size = 61440;
|
||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||
sh->samplerate = 192000;
|
||||
num_channels = 8;
|
||||
sh->i_bps = bps;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (num_channels)
|
||||
mp_chmap_from_channels(&sh->channels, num_channels);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
uninit(sh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_audio(sh_audio_t *sh, unsigned char *buf,
|
||||
int minlen, int maxlen)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = sh->context;
|
||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
||||
AVPacket pkt;
|
||||
|
||||
spdif_ctx->out_buffer_len = 0;
|
||||
spdif_ctx->out_buffer_size = maxlen;
|
||||
spdif_ctx->out_buffer = buf;
|
||||
while (spdif_ctx->out_buffer_len + spdif_ctx->iec61937_packet_size < maxlen
|
||||
&& spdif_ctx->out_buffer_len < minlen) {
|
||||
struct demux_packet *mpkt = demux_read_packet(sh->gsh);
|
||||
if (!mpkt)
|
||||
break;
|
||||
mp_set_av_packet(&pkt, mpkt);
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V, "pkt.data[%p] pkt.size[%d]\n",
|
||||
pkt.data, pkt.size);
|
||||
if (mpkt->pts != MP_NOPTS_VALUE) {
|
||||
sh->pts = mpkt->pts;
|
||||
sh->pts_bytes = 0;
|
||||
}
|
||||
int out_len = spdif_ctx->out_buffer_len;
|
||||
int ret = lavf_ctx->oformat->write_packet(lavf_ctx, &pkt);
|
||||
avio_flush(lavf_ctx->pb);
|
||||
sh->pts_bytes += spdif_ctx->out_buffer_len - out_len;
|
||||
talloc_free(mpkt);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
return spdif_ctx->out_buffer_len;
|
||||
}
|
||||
|
||||
static int control(sh_audio_t *sh, int cmd, void *arg)
|
||||
{
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
static void uninit(sh_audio_t *sh)
|
||||
{
|
||||
struct spdifContext *spdif_ctx = sh->context;
|
||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
||||
|
||||
if (lavf_ctx) {
|
||||
if (lavf_ctx->oformat)
|
||||
lavf_ctx->oformat->write_trailer(lavf_ctx);
|
||||
av_freep(&lavf_ctx->pb);
|
||||
if (lavf_ctx->streams) {
|
||||
av_freep(&lavf_ctx->streams[0]->codec);
|
||||
av_freep(&lavf_ctx->streams[0]->info);
|
||||
av_freep(&lavf_ctx->streams[0]);
|
||||
}
|
||||
av_freep(&lavf_ctx->streams);
|
||||
av_freep(&lavf_ctx->priv_data);
|
||||
}
|
||||
av_freep(&lavf_ctx);
|
||||
av_freep(&spdif_ctx);
|
||||
}
|
||||
|
||||
static void add_decoders(struct mp_decoder_list *list)
|
||||
{
|
||||
for (int n = 0; codecs[n] != AV_CODEC_ID_NONE; n++) {
|
||||
@@ -247,8 +271,9 @@ static void add_decoders(struct mp_decoder_list *list)
|
||||
const struct ad_functions ad_spdif = {
|
||||
.name = "spdif",
|
||||
.add_decoders = add_decoders,
|
||||
.preinit = preinit,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode_packet = decode_packet,
|
||||
.decode_audio = decode_audio,
|
||||
};
|
||||
+184
-180
@@ -26,9 +26,9 @@
|
||||
#include "demux/codec_tags.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "common/codecs.h"
|
||||
#include "common/msg.h"
|
||||
#include "bstr/bstr.h"
|
||||
#include "mpvcore/codecs.h"
|
||||
#include "mpvcore/mp_msg.h"
|
||||
#include "mpvcore/bstr.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demux/demux.h"
|
||||
@@ -38,8 +38,6 @@
|
||||
#include "dec_audio.h"
|
||||
#include "ad.h"
|
||||
#include "audio/format.h"
|
||||
#include "audio/audio.h"
|
||||
#include "audio/audio_buffer.h"
|
||||
|
||||
#include "audio/filter/af.h"
|
||||
|
||||
@@ -48,7 +46,7 @@ extern const struct ad_functions ad_lavc;
|
||||
extern const struct ad_functions ad_spdif;
|
||||
|
||||
static const struct ad_functions * const ad_drivers[] = {
|
||||
#if HAVE_MPG123
|
||||
#ifdef CONFIG_MPG123
|
||||
&ad_mpg123,
|
||||
#endif
|
||||
&ad_lavc,
|
||||
@@ -56,44 +54,51 @@ static const struct ad_functions * const ad_drivers[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
// 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)
|
||||
static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder)
|
||||
{
|
||||
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;
|
||||
assert(!sh_audio->initialized);
|
||||
resync_audio_stream(sh_audio);
|
||||
sh_audio->samplesize = 4;
|
||||
sh_audio->sample_format = AF_FORMAT_FLOAT_NE;
|
||||
sh_audio->audio_out_minsize = 8192; // default, preinit() may change it
|
||||
if (!sh_audio->ad_driver->preinit(sh_audio)) {
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder preinit failed.\n");
|
||||
return 0;
|
||||
}
|
||||
mp_audio_buffer_reinit(da->decode_buffer, &da->decoded);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void uninit_decoder(struct dec_audio *d_audio)
|
||||
{
|
||||
if (d_audio->ad_driver) {
|
||||
MP_VERBOSE(d_audio, "Uninit audio decoder.\n");
|
||||
d_audio->ad_driver->uninit(d_audio);
|
||||
const int base_size = 65536;
|
||||
// At least 64 KiB plus rounding up to next decodable unit size
|
||||
sh_audio->a_buffer_size = base_size + sh_audio->audio_out_minsize;
|
||||
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_V,
|
||||
"dec_audio: Allocating %d + %d = %d bytes for output buffer.\n",
|
||||
sh_audio->audio_out_minsize, base_size,
|
||||
sh_audio->a_buffer_size);
|
||||
|
||||
sh_audio->a_buffer = av_mallocz(sh_audio->a_buffer_size);
|
||||
if (!sh_audio->a_buffer)
|
||||
abort();
|
||||
sh_audio->a_buffer_len = 0;
|
||||
|
||||
if (!sh_audio->ad_driver->init(sh_audio, decoder)) {
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Audio decoder init failed.\n");
|
||||
uninit_audio(sh_audio); // free buffers
|
||||
return 0;
|
||||
}
|
||||
d_audio->ad_driver = NULL;
|
||||
talloc_free(d_audio->priv);
|
||||
d_audio->priv = NULL;
|
||||
}
|
||||
|
||||
sh_audio->initialized = 1;
|
||||
|
||||
static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
|
||||
{
|
||||
if (!d_audio->ad_driver->init(d_audio, decoder)) {
|
||||
MP_VERBOSE(d_audio, "Audio decoder init failed.\n");
|
||||
d_audio->ad_driver = NULL;
|
||||
uninit_decoder(d_audio);
|
||||
if (mp_chmap_is_empty(&sh_audio->channels) || !sh_audio->samplerate) {
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify "
|
||||
"audio format!\n");
|
||||
uninit_audio(sh_audio); // free buffers
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_audio->decode_buffer = mp_audio_buffer_create(NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct mp_decoder_list *audio_decoder_list(void)
|
||||
struct mp_decoder_list *mp_audio_decoder_list(void)
|
||||
{
|
||||
struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
|
||||
for (int i = 0; ad_drivers[i] != NULL; i++)
|
||||
@@ -101,10 +106,10 @@ struct mp_decoder_list *audio_decoder_list(void)
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct mp_decoder_list *audio_select_decoders(const char *codec,
|
||||
char *selection)
|
||||
static struct mp_decoder_list *mp_select_audio_decoders(const char *codec,
|
||||
char *selection)
|
||||
{
|
||||
struct mp_decoder_list *list = audio_decoder_list();
|
||||
struct mp_decoder_list *list = mp_audio_decoder_list();
|
||||
struct mp_decoder_list *new = mp_select_decoders(list, codec, selection);
|
||||
talloc_free(list);
|
||||
return new;
|
||||
@@ -119,92 +124,103 @@ static const struct ad_functions *find_driver(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
|
||||
int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders)
|
||||
{
|
||||
assert(!d_audio->ad_driver);
|
||||
audio_reset_decoding(d_audio);
|
||||
assert(!sh_audio->initialized);
|
||||
|
||||
struct mp_decoder_entry *decoder = NULL;
|
||||
struct mp_decoder_list *list =
|
||||
audio_select_decoders(d_audio->header->codec, audio_decoders);
|
||||
mp_select_audio_decoders(sh_audio->gsh->codec, audio_decoders);
|
||||
|
||||
mp_print_decoders(d_audio->log, MSGL_V, "Codec list:", list);
|
||||
mp_print_decoders(MSGT_DECAUDIO, MSGL_V, "Codec list:", list);
|
||||
|
||||
for (int n = 0; n < list->num_entries; n++) {
|
||||
struct mp_decoder_entry *sel = &list->entries[n];
|
||||
const struct ad_functions *driver = find_driver(sel->family);
|
||||
if (!driver)
|
||||
continue;
|
||||
MP_VERBOSE(d_audio, "Opening audio decoder %s:%s\n",
|
||||
sel->family, sel->decoder);
|
||||
d_audio->ad_driver = driver;
|
||||
if (init_audio_codec(d_audio, sel->decoder)) {
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder %s:%s\n",
|
||||
sel->family, sel->decoder);
|
||||
sh_audio->ad_driver = driver;
|
||||
if (init_audio_codec(sh_audio, sel->decoder)) {
|
||||
decoder = sel;
|
||||
break;
|
||||
}
|
||||
MP_WARN(d_audio, "Audio decoder init failed for "
|
||||
sh_audio->ad_driver = NULL;
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for "
|
||||
"%s:%s\n", sel->family, sel->decoder);
|
||||
}
|
||||
|
||||
if (d_audio->ad_driver) {
|
||||
d_audio->decoder_desc =
|
||||
talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
|
||||
if (sh_audio->initialized) {
|
||||
sh_audio->gsh->decoder_desc =
|
||||
talloc_asprintf(NULL, "%s [%s:%s]", decoder->desc, decoder->family,
|
||||
decoder->decoder);
|
||||
MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s\n",
|
||||
sh_audio->gsh->decoder_desc);
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V,
|
||||
"AUDIO: %d Hz, %d ch, %s\n",
|
||||
sh_audio->samplerate, sh_audio->channels.num,
|
||||
af_fmt2str_short(sh_audio->sample_format));
|
||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
|
||||
"ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
|
||||
sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->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>");
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_ERR,
|
||||
"Failed to initialize an audio decoder for codec '%s'.\n",
|
||||
sh_audio->gsh->codec ? sh_audio->gsh->codec : "<unknown>");
|
||||
}
|
||||
|
||||
talloc_free(list);
|
||||
return !!d_audio->ad_driver;
|
||||
return sh_audio->initialized;
|
||||
}
|
||||
|
||||
void audio_uninit(struct dec_audio *d_audio)
|
||||
void uninit_audio(sh_audio_t *sh_audio)
|
||||
{
|
||||
if (!d_audio)
|
||||
return;
|
||||
if (d_audio->afilter) {
|
||||
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
|
||||
af_destroy(d_audio->afilter);
|
||||
d_audio->afilter = NULL;
|
||||
if (sh_audio->afilter) {
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "Uninit audio filters...\n");
|
||||
af_destroy(sh_audio->afilter);
|
||||
sh_audio->afilter = NULL;
|
||||
}
|
||||
uninit_decoder(d_audio);
|
||||
talloc_free(d_audio->decode_buffer);
|
||||
talloc_free(d_audio);
|
||||
if (sh_audio->initialized) {
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Uninit audio.\n");
|
||||
sh_audio->ad_driver->uninit(sh_audio);
|
||||
sh_audio->initialized = 0;
|
||||
}
|
||||
talloc_free(sh_audio->gsh->decoder_desc);
|
||||
sh_audio->gsh->decoder_desc = NULL;
|
||||
av_freep(&sh_audio->a_buffer);
|
||||
}
|
||||
|
||||
|
||||
int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
|
||||
int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
|
||||
int *out_samplerate, struct mp_chmap *out_channels,
|
||||
int *out_format)
|
||||
{
|
||||
if (!d_audio->afilter)
|
||||
d_audio->afilter = af_new(d_audio->global);
|
||||
struct af_stream *afs = d_audio->afilter;
|
||||
if (!sh_audio->afilter)
|
||||
sh_audio->afilter = af_new(sh_audio->opts);
|
||||
struct af_stream *afs = sh_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;
|
||||
mp_audio_set_channels(&afs->input, &sh_audio->channels);
|
||||
mp_audio_set_format(&afs->input, sh_audio->sample_format);
|
||||
|
||||
// output format: same as ao driver's input format (if missing, fallback to input)
|
||||
afs->output.rate = *out_samplerate;
|
||||
mp_audio_set_channels(&afs->output, out_channels);
|
||||
mp_audio_set_format(&afs->output, *out_format);
|
||||
|
||||
afs->replaygain_data = d_audio->replaygain_data;
|
||||
|
||||
char *s_from = mp_audio_config_to_str(&afs->input);
|
||||
char *s_to = mp_audio_config_to_str(&afs->output);
|
||||
MP_VERBOSE(d_audio, "Building audio filter chain for %s -> %s...\n", s_from, s_to);
|
||||
mp_tmsg(MSGT_DECAUDIO, MSGL_V,
|
||||
"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;
|
||||
sh_audio->afilter = NULL;
|
||||
return 0; // failed :(
|
||||
}
|
||||
|
||||
@@ -215,149 +231,137 @@ int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
static void set_min_out_buffer_size(struct bstr *outbuf, int len)
|
||||
{
|
||||
while (!mp_audio_config_valid(&da->decoded)) {
|
||||
if (da->decoded.samples > 0)
|
||||
return AD_ERR; // invalid format, rather than uninitialized
|
||||
int ret = da->ad_driver->decode_packet(da);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
size_t oldlen = talloc_get_size(outbuf->start);
|
||||
if (oldlen < len) {
|
||||
assert(outbuf->start); // talloc context should be already set
|
||||
mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size "
|
||||
"from %zd to %d\n", oldlen, len);
|
||||
outbuf->start = talloc_realloc_size(NULL, outbuf->start, len);
|
||||
}
|
||||
if (mp_audio_buffer_samples(da->decode_buffer) > 0) // avoid accidental flush
|
||||
return AD_OK;
|
||||
return reinit_audio_buffer(da) ? AD_OK : AD_ERR;
|
||||
}
|
||||
|
||||
// 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)
|
||||
static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len)
|
||||
{
|
||||
bool format_change = false;
|
||||
assert(len - 1 + sh->audio_out_minsize <= sh->a_buffer_size);
|
||||
|
||||
int error = 0;
|
||||
|
||||
assert(len > 0); // would break EOF logic below
|
||||
|
||||
while (mp_audio_buffer_samples(da->decode_buffer) < len) {
|
||||
// Check for a format change
|
||||
struct mp_audio config;
|
||||
mp_audio_buffer_get_format(da->decode_buffer, &config);
|
||||
format_change = !mp_audio_config_equals(&da->decoded, &config);
|
||||
if (format_change) {
|
||||
error = AD_EOF; // drain remaining data left in the current buffer
|
||||
// Decode more bytes if needed
|
||||
int old_samplerate = sh->samplerate;
|
||||
struct mp_chmap old_channels = sh->channels;
|
||||
int old_sample_format = sh->sample_format;
|
||||
while (sh->a_buffer_len < len) {
|
||||
unsigned char *buf = sh->a_buffer + sh->a_buffer_len;
|
||||
int minlen = len - sh->a_buffer_len;
|
||||
int maxlen = sh->a_buffer_size - sh->a_buffer_len;
|
||||
int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen);
|
||||
int format_change = sh->samplerate != old_samplerate
|
||||
|| !mp_chmap_equals(&sh->channels, &old_channels)
|
||||
|| sh->sample_format != old_sample_format;
|
||||
if (ret <= 0 || format_change) {
|
||||
error = format_change ? -2 : -1;
|
||||
// samples from format-changing call get discarded too
|
||||
len = sh->a_buffer_len;
|
||||
break;
|
||||
}
|
||||
if (da->decoded.samples > 0) {
|
||||
int copy = MPMIN(da->decoded.samples, len);
|
||||
struct mp_audio append = da->decoded;
|
||||
append.samples = copy;
|
||||
mp_audio_buffer_append(da->decode_buffer, &append);
|
||||
mp_audio_skip_samples(&da->decoded, copy);
|
||||
da->pts_offset += copy;
|
||||
continue;
|
||||
}
|
||||
error = da->ad_driver->decode_packet(da);
|
||||
if (error < 0)
|
||||
break;
|
||||
sh->a_buffer_len += ret;
|
||||
}
|
||||
|
||||
if (error == AD_WAIT)
|
||||
return error;
|
||||
|
||||
// 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 = error == AD_EOF && filter_data.samples == 0;
|
||||
struct mp_audio filter_input = {
|
||||
.audio = sh->a_buffer,
|
||||
.len = len,
|
||||
.rate = sh->samplerate,
|
||||
};
|
||||
mp_audio_set_format(&filter_input, sh->sample_format);
|
||||
mp_audio_set_channels(&filter_input, &sh->channels);
|
||||
|
||||
if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0)
|
||||
return AD_ERR;
|
||||
|
||||
mp_audio_buffer_append(outbuf, &filter_data);
|
||||
if (error == AD_EOF && filter_data.samples > 0)
|
||||
error = 0; // don't end playback yet
|
||||
struct mp_audio *filter_output = af_play(sh->afilter, &filter_input);
|
||||
if (!filter_output)
|
||||
return -1;
|
||||
set_min_out_buffer_size(outbuf, outbuf->len + filter_output->len);
|
||||
memcpy(outbuf->start + outbuf->len, filter_output->audio,
|
||||
filter_output->len);
|
||||
outbuf->len += filter_output->len;
|
||||
|
||||
// remove processed data from decoder buffer:
|
||||
mp_audio_buffer_skip(da->decode_buffer, len);
|
||||
|
||||
// if format was changed, and all data was drained, execute the format change
|
||||
if (format_change && eof) {
|
||||
error = AD_NEW_FMT;
|
||||
if (!reinit_audio_buffer(da))
|
||||
error = AD_ERR; // switch to invalid format
|
||||
}
|
||||
sh->a_buffer_len -= len;
|
||||
memmove(sh->a_buffer, sh->a_buffer + len, sh->a_buffer_len);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Try to get at least minsamples decoded+filtered samples in outbuf
|
||||
/* Try to get at least minlen decoded+filtered bytes in outbuf
|
||||
* (total length including possible existing data).
|
||||
* Return 0 on success, or negative AD_* error code.
|
||||
* In the former case outbuf has at least minsamples buffered on return.
|
||||
* In case of EOF/error it might or might not be. */
|
||||
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
|
||||
int minsamples)
|
||||
* Return 0 on success, -1 on error/EOF (not distinguished).
|
||||
* In the former case outbuf->len is always >= minlen on return.
|
||||
* In case of EOF/error it might or might not be.
|
||||
* Outbuf.start must be talloc-allocated, and will be reallocated
|
||||
* if needed to fit all filter output. */
|
||||
int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen)
|
||||
{
|
||||
if (!d_audio->afilter)
|
||||
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 bytes
|
||||
int unitsize = sh_audio->channels.num * sh_audio->samplesize * 16;
|
||||
|
||||
/* Filter output size will be about filter_multiplier times input size.
|
||||
* If some filter buffers audio in big blocks this might only hold
|
||||
* as average over time. */
|
||||
double filter_multiplier = af_calc_filter_multiplier(d_audio->afilter);
|
||||
double filter_multiplier = af_calc_filter_multiplier(sh_audio->afilter);
|
||||
|
||||
int prev_buffered = -1;
|
||||
int res = 0;
|
||||
MP_STATS(d_audio, "start audio");
|
||||
while (res >= 0 && minsamples >= 0) {
|
||||
int buffered = mp_audio_buffer_samples(outbuf);
|
||||
if (minsamples < buffered || buffered == prev_buffered)
|
||||
break;
|
||||
prev_buffered = buffered;
|
||||
/* If the decoder set audio_out_minsize then it can do the equivalent of
|
||||
* "while (output_len < target_len) output_len += audio_out_minsize;",
|
||||
* so we must guarantee there is at least audio_out_minsize-1 bytes
|
||||
* more space in the output buffer than the minimum length we try to
|
||||
* decode. */
|
||||
int max_decode_len = sh_audio->a_buffer_size - sh_audio->audio_out_minsize;
|
||||
if (!unitsize)
|
||||
return -1;
|
||||
max_decode_len -= max_decode_len % unitsize;
|
||||
|
||||
int decsamples = (minsamples - buffered) / filter_multiplier;
|
||||
// + some extra for possible filter buffering, and avoid 0
|
||||
decsamples += 512;
|
||||
|
||||
if (huge_filter_buffer) {
|
||||
while (minlen >= 0 && outbuf->len < minlen) {
|
||||
// + some extra for possible filter buffering
|
||||
int declen = (minlen - outbuf->len) / filter_multiplier + (unitsize << 5);
|
||||
if (huge_filter_buffer)
|
||||
/* Some filter must be doing significant buffering if the estimated
|
||||
* input length didn't produce enough output from filters.
|
||||
* Feed the filters 250 samples at a time until we have enough
|
||||
* output. Very small amounts could make filtering inefficient while
|
||||
* large amounts can make mpv demux the file unnecessarily far ahead
|
||||
* Feed the filters 2k bytes at a time until we have enough output.
|
||||
* Very small amounts could make filtering inefficient while large
|
||||
* amounts can make MPlayer demux the file unnecessarily far ahead
|
||||
* to get audio data and buffer video frames in memory while doing
|
||||
* so. However the performance impact of either is probably not too
|
||||
* significant as long as the value is not completely insane. */
|
||||
decsamples = 250;
|
||||
}
|
||||
|
||||
/* if this iteration does not fill buffer, we must have lots
|
||||
* of buffering in filters */
|
||||
huge_filter_buffer = 1;
|
||||
|
||||
res = filter_n_bytes(d_audio, outbuf, decsamples);
|
||||
declen = 2000;
|
||||
declen -= declen % unitsize;
|
||||
if (declen > max_decode_len)
|
||||
declen = max_decode_len;
|
||||
else
|
||||
/* if this iteration does not fill buffer, we must have lots
|
||||
* of buffering in filters */
|
||||
huge_filter_buffer = 1;
|
||||
int res = filter_n_bytes(sh_audio, outbuf, declen);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
MP_STATS(d_audio, "end audio");
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_reset_decoding(struct dec_audio *d_audio)
|
||||
void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte)
|
||||
{
|
||||
if (d_audio->ad_driver)
|
||||
d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
|
||||
if (d_audio->afilter)
|
||||
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
|
||||
d_audio->pts = MP_NOPTS_VALUE;
|
||||
d_audio->pts_offset = 0;
|
||||
if (d_audio->decode_buffer)
|
||||
mp_audio_buffer_clear(d_audio->decode_buffer);
|
||||
set_min_out_buffer_size(outbuf, outbuf->len + count);
|
||||
memmove(outbuf->start + count, outbuf->start, outbuf->len);
|
||||
memset(outbuf->start, byte, count);
|
||||
outbuf->len += count;
|
||||
}
|
||||
|
||||
|
||||
void resync_audio_stream(sh_audio_t *sh_audio)
|
||||
{
|
||||
sh_audio->pts = MP_NOPTS_VALUE;
|
||||
if (!sh_audio->initialized)
|
||||
return;
|
||||
sh_audio->ad_driver->control(sh_audio, ADCTRL_RESYNC_STREAM, NULL);
|
||||
}
|
||||
@@ -20,52 +20,20 @@
|
||||
#define MPLAYER_DEC_AUDIO_H
|
||||
|
||||
#include "audio/chmap.h"
|
||||
#include "audio/audio.h"
|
||||
#include "demux/demux.h"
|
||||
#include "demux/stheader.h"
|
||||
|
||||
struct mp_audio_buffer;
|
||||
struct bstr;
|
||||
struct mp_decoder_list;
|
||||
|
||||
struct dec_audio {
|
||||
struct mp_log *log;
|
||||
struct MPOpts *opts;
|
||||
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;
|
||||
struct replaygain_data *replaygain_data;
|
||||
int init_retries;
|
||||
// set by decoder
|
||||
struct mp_audio decoded; // decoded audio set by last decode_packet() call
|
||||
int bitrate; // input bitrate, can change with VBR sources
|
||||
// last known pts value in output from decoder
|
||||
double pts;
|
||||
// number of samples output by decoder after last known pts
|
||||
int pts_offset;
|
||||
// For free use by the ad_driver
|
||||
void *priv;
|
||||
};
|
||||
struct mp_decoder_list *mp_audio_decoder_list(void);
|
||||
int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders);
|
||||
int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen);
|
||||
void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte);
|
||||
void resync_audio_stream(sh_audio_t *sh_audio);
|
||||
void skip_audio_frame(sh_audio_t *sh_audio);
|
||||
void uninit_audio(sh_audio_t *sh_audio);
|
||||
|
||||
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 init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
|
||||
int *out_samplerate, struct mp_chmap *out_channels,
|
||||
int *out_format);
|
||||
|
||||
|
||||
+178
-211
@@ -22,53 +22,48 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/global.h"
|
||||
|
||||
#include "options/m_option.h"
|
||||
#include "options/m_config.h"
|
||||
#include "mpvcore/m_option.h"
|
||||
#include "mpvcore/m_config.h"
|
||||
|
||||
#include "af.h"
|
||||
|
||||
// Static list of filters
|
||||
extern const struct af_info af_info_dummy;
|
||||
extern const struct af_info af_info_delay;
|
||||
extern const struct af_info af_info_channels;
|
||||
extern const struct af_info af_info_format;
|
||||
extern const struct af_info af_info_force;
|
||||
extern const struct af_info af_info_volume;
|
||||
extern const struct af_info af_info_equalizer;
|
||||
extern const struct af_info af_info_pan;
|
||||
extern const struct af_info af_info_surround;
|
||||
extern const struct af_info af_info_sub;
|
||||
extern const struct af_info af_info_export;
|
||||
extern const struct af_info af_info_drc;
|
||||
extern const struct af_info af_info_extrastereo;
|
||||
extern const struct af_info af_info_lavcac3enc;
|
||||
extern const struct af_info af_info_lavrresample;
|
||||
extern const struct af_info af_info_sweep;
|
||||
extern const struct af_info af_info_hrtf;
|
||||
extern const struct af_info af_info_ladspa;
|
||||
extern const struct af_info af_info_center;
|
||||
extern const struct af_info af_info_sinesuppress;
|
||||
extern const struct af_info af_info_karaoke;
|
||||
extern const struct af_info af_info_scaletempo;
|
||||
extern const struct af_info af_info_bs2b;
|
||||
extern const struct af_info af_info_lavfi;
|
||||
extern const struct af_info af_info_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;
|
||||
|
||||
static const struct af_info *const filter_list[] = {
|
||||
static struct af_info* filter_list[] = {
|
||||
&af_info_dummy,
|
||||
&af_info_delay,
|
||||
&af_info_channels,
|
||||
&af_info_format,
|
||||
&af_info_force,
|
||||
&af_info_volume,
|
||||
&af_info_equalizer,
|
||||
&af_info_pan,
|
||||
&af_info_surround,
|
||||
&af_info_sub,
|
||||
#if HAVE_SYS_MMAN_H
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
&af_info_export,
|
||||
#endif
|
||||
&af_info_drc,
|
||||
@@ -77,22 +72,21 @@ static const struct af_info *const filter_list[] = {
|
||||
&af_info_lavrresample,
|
||||
&af_info_sweep,
|
||||
&af_info_hrtf,
|
||||
#if HAVE_LADSPA
|
||||
#ifdef CONFIG_LADSPA
|
||||
&af_info_ladspa,
|
||||
#endif
|
||||
&af_info_center,
|
||||
&af_info_sinesuppress,
|
||||
&af_info_karaoke,
|
||||
&af_info_scaletempo,
|
||||
#if HAVE_LIBBS2B
|
||||
#ifdef CONFIG_LIBBS2B
|
||||
&af_info_bs2b,
|
||||
#endif
|
||||
#if HAVE_LIBAVFILTER
|
||||
#ifdef CONFIG_AF_LAVFI
|
||||
&af_info_lavfi,
|
||||
#endif
|
||||
// Must come last, because they're fallback format conversion filter
|
||||
&af_info_convert24,
|
||||
&af_info_convertsignendian,
|
||||
// Must come last, because it's the fallback format conversion filter
|
||||
&af_info_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -115,10 +109,7 @@ static bool get_desc(struct m_obj_desc *dst, int index)
|
||||
const struct m_obj_list af_obj_list = {
|
||||
.get_desc = get_desc,
|
||||
.description = "audio filters",
|
||||
.aliases = {
|
||||
{"force", "format"},
|
||||
{0}
|
||||
},
|
||||
.legacy_hacks = true, // many filters have custom option parsing
|
||||
};
|
||||
|
||||
static bool af_config_equals(struct mp_audio *a, struct mp_audio *b)
|
||||
@@ -142,7 +133,7 @@ static int input_control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT:
|
||||
assert(arg == &((struct af_stream *)af->priv)->input);
|
||||
assert(arg == &((struct af_stream *)af->setup)->input);
|
||||
return AF_OK;
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
@@ -150,7 +141,7 @@ static int input_control(struct af_instance* af, int cmd, void* arg)
|
||||
|
||||
static int output_control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
struct af_stream *s = af->priv;
|
||||
struct af_stream *s = af->setup;
|
||||
struct mp_audio *output = &s->output;
|
||||
struct mp_audio *filter_output = &s->filter_output;
|
||||
|
||||
@@ -168,9 +159,9 @@ static int output_control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int dummy_filter(struct af_instance* af, struct mp_audio* data, int f)
|
||||
static struct mp_audio *dummy_play(struct af_instance* af, struct mp_audio* data)
|
||||
{
|
||||
return 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Function for creating a new filter of type name.The name may
|
||||
@@ -180,7 +171,8 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
|
||||
{
|
||||
struct m_obj_desc desc;
|
||||
if (!m_obj_list_find(&desc, &af_obj_list, bstr0(name))) {
|
||||
MP_ERR(s, "Couldn't find audio filter '%s'.\n", name);
|
||||
mp_tmsg(MSGT_VFILTER, MSGL_ERR,
|
||||
"Couldn't find audio filter '%s'.\n", name);
|
||||
return NULL;
|
||||
}
|
||||
const struct af_info *info = desc.p;
|
||||
@@ -189,38 +181,40 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
|
||||
if (info->flags & AF_FLAGS_NOT_REENTRANT) {
|
||||
for (struct af_instance *cur = s->first; cur; cur = cur->next) {
|
||||
if (cur->info == info) {
|
||||
MP_ERR(s, "There can only be one "
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] There can only be one "
|
||||
"instance of the filter '%s' in each stream\n", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP_VERBOSE(s, "Adding filter %s \n", name);
|
||||
mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Adding filter %s \n", name);
|
||||
|
||||
struct af_instance *af = talloc_zero(NULL, struct af_instance);
|
||||
*af = (struct af_instance) {
|
||||
.info = info,
|
||||
.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)
|
||||
struct m_config *config = m_config_from_obj_desc(af, &desc);
|
||||
if (m_config_initialize_obj(config, &desc, &af->priv, &args) < 0)
|
||||
goto error;
|
||||
if (m_config_set_obj_params(config, args) < 0)
|
||||
goto error;
|
||||
af->priv = config->optstruct;
|
||||
|
||||
// Initialize the new filter
|
||||
if (af->info->open(af) != AF_OK)
|
||||
goto error;
|
||||
if (args && af->control) {
|
||||
// Single option string for old filters
|
||||
char *opts = (char *)args; // m_config_initialize_obj did this
|
||||
assert(!af->priv);
|
||||
if (af->control(af, AF_CONTROL_COMMAND_LINE, opts) <= AF_ERROR)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return af;
|
||||
|
||||
error:
|
||||
MP_ERR(s, "Couldn't create or open audio filter '%s'\n", name);
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR,
|
||||
"[libaf] Couldn't create or open audio filter '%s'\n", name);
|
||||
talloc_free(af);
|
||||
return NULL;
|
||||
}
|
||||
@@ -281,14 +275,17 @@ static void af_remove(struct af_stream *s, struct af_instance *af)
|
||||
return;
|
||||
|
||||
// Print friendly message
|
||||
MP_VERBOSE(s, "Removing filter %s \n", af->info->name);
|
||||
mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Removing filter %s \n",
|
||||
af->info->name);
|
||||
|
||||
// Notify filter before changing anything
|
||||
af->control(af, AF_CONTROL_PRE_DESTROY, 0);
|
||||
|
||||
// Detach pointers
|
||||
af->prev->next = af->next;
|
||||
af->next->prev = af->prev;
|
||||
|
||||
if (af->uninit)
|
||||
af->uninit(af);
|
||||
af->uninit(af);
|
||||
talloc_free(af);
|
||||
}
|
||||
|
||||
@@ -306,26 +303,26 @@ repeat:
|
||||
static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
|
||||
int msg_level)
|
||||
{
|
||||
MP_MSG(s, msg_level, "Audio filter chain:\n");
|
||||
mp_msg(MSGT_AFILTER, msg_level, "Audio filter chain:\n");
|
||||
|
||||
struct af_instance *af = s->first;
|
||||
while (af) {
|
||||
char b[128] = {0};
|
||||
mp_snprintf_cat(b, sizeof(b), " [%s] ", af->info->name);
|
||||
mp_msg(MSGT_AFILTER, msg_level, " [%s] ", af->info->name);
|
||||
if (af->data) {
|
||||
char *info = mp_audio_config_to_str(af->data);
|
||||
mp_snprintf_cat(b, sizeof(b), "%s", info);
|
||||
mp_msg(MSGT_AFILTER, 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(MSGT_AFILTER, msg_level, " <-");
|
||||
mp_msg(MSGT_AFILTER, msg_level, "\n");
|
||||
|
||||
af = af->next;
|
||||
}
|
||||
|
||||
mp_msg(MSGT_AFILTER, msg_level, " [ao] ");
|
||||
char *info = mp_audio_config_to_str(&s->output);
|
||||
MP_MSG(s, msg_level, " [ao] %s\n", info);
|
||||
mp_msg(MSGT_AFILTER, msg_level, "%s\n", info);
|
||||
talloc_free(info);
|
||||
}
|
||||
|
||||
@@ -337,76 +334,14 @@ static int af_count_filters(struct af_stream *s)
|
||||
return count;
|
||||
}
|
||||
|
||||
// Finds the first conversion filter on the way from srcfmt to dstfmt.
|
||||
// Conversions form a DAG: each node is a format/filter pair, and possible
|
||||
// conversions are edges. We search the DAG for the shortest path.
|
||||
// Some cases visit the same filter multiple times, but with different formats
|
||||
// (like u24le->s8), so one node per format or filter separate is not enough.
|
||||
// Returns the filter and dest. format for the first conversion step.
|
||||
// (So we know what conversion filter with what format to insert next.)
|
||||
static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
|
||||
static char *af_find_conversion_filter(int srcfmt, int dstfmt)
|
||||
{
|
||||
#define MAX_NODES (64 * 32)
|
||||
int num_fmt = 0, num_filt = 0;
|
||||
for (int n = 0; filter_list[n]; n++)
|
||||
num_filt = n + 1;
|
||||
for (int n = 0; af_fmtstr_table[n].format; n++)
|
||||
num_fmt = n + 1;
|
||||
|
||||
int num_nodes = num_fmt * num_filt;
|
||||
assert(num_nodes < MAX_NODES);
|
||||
|
||||
bool visited[MAX_NODES] = {0};
|
||||
unsigned char distance[MAX_NODES];
|
||||
short previous[MAX_NODES] = {0};
|
||||
for (int n = 0; n < num_nodes; n++) {
|
||||
distance[n] = 255;
|
||||
if (af_fmtstr_table[n % num_fmt].format == srcfmt)
|
||||
distance[n] = 0;
|
||||
for (int n = 0; filter_list[n]; n++) {
|
||||
struct af_info *af = filter_list[n];
|
||||
if (af->test_conversion && af->test_conversion(srcfmt, dstfmt))
|
||||
return (char *)af->name;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int next = -1;
|
||||
for (int n = 0; n < num_nodes; n++) {
|
||||
if (!visited[n] && (next < 0 || (distance[n] < distance[next])))
|
||||
next = n;
|
||||
}
|
||||
if (next < 0 || distance[next] == 255)
|
||||
return NULL;
|
||||
visited[next] = true;
|
||||
|
||||
int fmt = next % num_fmt;
|
||||
if (af_fmtstr_table[fmt].format == *dstfmt) {
|
||||
// Best match found
|
||||
for (int cur = next; cur >= 0; cur = previous[cur] - 1) {
|
||||
if (distance[cur] == 1) {
|
||||
*dstfmt = af_fmtstr_table[cur % num_fmt].format;
|
||||
return (char *)filter_list[cur / num_fmt]->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int n = 0; filter_list[n]; n++) {
|
||||
const struct af_info *af = filter_list[n];
|
||||
if (!af->test_conversion)
|
||||
continue;
|
||||
for (int i = 0; af_fmtstr_table[i].format; i++) {
|
||||
if (i != fmt && af->test_conversion(af_fmtstr_table[fmt].format,
|
||||
af_fmtstr_table[i].format))
|
||||
{
|
||||
int other = n * num_fmt + i;
|
||||
int ndist = distance[next] + 1;
|
||||
if (ndist < distance[other]) {
|
||||
distance[other] = ndist;
|
||||
previous[other] = next + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
#undef MAX_NODES
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool af_is_conversion_filter(struct af_instance *af)
|
||||
@@ -417,7 +352,7 @@ static bool af_is_conversion_filter(struct af_instance *af)
|
||||
// in is what af can take as input - insert a conversion filter if the actual
|
||||
// input format doesn't match what af expects.
|
||||
// Returns:
|
||||
// AF_OK: must call af_reinit() or equivalent, format matches (or is closer)
|
||||
// AF_OK: must call af_reinit() or equivalent, format matches
|
||||
// AF_FALSE: nothing was changed, format matches
|
||||
// else: error
|
||||
static int af_fix_format_conversion(struct af_stream *s,
|
||||
@@ -430,21 +365,18 @@ static int af_fix_format_conversion(struct af_stream *s,
|
||||
struct mp_audio actual = *prev->data;
|
||||
if (actual.format == in.format)
|
||||
return AF_FALSE;
|
||||
int dstfmt = in.format;
|
||||
char *filter = af_find_conversion_filter(actual.format, &dstfmt);
|
||||
if (prev->control(prev, AF_CONTROL_FORMAT_FMT, &in.format) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
char *filter = af_find_conversion_filter(actual.format, in.format);
|
||||
if (!filter)
|
||||
return AF_ERROR;
|
||||
if (strcmp(filter, prev->info->name) == 0) {
|
||||
if (prev->control(prev, AF_CONTROL_SET_FORMAT, &dstfmt) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
struct af_instance *new = af_prepend(s, af, filter, NULL);
|
||||
if (new == NULL)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_FORMAT, &dstfmt)))
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_FORMAT_FMT, &in.format)))
|
||||
return rv;
|
||||
*p_af = new;
|
||||
return AF_OK;
|
||||
@@ -460,7 +392,7 @@ static int af_fix_channels(struct af_stream *s, struct af_instance **p_af,
|
||||
struct mp_audio actual = *prev->data;
|
||||
if (mp_chmap_equals(&actual.channels, &in.channels))
|
||||
return AF_FALSE;
|
||||
if (prev->control(prev, AF_CONTROL_SET_CHANNELS, &in.channels) == AF_OK) {
|
||||
if (prev->control(prev, AF_CONTROL_CHANNELS, &in.channels) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
@@ -469,7 +401,7 @@ static int af_fix_channels(struct af_stream *s, struct af_instance **p_af,
|
||||
if (new == NULL)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_CHANNELS, &in.channels)))
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_CHANNELS, &in.channels)))
|
||||
return rv;
|
||||
*p_af = new;
|
||||
return AF_OK;
|
||||
@@ -484,7 +416,7 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
|
||||
struct mp_audio actual = *prev->data;
|
||||
if (actual.rate == in.rate)
|
||||
return AF_FALSE;
|
||||
if (prev->control(prev, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate) == AF_OK) {
|
||||
if (prev->control(prev, AF_CONTROL_RESAMPLE_RATE, &in.rate) == AF_OK) {
|
||||
*p_af = prev;
|
||||
return AF_OK;
|
||||
}
|
||||
@@ -493,7 +425,7 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
|
||||
if (new == NULL)
|
||||
return AF_ERROR;
|
||||
new->auto_inserted = true;
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate)))
|
||||
if (AF_OK != (rv = new->control(new, AF_CONTROL_RESAMPLE_RATE, &in.rate)))
|
||||
return rv;
|
||||
*p_af = new;
|
||||
return AF_OK;
|
||||
@@ -505,14 +437,14 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
|
||||
// state (for example, format filters that were tentatively inserted stay
|
||||
// inserted).
|
||||
// In that case, you should always rebuild the filter chain, or abort.
|
||||
// Also, note that for complete reinit, fixup_output_format() may have to be
|
||||
// called after this function.
|
||||
static int af_reinit(struct af_stream *s)
|
||||
{
|
||||
remove_auto_inserted_filters(s);
|
||||
// Start with the second filter, as the first filter is the special input
|
||||
// filter which needs no initialization.
|
||||
struct af_instance *af = s->first->next;
|
||||
// Up to 7 retries per filter (channel, rate, 5x format conversions)
|
||||
int max_retry = af_count_filters(s) * 7;
|
||||
int max_retry = af_count_filters(s) * 4; // up to 4 retries per filter
|
||||
int retry = 0;
|
||||
while (af) {
|
||||
if (retry >= max_retry)
|
||||
@@ -521,11 +453,10 @@ static int af_reinit(struct af_stream *s)
|
||||
// Check if this is the first filter
|
||||
struct mp_audio in = *af->prev->data;
|
||||
// Reset just in case...
|
||||
mp_audio_set_null_data(&in);
|
||||
in.audio = NULL;
|
||||
in.len = 0;
|
||||
|
||||
int rv = af->control(af, AF_CONTROL_REINIT, &in);
|
||||
if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data))
|
||||
rv = AF_FALSE; // conversion filter needed
|
||||
switch (rv) {
|
||||
case AF_OK:
|
||||
af = af->next;
|
||||
@@ -555,8 +486,8 @@ static int af_reinit(struct af_stream *s)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MP_ERR(s, "Reinitialization did not work, "
|
||||
"audio filter '%s' returned error code %i\n",
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Reinitialization did not "
|
||||
"work, audio filter '%s' returned error code %i\n",
|
||||
af->info->name, rv);
|
||||
af_print_filter_chain(s, af, MSGL_ERR);
|
||||
return AF_ERROR;
|
||||
@@ -565,15 +496,11 @@ static int af_reinit(struct af_stream *s)
|
||||
|
||||
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);
|
||||
return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
|
||||
return AF_OK;
|
||||
|
||||
negotiate_error:
|
||||
MP_ERR(s, "Unable to convert audio input format to output format.\n");
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to correct audio format. "
|
||||
"This error should never occur, please send a bug report.\n");
|
||||
af_print_filter_chain(s, af, MSGL_ERR);
|
||||
return AF_ERROR;
|
||||
}
|
||||
@@ -585,33 +512,32 @@ void af_uninit(struct af_stream *s)
|
||||
af_remove(s, s->first->next);
|
||||
}
|
||||
|
||||
struct af_stream *af_new(struct mpv_global *global)
|
||||
struct af_stream *af_new(struct MPOpts *opts)
|
||||
{
|
||||
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,
|
||||
.control = input_control,
|
||||
.filter = dummy_filter,
|
||||
.priv = s,
|
||||
.play = dummy_play,
|
||||
.setup = s,
|
||||
.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,
|
||||
.control = output_control,
|
||||
.filter = dummy_filter,
|
||||
.priv = s,
|
||||
.play = dummy_play,
|
||||
.setup = s,
|
||||
.data = &s->filter_output,
|
||||
.mul = 1.0,
|
||||
};
|
||||
s->first->next = s->last;
|
||||
s->last->prev = s->first;
|
||||
s->opts = global->opts;
|
||||
s->log = mp_log_new(s, global->log, "!af");
|
||||
s->opts = opts;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -621,10 +547,25 @@ void af_destroy(struct af_stream *s)
|
||||
talloc_free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* \return AF_ERROR on error, AF_OK if successful.
|
||||
*/
|
||||
static int fixup_output_format(struct af_stream *s)
|
||||
{
|
||||
if (AF_OK != af_reinit(s))
|
||||
return AF_ERROR;
|
||||
|
||||
af_copy_unset_fields(&s->output, &s->filter_output);
|
||||
return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
|
||||
}
|
||||
|
||||
/* Initialize the stream "s". This function creates a new filter list
|
||||
if necessary according to the values set in input and output. Input
|
||||
and output should contain the format of the current movie and the
|
||||
format of the preferred output respectively. The function is
|
||||
formate of the preferred output respectively. The function is
|
||||
reentrant i.e. if called with an already initialized stream the
|
||||
stream will be reinitialized.
|
||||
If one of the prefered output parameters is 0 the one that needs
|
||||
@@ -637,24 +578,31 @@ int af_init(struct af_stream *s)
|
||||
return -1;
|
||||
|
||||
// Precaution in case caller is misbehaving
|
||||
mp_audio_set_null_data(&s->input);
|
||||
mp_audio_set_null_data(&s->output);
|
||||
s->input.audio = s->output.audio = NULL;
|
||||
s->input.len = s->output.len = 0;
|
||||
|
||||
// Check if this is the first call
|
||||
if (s->first->next == s->last) {
|
||||
// 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++) {
|
||||
if (!af_prepend(s, s->last, list[i].name, list[i].attribs)) {
|
||||
af_uninit(s);
|
||||
if (!af_prepend(s, s->last, list[i].name, list[i].attribs))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (af_reinit(s) != AF_OK) {
|
||||
remove_auto_inserted_filters(s);
|
||||
|
||||
// Init filters
|
||||
if (AF_OK != af_reinit(s))
|
||||
return -1;
|
||||
|
||||
if (AF_OK != fixup_output_format(s)) {
|
||||
// Something is stuffed audio out will not work
|
||||
MP_ERR(s, "Could not create audio filter chain.\n");
|
||||
mp_msg(
|
||||
MSGT_AFILTER, MSGL_ERR,
|
||||
"[libaf] Unable to setup filter system can not"
|
||||
" meet sound-card demands, please send a bug report. \n");
|
||||
af_uninit(s);
|
||||
return -1;
|
||||
}
|
||||
@@ -680,7 +628,7 @@ struct af_instance *af_add(struct af_stream *s, char *name, char **args)
|
||||
return NULL;
|
||||
|
||||
// Reinitalize the filter list
|
||||
if (af_reinit(s) != AF_OK) {
|
||||
if (af_reinit(s) != AF_OK || fixup_output_format(s) != AF_OK) {
|
||||
af_uninit(s);
|
||||
af_init(s);
|
||||
return NULL;
|
||||
@@ -688,31 +636,36 @@ struct af_instance *af_add(struct af_stream *s, char *name, char **args)
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Filter data chunk through the filters in the list.
|
||||
* On success, *data is set to the filtered data/format.
|
||||
* Warning: input audio data will be overwritten.
|
||||
*/
|
||||
int af_filter(struct af_stream *s, struct mp_audio *data, int flags)
|
||||
// Filter data chunk through the filters in the list
|
||||
struct mp_audio *af_play(struct af_stream *s, struct mp_audio *data)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
assert(mp_audio_config_equals(af->data, data));
|
||||
// Iterate through all filters
|
||||
while (af) {
|
||||
int r = af->filter(af, data, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(mp_audio_config_equals(af->data, data));
|
||||
do {
|
||||
if (data->len <= 0)
|
||||
break;
|
||||
data = af->play(af, data);
|
||||
af = af->next;
|
||||
}
|
||||
return 0;
|
||||
} while (af && data);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Calculate average ratio of filter output samples to input samples.
|
||||
// e.g: num_output_samples = mul * num_input_samples
|
||||
/* Calculate the minimum output buffer size for given input data d
|
||||
* when using the RESIZE_LOCAL_BUFFER macro. The +t+1 part ensures the
|
||||
* value is >= len*mul rounded upwards to whole samples even if the
|
||||
* double 'mul' is inexact. */
|
||||
int af_lencalc(double mul, struct mp_audio *d)
|
||||
{
|
||||
int t = d->bps * d->nch;
|
||||
return d->len * mul + t + 1;
|
||||
}
|
||||
|
||||
// Calculate average ratio of filter output size to input size
|
||||
double af_calc_filter_multiplier(struct af_stream *s)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
double mul = 1;
|
||||
// Iterate through all filters and calculate total multiplication factor
|
||||
do {
|
||||
mul *= af->mul;
|
||||
af = af->next;
|
||||
@@ -721,20 +674,41 @@ double af_calc_filter_multiplier(struct af_stream *s)
|
||||
return mul;
|
||||
}
|
||||
|
||||
/* Calculate the total delay [seconds of output] caused by the filters */
|
||||
/* Calculate the total delay [bytes output] caused by the filters */
|
||||
double af_calc_delay(struct af_stream *s)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
double delay = 0.0;
|
||||
register double delay = 0.0;
|
||||
// Iterate through all filters
|
||||
while (af) {
|
||||
delay += af->delay;
|
||||
delay *= af->mul;
|
||||
af = af->next;
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/* Send control to all filters, starting with the last until one accepts the
|
||||
* command with AF_OK. Return the accepting filter. */
|
||||
/* Helper function called by the macro with the same name this
|
||||
function should not be called directly */
|
||||
int af_resize_local_buffer(struct af_instance *af, struct mp_audio *data)
|
||||
{
|
||||
// Calculate new length
|
||||
register int len = af_lencalc(af->mul, data);
|
||||
mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, "
|
||||
"old len = %i, new len = %i\n", af->info->name, af->data->len, len);
|
||||
// If there is a buffer free it
|
||||
free(af->data->audio);
|
||||
// Create new buffer and check that it is OK
|
||||
af->data->audio = malloc(len);
|
||||
if (!af->data->audio) {
|
||||
mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
|
||||
return AF_ERROR;
|
||||
}
|
||||
af->data->len = len;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
// documentation in af.h
|
||||
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg)
|
||||
{
|
||||
int res = AF_UNKNOWN;
|
||||
@@ -747,10 +721,3 @@ struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Send control to all filters. Never stop, even if a filter returns AF_OK. */
|
||||
void af_control_all(struct af_stream *s, int cmd, void *arg)
|
||||
{
|
||||
for (struct af_instance *af = s->first; af; af = af->next)
|
||||
af->control(af, cmd, arg);
|
||||
}
|
||||
+193
-52
@@ -21,16 +21,17 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "options/options.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "mpvcore/options.h"
|
||||
#include "audio/format.h"
|
||||
#include "audio/chmap.h"
|
||||
#include "audio/audio.h"
|
||||
#include "common/msg.h"
|
||||
#include "control.h"
|
||||
#include "mpvcore/mp_msg.h"
|
||||
|
||||
struct af_instance;
|
||||
struct mpv_global;
|
||||
|
||||
// Number of channels
|
||||
#define AF_NCH MP_NUM_CHANNELS
|
||||
@@ -39,14 +40,13 @@ struct mpv_global;
|
||||
#define AF_FLAGS_REENTRANT 0x00000000
|
||||
#define AF_FLAGS_NOT_REENTRANT 0x00000001
|
||||
|
||||
// Flags for af->filter()
|
||||
#define AF_FILTER_FLAG_EOF 1
|
||||
|
||||
/* Audio filter information not specific for current instance, but for
|
||||
a specific filter */
|
||||
struct af_info {
|
||||
const char *info;
|
||||
const char *name;
|
||||
const char *author;
|
||||
const char *comment;
|
||||
const int flags;
|
||||
int (*open)(struct af_instance *vf);
|
||||
bool (*test_conversion)(int src_format, int dst_format);
|
||||
@@ -58,23 +58,18 @@ struct af_info {
|
||||
// Linked list of audio filters
|
||||
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
|
||||
* returns 0 on success, negative value on error
|
||||
*/
|
||||
int (*filter)(struct af_instance *af, struct mp_audio *data, int flags);
|
||||
struct mp_audio * (*play)(struct af_instance *af, struct mp_audio *data);
|
||||
void *setup; // old field for priv structs
|
||||
void *priv;
|
||||
struct mp_audio *data; // configuration and buffer for outgoing data stream
|
||||
struct mp_audio *data; // configuration for outgoing data stream
|
||||
struct af_instance *next;
|
||||
struct af_instance *prev;
|
||||
double delay; /* Delay caused by the filter, in seconds of audio consumed
|
||||
* without corresponding output */
|
||||
double delay; /* Delay caused by the filter, in units of bytes read without
|
||||
* corresponding output */
|
||||
double mul; /* length multiplier: how much does this instance change
|
||||
* the number of samples passed though. (Ratio of input
|
||||
* and output, e.g. mul=4 => 1 sample becomes 4 samples) .*/
|
||||
the length of the buffer. */
|
||||
bool auto_inserted; // inserted by af.c, such as conversion filters
|
||||
};
|
||||
|
||||
@@ -85,16 +80,18 @@ struct af_stream {
|
||||
struct af_instance *last;
|
||||
// The user sets the input format (what the decoder outputs), and sets some
|
||||
// or all fields in output to the output format the AO accepts.
|
||||
// See fixup_output_format().
|
||||
struct mp_audio input;
|
||||
struct mp_audio output;
|
||||
struct mp_audio filter_output;
|
||||
|
||||
struct mp_log *log;
|
||||
struct MPOpts *opts;
|
||||
struct replaygain_data *replaygain_data;
|
||||
};
|
||||
|
||||
// Return values
|
||||
/*********************************************
|
||||
// Return values
|
||||
*/
|
||||
|
||||
#define AF_DETACH 2
|
||||
#define AF_OK 1
|
||||
#define AF_TRUE 1
|
||||
@@ -103,46 +100,190 @@ struct af_stream {
|
||||
#define AF_ERROR -2
|
||||
#define AF_FATAL -3
|
||||
|
||||
// Parameters for af_control_*
|
||||
enum af_control {
|
||||
AF_CONTROL_REINIT = 1,
|
||||
AF_CONTROL_RESET,
|
||||
AF_CONTROL_SET_RESAMPLE_RATE,
|
||||
AF_CONTROL_SET_FORMAT,
|
||||
AF_CONTROL_SET_CHANNELS,
|
||||
AF_CONTROL_SET_VOLUME,
|
||||
AF_CONTROL_GET_VOLUME,
|
||||
AF_CONTROL_SET_PAN_LEVEL,
|
||||
AF_CONTROL_SET_PAN_NOUT,
|
||||
AF_CONTROL_SET_PAN_BALANCE,
|
||||
AF_CONTROL_GET_PAN_BALANCE,
|
||||
AF_CONTROL_SET_PLAYBACK_SPEED,
|
||||
};
|
||||
|
||||
// Argument for AF_CONTROL_SET_PAN_LEVEL
|
||||
typedef struct af_control_ext_s {
|
||||
void* arg; // Argument
|
||||
int ch; // Chanel number
|
||||
} af_control_ext_t;
|
||||
|
||||
struct af_stream *af_new(struct mpv_global *global);
|
||||
/*********************************************
|
||||
// Export functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup af_chain Audio filter chain functions
|
||||
* \{
|
||||
* \param s filter chain
|
||||
*/
|
||||
|
||||
struct af_stream *af_new(struct MPOpts *opts);
|
||||
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_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);
|
||||
|
||||
/**
|
||||
* \brief Initialize the stream "s".
|
||||
* \return 0 on success, -1 on failure
|
||||
*
|
||||
* This function creates a new filter list if necessary, according
|
||||
* to the values set in input and output. Input and output should contain
|
||||
* the format of the current movie and the format of the preferred output
|
||||
* respectively.
|
||||
* Filters to convert to the preferred output format are inserted
|
||||
* automatically, except when they are set to 0.
|
||||
* The function is reentrant i.e. if called with an already initialized
|
||||
* stream the stream will be reinitialized.
|
||||
*/
|
||||
int af_init(struct af_stream *s);
|
||||
|
||||
/**
|
||||
* \brief Uninit and remove all filters from audio filter chain
|
||||
*/
|
||||
void af_uninit(struct af_stream *s);
|
||||
|
||||
/**
|
||||
* \brief This function adds the filter "name" to the stream s.
|
||||
* \param name name of filter to add
|
||||
* \return pointer to the new filter, NULL if insert failed
|
||||
*
|
||||
* The filter will be inserted somewhere nice in the
|
||||
* list of filters (i.e. at the beginning unless the
|
||||
* first filter is the format filter (why??).
|
||||
*/
|
||||
struct af_instance *af_add(struct af_stream *s, char *name, char **args);
|
||||
|
||||
/**
|
||||
* \brief filter data chunk through the filters in the list
|
||||
* \param data data to play
|
||||
* \return resulting data
|
||||
* \ingroup af_chain
|
||||
*/
|
||||
struct mp_audio *af_play(struct af_stream *s, struct mp_audio *data);
|
||||
|
||||
/**
|
||||
* \brief send control to all filters, starting with the last until
|
||||
* one accepts the command with AF_OK.
|
||||
* \param cmd filter control command
|
||||
* \param arg argument for filter command
|
||||
* \return the accepting filter or NULL if none was found
|
||||
*/
|
||||
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
|
||||
|
||||
/**
|
||||
* \brief calculate average ratio of filter output lenth to input length
|
||||
* \return the ratio
|
||||
*/
|
||||
double af_calc_filter_multiplier(struct af_stream *s);
|
||||
|
||||
/**
|
||||
* \brief Calculate the total delay caused by the filters
|
||||
* \return delay in bytes of "missing" output
|
||||
*/
|
||||
double af_calc_delay(struct af_stream *s);
|
||||
|
||||
/** \} */ // end of af_chain group
|
||||
|
||||
// Helper functions and macros used inside the audio filters
|
||||
|
||||
/**
|
||||
* \defgroup af_filter Audio filter helper functions
|
||||
* \{
|
||||
*/
|
||||
|
||||
/* Helper function called by the macro with the same name only to be
|
||||
called from inside filters */
|
||||
int af_resize_local_buffer(struct af_instance *af, struct mp_audio *data);
|
||||
|
||||
/* Helper function used to calculate the exact buffer length needed
|
||||
when buffers are resized. The returned length is >= than what is
|
||||
needed */
|
||||
int af_lencalc(double mul, struct mp_audio *data);
|
||||
|
||||
/**
|
||||
* \brief convert dB to gain value
|
||||
* \param n number of values to convert
|
||||
* \param in [in] values in dB, <= -200 will become 0 gain
|
||||
* \param out [out] gain values
|
||||
* \param k input values are divided by this
|
||||
* \param mi minimum dB value, input will be clamped to this
|
||||
* \param ma maximum dB value, input will be clamped to this
|
||||
* \return AF_ERROR on error, AF_OK otherwise
|
||||
*/
|
||||
int af_from_dB(int n, float *in, float *out, float k, float mi, float ma);
|
||||
|
||||
/**
|
||||
* \brief convert gain value to dB
|
||||
* \param n number of values to convert
|
||||
* \param in [in] gain values, 0 wil become -200 dB
|
||||
* \param out [out] values in dB
|
||||
* \param k output values will be multiplied by this
|
||||
* \return AF_ERROR on error, AF_OK otherwise
|
||||
*/
|
||||
int af_to_dB(int n, float *in, float *out, float k);
|
||||
|
||||
/**
|
||||
* \brief convert milliseconds to sample time
|
||||
* \param n number of values to convert
|
||||
* \param in [in] values in milliseconds
|
||||
* \param out [out] sample time values
|
||||
* \param rate sample rate
|
||||
* \param mi minimum ms value, input will be clamped to this
|
||||
* \param ma maximum ms value, input will be clamped to this
|
||||
* \return AF_ERROR on error, AF_OK otherwise
|
||||
*/
|
||||
int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma);
|
||||
|
||||
/**
|
||||
* \brief convert sample time to milliseconds
|
||||
* \param n number of values to convert
|
||||
* \param in [in] sample time values
|
||||
* \param out [out] values in milliseconds
|
||||
* \param rate sample rate
|
||||
* \return AF_ERROR on error, AF_OK otherwise
|
||||
*/
|
||||
int af_to_ms(int n, int *in, float *out, int rate);
|
||||
|
||||
/**
|
||||
* \brief test if output format matches
|
||||
* \param af audio filter
|
||||
* \param out needed format, will be overwritten by available
|
||||
* format if they do not match
|
||||
* \return AF_FALSE if formats do not match, AF_OK if they match
|
||||
*
|
||||
* compares the format, bps, rate and nch values of af->data with out
|
||||
*/
|
||||
int af_test_output(struct af_instance *af, struct mp_audio *out);
|
||||
|
||||
int af_from_dB(int n, float *in, float *out, float k, float mi, float ma);
|
||||
int af_to_dB(int n, float *in, float *out, float k);
|
||||
int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma);
|
||||
int af_to_ms(int n, int *in, float *out, int rate);
|
||||
/**
|
||||
* \brief soft clipping function using sin()
|
||||
* \param a input value
|
||||
* \return clipped value
|
||||
*/
|
||||
float af_softclip(float a);
|
||||
|
||||
/** \} */ // end of af_filter group, but more functions of this group below
|
||||
|
||||
/** Memory reallocation macro: if a local buffer is used (i.e. if the
|
||||
filter doesn't operate on the incoming buffer this macro must be
|
||||
called to ensure the buffer is big enough.
|
||||
* \ingroup af_filter
|
||||
*/
|
||||
#define RESIZE_LOCAL_BUFFER(a, d) \
|
||||
((a->data->len < af_lencalc(a->mul, d)) ? af_resize_local_buffer(a, d) : AF_OK)
|
||||
|
||||
/* Some other useful macro definitions*/
|
||||
#ifndef min
|
||||
#define min(a, b)(((a) > (b)) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b)(((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef clamp
|
||||
#define clamp(a, min, max) (((a) > (max)) ? (max) : (((a) < (min)) ? (min) : (a)))
|
||||
#endif
|
||||
|
||||
#ifndef sign
|
||||
#define sign(a) (((a) > 0) ? (1) : (-1))
|
||||
#endif
|
||||
|
||||
#ifndef lrnd
|
||||
#define lrnd(a, b) ((b)((a) >= 0.0 ? (a) + 0.5 : (a) - 0.5))
|
||||
#endif
|
||||
|
||||
#endif /* MPLAYER_AF_H */
|
||||
+58
-48
@@ -27,7 +27,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "af.h"
|
||||
#include "options/m_option.h"
|
||||
#include "mpvcore/m_option.h"
|
||||
|
||||
/// Internal specific data of the filter
|
||||
struct af_bs2b {
|
||||
@@ -37,33 +37,33 @@ struct af_bs2b {
|
||||
t_bs2bdp filter; ///< instance of a library filter
|
||||
};
|
||||
|
||||
#define FILTER(name, type) \
|
||||
static int filter_##name(struct af_instance *af, struct mp_audio *data, int f) \
|
||||
#define PLAY(name, type) \
|
||||
static struct mp_audio *play_##name(struct af_instance *af, struct mp_audio *data) \
|
||||
{ \
|
||||
/* filter is called for all pairs of samples available in the buffer */ \
|
||||
bs2b_cross_feed_##name(((struct af_bs2b*)(af->priv))->filter, \
|
||||
(type*)(data->planes[0]), data->samples); \
|
||||
(type*)(data->audio), data->len/data->bps/2); \
|
||||
\
|
||||
return 0; \
|
||||
return data; \
|
||||
}
|
||||
|
||||
FILTER(f, float)
|
||||
FILTER(fbe, float)
|
||||
FILTER(fle, float)
|
||||
FILTER(s32be, int32_t)
|
||||
FILTER(u32be, uint32_t)
|
||||
FILTER(s32le, int32_t)
|
||||
FILTER(u32le, uint32_t)
|
||||
FILTER(s24be, bs2b_int24_t)
|
||||
FILTER(u24be, bs2b_uint24_t)
|
||||
FILTER(s24le, bs2b_int24_t)
|
||||
FILTER(u24le, bs2b_uint24_t)
|
||||
FILTER(s16be, int16_t)
|
||||
FILTER(u16be, uint16_t)
|
||||
FILTER(s16le, int16_t)
|
||||
FILTER(u16le, uint16_t)
|
||||
FILTER(s8, int8_t)
|
||||
FILTER(u8, uint8_t)
|
||||
PLAY(f, float)
|
||||
PLAY(fbe, float)
|
||||
PLAY(fle, float)
|
||||
PLAY(s32be, int32_t)
|
||||
PLAY(u32be, uint32_t)
|
||||
PLAY(s32le, int32_t)
|
||||
PLAY(u32le, uint32_t)
|
||||
PLAY(s24be, bs2b_int24_t)
|
||||
PLAY(u24be, bs2b_uint24_t)
|
||||
PLAY(s24le, bs2b_int24_t)
|
||||
PLAY(u24le, bs2b_uint24_t)
|
||||
PLAY(s16be, int16_t)
|
||||
PLAY(u16be, uint16_t)
|
||||
PLAY(s16le, int16_t)
|
||||
PLAY(u16le, uint16_t)
|
||||
PLAY(s8, int8_t)
|
||||
PLAY(u8, uint8_t)
|
||||
|
||||
|
||||
/// Initialization and runtime control
|
||||
@@ -74,6 +74,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
int format;
|
||||
char buf[256];
|
||||
// Sanity check
|
||||
if (!arg) return AF_ERROR;
|
||||
|
||||
@@ -86,69 +87,70 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
and assign corresponding handlers */
|
||||
switch (format) {
|
||||
case AF_FORMAT_FLOAT_BE:
|
||||
af->filter = filter_fbe;
|
||||
af->play = play_fbe;
|
||||
break;
|
||||
case AF_FORMAT_FLOAT_LE:
|
||||
af->filter = filter_fle;
|
||||
af->play = play_fle;
|
||||
break;
|
||||
case AF_FORMAT_S32_BE:
|
||||
af->filter = filter_s32be;
|
||||
af->play = play_s32be;
|
||||
break;
|
||||
case AF_FORMAT_U32_BE:
|
||||
af->filter = filter_u32be;
|
||||
af->play = play_u32be;
|
||||
break;
|
||||
case AF_FORMAT_S32_LE:
|
||||
af->filter = filter_s32le;
|
||||
af->play = play_s32le;
|
||||
break;
|
||||
case AF_FORMAT_U32_LE:
|
||||
af->filter = filter_u32le;
|
||||
af->play = play_u32le;
|
||||
break;
|
||||
case AF_FORMAT_S24_BE:
|
||||
af->filter = filter_s24be;
|
||||
af->play = play_s24be;
|
||||
break;
|
||||
case AF_FORMAT_U24_BE:
|
||||
af->filter = filter_u24be;
|
||||
af->play = play_u24be;
|
||||
break;
|
||||
case AF_FORMAT_S24_LE:
|
||||
af->filter = filter_s24le;
|
||||
af->play = play_s24le;
|
||||
break;
|
||||
case AF_FORMAT_U24_LE:
|
||||
af->filter = filter_u24le;
|
||||
af->play = play_u24le;
|
||||
break;
|
||||
case AF_FORMAT_S16_BE:
|
||||
af->filter = filter_s16be;
|
||||
af->play = play_s16be;
|
||||
break;
|
||||
case AF_FORMAT_U16_BE:
|
||||
af->filter = filter_u16be;
|
||||
af->play = play_u16be;
|
||||
break;
|
||||
case AF_FORMAT_S16_LE:
|
||||
af->filter = filter_s16le;
|
||||
af->play = play_s16le;
|
||||
break;
|
||||
case AF_FORMAT_U16_LE:
|
||||
af->filter = filter_u16le;
|
||||
af->play = play_u16le;
|
||||
break;
|
||||
case AF_FORMAT_S8:
|
||||
af->filter = filter_s8;
|
||||
af->play = play_s8;
|
||||
break;
|
||||
case AF_FORMAT_U8:
|
||||
af->filter = filter_u8;
|
||||
af->play = play_u8;
|
||||
break;
|
||||
default:
|
||||
af->filter = filter_f;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
af->play = play_f;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
|
||||
break;
|
||||
}
|
||||
|
||||
// bs2b have srate limits, try to resample if needed
|
||||
if (af->data->rate > BS2B_MAXSRATE || af->data->rate < BS2B_MINSRATE) {
|
||||
af->data->rate = BS2B_DEFAULT_SRATE;
|
||||
MP_WARN(af, "Requested sample rate %d Hz is out of bounds [%d..%d] Hz.\n"
|
||||
"Trying to resample to %d Hz.\n",
|
||||
mp_msg(MSGT_AFILTER, MSGL_WARN,
|
||||
"[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",
|
||||
af_fmt_to_str(af->data->format));
|
||||
mp_msg(MSGT_AFILTER, MSGL_V, "[bs2b] using format %s\n",
|
||||
af_fmt2str(af->data->format,buf,256));
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
@@ -160,6 +162,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
static void uninit(struct af_instance *af)
|
||||
{
|
||||
struct af_bs2b *s = af->priv;
|
||||
free(af->data);
|
||||
if (s->filter)
|
||||
bs2b_close(s->filter);
|
||||
}
|
||||
@@ -170,9 +173,13 @@ static int af_open(struct af_instance *af)
|
||||
struct af_bs2b *s = af->priv;
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->mul = 1;
|
||||
if (!(af->data = calloc(1, sizeof(struct mp_audio))))
|
||||
return AF_ERROR;
|
||||
|
||||
// NULL means failed initialization
|
||||
if (!(s->filter = bs2b_open())) {
|
||||
free(af->data);
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
@@ -189,10 +196,13 @@ 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 = {
|
||||
.info = "Bauer stereophonic-to-binaural audio filter",
|
||||
.name = "bs2b",
|
||||
.open = af_open,
|
||||
struct af_info af_info_bs2b = {
|
||||
"Bauer stereophonic-to-binaural audio filter",
|
||||
"bs2b",
|
||||
"Andrew Savchenko",
|
||||
"",
|
||||
AF_FLAGS_REENTRANT,
|
||||
af_open,
|
||||
.priv_size = sizeof(struct af_bs2b),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_INTRANGE("fcut", fcut, 0, BS2B_MINFCUT, BS2B_MAXFCUT),
|
||||
|
||||
+55
-26
@@ -29,19 +29,18 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_center_s
|
||||
{
|
||||
int ch; // Channel number which to insert the filtered data
|
||||
int ch; // Channel number which to insert the filtered data
|
||||
}af_center_t;
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_center_t* s = af->priv;
|
||||
af_center_t* s = af->setup;
|
||||
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:{
|
||||
@@ -49,24 +48,48 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
if(!arg) return AF_ERROR;
|
||||
|
||||
af->data->rate = ((struct mp_audio*)arg)->rate;
|
||||
mp_audio_set_channels_old(af->data, MPMAX(s->ch+1,((struct mp_audio*)arg)->nch));
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
mp_audio_set_channels_old(af->data, max(s->ch+1,((struct mp_audio*)arg)->nch));
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
case AF_CONTROL_COMMAND_LINE:{
|
||||
int ch=1;
|
||||
sscanf(arg,"%i", &ch);
|
||||
return control(af,AF_CONTROL_CENTER_CH | AF_CONTROL_SET, &ch);
|
||||
}
|
||||
case AF_CONTROL_CENTER_CH | AF_CONTROL_SET: // Requires reinit
|
||||
// Sanity check
|
||||
if((*(int*)arg >= AF_NCH) || (*(int*)arg < 0)){
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR, "[sub] Center channel number must be between "
|
||||
" 0 and %i current value is %i\n", AF_NCH-1, *(int*)arg);
|
||||
return AF_ERROR;
|
||||
}
|
||||
s->ch = *(int*)arg;
|
||||
return AF_OK;
|
||||
case AF_CONTROL_CENTER_CH | AF_CONTROL_GET:
|
||||
*(int*)arg = s->ch;
|
||||
return AF_OK;
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
// Deallocate memory
|
||||
static void uninit(struct af_instance* af)
|
||||
{
|
||||
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
|
||||
free(af->data);
|
||||
free(af->setup);
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_center_t* s = af->setup; // Setup for this instance
|
||||
float* a = c->audio; // Audio data
|
||||
int len = c->len/4; // Number of samples in current audio block
|
||||
int nch = c->nch; // Number of channels
|
||||
int ch = s->ch; // Channel in which to insert the center audio
|
||||
register int i;
|
||||
|
||||
// Run filter
|
||||
@@ -75,25 +98,31 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
a[i+ch] = (a[i]/2) + (a[i+1]/2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af_center_t* s;
|
||||
af->control=control;
|
||||
af->filter=filter;
|
||||
af->uninit=uninit;
|
||||
af->play=play;
|
||||
af->mul=1;
|
||||
af->data=calloc(1,sizeof(struct mp_audio));
|
||||
af->setup=s=calloc(1,sizeof(af_center_t));
|
||||
if(af->data == NULL || af->setup == NULL)
|
||||
return AF_ERROR;
|
||||
// Set default values
|
||||
s->ch = 1; // Channel nr 2
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_center_t
|
||||
const struct af_info af_info_center = {
|
||||
.info = "Audio filter for adding a center channel",
|
||||
.name = "center",
|
||||
.flags = AF_FLAGS_NOT_REENTRANT,
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_center_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_INTRANGE("channel", ch, 0, 0, AF_NCH - 1, OPTDEF_INT(1)),
|
||||
{0}
|
||||
},
|
||||
// Description of this filter
|
||||
struct af_info af_info_center = {
|
||||
"Audio filter for adding a center channel",
|
||||
"center",
|
||||
"Alex Beregszaszi",
|
||||
"",
|
||||
AF_FLAGS_NOT_REENTRANT,
|
||||
af_open
|
||||
};
|
||||
+104
-84
@@ -3,8 +3,6 @@
|
||||
* command line parameter channels. It is stupid and can only add
|
||||
* silence or copy channels, not mix or filter.
|
||||
*
|
||||
* Original author: Anders
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
@@ -27,7 +25,6 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
#define FR 0
|
||||
@@ -35,14 +32,12 @@
|
||||
|
||||
typedef struct af_channels_s{
|
||||
int route[AF_NCH][2];
|
||||
int nch, nr;
|
||||
int nr;
|
||||
int router;
|
||||
char *routes;
|
||||
}af_channels_t;
|
||||
|
||||
// Local function for copying data
|
||||
static void copy(struct af_instance *af, void* in, void* out,
|
||||
int ins, int inos,int outs, int outos, int len, int bps)
|
||||
static void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps)
|
||||
{
|
||||
switch(bps){
|
||||
case 1:{
|
||||
@@ -113,25 +108,24 @@ static void copy(struct af_instance *af, void* in, void* out,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MP_ERR(af, "Unsupported number of bytes/sample: %i"
|
||||
" please report this error on the MPlayer mailing list. \n",bps);
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] Unsupported number of bytes/sample: %i"
|
||||
" please report this error on the MPlayer mailing list. \n",bps);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the routes are sane
|
||||
static int check_routes(struct af_instance *af, int nin, int nout)
|
||||
static int check_routes(af_channels_t* s, 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_msg(MSGT_AFILTER, MSGL_ERR, "[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_msg(MSGT_AFILTER, MSGL_ERR, "[channels] Invalid routing in pair nr. %i.\n", i);
|
||||
return AF_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -141,111 +135,137 @@ static int check_routes(struct af_instance *af, int nin, int nout)
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_channels_t* s = af->priv;
|
||||
af_channels_t* s = af->setup;
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT: ;
|
||||
|
||||
struct mp_chmap chmap;
|
||||
mp_chmap_set_unknown(&chmap, s->nch);
|
||||
mp_audio_set_channels(af->data, &chmap);
|
||||
case AF_CONTROL_REINIT:
|
||||
|
||||
// Set default channel assignment
|
||||
if(!s->router){
|
||||
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 = min(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 = min(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
af->data->rate = ((struct mp_audio*)arg)->rate;
|
||||
mp_audio_force_interleaved_format((struct mp_audio*)arg);
|
||||
mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format);
|
||||
return check_routes(af,((struct mp_audio*)arg)->nch,af->data->nch);
|
||||
af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
|
||||
return check_routes(s,((struct mp_audio*)arg)->nch,af->data->nch);
|
||||
case AF_CONTROL_COMMAND_LINE:{
|
||||
int nch = 0;
|
||||
int n = 0;
|
||||
// Check number of channels and number of routing pairs
|
||||
sscanf(arg, "%i:%i%n", &nch, &s->nr, &n);
|
||||
|
||||
// If router scan commandline for routing pairs
|
||||
if(s->nr){
|
||||
char* cp = &((char*)arg)[n];
|
||||
int ch = 0;
|
||||
// Sanity check
|
||||
if((s->nr < 1) || (s->nr > AF_NCH)){
|
||||
mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of routing pairs must be"
|
||||
" between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
|
||||
}
|
||||
s->router = 1;
|
||||
// Scan for pairs on commandline
|
||||
while((*cp == ':') && (ch < s->nr)){
|
||||
sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
|
||||
mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Routing from channel %i to"
|
||||
" channel %i\n",s->route[ch][FR],s->route[ch][TO]);
|
||||
cp = &cp[n];
|
||||
ch++;
|
||||
}
|
||||
}
|
||||
|
||||
struct mp_chmap chmap;
|
||||
mp_chmap_from_channels(&chmap, nch);
|
||||
if (AF_OK != af->control(af, AF_CONTROL_CHANNELS | AF_CONTROL_SET, &chmap))
|
||||
return AF_ERROR;
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_CHANNELS | AF_CONTROL_SET:
|
||||
// Reinit must be called after this function has been called
|
||||
|
||||
mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
|
||||
if(!s->router)
|
||||
mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Changing number of channels"
|
||||
" to %i\n",af->data->nch);
|
||||
return AF_OK;
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
// Deallocate memory
|
||||
static void uninit(struct af_instance* af)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
struct mp_audio* l = af->data; // Local data
|
||||
af_channels_t* s = af->priv;
|
||||
int i;
|
||||
free(af->setup);
|
||||
if (af->data)
|
||||
free(af->data->audio);
|
||||
free(af->data);
|
||||
}
|
||||
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
// Filter data through filter
|
||||
static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
struct mp_audio* l = af->data; // Local data
|
||||
af_channels_t* s = af->setup;
|
||||
int i;
|
||||
|
||||
if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
|
||||
return NULL;
|
||||
|
||||
// Reset unused channels
|
||||
memset(l->planes[0],0,mp_audio_psize(c) / c->nch * l->nch);
|
||||
memset(l->audio,0,c->len / c->nch * l->nch);
|
||||
|
||||
if(AF_OK == check_routes(af,c->nch,l->nch))
|
||||
if(AF_OK == check_routes(s,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);
|
||||
copy(c->audio,l->audio,c->nch,s->route[i][FR],
|
||||
l->nch,s->route[i][TO],c->len,c->bps);
|
||||
|
||||
// Set output data
|
||||
c->planes[0] = l->planes[0];
|
||||
c->audio = l->audio;
|
||||
c->len = c->len / c->nch * l->nch;
|
||||
mp_audio_set_channels(c, &l->channels);
|
||||
|
||||
return 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter=filter;
|
||||
af_channels_t *s = af->priv;
|
||||
|
||||
// If router scan commandline for routing pairs
|
||||
if(s->routes && s->routes[0]){
|
||||
char* cp = s->routes;
|
||||
int ch = 0;
|
||||
// Scan for pairs on commandline
|
||||
do {
|
||||
int n = 0;
|
||||
if (ch >= AF_NCH) {
|
||||
MP_FATAL(af, "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"
|
||||
" channel %i\n",s->route[ch][FR],s->route[ch][TO]);
|
||||
cp = &cp[n];
|
||||
ch++;
|
||||
} while(*cp == ',' && *(cp++));
|
||||
s->nr = ch;
|
||||
if (s->nr > 0)
|
||||
s->router = 1;
|
||||
}
|
||||
|
||||
return AF_OK;
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->play=play;
|
||||
af->mul=1;
|
||||
af->data=calloc(1,sizeof(struct mp_audio));
|
||||
af->setup=calloc(1,sizeof(af_channels_t));
|
||||
if((af->data == NULL) || (af->setup == NULL))
|
||||
return AF_ERROR;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_channels_t
|
||||
const struct af_info af_info_channels = {
|
||||
.info = "Insert or remove channels",
|
||||
.name = "channels",
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_channels_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_INTRANGE("nch", nch, 0, 1, AF_NCH, OPTDEF_INT(2)),
|
||||
OPT_STRING("routes", routes, 0),
|
||||
{0}
|
||||
},
|
||||
// Description of this filter
|
||||
struct af_info af_info_channels = {
|
||||
"Insert or remove channels",
|
||||
"channels",
|
||||
"Anders",
|
||||
"",
|
||||
AF_FLAGS_REENTRANT,
|
||||
af_open
|
||||
};
|
||||
@@ -1,116 +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 <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "audio/format.h"
|
||||
#include "af.h"
|
||||
|
||||
static bool test_conversion(int src_format, int dst_format)
|
||||
{
|
||||
return (src_format == AF_FORMAT_U24 && dst_format == AF_FORMAT_U32) ||
|
||||
(src_format == AF_FORMAT_S24 && dst_format == AF_FORMAT_S32) ||
|
||||
(src_format == AF_FORMAT_U32 && dst_format == AF_FORMAT_U24) ||
|
||||
(src_format == AF_FORMAT_S32 && dst_format == AF_FORMAT_S24);
|
||||
}
|
||||
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
struct mp_audio *in = arg;
|
||||
struct mp_audio orig_in = *in;
|
||||
struct mp_audio *out = af->data;
|
||||
|
||||
if (!test_conversion(in->format, out->format))
|
||||
return AF_DETACH;
|
||||
|
||||
if ((in->format & AF_FORMAT_BITS_MASK) == AF_FORMAT_24BIT) {
|
||||
mp_audio_set_format(out, af_fmt_change_bits(in->format, 32));
|
||||
} else if ((in->format & AF_FORMAT_BITS_MASK) == AF_FORMAT_32BIT) {
|
||||
mp_audio_set_format(out, af_fmt_change_bits(in->format, 24));
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
out->rate = in->rate;
|
||||
mp_audio_set_channels(out, &in->channels);
|
||||
|
||||
assert(test_conversion(in->format, out->format));
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
case AF_CONTROL_SET_FORMAT: {
|
||||
mp_audio_set_format(af->data, *(int*)arg);
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// The LSB is always ignored.
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define SHIFT(x) ((3-(x))*8)
|
||||
#else
|
||||
#define SHIFT(x) (((x)+1)*8)
|
||||
#endif
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
struct mp_audio *out = af->data;
|
||||
size_t len = mp_audio_psize(data) / data->bps;
|
||||
|
||||
if (data->bps == 4) {
|
||||
for (int s = 0; s < len; s++) {
|
||||
uint32_t val = *((uint32_t *)data->planes[0] + s);
|
||||
uint8_t *ptr = (uint8_t *)out->planes[0] + s * 3;
|
||||
ptr[0] = val >> SHIFT(0);
|
||||
ptr[1] = val >> SHIFT(1);
|
||||
ptr[2] = val >> SHIFT(2);
|
||||
}
|
||||
mp_audio_set_format(data, af_fmt_change_bits(data->format, 24));
|
||||
} else {
|
||||
for (int s = 0; s < len; s++) {
|
||||
uint8_t *ptr = (uint8_t *)data->planes[0] + s * 3;
|
||||
uint32_t val = ptr[0] << SHIFT(0)
|
||||
| ptr[1] << SHIFT(1)
|
||||
| ptr[2] << SHIFT(2);
|
||||
*((uint32_t *)out->planes[0] + s) = val;
|
||||
}
|
||||
mp_audio_set_format(data, af_fmt_change_bits(data->format, 32));
|
||||
}
|
||||
|
||||
data->planes[0] = out->planes[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter = filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
const struct af_info af_info_convert24 = {
|
||||
.info = "Convert between 24 and 32 bit sample format",
|
||||
.name = "convert24",
|
||||
.open = af_open,
|
||||
.test_conversion = test_conversion,
|
||||
};
|
||||
@@ -1,131 +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 <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "af.h"
|
||||
#include "audio/format.h"
|
||||
#include "compat/mpbswap.h"
|
||||
|
||||
static bool test_conversion(int src_format, int dst_format)
|
||||
{
|
||||
if ((src_format & AF_FORMAT_PLANAR) ||
|
||||
(dst_format & AF_FORMAT_PLANAR))
|
||||
return false;
|
||||
int src_noend = src_format & ~AF_FORMAT_END_MASK;
|
||||
int dst_noend = dst_format & ~AF_FORMAT_END_MASK;
|
||||
// We can swap endian for all formats, but sign only for integer formats.
|
||||
if (src_noend == dst_noend)
|
||||
return true;
|
||||
if (((src_noend & ~AF_FORMAT_SIGN_MASK) ==
|
||||
(dst_noend & ~AF_FORMAT_SIGN_MASK)) &&
|
||||
((src_noend & AF_FORMAT_POINT_MASK) == AF_FORMAT_I))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
struct mp_audio *in = arg;
|
||||
struct mp_audio orig_in = *in;
|
||||
struct mp_audio *out = af->data;
|
||||
|
||||
if (!test_conversion(in->format, out->format))
|
||||
return AF_DETACH;
|
||||
|
||||
out->rate = in->rate;
|
||||
mp_audio_set_channels(out, &in->channels);
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
case AF_CONTROL_SET_FORMAT: {
|
||||
mp_audio_set_format(af->data, *(int*)arg);
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static void endian(void *data, int len, int bps)
|
||||
{
|
||||
switch (bps) {
|
||||
case 2:
|
||||
for (int i = 0; i < len; i++) {
|
||||
((uint16_t*)data)[i] = bswap_16(((uint16_t *)data)[i]);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for(int i = 0; i < len; i++) {
|
||||
uint8_t s = ((uint8_t *)data)[3 * i];
|
||||
((uint8_t *)data)[3 * i] = ((uint8_t *)data)[3 * i + 2];
|
||||
((uint8_t *)data)[3 * i + 2] = s;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for(int i = 0; i < len; i++) {
|
||||
((uint32_t*)data)[i] = bswap_32(((uint32_t *)data)[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void si2us(void *data, int len, int bps, bool le)
|
||||
{
|
||||
ptrdiff_t i = -(len * bps);
|
||||
uint8_t *p = &((uint8_t *)data)[len * bps];
|
||||
if (le && bps > 1)
|
||||
p += bps - 1;
|
||||
if (len <= 0)
|
||||
return;
|
||||
do {
|
||||
p[i] ^= 0x80;
|
||||
} while (i += bps);
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
int infmt = data->format;
|
||||
int outfmt = af->data->format;
|
||||
size_t len = data->samples * data->nch;
|
||||
|
||||
if ((infmt & AF_FORMAT_END_MASK) != (outfmt & AF_FORMAT_END_MASK))
|
||||
endian(data->planes[0], len, data->bps);
|
||||
|
||||
if ((infmt & AF_FORMAT_SIGN_MASK) != (outfmt & AF_FORMAT_SIGN_MASK))
|
||||
si2us(data->planes[0], len, data->bps,
|
||||
(outfmt & AF_FORMAT_END_MASK) == AF_FORMAT_LE);
|
||||
|
||||
mp_audio_set_format(data, outfmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter = filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
const struct af_info af_info_convertsignendian = {
|
||||
.info = "Convert between sample format sign/endian",
|
||||
.name = "convertsignendian",
|
||||
.open = af_open,
|
||||
.test_conversion = test_conversion,
|
||||
};
|
||||
+82
-75
@@ -3,8 +3,6 @@
|
||||
* channels and can be used for simple position panning.
|
||||
* An extension for this filter would be a reverb.
|
||||
*
|
||||
* Original author: Anders
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
@@ -27,7 +25,6 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
#define L 65536
|
||||
@@ -37,52 +34,71 @@
|
||||
// Data for specific instances of this filter
|
||||
typedef struct af_delay_s
|
||||
{
|
||||
void* q[AF_NCH]; // Circular queues used for delaying audio signal
|
||||
int wi[AF_NCH]; // Write index
|
||||
int ri; // Read index
|
||||
float d[AF_NCH]; // Delay [ms]
|
||||
char *delaystr;
|
||||
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]
|
||||
}af_delay_t;
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_delay_t* s = af->priv;
|
||||
af_delay_t* s = af->setup;
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:{
|
||||
int i;
|
||||
struct mp_audio *in = arg;
|
||||
|
||||
if (in->bps != 1 && in->bps != 2 && in->bps != 4) {
|
||||
MP_FATAL(af, "Sample format not supported\n");
|
||||
return AF_ERROR;
|
||||
}
|
||||
|
||||
// Free prevous delay queues
|
||||
for(i=0;i<af->data->nch;i++)
|
||||
free(s->q[i]);
|
||||
|
||||
mp_audio_force_interleaved_format(in);
|
||||
mp_audio_copy_config(af->data, in);
|
||||
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
|
||||
|
||||
// Allocate new delay queues
|
||||
for(i=0;i<af->data->nch;i++){
|
||||
s->q[i] = calloc(L,af->data->bps);
|
||||
if(NULL == s->q[i])
|
||||
MP_FATAL(af, "Out of memory\n");
|
||||
mp_msg(MSGT_AFILTER, MSGL_FATAL, "[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 control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,s->d);
|
||||
}
|
||||
case AF_CONTROL_COMMAND_LINE:{
|
||||
int n = 1;
|
||||
int i = 0;
|
||||
char* cl = arg;
|
||||
while(n && i < AF_NCH ){
|
||||
sscanf(cl,"%f:%n",&s->d[i],&n);
|
||||
if(n==0 || cl[n-1] == '\0')
|
||||
break;
|
||||
cl=&cl[n];
|
||||
i++;
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_DELAY_LEN | AF_CONTROL_SET:{
|
||||
int i;
|
||||
if(AF_OK != af_from_ms(AF_NCH, arg, s->wi, af->data->rate, 0.0, 1000.0))
|
||||
return AF_ERROR;
|
||||
s->ri = 0;
|
||||
for(i=0;i<AF_NCH;i++){
|
||||
MP_DBG(af, "Channel %i delayed by %0.3fms\n",
|
||||
i,MPCLAMP(s->d[i],0.0,1000.0));
|
||||
MP_TRACE(af, "Channel %i delayed by %i samples\n",
|
||||
i,s->wi[i]);
|
||||
mp_msg(MSGT_AFILTER, MSGL_DBG2, "[delay] Channel %i delayed by %0.3fms\n",
|
||||
i,clamp(s->d[i],0.0,1000.0));
|
||||
mp_msg(MSGT_AFILTER, MSGL_DBG3, "[delay] Channel %i delayed by %i samples\n",
|
||||
i,s->wi[i]);
|
||||
}
|
||||
return AF_OK;
|
||||
}
|
||||
case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET:{
|
||||
int i;
|
||||
for(i=0;i<AF_NCH;i++){
|
||||
if(s->ri > s->wi[i])
|
||||
s->wi[i] = L - (s->ri - s->wi[i]);
|
||||
else
|
||||
s->wi[i] = s->wi[i] - s->ri;
|
||||
}
|
||||
return af_to_ms(AF_NCH, s->wi, arg, af->data->rate);
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
@@ -92,59 +108,61 @@ static void uninit(struct af_instance* af)
|
||||
{
|
||||
int i;
|
||||
|
||||
free(af->data);
|
||||
for(i=0;i<AF_NCH;i++)
|
||||
free(((af_delay_t*)(af->priv))->q[i]);
|
||||
free(((af_delay_t*)(af->setup))->q[i]);
|
||||
free(af->setup);
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
|
||||
{
|
||||
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->setup; // Setup for this instance
|
||||
int nch = c->nch; // Number of channels
|
||||
int len = c->len/c->bps; // Number of sample in data chunk
|
||||
int ri = 0;
|
||||
int ch,i;
|
||||
for(ch=0;ch<nch;ch++){
|
||||
switch(c->bps){
|
||||
case 1:{
|
||||
int8_t* a = c->planes[0];
|
||||
int8_t* a = c->audio;
|
||||
int8_t* q = s->q[ch];
|
||||
int wi = s->wi[ch];
|
||||
ri = s->ri;
|
||||
for(i=ch;i<len;i+=nch){
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
}
|
||||
s->wi[ch] = wi;
|
||||
break;
|
||||
}
|
||||
case 2:{
|
||||
int16_t* a = c->planes[0];
|
||||
int16_t* a = c->audio;
|
||||
int16_t* q = s->q[ch];
|
||||
int wi = s->wi[ch];
|
||||
ri = s->ri;
|
||||
for(i=ch;i<len;i+=nch){
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
}
|
||||
s->wi[ch] = wi;
|
||||
break;
|
||||
}
|
||||
case 4:{
|
||||
int32_t* a = c->planes[0];
|
||||
int32_t* a = c->audio;
|
||||
int32_t* q = s->q[ch];
|
||||
int wi = s->wi[ch];
|
||||
ri = s->ri;
|
||||
for(i=ch;i<len;i+=nch){
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
q[wi] = a[i];
|
||||
a[i] = q[ri];
|
||||
UPDATEQI(wi);
|
||||
UPDATEQI(ri);
|
||||
}
|
||||
s->wi[ch] = wi;
|
||||
break;
|
||||
@@ -152,39 +170,28 @@ static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
}
|
||||
}
|
||||
s->ri = ri;
|
||||
return 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->filter=filter;
|
||||
af_delay_t *s = af->priv;
|
||||
int n = 1;
|
||||
int i = 0;
|
||||
char* cl = s->delaystr;
|
||||
while(cl && n && i < AF_NCH ){
|
||||
sscanf(cl,"%f%n",&s->d[i],&n);
|
||||
if(n==0 || cl[n-1] == '\0')
|
||||
break;
|
||||
cl=&cl[n];
|
||||
if (*cl != ',')
|
||||
break;
|
||||
cl++;
|
||||
i++;
|
||||
}
|
||||
return AF_OK;
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->play=play;
|
||||
af->mul=1;
|
||||
af->data=calloc(1,sizeof(struct mp_audio));
|
||||
af->setup=calloc(1,sizeof(af_delay_t));
|
||||
if(af->data == NULL || af->setup == NULL)
|
||||
return AF_ERROR;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_delay_t
|
||||
const struct af_info af_info_delay = {
|
||||
.info = "Delay audio filter",
|
||||
.name = "delay",
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_delay_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("delays", delaystr, 0),
|
||||
{0}
|
||||
},
|
||||
// Description of this filter
|
||||
struct af_info af_info_delay = {
|
||||
"Delay audio filter",
|
||||
"delay",
|
||||
"Anders",
|
||||
"",
|
||||
AF_FLAGS_REENTRANT,
|
||||
af_open
|
||||
};
|
||||
+74
-53
@@ -26,7 +26,6 @@
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "af.h"
|
||||
|
||||
// Methods:
|
||||
@@ -70,8 +69,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;
|
||||
@@ -81,27 +80,46 @@ typedef struct af_volume_s
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
af_drc_t* s = (af_drc_t*)af->setup;
|
||||
|
||||
switch(cmd){
|
||||
case AF_CONTROL_REINIT:
|
||||
// Sanity check
|
||||
if(!arg) return AF_ERROR;
|
||||
|
||||
mp_audio_force_interleaved_format((struct mp_audio*)arg);
|
||||
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
|
||||
|
||||
if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16)){
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16_NE)){
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
|
||||
}
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
case AF_CONTROL_COMMAND_LINE:{
|
||||
int i = 0;
|
||||
float target = DEFAULT_TARGET;
|
||||
sscanf((char*)arg,"%d:%f", &i, &target);
|
||||
if (i != 1 && i != 2)
|
||||
return AF_ERROR;
|
||||
s->method = i-1;
|
||||
s->mid_s16 = ((float)SHRT_MAX) * target;
|
||||
s->mid_float = target;
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
// Deallocate memory
|
||||
static void uninit(struct af_instance* af)
|
||||
{
|
||||
free(af->data);
|
||||
free(af->setup);
|
||||
}
|
||||
|
||||
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->audio; // Audio data
|
||||
int len = c->len/2; // Number of samples
|
||||
float curavg = 0.0, newavg, neededmul;
|
||||
int tmp;
|
||||
|
||||
@@ -121,14 +139,14 @@ static void method1_int16(af_drc_t *s, struct mp_audio *c)
|
||||
s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul;
|
||||
|
||||
// clamp the mul coefficient
|
||||
s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
|
||||
s->mul = clamp(s->mul, MUL_MIN, MUL_MAX);
|
||||
}
|
||||
|
||||
// Scale & clamp the samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp = s->mul * data[i];
|
||||
tmp = MPCLAMP(tmp, SHRT_MIN, SHRT_MAX);
|
||||
tmp = clamp(tmp, SHRT_MIN, SHRT_MAX);
|
||||
data[i] = tmp;
|
||||
}
|
||||
|
||||
@@ -142,8 +160,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->audio; // Audio data
|
||||
int len = c->len/4; // Number of samples
|
||||
float curavg = 0.0, newavg, neededmul, tmp;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
@@ -162,7 +180,7 @@ static void method1_float(af_drc_t *s, struct mp_audio *c)
|
||||
s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul;
|
||||
|
||||
// clamp the mul coefficient
|
||||
s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
|
||||
s->mul = clamp(s->mul, MUL_MIN, MUL_MAX);
|
||||
}
|
||||
|
||||
// Scale & clamp the samples
|
||||
@@ -179,8 +197,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->audio; // Audio data
|
||||
int len = c->len/2; // Number of samples
|
||||
float curavg = 0.0, newavg, avg = 0.0;
|
||||
int tmp, totallen = 0;
|
||||
|
||||
@@ -204,8 +222,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 = clamp(s->mul, MUL_MIN, MUL_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +231,7 @@ static void method2_int16(af_drc_t *s, struct mp_audio *c)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp = s->mul * data[i];
|
||||
tmp = MPCLAMP(tmp, SHRT_MIN, SHRT_MAX);
|
||||
tmp = clamp(tmp, SHRT_MIN, SHRT_MAX);
|
||||
data[i] = tmp;
|
||||
}
|
||||
|
||||
@@ -229,8 +247,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->audio; // Audio data
|
||||
int len = c->len/4; // Number of samples
|
||||
float curavg = 0.0, newavg, avg = 0.0, tmp;
|
||||
int totallen = 0;
|
||||
|
||||
@@ -254,8 +272,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 = clamp(s->mul, MUL_MIN, MUL_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,56 +290,59 @@ static void method2_float(af_drc_t *s, struct mp_audio *c)
|
||||
s->idx = (s->idx + 1) % NSAMPLES;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
// Filter data through filter
|
||||
static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
|
||||
{
|
||||
af_drc_t *s = af->priv;
|
||||
af_drc_t *s = af->setup;
|
||||
|
||||
if(af->data->format == (AF_FORMAT_S16))
|
||||
if(af->data->format == (AF_FORMAT_S16_NE))
|
||||
{
|
||||
if (s->method == 2)
|
||||
method2_int16(s, data);
|
||||
if (s->method)
|
||||
method2_int16(s, data);
|
||||
else
|
||||
method1_int16(s, data);
|
||||
method1_int16(s, data);
|
||||
}
|
||||
else if(af->data->format == (AF_FORMAT_FLOAT))
|
||||
else if(af->data->format == (AF_FORMAT_FLOAT_NE))
|
||||
{
|
||||
if (s->method == 2)
|
||||
method2_float(s, data);
|
||||
if (s->method)
|
||||
method2_float(s, data);
|
||||
else
|
||||
method1_float(s, data);
|
||||
method1_float(s, data);
|
||||
}
|
||||
return 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
int i = 0;
|
||||
af->control=control;
|
||||
af->filter=filter;
|
||||
af_drc_t *priv = af->priv;
|
||||
af->uninit=uninit;
|
||||
af->play=play;
|
||||
af->mul=1;
|
||||
af->data=calloc(1,sizeof(struct mp_audio));
|
||||
af->setup=calloc(1,sizeof(af_drc_t));
|
||||
if(af->data == NULL || af->setup == NULL)
|
||||
return AF_ERROR;
|
||||
|
||||
priv->mul = MUL_INIT;
|
||||
priv->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET;
|
||||
priv->idx = 0;
|
||||
((af_drc_t*)af->setup)->mul = MUL_INIT;
|
||||
((af_drc_t*)af->setup)->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET;
|
||||
((af_drc_t*)af->setup)->idx = 0;
|
||||
((af_drc_t*)af->setup)->mid_s16 = ((float)SHRT_MAX) * DEFAULT_TARGET;
|
||||
((af_drc_t*)af->setup)->mid_float = DEFAULT_TARGET;
|
||||
for (i = 0; i < NSAMPLES; i++)
|
||||
{
|
||||
priv->mem[i].len = 0;
|
||||
priv->mem[i].avg = 0;
|
||||
((af_drc_t*)af->setup)->mem[i].len = 0;
|
||||
((af_drc_t*)af->setup)->mem[i].avg = 0;
|
||||
}
|
||||
priv->mid_s16 = ((float)SHRT_MAX) * priv->mid_float;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT af_drc_t
|
||||
const struct af_info af_info_drc = {
|
||||
.info = "Dynamic range compression filter",
|
||||
.name = "drc",
|
||||
.flags = AF_FLAGS_NOT_REENTRANT,
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(af_drc_t),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_INTRANGE("method", method, 0, 1, 2, OPTDEF_INT(1)),
|
||||
OPT_FLOAT("target", mid_float, 0, OPTDEF_FLOAT(DEFAULT_TARGET)),
|
||||
{0}
|
||||
},
|
||||
// Description of this filter
|
||||
struct af_info af_info_drc = {
|
||||
"Dynamic range compression filter",
|
||||
"drc",
|
||||
"Alex Beregszaszi & Pierre Lombard",
|
||||
"",
|
||||
AF_FLAGS_NOT_REENTRANT,
|
||||
af_open
|
||||
};
|
||||
Loaded 100 of 613 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user