Compare commits

..
18 Commits
Author SHA1 Message Date
Alessandro Ghedini b677937c27 Release 0.5.1 2014-08-26 10:27:40 +02:00
Otto Modinos fdd648bdf9 manpage: mention that mp.commandv doesn't expand properties
The little lua snippet at #488 as well as the actual implementation
seems to indicate that not expanding properties is indeed the correct
behavior.  Document that.

Signed-off-by: wm4 <wm4@nowhere>
2014-08-26 10:24:21 +02:00
Stefano Pigozzi 334fd10f1c coreaudio_device: fix overwriting of user input
Fixes #1030
2014-08-25 11:24:01 +02:00
wm4 226735331c options: compatibility hack for --slave-broken
Seems some programs were still relying on it. Whatever, it's not hard to
support.

CC: @mpv-player/stable
2014-08-25 11:23:30 +02:00
wm4 5523370ab9 player: don't clobber playback position on video end
If video reaches EOF, and audio is also EOF (or is otherwise not
meaningful, like audio disabled), then the playback position was briefly
set to 0. Fix this by not trying to use a bogus audio PTS.

CC: @mpv-player/stable (maybe)
2014-08-25 11:23:26 +02:00
Bin Jin 8c7d61f1d9 manpage: remove duplicated content
Probably be accidentally added in b6b8bffd.

CC: @mpv-player/stable
Signed-off-by: wm4 <wm4@nowhere>
2014-08-25 11:23:05 +02:00
wm4 f021b5a379 etc/mpv.desktop: add audio/flac mimetype
Fixes #1025.

CC: @mpv-player/stable
2014-08-21 15:16:58 +02:00
wm4 43e164964c manpage: fix opengl-hq defaults
The FBO format was changed some time ago.

CC: @mpv-player/stable
2014-08-18 11:14:48 +02:00
Philip Sequeira aeb64723fd TOOLS/zsh.pl: protect global environment 2014-08-17 14:14:48 +02:00
Philip Sequeira f935838b2d TOOLS/zsh.pl: fix a ret that hadn't been changed to rc 2014-08-17 14:14:30 +02:00
Alessandro Ghedini ec46ad79e2 TOOLS/zsh.pl: properly set the return value
The previous commit made the completion script always return non-zero, even when
a match is found. This explicitly sets the return value to zero whenever a match
is found but defaults to non-zero in case nothing is matched.
2014-08-15 16:31:18 +02:00
c_14 d6ccc4d8de TOOLS/zsh.pl: properly return non-zero when no matches are found
Returning a non-zero value signals to the zsh completion system that no matches
were added by the script so that it can try the user-defined matchers (e.g.
those defined with matcher-list).

Fixes #1008.
2014-08-13 23:00:36 +02:00
Alexander Preisinger 8664dc3c47 wayland: pointer interface is created after theme
Just always load the theme. It gets freed properly and dosn't bother anyone.

Fixes #1012.

CC: @mpv-player/stable
2014-08-13 23:00:26 +02:00
wm4 51ce535822 player: don't quit with --loop-file
Fixes #1009.

CC: @mpv-player/stable
2014-08-13 23:00:21 +02:00
Alessandro Ghedini e33df9b7bc vdpau: correctly mark invalid mixer as such on vdp_video_mixer_create() failure
Otherwise vdp_video_mixer_destroy() would later fail when called on an invalid
video mixer handle. With mesa r600 vdpau driver, this would cause a segfault.
2014-08-13 19:16:53 +02:00
wm4 6310bd60e6 vo_vdpau: fix screenshots with anamorphic video
Fixes #1007.

CC: @mpv-player/stable
2014-08-13 10:55:49 +02:00
wm4 6729e39983 DOCS: mark the recent release in client-api-changes.rst
Also add instructions to release-policy.md, since this can be easily
forgotten.

CC: @mpv-player/stable
2014-08-13 10:55:44 +02:00
Alessandro Ghedini 88f247c0af Release 0.5.0 2014-08-12 10:50:38 +02:00
262 changed files with 6530 additions and 8835 deletions

No files matched your search

-7
View File
@@ -25,13 +25,6 @@ API changes
::
--- mpv 0.6.0 is released ---
1.5 - change in X11 and "--wid" behavior again. The previous change didn't
work as expected, and now the behavior can be explicitly controlled
with the "input-x11-keyboard" option. This is only a temporary
measure until XEmbed is implemented and confirmed working.
1.4 - subtle change in X11 and "--wid" behavior
(this change was added to 0.5.2, and broke some things, see #1090)
--- mpv 0.5.0 is released ---
1.3 - add MPV_MAKE_VERSION()
1.2 - remove "stream-time-pos" property (no replacement)
-117
View File
@@ -1,117 +0,0 @@
// Plays a video from the command line in a window provided by mpv.
// You likely want to play the video in your own window instead,
// but that's not quite ready yet.
// You may need a basic Info.plist and MainMenu.xib to make this work.
#include "../../libmpv/client.h"
#include "shared.h"
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
mpv_handle *mpv;
dispatch_queue_t queue;
}
@end
static void wakeup(void *);
@implementation AppDelegate
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
// Read filename
NSArray *args = [NSProcessInfo processInfo].arguments;
if (args.count < 2) {
NSLog(@"Expected filename on command line");
exit(1);
}
NSString *filename = args[1];
// Deal with MPV in the background.
queue = dispatch_queue_create("mpv", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
mpv = mpv_create();
if (!mpv) {
printf("failed creating context\n");
exit(1);
}
// Maybe set some options here, like default key bindings.
// NOTE: Interaction with the window seems to be broken for now.
check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes"));
check_error(mpv_initialize(mpv));
// Register to be woken up whenever mpv generates new events.
mpv_set_wakeup_callback(mpv, wakeup, (__bridge void *) self);
// Load the indicated file
const char *cmd[] = {"loadfile", filename.UTF8String, NULL};
check_error(mpv_command(mpv, cmd));
});
}
- (void) handleEvent:(mpv_event *)event
{
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN:
// Clean up and shut down.
mpv_terminate_destroy(mpv);
mpv = NULL;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSApplication sharedApplication] terminate:nil];
});
break;
default:
printf("event: %s\n", mpv_event_name(event->event_id));
}
}
- (void) readEvents
{
dispatch_async(queue, ^{
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
[self handleEvent:event];
}
});
}
static void wakeup(void *context) {
AppDelegate *a = (__bridge AppDelegate *) context;
[a readEvents];
}
// Ostensibly, mpv's window would be hooked up to this.
- (BOOL) windowShouldClose:(id)sender
{
[self shutdown];
return YES;
}
- (void) shutdown
{
if (mpv) {
const char *args[] = {"quit", NULL};
mpv_command(mpv, args);
}
}
@end
// Delete this if you already have a main.m.
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication new];
AppDelegate *delegate = [AppDelegate new];
app.delegate = delegate;
[app run];
}
return EXIT_SUCCESS;
}
-23
View File
@@ -45,7 +45,6 @@ MainWindow::MainWindow(QWidget *parent) :
mpv_container = new QWidget(this);
setCentralWidget(mpv_container);
mpv_container->setAttribute(Qt::WA_NativeWindow);
// If you have a HWND, use: int64_t wid = (intptr_t)hwnd;
int64_t wid = mpv_container->winId();
mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);
@@ -53,10 +52,6 @@ MainWindow::MainWindow(QWidget *parent) :
// mpv as backend would implement its own key bindings.
mpv_set_option_string(mpv, "input-default-bindings", "yes");
// Enable keyboard input on the X11 window. For the messy details, see
// --input-x11-keyboard on the manpage.
mpv_set_option_string(mpv, "input-x11-keyboard", "yes");
// Let us receive property change events with MPV_EVENT_PROPERTY_CHANGE if
// this property changes.
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
@@ -89,24 +84,6 @@ void MainWindow::handle_mpv_event(mpv_event *event)
}
break;
}
case MPV_EVENT_VIDEO_RECONFIG: {
// Retrieve the new video size.
int64_t w, h;
if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 &&
mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 &&
w > 0 && h > 0)
{
// Note that the MPV_EVENT_VIDEO_RECONFIG event doesn't necessarily
// imply a resize, and you should check yourself if the video
// dimensions really changed.
// mpv itself will scale/letter box the video to the container size
// if the video doesn't fit.
std::stringstream ss;
ss << "Reconfig: " << w << " " << h;
statusBar()->showMessage(QString::fromStdString(ss.str()));
}
break;
}
case MPV_EVENT_SHUTDOWN: {
mpv_terminate_destroy(mpv);
mpv = NULL;
-1
View File
@@ -21,7 +21,6 @@ int main(int argc, char *argv[])
// Enable default key bindings, so the user can actually interact with
// the player (and e.g. close the window).
check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes"));
mpv_set_option_string(ctx, "input-x11-keyboard", "yes");
int val = 1;
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
-9
View File
@@ -26,15 +26,6 @@ created scripts to help ease the process. These are the two recommended methods:
Note that MinGW environments included in Linux distributions are often broken,
outdated and useless, and usually don't use MinGW-w64.
Additional dependencies
-----------------------
You need a pthread wrapper. It must be interoperable with native Windows
threads. pthreads-win32 or MinGW pthreads might work.
If you want ``--input-file=...`` to work, you need libwaio. It's available
from: git://midipix.org/waio
Example with MXE
----------------
+19 -20
View File
@@ -72,17 +72,15 @@ Available filters are:
``tospdif=<yes|no>``
Output raw AC-3 stream if ``no``, output to S/PDIF for
pass-through if ``yes`` (default).
passthrough if ``yes`` (default).
``bitrate=<rate>``
The bitrate use for the AC-3 stream. Set it to 384 to get 384 kbps.
The default is 640. Some receivers might not be able to handle this.
Valid values: 32, 40, 48, 56, 64, 80, 96, 112, 128,
160, 192, 224, 256, 320, 384, 448, 512, 576, 640.
The special value ``auto`` selects a default bitrate based on the
The special value ``default`` selects a default bitrate based on the
input channel number:
:1ch: 96
@@ -94,7 +92,7 @@ Available filters are:
``minchn=<n>``
If the input channel number is less than ``<minchn>``, the filter will
detach itself (default: 3).
detach itself (default: 5).
``sweep[=speed]``
Produces a sine sweep.
@@ -103,7 +101,7 @@ Available filters are:
Sine function delta, use very low values to hear the sweep.
``sinesuppress[=freq:decay]``
Remove a sine at the specified frequency. Useful to get rid of the 50/60 Hz
Remove a sine at the specified frequency. Useful to get rid of the 50/60Hz
noise on low quality audio equipment. It only works on mono input.
``<freq>``
@@ -184,7 +182,7 @@ Available filters are:
``mpv --af=equalizer=11:11:10:5:0:-12:0:5:12:12 media.avi``
Would amplify the sound in the upper and lower frequency region
while canceling it almost completely around 1 kHz.
while canceling it almost completely around 1kHz.
``channels=nch[:routes]``
Can be used for adding, removing, routing and copying audio channels. If
@@ -265,8 +263,9 @@ Available filters are:
Filter for internal use only. Converts between 24-bit and 32-bit sample
formats.
``convertsign``
Filter for internal use only. Converts between signed/unsigned formats.
``convertsignendian``
Filter for internal use only. Converts between signed/unsigned formats
and formats with different endian.
``volume[=<volumedb>[:...]]``
Implements software volume control. Use this filter with caution since it
@@ -278,8 +277,8 @@ Available filters are:
once for every audio stream.
``<volumedb>``
Sets the desired gain in dB for all channels in the stream from -200 dB
to +60 dB, where -200 dB mutes the sound completely and +60 dB equals a
Sets the desired gain in dB for all channels in the stream from -200dB
to +60dB, where -200dB mutes the sound completely and +60dB equals a
gain of 1000 (default: 0).
``replaygain-track``
Adjust volume gain according to the track-gain replaygain value stored
@@ -312,7 +311,7 @@ Available filters are:
.. admonition:: Example
``mpv --af=volume=10.1 media.avi``
Would amplify the sound by 10.1 dB and hard-clip if the sound level
Would amplify the sound by 10.1dB and hard-clip if the sound level
is too high.
``pan=n:[<matrix>]``
@@ -369,8 +368,8 @@ Available filters are:
to the subwoofer.
``<fc>``
cutoff frequency in Hz for the low-pass filter (20 Hz to 300 Hz)
(default: 60 Hz) For the best result try setting the cutoff frequency
cutoff frequency in Hz for the low-pass filter (20Hz to 300Hz)
(default: 60Hz) For the best result try setting the cutoff frequency
as low as possible. This will improve the stereo or surround sound
experience.
``<ch>``
@@ -382,7 +381,7 @@ Available filters are:
.. admonition:: Example
``mpv --af=sub=100:4 --audio-channels=5 media.avi``
Would add a subwoofer channel with a cutoff frequency of 100 Hz to
Would add a subwoofer channel with a cutoff frequency of 100Hz to
output channel 4.
``center``
@@ -410,7 +409,7 @@ Available filters are:
.. admonition:: Example
``mpv --af=surround=15 --audio-channels=4 media.avi``
Would add surround sound decoding with 15 ms delay for the sound to
Would add surround sound decoding with 15ms delay for the sound to
the rear speakers.
``delay[=[ch1,ch2,...]]``
@@ -438,8 +437,8 @@ Available filters are:
.. admonition:: Example
``mpv --af=delay=[10.5,10.5,0,0,7,0] media.avi``
Would delay front left and right by 10.5 ms, the two rear channels
and the subwoofer by 0 ms and the center channel by 7 ms.
Would delay front left and right by 10.5ms, the two rear channels
and the subwoofer by 0ms and the center channel by 7ms.
``export=mmapped_file:nsamples]``
Exports the incoming signal to other processes using memory mapping
@@ -589,7 +588,7 @@ Available filters are:
tempo.
``mpv --af=scaletempo=stride=30:overlap=.50:search=10 media.ogg``
Would tweak the quality and performance parameters.
Would tweak the quality and performace parameters.
``mpv --af=format=float,scaletempo media.ogg``
Would make scaletempo use float code. Maybe faster on some
@@ -601,7 +600,7 @@ Available filters are:
1.2x.
``lavfi=graph``
Filter audio using FFmpeg's libavfilter.
Filter audio using ffmpeg's libavfilter.
``<graph>``
Libavfilter graph. See ``lavfi`` video filter for details - the graph
+1 -4
View File
@@ -23,7 +23,7 @@ normal driver parameters.
where PulseAudio is used. On Windows, ``--ao=wasapi`` is preferred,
though it might cause trouble sometimes, in which case ``--ao=dsound``
should be used. On BSD systems, ``--ao=oss`` or `--ao=sndio`` may work
(the latter being experimental). On OS X systems, use ``--ao=coreaudio``.
(the latter being experimental). On OSX systems, use ``--ao=coreaudio``.
.. admonition:: Examples
@@ -181,9 +181,6 @@ Available audio output drivers are:
Sets the device number to use. Playing a file with ``-v`` will show a
list of available devices.
``buffersize=<ms>``
DirectSound buffer size in milliseconds (default: 200).
``sdl``
SDL 1.2+ audio output driver. Should work on any platform supported by SDL
1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
+16 -16
View File
@@ -19,14 +19,14 @@ General Changes for MPlayer to mpv
Linux 2.4 (including VIDIX)
* Large internal cleanups
* Removal of support for dead platforms
* New build system
* No embedded copy of FFmpeg and other libraries
* New buildsystem
* No embedded copy of ffmpeg and other libraries
* Better pause handling (do not unpause on a command)
* Better MKV support (such as ordered chapters)
* vo_vdpau improvements
* Precise seeking support
* Native OpenGL backend for OS X
* General OS X improvements
* Native OpenGL backend for OSX
* General OSX improvements
* Improvements in audio/video sync handling
* Cleaned up terminal output
* Gapless audio support (``--gapless-audio``)
@@ -35,14 +35,14 @@ General Changes for MPlayer to mpv
* OSS4 volume control
* More correct color reproduction (color matrix generation)
* Use libass for subtitle rendering by default (better quality)
* Generally preferring FFmpeg/Libav over internal demuxers and decoders
* Generally preferring ffmpeg/libav over internal demuxers and decoders
* Improvements when playing multiple files (``--fixed-vo``)
* Screenshot improvements (instant screenshots without 1-frame delay, allow
taking screenshots even with hardware decoding)
* Improved support for PulseAudio
* Generally improved MS Windows support (dealing with Unicode file names,
* 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
* Better OSD rendering (using libass). This has full unicode support, and
languages like Arabic should be better supported.
* Cleaned up terminal output (nicer status line, less useless noise)
* Support for playing URLs of popular streaming sites directly
@@ -50,19 +50,19 @@ General Changes for MPlayer to mpv
* Improved OpenGL output (``--vo=opengl-hq``)
* Make ``--softvol`` default (**mpv** is not a mixer control panel)
* Improved support for .cue files
* Screenshot improvements (can save screenshots as JPEG or PNG, configurable
file names, support for taking screenshots with or without subtitles - the
* Screenshot improvements (can save screenshots as JPG or PNG, configurable
filenames, support for taking screenshots with or without subtitles - the
``screenshot`` video filter is not needed anymore, and should not be put
into the mpv config file)
* Removal of teletext support
* Removal of most built-in demuxers, using libavformat instead
* Removal of built-in network support, using libavformat instead (also,
* Removal of most builtin demuxers, using libavformat instead
* Removal of builtin network support, using libavformat instead (also,
support https via libavformat)
* Replace image VOs (``--vo=jpeg`` etc.) with ``--vo=image``
* Do not lose settings when playing a new file in the same player instance
* New location for config files, new name for the binary.
* Slave mode compatibility broken (see below)
* Encoding functionality (replacement for MEncoder, see ``DOCS/encoding.rst``)
* Encoding functionality (replacement for mencoder, see ``DOCS/encoding.rst``)
* Remove ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding can
handle these use cases. For yuv4mpeg, for example, use:
``mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop``.
@@ -71,10 +71,10 @@ General Changes for MPlayer to mpv
* Wayland support
* Support for precise scrolling which scales the parameter of commands. If the
input doesn't support precise scrolling the scale factor stays 1.
* OS X: Cocoa event loop is independent from MPlayer's event loop, so user
* OSX: Cocoa event loop is independent from mplayer's event loop, so user
actions like accessing menus and live resizing do not block the playback.
* OS X: Apple Remote support.
* OS X: Media Keys support.
* OSX: Apple Remote support.
* OSX: Media Keys support.
* Windows: Added WASAPI audio output.
* New OSD bar with chapter marks and not positioned in the middle of the video
(though this can be customized with the ``--osd-bar-align-y`` option).
@@ -99,7 +99,7 @@ General Changes for MPlayer to mpv
* 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
* OS X: VDA support using libavcodec hwaccel API instead of FFmpeg's decoder. Up
* 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`_)
+2 -2
View File
@@ -38,7 +38,7 @@ You can encode files from one format/codec to another using this facility.
``--oautofps``
Sets the output format time base to the guessed frame rate of the input
video (simulates MEncoder behavior, useful for AVI; may cause frame drops).
video (simulates mencoder behavior, useful for AVI; may cause frame drops).
Note that not all codecs and not all formats support VFR encoding, and some
which do have bugs when a target bitrate is specified - use ``--ofps`` or
``--oautofps`` to force CFR encoding in these cases.
@@ -74,7 +74,7 @@ You can encode files from one format/codec to another using this facility.
.. admonition:: Example
"``--oac=libmp3lame --oacopts=b=128000``"
selects 128 kbps MP3 encoding.
selects 128kbps MP3 encoding.
Options are managed in lists. There are a few commands to manage the
options list.
+21 -75
View File
@@ -114,7 +114,7 @@ List of Input Commands
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
post-processing that modifies timing of frames (e.g. deinterlacing) should
postprocessing that modifies timing of frames (e.g. deinterlacing) should
usually work, but might make backstepping silently behave incorrectly in
corner cases. Using ``--hr-seek-framedrop=no`` should help, although it
might make precise seeking slower.
@@ -159,9 +159,7 @@ List of Input Commands
Take a single screenshot.
<each-frame>
Take a screenshot each frame. Issue this command again to stop taking
screenshots. Note that you should disable frame-dropping when using
this mode - or you might receive duplicate images in cases when a
frame was dropped.
screenshots.
``screenshot_to_file "<filename>" [subtitles|video|window]``
Take a screenshot and save it to a given file. The format of the file will
@@ -260,7 +258,7 @@ List of Input Commands
exactly as in the ``quit`` command.
``sub_add "<file>"``
Load the given subtitle file. It is selected as current subtitle after
Load the given subtitle file. It is not selected as current subtitle after
loading.
``sub_remove [<id>]``
@@ -268,7 +266,7 @@ List of Input Commands
the current track. (Works on external subtitle files only.)
``sub_reload [<id>]``
Reload the given subtitle tracks. If the ``id`` argument is missing, reload
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.
@@ -327,12 +325,6 @@ List of Input Commands
Write the resume config file that the ``quit_watch_later`` command writes,
but continue playback normally.
``stop``
Stop playback and clear playlist. With default settings, this is
essentially like ``quit``. Useful for the client API: playback can be
stopped without terminating the player.
Input Commands that are Possibly Subject to Change
--------------------------------------------------
@@ -509,8 +501,8 @@ Input Commands that are Possibly Subject to Change
be used in input.conf to reassign such bindings.)
Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``get_property`` (?),
``vo_cmdline`` (experimental).
Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``stop`` (questionable
use), ``get_property`` (?), ``vo_cmdline`` (experimental).
Input Command Prefixes
----------------------
@@ -580,7 +572,7 @@ Property list
See ``--osd-level``.
``osd-scale`` (RW)
OSD font size multiplier, see ``--osd-scale``.
OSD font size multiplicator, see ``--osd-scale``.
``loop`` (RW)
See ``--loop``.
@@ -602,18 +594,6 @@ Property list
``${stream-end}``. For ordered chapters and such, the
size of the currently played segment is returned.)
``estimated-frame-count``
Total number of frames in current file.
.. note:: This is only an estimate. (It's computed from two unreliable
quantities: fps and stream length.)
``estimated-frame-number``
Number of current frame in current stream.
.. note:: This is only an estimate. (It's computed from two unreliable
quantities: fps and possibly rounded timestamps.)
``path``
Full path of the currently played file.
@@ -655,12 +635,8 @@ Property list
disabled.
``drop-frame-count``
Frames dropped because they arrived too late. Doesn't necessarily indicate
actual frame-drops, just the number of times the decoder was asked to drop.
Unavailable if video is disabled
``vo-drop-frame-count``
Frames dropped by VO (when using ``--framedrop=vo``).
Frames dropped because they arrived to late. Unavailable if video
is disabled
``percent-pos`` (RW)
Position in current file (0-100). The advantage over using this instead of
@@ -789,7 +765,7 @@ Property list
::
MPV_FORMAT_NODE_MAP
(key and string value for each metadata entry)
(key and string value for each metdata entry)
``chapter-metadata``
Metadata of current chapter. Works similar to ``metadata`` property. It
@@ -833,7 +809,7 @@ Property list
this easier, the cache resizing code will allocate the new cache while the
old cache is still allocated.
Don't use this when playing DVD or Blu-ray.
Don't use this when playing DVD or Bluray.
``cache-free`` (R)
Total free cache size in KB.
@@ -845,15 +821,6 @@ Property list
Returns ``yes`` if the cache is idle, which means the cache is filled as
much as possible, and is currently not reading more data.
``demuxer-cache-duration``
Approximate duration of video buffered in the demuxer, in seconds. The
guess is very unreliable, and often the property will not be available
at all, even if data is buffered.
``demuxer-cache-idle``
Returns ``yes`` if the demuxer is idle, which means the demuxer cache is
filled to the requested amount, and is currently not reading more data.
``paused-for-cache``
Returns ``yes`` when playback is paused because of waiting for the cache.
@@ -1040,17 +1007,13 @@ Property list
``dwidth``, ``dheight``
Video display size. This is the video size after filters and aspect scaling
have been applied. The actual video window size can still be different
from this, e.g. if the user resized the video window manually.
These have the same values as ``video-out-params/dw`` and
``video-out-params/dh``.
from this.
``video-out-params``
Same as ``video-params``, but after video filters have been applied. If
there are no video filters in use, this will contain the same values as
``video-params``. Note that this is still not necessarily what the video
window uses, since the user can change the window size, and all real VOs
do their own scaling independently from the filter chain.
window uses, since all real VOs do their own scaling.
Has the same sub-properties as ``video-params``.
@@ -1062,7 +1025,7 @@ Property list
Estimated/measured FPS of the video filter chain output. (If no filters
are used, this corresponds to decoder output.) This uses the average of
the 10 past frame durations to calculate the FPS. It will be inaccurate
if frame-dropping is involved (such as when framedrop is explicitly
if framedropping is involved (such as when framedrop is explicitly
enabled, or after precise seeking). Files with imprecise timestamps (such
as Matroska) might lead to unstable results.
@@ -1070,7 +1033,7 @@ Property list
Window size multiplier. Setting this will resize the video window to the
values contained in ``dwidth`` and ``dheight`` multiplied with the value
set with this property. Setting ``1`` will resize to original video size
(or to be exact, the size the video filters output). ``2`` will set the
(or to be exactly, the size the video filters output). ``2`` will set the
double size, ``0.5`` halves the size.
``video-aspect`` (RW)
@@ -1127,7 +1090,7 @@ Property list
See ``--sub-forced-only``.
``sub-scale`` (RW)
Subtitle font size multiplier.
Subtitle font size multiplicator.
``ass-use-margins`` (RW)
See ``--ass-use-margins``.
@@ -1271,6 +1234,11 @@ Property list
"title" MPV_FORMAT_STRING
"time" MPV_FORMAT_DOUBLE
``quvi-format`` (RW)
See ``--quvi-format``. Cycling this property (``cycle``) will attempt to
cycle through known format, although currently this feature doesn't work
well at all.
``af`` (RW)
See ``--af`` and the ``af`` command.
@@ -1296,28 +1264,6 @@ Property list
``seekable``
Return whether it's generally possible to seek in the current file.
``osd-sym-cc``
Inserts the current OSD symbol as opaque OSD control code (cc). This makes
sense only with the ``show_text`` command or options which set OSD messages.
The control code is implementation specific and is useless for anything else.
``osd-ass-cc``
``${osd-ass-cc/0}`` disables escaping ASS sequences of text in OSD,
``${osd-ass-cc/1}`` enables it again. By default, ASS sequences are
escaped to avoid accidental formatting, and this property can disable
this behavior. Note that the properties return an opaque OSD control
code, which only makes sense for the ``show_text`` command or options
which set OSD messages.
.. admonition:: Example
--osd-status-msg='This is ${osd-ass-cc/0}{\\b1}bold text'
Any ASS override tags as understood by libass can be used.
Note that you need to escape the ``\`` character, because the string is
processed for C escape sequences before passing it to the OSD code.
``options/<name>`` (RW)
Read-only access to value of option ``--<name>``. Most options can be
changed at runtime by writing to this property. Note that many options
+11 -29
View File
@@ -2,14 +2,9 @@ LUA SCRIPTING
=============
mpv can load Lua scripts. Scripts in ``~/.mpv/lua/`` will be loaded on program
start, or if passed to ``--lua``. mpv appends ``~/.mpv/lua`` to the end of
lua's path so you can import them too. Since it's added to the end, don't name
scripts you want to import the same as lua libraries because they will be
overshadowed by them.
mpv provides the built-in module ``mp``, which provides functions to send
commands to the mpv core and to retrieve information about playback state, user
settings, file information, and so on.
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.
@@ -52,15 +47,6 @@ The event loop will wait for events and dispatch events registered with
``mp.register_event``. It will also handle timers added with ``mp.add_timeout``
and similar (by waiting with a timeout).
Since mpv 0.6.0, the player will wait until the script is fully loaded before
continuing normal operation. The player considers a script as fully loaded as
soon as it starts waiting for mpv events (or it exits). In practice this means
the player will more or less hang until the script returns from the main chunk
(and ``mp_event_loop`` is called), or the script calls ``mp_event_loop`` or
``mp.dispatch_events`` directly. This is done to make it possible for a script
to fully setup event handlers etc. before playback actually starts. In older
mpv versions, this happened asynchronously.
mp functions
------------
@@ -112,9 +98,9 @@ The ``mp`` module is preloaded, although it can be loaded manually with
will always result in a string.
``mp.get_property_bool(name [,def])``
Similar to ``mp.get_property``, but return the property value as Boolean.
Similar to ``mp.get_property``, but return the property value as boolean.
Returns a Boolean on success, or ``def, error`` on error.
Returns a boolean on success, or ``def, error`` on error.
``mp.get_property_number(name [,def])``
Similar to ``mp.get_property``, but return the property value as number.
@@ -127,7 +113,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``mp.get_property_native(name [,def])``
Similar to ``mp.get_property``, but return the property value using the best
Lua type for the property. Most time, this will return a string, Boolean,
Lua type for the property. Most time, this will return a string, boolean,
or number. Some properties (for example ``chapter-list``) are returned as
tables.
@@ -142,7 +128,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``mp.set_property_bool(name, value)``
Similar to ``mp.set_property``, but set the given property to the given
Boolean value.
boolean value.
``mp.set_property_number(name, value)``
Similar to ``mp.set_property``, but set the given property to the given
@@ -177,7 +163,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
(e.g. ``ctrl+a``).
After calling this function, key presses will cause the function ``fn`` to
be called (unless the user remapped the key with another binding).
be called (unless the user overmapped the key with another binding).
The ``name`` argument should be a short symbolic string. It allows the user
to remap the key binding via input.conf using the ``script_message``
@@ -215,7 +201,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
This will print the message when the key ``y`` is pressed. (``x`` will
still work, unless the user remaps it.)
still work, unless the user overmaps it.)
You can also explicitly send a message to a named script only. Assume the
above script was using the filename ``fooscript.lua``:
@@ -329,7 +315,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
``oneshot`` (RW)
Whether the timer is periodic (``false``) or fires just once
(``true``). This value is used when the timer expires (but before
the timer callback function fn is run).
the timer calback function fn is run).
``mp.get_opt(key)``
@@ -391,7 +377,7 @@ are useful only in special situations.
control what the Lua script does (instead of being called by the default
event loop), you can set the global variable ``mp_event_loop`` to your
own function running the event loop. From your event loop, you should call
``mp.dispatch_events()`` to dequeue and dispatch mpv events.
``mp.dispatch_events()`` to unqueue and dispatch mpv events.
If the ``allow_wait`` parameter is set to ``true``, the function will block
until the next event is received or the next timer expires. Otherwise (and
@@ -500,10 +486,6 @@ 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.getcwd()``
Returns the directory that mpv was launched from. On error, ``nil, error``
is returned.
``utils.readdir(path [, filter])``
Enumerate all entries at the given path on the filesystem, and return them
as array. Each entry is a directory entry (without the path).
+5 -57
View File
@@ -73,7 +73,7 @@ p / SPACE
Step backward. Pressing once will pause, every consecutive press will
play one frame in reverse and then go into pause mode again.
q
q / ESC
Stop playing and quit.
Q
@@ -98,9 +98,6 @@ m
f
Toggle fullscreen (see also ``--fs``).
ESC
Exit fullscreen mode.
T
Toggle stay-on-top (see also ``--ontop``).
@@ -148,10 +145,6 @@ PGUP and PGDWN
"previous" will actually go to the beginning of the current chapter; see
``--chapter-seek-threshold``.
Shift+PGUP and Shift+PGDWN
Seek backward or forward by 10 minutes. (This used to be mapped to
PGUP/PGDWN without Shift.)
D
Activate/deactivate deinterlacer.
@@ -170,7 +163,7 @@ corresponding adjustment, or the software equalizer (``--vf=eq``).)
7 and 8
Adjust saturation.
(The following keys are valid only on OS X.)
(The following keys are valid only on OSX.)
command + 0
Resize video window to half its original size.
@@ -411,51 +404,6 @@ taking screenshots is handled by the VOs, and adding the screenshot filter will
break hardware decoding. (The filter may still be useful for taking screenshots
at a certain point within the video chain when using multiple video filters.)
TERMINAL STATUS LINE
====================
During playback, mpv shows the playback status on the terminal. It looks like
something like this:
``AV: 00:03:12 / 00:24:25 (13%) A-V: -0.000``
The status line can be overridden with the ``--term-status-msg`` option.
The following is a list of things that can show up in the status line. Input
properties, that can be used to get the same information manually, are also
listed.
- ``AV:`` or ``V:`` (video only) or ``A:`` (audio only)
- The current time position in ``HH:MM:SS`` format (``playback-time`` property)
- The total file duration (or ``00:00:00`` if unknown) (``length`` property)
- Playback speed, e.g. `` x2.0``. Only visible if the speed is not normal. This
is the user-requested speed, and not the actual speed (usually they should
be the same, unless playback is too slow). (``speed`` property.)
- Playback percentage, e.g. ``(13%)``. How much of the file has been played.
Normally calculated out of playback position and duration, but can fallback
to other methods (like byte position) if these are not available.
(``percent-pos`` property.)
- The audio/video sync as ``A-V: 0.000``. This is the difference between
audio and video time. Normally it should be 0 or close to 0. If it's growing,
it might indicate a playback problem. (``avsync`` property.)
- Total A/V sync change, e.g. ``ct: -0.417``. Normally invisible. Can show up
if there is audio "missing", or not enough frames can be dropped. Usually
this will indicate a problem. (``total-avsync-change`` property.)
- Encoding state in ``{...}``, only shown in encoding mode.
- Decoder-dropped video frames, e.g. ``SD: 2``. Shows up only if the count is
not 0. Normally should never show up, unless ``--framedrop`` is set to enable
this mode, and your CPU is too slow. (``drop-frame-count`` property.)
- VO-dropped video frames, e.g. ``D: 4``. Shows up only if the count is not 0.
Can grow if the video framerate is higher than that of the display, or if
video rendering is too slow. Also can be incremented on "hiccups" and when
the video frame couldn't be displayed on time. (``vo-drop-frame-count``
property.)
- Cache state, e.g. ``Cache: 2s+134KB``. Visible if the stream cache is enabled.
The first value shows the amount of video buffered in the demuxer in seconds,
the second value shows *additional* data buffered in the stream cache in
kilobytes. (``demuxer-cache-duration`` and ``cached-used`` properties.)
PROTOCOLS
=========
@@ -471,8 +419,8 @@ PROTOCOLS
Play a path from Samba share.
``bd://[title][/device]`` ``--bluray-device=PATH``
Play a Blu-Ray disc. Currently, this does not accept ISO files. Instead,
you must mount the ISO file as filesystem, and point ``--bluray-device``
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]``
@@ -724,7 +672,7 @@ Play only chapters 5, 6, 7:
Play only titles 5, 6, 7:
``mpv dvd://5-7``
Play a multi-angle DVD:
Play a multiangle DVD:
``mpv dvd://1 --dvd-angle=2``
Play from a different DVD device:
+107 -253
View File
@@ -198,22 +198,26 @@ Playback Control
(i.e. not with stdin, pipe, etc).
``--load-unsafe-playlists``
Load URLs from playlists which are considered unsafe (default: no). This
includes special protocols and anything that doesn't refer to normal files.
Local files and HTTP links on the other hand are always considered safe.
Normally, something like ``mpv playlist.m3u`` won't load the playlist. This
is because the playlist code is unsafe. (This is the same in all other
variations of MPlayer.)
Note that ``--playlist`` always loads all entries, so you use that instead
if you really have the need for this functionality.
See ``--playlist`` for details.
``--loop-file=<N|inf|no>``
Loop a single file N times. ``inf`` means forever, ``no`` means normal
playback. For compatibility, ``--loop-file`` and ``--loop-file=yes`` are
also accepted, and are the same as ``--loop-file=inf``.
Note: this option will allow opening playlists using the ``playlist``
special demuxer. The ``--playlist`` uses different code, and supports more
playlist formats than the playlist demuxer. This means that for now, the
``--playlist`` option should always be used if you intend to open playlists.
Background: the special demuxer contains newly written code, while the
``--playlist`` option uses the old MPlayer code. Adding support for more
playlist formats to the special demuxer is work in progress, and eventually
the old code should disappear.
The difference to ``--loop`` is that this doesn't loop the playlist, just
the file itself. If the playlist contains only a single file, the difference
between the two option is that this option performs a seek on loop, instead
of reloading the file.
``--loop-file``
Loop a single file. The difference to ``--loop=inf`` is that this doesn't
loop the playlist, just the file itself. If the playlist contains only a
single file, the difference between the two option is that this option
performs a seek on loop, instead of reloading the file.
``--ordered-chapters``, ``--no-ordered-chapters``
Enabled by default.
@@ -241,8 +245,8 @@ Playback Control
Without ``--hr-seek``, skipping will snap to keyframes.
Program Behavior
----------------
Program Behaviour
-----------------
``--help``
Show short summary of options.
@@ -328,7 +332,7 @@ Program Behavior
``--merge-files``
Pretend that all files passed to mpv are concatenated into a single, big
file. This uses timeline/EDL support internally. Note that this won't work
for ordered chapter files or quvi-resolved URLs (such as YouTube links).
for ordered chapter files or quvi-resolved URLs (such as youtube links).
This option is interpreted at program start, and doesn't affect for
example files or playlists loaded with the ``loadfile`` or ``loadlist``
@@ -426,45 +430,16 @@ Video
Do not sleep when outputting video frames. Useful for benchmarks when used
with ``--no-audio.``
``--framedrop=<mode>``
Skip displaying some frames to maintain A/V sync on slow systems, or
playing high framerate video on video outputs that have an upper framerate
limit.
``--framedrop=<no|yes>``
Skip displaying some frames to maintain A/V sync on slow systems. Video
filters are not applied to such frames. For B-frames even decoding is
skipped completely. May produce unwatchably choppy output.
The argument selects the drop methods, and can be one of the following:
<no>
Disable any framedropping.
<vo>
Drop late frames on video output (default). This still decodes and
filters all frames, but doesn't render them on the VO. It tries to query
the display FPS (X11 only, not correct on multi-monitor systems), or
assumes infinite display FPS if that fails. Drops are indicated in
the terminal status line as ``D:`` field. If the decoder is too slow,
in theory all frames would have to be dropped (because all frames are
too late) - to avoid this, frame dropping stops if the effective
framerate is below 10 FPS.
<decoder>
Old, decoder-based framedrop mode. (This is the same as ``--framedrop=yes``
in mpv 0.5.x and before.) This tells the decoder to skip frames (unless
they are needed to decode future frames). May help with slow systems,
but can produce unwatchably choppy output, or even freeze the display
complete. Not recommended.
The ``--vd-lavc-framedrop`` option controls what frames to drop.
<decoder+vo>
Enable both modes. Not recommended.
The ``--vd-lavc-framedrop`` option controls what frames to drop.
.. note::
``--vo=vdpau`` has its own code for the ``vo`` framedrop mode. Slight
differences to other VOs are possible.
``--display-fps=<fps>``
Set the maximum assumed display FPS used with ``--framedrop``. By default
a detected value is used (X11 only, not correct on multi-monitor systems),
or infinite display FPS if that fails. Infinite FPS means only frames too
late are dropped. If a correct FPS is provided, frames that are predicted
to be too late are dropped too.
Practical use of this feature is questionable. Disabled by default.
``--hwdec=<api>``
Specify the hardware video decoding API that should be used if possible.
@@ -478,7 +453,7 @@ Video
:vdpau: requires ``--vo=vdpau`` or ``--vo=opengl`` (Linux only)
:vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux with Intel GPUs only)
:vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only)
:vda: requires ``--vo=opengl`` (OS X only)
:vda: requires ``--vo=opengl`` or ``--vo=corevideo`` (OSX only)
``auto`` tries to automatically enable hardware decoding using the first
available method. This still depends what VO you are using. For example,
@@ -556,22 +531,6 @@ Video
which means the value ``0`` would rotate the video according to the
rotation metadata.)
``--video-stereo-mode=<mode>``
Set the stereo 3D output mode (default: ``mono``). This is done by inserting
the ``stereo3d`` conversion filter.
The mode ``mono`` is an alias to ``ml``, which refers to the left frame in
2D. This is the default, which means mpv will try to show 3D movies in 2D,
instead of the mangled 3D image not intended for consumption (such as
showing the left and right frame side by side, etc.).
The pseudo-mode ``none`` disables automatic conversion completely.
Use ``--video-stereo-mode=help`` to list all available modes. Check with
the ``stereo3d`` filter documentation to see what the names mean. Note that
some names refer to modes not supported by ``stereo3d`` - these modes can
appear in files, but can't be handled properly by mpv.
``--video-zoom=<value>``
Adjust the video display scale factor by the given value. The unit is in
fractions of the (scaled) window video size.
@@ -682,6 +641,11 @@ Video
The following explanations are relevant:
`<http://quvi.sourceforge.net/r/api/0.9/glossary_termino.html#m_stream_id>`_
The ``quvi-format`` property can be used at runtime to cycle through the
list of formats. Unfortunately, this is slow. On libquvi 0.4.x, this
functionality is limited to switching between ``best`` and ``default`` if
the ``cycle`` input command is used.
``--vd-lavc-check-hw-profile=<yes|no>``
Check hardware decoder profile (default: yes). If ``no`` is set, the
highest profile of the hardware decoder is unconditionally selected, and
@@ -786,7 +750,7 @@ Audio
.. admonition:: Examples
``--ad=lavc:mp3float``
Prefer the FFmpeg/Libav ``mp3float`` decoder over all other MP3
Prefer the FFmpeg/Libav ``mp3float`` decoder over all other mp3
decoders.
``--ad=spdif:ac3,lavc:*``
@@ -857,12 +821,12 @@ Audio
welcome. A full list of AVOptions can be found in the FFmpeg manual.
``--ad-spdif-dtshd=<yes|no>``, ``--dtshd``, ``--no-dtshd``
When using DTS pass-through, output any DTS-HD track as-is.
When using DTS passthrough, output any DTS-HD track as-is.
With ``ad-spdif-dtshd=no`` (the default), only the DTS Core parts will be
output.
DTS-HD tracks can be sent over HDMI but not over the original
coax/TOSLINK S/PDIF system.
coax/toslink S/PDIF system.
Some receivers don't accept DTS core-only when ``--ad-spdif-dtshd=yes`` is
used, even though they accept DTS-HD.
@@ -976,6 +940,10 @@ Audio
maximum amplification, i.e. amplify by 200%. The default volume (no
change in volume) will be ``50`` in this case.
``--volstep=<0-100>``
Set the step size of mixer volume changes in percent of the full range
(default: 3).
``--volume-restore-data=<string>``
Used internally for use by playback resume (e.g. with ``quit_watch_later``).
Restoring value has to be done carefully, because different AOs as well as
@@ -988,20 +956,6 @@ Audio
Do not use.
``--audio-buffer=<seconds>``
Set the audio output minimum buffer. The audio device might actually create
a larger buffer if it pleases. If the device creates a smaller buffer,
additional audio is buffered in an additional software buffer.
Making this larger will make soft-volume and other filters react slower,
introduce additional issues on playback speed change, and block the
player on audio format changes. A smaller buffer might lead to audio
dropouts.
This option should be used for testing only. If a non-default value helps
significantly, the mpv developers should be contacted.
Default: 0.2 (200 ms).
Subtitles
---------
@@ -1182,7 +1136,7 @@ Subtitles
``--ass-vsfilter-color-compat=<basic|full|force-601|no>``
Mangle colors like (xy-)vsfilter do (default: basic). Historically, VSFilter
was not color space aware. This was no problem as long as the color space
was not colorspace aware. This was no problem as long as the colorspace
used for SD video (BT.601) was used. But when everything switched to HD
(BT.709), VSFilter was still converting RGB colors to BT.601, rendered
them into the video frame, and handled the frame to the video output, which
@@ -1192,16 +1146,16 @@ Subtitles
:basic: Handle only BT.601->BT.709 mangling, if the subtitles seem to
indicate that this is required (default).
:full: Handle the full ``YCbCr Matrix`` header with all video color spaces
:full: Handle the full ``YCbCr Matrix`` header with all video colorspaces
supported by libass and mpv. This might lead to bad breakages in
corner cases and is not strictly needed for compatibility
(hopefully), which is why this is not default.
:force-601: Force BT.601->BT.709 mangling, regardless of subtitle headers
or video color space.
or video colorspace.
:no: Disable color mangling completely. All colors are RGB.
Choosing anything other than ``no`` will make the subtitle color depend on
the video color space, and it's for example in theory not possible to reuse
the video colorspace, and it's for example in theory not possible to reuse
a subtitle script with another video file. The ``--ass-style-override``
option doesn't affect how this option is interpreted.
@@ -1223,7 +1177,7 @@ Subtitles
Many studios tend to use bitmap fonts designed for square pixels when
authoring DVDs, causing the fonts to look stretched on playback on DVD
players. This option fixes them, however at the price of possibly
misaligning some subtitles (e.g. sign translations).
misaligning sume subtitles (e.g. sign translations).
Disabled by default.
@@ -1330,7 +1284,7 @@ Subtitles
Also see ``--sub-speed`` option.
``--sub-gauss=<0.0-3.0>``
Apply Gaussian blur to image subtitles (default: 0). This can help making
Apply gaussian blur to image subtitles (default: 0). This can help making
pixelated DVD/Vobsubs look nicer. A value other than 0 also switches to
software subtitle scaling. Might be slow.
@@ -1368,13 +1322,6 @@ Subtitles
Can be used to disable display of subtitles, but still select and decode
them.
``--sub-clear-on-seek``
(Obscure, rarely useful.) Can be used to play broken mkv files with
duplicate ReadOrder fields. ReadOrder is the first field in a
Matroska-style ASS subtitle packets. It should be unique, and libass
uses it for fast elimination of duplicates. This option disables caching
of subtitles across seeks, so after a seek libass can't eliminate subtitle
packets with the same ReadOrder as earlier packets.
Window
------
@@ -1410,7 +1357,7 @@ Window
``--fs-screen=<all|current|0-32>``
In multi-monitor configurations (i.e. a single desktop that spans across
multiple displays), this option tells mpv which screen to go fullscreen to.
If ``default`` is provided mpv will fallback on using the behavior
If ``default`` is provided mpv will fallback on using the behaviour
depending on what the user provided with the ``screen`` option.
.. admonition:: Note (X11)
@@ -1420,13 +1367,12 @@ Window
.. admonition:: Note (OS X)
``all`` does not work on OS X and will behave like ``current``.
``all`` does not work on OSX and will behave like ``current``.
See also ``--screen``.
``--keep-open``
Do not terminate when playing or seeking beyond the end of the file, and
there is not next file to be played (and ``--loop`` is not used).
Do not terminate when playing or seeking beyond the end of the file.
Instead, pause the player. When trying to seek beyond end of the file, the
player will pause at an arbitrary playback position (or, in corner cases,
not redraw the window at all).
@@ -1439,12 +1385,6 @@ Window
chapter will terminate playback as well, even if ``--keep-open`` is
given.
Since mpv 0.6.0, this doesn't pause if there is a next file in the playlist,
or the playlist is looped. Approximately, this will pause when the player
would normally exit, but in practice there are corner cases in which this
is not the case (e.g. ``mpv --keep-open file.mkv /dev/null`` will play
file.mkv normally, then fail to open ``/dev/null``, then exit).
``--force-window``
Create a video output window even if there is no video. This can be useful
when pretending that mpv is a GUI application. Currently, the window
@@ -1489,7 +1429,7 @@ Window
.. admonition: Note (OS X)
On Mac OS X the origin of the screen coordinate system is located on the
On Mac OSX the origin of the screen coordinate system is located on the
bottom-left corner. For instance, ``0:0`` will place the window at the
bottom-left of the screen.
@@ -1651,7 +1591,7 @@ Window
.. note::
This does not affect the normal screensaver operation in any way.
``--no-keepaspect``, ``--keepaspect``
``--no-keepaspect`` will always stretch the video to window size, and will
disable the window manager hints that force the window aspect ratio.
@@ -1866,7 +1806,7 @@ Equalizer
such as PC monitors use full range color levels. However, some TVs and
video monitors expect studio RGB levels. Providing full range output to a
device expecting studio level input results in crushed blacks and whites,
the reverse in dim gray blacks and dim whites.
the reverse in dim grey blacks and dim whites.
The same limitations as with ``--colormatrix`` apply.
@@ -2000,10 +1940,9 @@ Demuxer
``--demuxer-rawaudio-format=<value>``
Sample format for ``--demuxer=rawaudio`` (default: s16le).
Use ``--demuxer-rawaudio-format=help`` to get a list of all formats.
``--demuxer-rawaudio-rate=<value>``
Sample rate for ``--demuxer=rawaudio`` (default: 44 kHz).
Sample rate for ``--demuxer=rawaudio`` (default: 44KHz).
``--demuxer-rawvideo-fps=<value>``
Rate in frames per second for ``--demuxer=rawvideo`` (default: 25.0).
@@ -2019,11 +1958,11 @@ Demuxer
--demuxer-rawvideo=w=720:h=576
``--demuxer-rawvideo-format=<value>``
Color space (fourcc) in hex or string for ``--demuxer=rawvideo``
Colorspace (fourcc) in hex or string for ``--demuxer=rawvideo``
(default: ``YV12``).
``--demuxer-rawvideo-mp-format=<value>``
Color space by internal video format for ``--demuxer=rawvideo``. Use
Colorspace by internal video format for ``--demuxer=rawvideo``. Use
``--demuxer-rawvideo-mp-format=help`` for a list of possible formats.
``--demuxer-rawvideo-codec=<value>``
@@ -2036,25 +1975,13 @@ Demuxer
``--demuxer-thread=<yes|no>``
Run the demuxer in a separate thread, and let it prefetch a certain amount
of packets (default: yes). Having this enabled may lead to smoother
playback, but on the other hand can add delays to seeking or track
switching.
``--demuxer-readahead-secs=N``
If ``--demuxer-thread`` is enabled, this controls how much the demuxer
should buffer ahead in seconds (default: 0.2). As long as no packet has
a timestamp difference higher than the readahead amount relative to the
last packet returned to the decoder, the demuxer keeps reading.
(This value tends to be fuzzy, because many file formats don't store linear
timestamps.)
of packets (default: no).
``--demuxer-readahead-packets=N``
If ``--demuxer-thread`` is enabled, this controls how much the demuxer
should buffer ahead. As long as the number of packets in the packet queue
doesn't exceed ``--demuxer-readahead-packets``, and the total number of
bytes doesn't exceed ``--demuxer-readahead-bytes``, the thread keeps
reading ahead.
should buffer ahead. If the number of packets in the packet queue exceeds
``--demuxer-readahead-packets``, or the total number of bytes exceeds
``--demuxer-readahead-bytes``, the thread stops reading ahead.
Note that if you set these options near the maximum, you might get a
packet queue overflow warning.
@@ -2085,7 +2012,7 @@ Input
``~/.config/mpv/input.conf``.
``--no-input-default-bindings``
Disable mpv default (built-in) key bindings.
Disable mpv default (builtin) key bindings.
``--input-cmdlist``
Prints all commands that can be bound to keys.
@@ -2151,31 +2078,13 @@ Input
Specifies a configuration file for LIRC (default: ``~/.lircrc``).
``--input-media-keys``, ``--no-input-media-keys``
OS X only: Enabled by default. Enables/disable media keys support.
OSX only: Enabled by default. Enables/disable media keys support.
``--input-right-alt-gr``, ``--no-input-right-alt-gr``
(Cocoa and Windows only)
Use the right Alt key as Alt Gr to produce special characters. If disabled,
count the right Alt as an Alt modifier key. Enabled by default.
``--input-x11-keyboard=<yes|no>``
Disable all keyboard input on the X11 VO window. Generally useful for
embedding only.
On X11, a sub-window with input enabled grabs all keyboard input as long
as it is 1. a child of a focused window, and 2. the mouse is inside of
the sub-window. The can steal away all keyboard input from the
application embedding the mpv window, and on the other hand, the mpv
window will receive no input if the mouse is outside of the mpv window,
even though mpv has focus. Modern toolkits work around this weird X11
behavior, but naively embedding foreign windows breaks it.
The only way to handle this reasonably is using the XEmbed protocol, which
was designed to solve these problems. But Qt has questionable support, and
mpv doesn't implement it yet.
As a workaround, this option is disabled by default in libmpv. (Note that
``input-default-bindings`` is disabled by default in libmpv as well.)
OSD
---
@@ -2217,26 +2126,6 @@ OSD
Default: 45.
``--osd-msg1=<string>``
Show this string as message on OSD with OSD level 1 (visible by default).
The message will be visible by default, and as long no other message
covers it, and the OSD level isn't changed (see ``--osd-level``).
Expands properties; see `Property Expansion`_.
``--osd-msg2=<string>``
Similar as ``--osd-msg1``, but for OSD level 2. If this is an empty string
(default), then the playback time is shown.
``--osd-msg3=<string>``
Similar as ``--osd-msg1``, but for OSD level 3. If this is an empty string
(default), then the playback time, duration, and some more information is
shown.
This is also used for the ``show_progress`` command (by default mapped to
``P``), or in some non-default cases when seeking.
``--osd-status-msg`` is a legacy equivalent (but with a minor difference).
``--osd-status-msg=<string>``
Show a custom string during playback instead of the standard status text.
This overrides the status text used for ``--osd-level=3``, when using the
@@ -2244,17 +2133,6 @@ OSD
non-default cases when seeking. Expands properties. See
`Property Expansion`_.
This option has been replaced with ``--osd-msg3``. The only difference is
that this option implicitly includes ``${osd-sym-cc}``. This option is
ignored if ``--osd-msg3`` is not empty.
``--osd-playing-msg=<string>``
Show a message on OSD when playback starts. The string is expanded for
properties, e.g. ``--osd-playing-msg='file: ${filename}'`` will show the
message ``file:`` followed by a space and the currently played filename.
See `Property Expansion`_.
``--osd-bar-align-x=<-1-1>``
Position of the OSD bar. -1 is far left, 0 is centered, 1 is far right.
Fractional values (like 0.5) are allowed.
@@ -2350,7 +2228,7 @@ OSD
Default: 10.
``--osd-scale=<factor>``
OSD font size multiplier, multiplied with ``--osd-font-size`` value.
OSD font size multiplicator, multiplied with ``--osd-font-size`` value.
``--osd-scale-by-window=yes|no``
Whether to scale the OSD with the window size (default: yes). If this is
@@ -2394,7 +2272,7 @@ Screenshot
``--screenshot-template=<template>``
Specify the filename template used to save screenshots. The template
specifies the filename without file extension, and can contain format
specifiers, which will be substituted when taking a screenshot.
specifiers, which will be substituted when taking a screeshot.
By default the template is ``shot%n``, which results in filenames like
``shot0012.png`` for example.
@@ -2507,10 +2385,10 @@ Software Scaler
Default: ``bicubic``.
``--sws-lgb=<0-100>``
Software scaler Gaussian blur filter (luma). See ``--sws-scaler``.
Software scaler gaussian blur filter (luma). See ``--sws-scaler``.
``--sws-cgb=<0-100>``
Software scaler Gaussian blur filter (chroma). See ``--sws-scaler``.
Software scaler gaussian blur filter (chroma). See ``--sws-scaler``.
``--sws-ls=<-100-100>``
Software scaler sharpen filter (luma). See ``--sws-scaler``.
@@ -2589,7 +2467,7 @@ Terminal
``--term-osd-bar-chars=<string>``
Customize the ``--term-osd-bar`` feature. The string is expected to
consist of 5 characters (start, left space, position indicator,
right space, end). You can use Unicode characters, but note that double-
right space, end). You can use unicode characters, but note that double-
width characters will not be treated correctly.
Default: ``[-+-]``.
@@ -2806,7 +2684,7 @@ Cache
May be useful when playing files from slow media, but can also have
negative effects, especially with file formats that require a lot of
seeking, such as MP4.
seeking, such as mp4.
Note that half the cache size will be used to allow fast seeking back. This
is also the reason why a full cache is usually reported as 50% full. The
@@ -2819,6 +2697,20 @@ Cache
will not automatically enable the cache e.g. when playing from a network
stream. Note that using ``--cache`` will always override this option.
``--cache-pause-below=<kBytes|no>``
If the cache size goes below the specified value (in KB), pause and wait
until the size set by ``--cache-pause-restart`` is reached, then resume
playback (default: 50). If ``no`` is specified, this behavior is disabled.
When the player is paused this way, the status line shows ``Buffering``
instead of ``Paused``, and the OSD uses a clock symbol instead of the
normal paused symbol.
``--cache-pause-restart=<kBytes>``
If the cache is paused due to the ``--cache-pause-below`` functionality,
then the player unpauses as soon as the cache has this much data (in KB).
(Default: 100)
``--cache-initial=<kBytes>``
Playback will start when the cache has been filled up with this many
kilobytes of data (default: 0).
@@ -2829,46 +2721,28 @@ Cache
filled to this position rather than performing a stream seek (default:
500).
This matters for small forward seeks. With slow streams (especially HTTP
This matters for small forward seeks. With slow streams (especially http
streams) there is a tradeoff between skipping the data between current
position and seek destination, or performing an actual seek. Depending
on the situation, either of these might be slower than the other method.
This option allows control over this.
``--cache-file=<TMP|path>``
Create a cache file on the filesystem.
``--cache-file=<path>``
Create a cache file on the filesystem with the given name. The file is
always overwritten. When the general cache is enabled, this file cache
will be used to store whatever is read from the source stream.
There are two ways of using this:
This will always overwrite the cache file, and you can't use an existing
cache file to resume playback of a stream. (Technically, mpv wouldn't
even know which blocks in the file are valid and which not.)
1. Passing a path (a filename). The file will always be overwritten. When
the general cache is enabled, this file cache will be used to store
whatever is read from the source stream.
The resulting file will not necessarily contain all data of the source
stream. For example, if you seek, the parts that were skipped over are
never read and consequently are not written to the cache. The skipped over
parts are filled with zeros. This means that the cache file doesn't
necessarily correspond to a full download of the source stream.
This will always overwrite the cache file, and you can't use an existing
cache file to resume playback of a stream. (Technically, mpv wouldn't
even know which blocks in the file are valid and which not.)
The resulting file will not necessarily contain all data of the source
stream. For example, if you seek, the parts that were skipped over are
never read and consequently are not written to the cache. The skipped over
parts are filled with zeros. This means that the cache file doesn't
necessarily correspond to a full download of the source stream.
Both of these issues could be improved if there is any user interest.
.. warning:: Causes random corruption when used with ordered chapters or
with ``--audio-file``.
2. Passing the string ``TMP``. This will not be interpreted as filename.
Instead, an invisible temporary file is created. It depends on your
C library where this file is created (usually ``/tmp/``), and whether
filename is visible (the ``tmpfile()`` function is used). On some
systems, automatic deletion of the cache file might not be guaranteed.
If you want to use a file cache, this mode is recommended, because it
doesn't break ordered chapters or ``--audio-file``. These modes open
multiple cache streams, and using the same file for them obviously
clashes.
Both of these issues could be improved if there is any user interest.
Also see ``--cache-file-size``.
@@ -2876,24 +2750,11 @@ Cache
Maximum size of the file created with ``--cache-file``. For read accesses
above this size, the cache is simply not used.
Keep in mind that some use-cases, like playing ordered chapters with cache
enabled, will actually create multiple cache files, each of which will
use up to this much disk space.
(Default: 1048576, 1 GB.)
``--no-cache``
Turn off input stream caching. See ``--cache``.
``--cache-secs=<seconds>``
How many seconds of audio/video to prefetch if the cache is active. This
overrides the ``--demuxer-readahead-secs`` option if and only if the cache
is enabled. (Default: 2.)
``--cache-pause``, ``--no-cache-pause``
Whether the player should automatically pause when the cache runs low,
and unpause once more data is available ("buffering").
Network
-------
@@ -2902,9 +2763,11 @@ Network
Use ``<string>`` as user agent for HTTP streaming.
``--cookies``, ``--no-cookies``
(network only)
Support cookies when making HTTP requests. Disabled by default.
``--cookies-file=<filename>``
(network only)
Read HTTP cookies from <filename>. The file is assumed to be in Netscape
format.
@@ -2930,11 +2793,11 @@ Network
``--tls-ca-file=<filename>``
Certificate authority database file for use with TLS. (Silently fails with
older FFmpeg or Libav versions.)
older ffmpeg or libav versions.)
``--tls-verify``
Verify peer certificates when using TLS (e.g. with ``https://...``).
(Silently fails with older FFmpeg or Libav versions.)
(Silently fails with older ffmpeg or libav versions.)
``--referrer=<string>``
Specify a referrer path or URL for HTTP requests.
@@ -2944,17 +2807,6 @@ Network
network transport when playing ``rtsp://...`` URLs. The value ``lavf``
leaves the decision to libavformat.
``--hls-bitrate=<no|min|max>``
If HLS streams are played, this option controls what streams are selected
by default. The option allows the following parameters:
:no: Don't do anything special. Typically, this will simply pick the
first audio/video streams it can find. (Default.)
:min: Pick the streams with the lowest bitrate.
:max: Same, but highest bitrate.
The bitrate as used is sent by the server, and there's no guarantee it's
actually meaningful.
DVB
---
@@ -3013,8 +2865,8 @@ PVR
``--pvr-vmode=<value>``
Specify video encoding mode:
:vbr: Variable Bit Rate (default)
:cbr: Constant Bit Rate
:vbr: Variable BitRate (default)
:cbr: Constant BitRate
``--pvr-vpeak=<value>``
Specify peak video bitrate encoding in Mbps (only useful for VBR
@@ -3089,11 +2941,6 @@ Miscellaneous
You can also try to use ``--no-correct-pts`` for files with completely
broken timestamps.
``--media-title=<string>``
Force the contents of the ``media-title`` property to this value. Useful
for scripts which want to set a title, without overriding the user's
setting in ``--title``.
``--slave-broken``
Switches on the old slave mode. This is for testing only, and incompatible
to the removed ``--slave`` switch.
@@ -3111,3 +2958,10 @@ Miscellaneous
if there is enough interest).
This affects most third-party GUI frontends.
``--softsleep``
Time frames by repeatedly checking the current time instead of asking
the kernel to wake up mpv at the correct time. Useful if your kernel
timing is imprecise and you cannot use the RTC either. Comes at the
price of higher CPU consumption.
+4 -4
View File
@@ -122,11 +122,11 @@ time remaining
left-click toggle between total and remaining time
============= ================================================
Key Bindings
~~~~~~~~~~~~
Keybindings
~~~~~~~~~~~
These key bindings are active by default if nothing else is already bound to
these keys. In case of collision, the function needs to be bound to a
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.
============= ================================================
+21 -27
View File
@@ -93,7 +93,7 @@ Available filters are:
``scale[=w:h:param:param2:chr-drop:noup:arnd``
Scales the image with the software scaler (slow) and performs a YUV<->RGB
color space conversion (see also ``--sws``).
colorspace conversion (see also ``--sws``).
All parameters are optional.
@@ -120,9 +120,9 @@ Available filters are:
0.33:0.33 Mitchell-Netravali spline
1.00:0.00 cubic B-spline
--sws=7 (Gaussian): sharpness (0 (soft) - 100 (sharp))
--sws=7 (gaussian): sharpness (0 (soft) - 100 (sharp))
--sws=9 (Lanczos): filter length (1-10)
--sws=9 (lanczos): filter length (1-10)
``<chr-drop>``
chroma skipping
@@ -222,8 +222,8 @@ Available filters are:
====================== =====================
``noformat[=fmt]``
Restricts the color space for the next filter without doing any conversion.
Unlike the format filter, this will allow any color space except the one
Restricts the colorspace for the next filter without doing any conversion.
Unlike the format filter, this will allow any colorspace except the one
you specify.
.. note:: For a list of available formats, see ``noformat=fmt=help``.
@@ -231,23 +231,12 @@ Available filters are:
``<fmt>``
Format name, e.g. rgb15, bgr24, 420p, etc. (default: 420p).
``pp=[filter string]``
Enables the specified chain of post-processing subfilters. Subfilters must
``pp[=[filter1[:option1[:option2...]]/[-]filter2...]]``
Enables the specified chain of postprocessing subfilters. Subfilters must
be separated by '/' and can be disabled by prepending a '-'. Each
subfilter and some options have a short and a long name that can be used
interchangeably, i.e. ``dr``/``dering`` are the same.
.. note::
Unlike in MPlayer or in earlier versions, you must quote the pp string
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
.. admonition:: Warning
This filter is most likely useless on modern HD video. It might be
helpful with old low-resolution files.
All subfilters share common options to determine their scope:
interchangeably, i.e. ``dr``/``dering`` are the same. All subfilters share
common options to determine their scope:
``a/autoq``
Automatically switch the subfilter off if the CPU is too slow.
@@ -262,6 +251,11 @@ Available filters are:
``--vf=pp:help`` shows a list of available subfilters.
.. note::
Unlike in MPlayer or in earlier versions, you must quote the pp string
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
Available subfilters are:
``hb/hdeblock[:difference[:flatness]]``
@@ -342,7 +336,7 @@ Available filters are:
filtering every second line with a (-1 4 2 4 -1) filter.
``l5/lowpass5``
Vertically applied FIR low-pass deinterlacing filter that deinterlaces
Vertically applied FIR lowpass deinterlacing filter that deinterlaces
the given block by filtering all lines with a (-1 2 6 2 -1) filter.
``fq/forceQuant[:quantizer]``
@@ -362,7 +356,7 @@ Available filters are:
.. note::
This filter is only available if FFmpeg/Libav has been compiled
This filter is only available if FFmpeg/libav has been compiled
with libpostproc enabled.
.. admonition:: Examples
@@ -449,7 +443,7 @@ Available filters are:
temporal noise (noise pattern changes between frames)
``uniform``
uniform noise (Gaussian otherwise)
uniform noise (gaussian otherwise)
``hq``
high quality (slightly better looking, slightly slower) - not available
@@ -509,7 +503,7 @@ Available filters are:
:1: linear interpolation (default)
``unsharp[=lx:ly:la:cx:cy:ca]``
unsharp mask / Gaussian blur
unsharp mask / gaussian blur
``l`` is for the luma component, ``c`` for the chroma component. ``x``/``y``
is the filter size. ``a`` is the amount.
@@ -775,8 +769,8 @@ Available filters are:
anaglyph red/cyan color (red filter on left eye, cyan filter on
right eye)
``arcd`` or ``anaglyph_red_cyan_dubois``
anaglyph red/cyan color optimized with the least-squares
projection of Dubois (red filter on left eye, cyan filter on right
anaglyph red/cyan color optimized with the least squares
projection of dubois (red filter on left eye, cyan filter on right
eye)
``agmg`` or ``anaglyph_green_magenta_gray``
anaglyph green/magenta gray (green filter on left eye, magenta
@@ -809,7 +803,7 @@ Available filters are:
``gradfun[=strength[:radius|:size=<size>]]``
Fix the banding artifacts that are sometimes introduced into nearly flat
regions by truncation to 8-bit color depth. Interpolates the gradients that
regions by truncation to 8bit color depth. Interpolates the gradients that
should go where the bands are, and dithers them.
``<strength>``
+31 -59
View File
@@ -38,36 +38,36 @@ Available video output drivers are:
.. note:: This driver is for compatibility with old systems.
``adaptor=<number>``
Select a specific XVideo adapter (check xvinfo results).
Select a specific XVideo adaptor (check xvinfo results).
``port=<number>``
Select a specific XVideo port.
``ck=<cur|use|set>``
Select the source from which the color key is taken (default: cur).
Select the source from which the colorkey is taken (default: cur).
cur
The default takes the color key currently set in Xv.
The default takes the colorkey currently set in Xv.
use
Use but do not set the color key from mpv (use the ``--colorkey``
Use but do not set the colorkey from mpv (use the ``--colorkey``
option to change it).
set
Same as use but also sets the supplied color key.
Same as use but also sets the supplied colorkey.
``ck-method=<man|bg|auto>``
Sets the color key drawing method (default: man).
Sets the colorkey drawing method (default: man).
man
Draw the color key manually (reduces flicker in some cases).
Draw the colorkey manually (reduces flicker in some cases).
bg
Set the color key as window background.
Set the colorkey as window background.
auto
Let Xv draw the color key.
Let Xv draw the colorkey.
``colorkey=<number>``
Changes the color key to an RGB value of your choice. ``0x000000`` is
Changes the colorkey to an RGB value of your choice. ``0x000000`` is
black and ``0xffffff`` is white.
``no-colorkey``
Disables color-keying.
Disables colorkeying.
``x11`` (X11 only)
Shared memory video output driver without hardware acceleration that works
@@ -82,7 +82,7 @@ Available video output drivers are:
.. note::
Earlier versions of mpv (and MPlayer, mplayer2) provided sub-options
to tune vdpau post-processing, like ``deint``, ``sharpen``, ``denoise``,
to tune vdpau postprocessing, like ``deint``, ``sharpen``, ``denoise``,
``chroma-deint``, ``pullup``, ``hqscaling``. These sub-options are
deprecated, and you should use the ``vdpaupp`` video filter instead.
@@ -173,7 +173,7 @@ Available video output drivers are:
to a YUV format before the VO. Sometimes useful to force availability
of certain YUV-only features, like video equalizer or deinterlacing.
Using the VDPAU frame queuing functionality controlled by the queuetime
Using the VDPAU frame queueing functionality controlled by the queuetime
options makes mpv's frame flip timing less sensitive to system CPU load and
allows mpv to start decoding the next frame(s) slightly earlier, which can
reduce jitter caused by individual slow-to-decode frames. However, the
@@ -259,6 +259,13 @@ Available video output drivers are:
.. 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.
@@ -275,7 +282,7 @@ Available video output drivers are:
Hardware decoding over OpenGL-interop is supported to some degree. Note
that in this mode, some corner case might not be gracefully handled, and
color space conversion and chroma upsampling is generally in the hand of
colorspace conversion and chroma upsampling is generally in the hand of
the hardware decoder APIs.
``lscale=<filter>``
@@ -290,9 +297,6 @@ Available video output drivers are:
``lanczos3``
Lanczos with radius=3.
``lanczos``
Generic Lanczos scaling filter. Set radius with ``lradius``.
``spline36``
This is the default when using ``opengl-hq``.
@@ -312,14 +316,6 @@ Available video output drivers are:
Mitchell-Netravali. The ``b`` and ``c`` parameters can be set with
``lparam1`` and ``lparam2``. Both are set to 1/3 by default.
``gaussian``
Gaussian filter with a parameter ``p`` for sharpness control.
``p`` can be set to float number between 1(blurry) and 100(sharp)
and has a default value of about 28.8 (see ``lparam1``).
Note that for extremely small value of ``p``, a large filter radius
might be required to avoid unintended artifacts (see ``lradius``).
There are some more filters. For a complete list, pass ``help`` as
value, e.g.::
@@ -333,16 +329,6 @@ Available video output drivers are:
``lparam2=<value>``
See ``lparam1``.
``lradius=<r>``
Set radius for filters listed below, must be a float number between 1.0
and 8.0. Defaults to be 2.0 if not specified.
``sinc``, ``lanczos``, ``blackman``, ``gaussian``
Note that depending on filter implementation details and video scaling
ratio, the radius that actually being used might be different
(most likely being increased a bit).
``scaler-resizes-only``
Disable the scaler if the video image is not resized. In that case,
``bilinear`` is used instead whatever is set with ``lscale``. Bilinear
@@ -363,7 +349,7 @@ Available video output drivers are:
green-magenta
Convert side by side input to full-color green-magenta stereo.
quadbuffer
Convert side by side input to quad buffered stereo. Only supported
Convert side by side input to quadbuffered stereo. Only supported
by very few OpenGL cards.
``srgb``
@@ -444,11 +430,6 @@ Available video output drivers are:
RGB. If chroma is not subsampled, this option is ignored, and the
luma scaler is used instead. Setting this option is often useless.
``cparam1``, ``cparam2``, ``cradius``
Set filter parameters and radius for ``cscale``.
See ``lparam1``, ``lparam2`` and ``lradius``.
``fancy-downscaling``
When using convolution based filters, extend the filter size
when downscaling. Trades quality for reduced downscaling performance.
@@ -458,16 +439,7 @@ Available video output drivers are:
Borders will be distorted due to filtering.
``glfinish``
Call ``glFinish()`` before and after swapping buffers (default: disabled).
Slower, but might help getting better results when doing framedropping.
The details depend entirely on the OpenGL driver.
``waitvsync``
Call ``glXWaitVideoSyncSGI`` after each buffer swap (default: disabled).
This may or may not help with video timing accuracy and frame drop. It's
possible that this makes video output slower, or has no effect at all.
X11 only.
Call ``glFinish()`` before swapping buffers
``sw``
Continue even if a software renderer is detected.
@@ -480,7 +452,7 @@ Available video output drivers are:
auto
auto-select (default)
cocoa
Cocoa/OS X
Cocoa/OSX
win
Win32/WGL
x11
@@ -507,7 +479,7 @@ Available video output drivers are:
``gamma=<0.0..10.0>``
Set a gamma value. If gamma is adjusted in other ways (like with
the ``--gamma`` option or key bindings and the ``gamma`` property), the
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.
@@ -515,7 +487,7 @@ Available video output drivers are:
``icc-profile=<file>``
Load an ICC profile and use it to transform linear RGB to screen output.
Needs LittleCMS 2 support compiled in. This option overrides the ``srgb``
Needs LittleCMS2 support compiled in. This option overrides the ``srgb``
property, as using both is somewhat redundant. It also enables linear
light scaling.
@@ -528,12 +500,12 @@ Available video output drivers are:
``icc-cache=<file>``
Store and load the 3D LUT created from the ICC profile in this file.
This can be used to speed up loading, since LittleCMS 2 can take a while
This can be used to speed up loading, since LittleCMS2 can take a while
to create the 3D LUT. Note that this file contains an uncompressed LUT.
Its size depends on the ``3dlut-size``, and can be very big.
``icc-intent=<value>``
Specifies the ICC Intent used for transformations between color spaces.
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.
@@ -599,7 +571,7 @@ Available video output drivers are:
can achieve better quality or performance by changing the ``fbo-format``
suboption to ``rgb16f``, ``rgb32f`` or ``rgb``. Known problems include
Mesa/Intel not accepting ``rgb16``, Mesa sometimes not being compiled with
float texture support, and some OS X setups being very slow with ``rgb16``
float texture support, and some OSX setups being very slow with ``rgb16``
but fast with ``rgb32f``.
``opengl-old``
@@ -734,7 +706,7 @@ Available video output drivers are:
2
Convert side by side input to full-color green-magenta stereo.
3
Convert side by side input to quad buffered stereo. Only supported
Convert side by side input to quadbuffered stereo. Only supported
by very few OpenGL cards.
The following options are only useful if writing your own fragment programs.
@@ -776,7 +748,7 @@ Available video output drivers are:
auto
auto-select (default)
cocoa
Cocoa/OS X
Cocoa/OSX
win
Win32/WGL
x11
+17 -35
View File
@@ -1,4 +1,4 @@
This file intends to give a big picture overview of how mpv is structured.
This file intends to give a big picture of how mpv is structured.
player/*.c:
Essentially makes up the player applications, including the main() function
@@ -31,28 +31,15 @@ player/*.c:
* loop, or exit if no next file or quit is requested
(see enum stop_play_reason)
* call exit_player_with_rc()
* run_playloop():
* calls fill_audio_out_buffers()
This checks whether new audio needs to be decoded, and pushes it
to the AO.
* calls write_video()
Decode new video, and push it to the VO.
* determines whether playback of the current file has ended
* determines when to start playback after seeks
* and calls a whole lot of other stuff
(Really, this function does everything.)
Things worth saying about the playback core:
- most state is in MPContext (core.h), which is not available to the
subsystems
- the currently played tracks are in mpctx->current_tracks, and decoder
state in d_video/d_audio/d_sub
- the currently played tracks are in sh_video and sh_audio
- the timeline stuff is used only with MKV ordered chapters (and some other
minor features: cue, edl)
- most state is in MPContext (mp_core.h), which is not available to the
subsystems
- the other subsystems rarely call back into the frontend, and the frontend
polls them instead (probably a good thing)
- one exceptions are wakeup callbacks, which notify a "higher" component
of a changed situation in a subsystem
I like to call the player/*.c files the "frontend".
@@ -116,7 +103,7 @@ options/options.h, options/options.c
options.c. Most default values for options and MPOpts are in
mp_default_opts at the end of options.c.
MPOpts is unfortunately quite monolithic, and virtually accessed by
MPOpts is unfortunarely quite monolithic, and virtually accessed by
everything.But some components (like video outputs and video filters) have
their own sub-option tables separate from MPOpts.
@@ -124,7 +111,7 @@ options/options.h, options/options.c
parser-mpcmd.c, and uses the option table in options.c.
input/input.c:
This translates keyboard input comming from VOs and other sources (such
This translates keyboard input comming from libvo and other sources (such
as remote control devices like Apple IR or client API 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
@@ -135,7 +122,7 @@ input/input.c:
of input commands somewhere else.
common/msg.h:
All terminal output must go through mp_msg().
All terminal output should go through mp_msg().
stream/*:
File input is implemented here. stream.h/.c provides a simple stream based
@@ -194,7 +181,7 @@ video/out/:
vo_opengl can pick a windowing system at runtime, e.g. the same binary can
provide both X11 and Cocoa support on OSX.
VOs can be reconfigured at runtime. A vo_config() call can change the video
VOs can be reconfigured at runtime. A config() call can change the video
resolution and format, without destroying the window.
vo_vdpau and vo_opengl should be taken as reference.
@@ -216,12 +203,9 @@ audio/filter/:
audio/out/:
Audio outputs.
Unlike VOs, AOs can't be reconfigured on a format change. On audio format
changes, the AO will simply be closed and re-opened.
There are wrappers to support for two types of audio APIs: push.c and
pull.c. ao.c calls into one of these. They contain generic code to deal
with the data flow these APIs impose.
Unlike VOs, AOs can't be reconfigured on a format change. Without
--gapless-audio, even playing a new file will close and re-open the audio
device.
Note that mpv synchronizes the video to the audio. That's the reason
why buggy audio drivers can have a bad influence on playback quality.
@@ -234,14 +218,12 @@ sub/:
the OSD text renderer (which uses libass, and takes care of all the tricky
fontconfig/freetype API usage and text layouting).
The VOs call osd.c to render OSD and subtitle (via e.g. osd_draw()). osd.c
in turn asks dec_sub.c for subtitle overlay bitmaps, which relays the
request to one of the sd_*.c subtitle decoders/renderers.
Subtitle loading is in demux/. The MPlayer subreader.c is mostly gone - parts
of it survive in demux_subreader.c. It's used as last fallback, or to handle
some text subtitle types on Libav. It should go away eventually. Normally,
subtitles are loaded via demux_lavf.c.
Subtitle loading is now in demux/ instead. demux_libass.c wraps loading
.ass subtitles via libass. demux_lavf.c loads most subtitle types via
FFmpeg. demux_subreader.c is the old MPlayer code. It's used as last
fallback, or to handle some text subtitle types on Libav. (It also can
load UTF-16 encoded subtitles without requiring the use of -sub-codepage.)
demux_subreader.c should eventually go away (maybe).
The subtitles are passed to dec_sub.c and the subtitle decoders in sd_*.c
as they are demuxed. All text subtitles are rendered by sd_ass.c. If text
+102 -56
View File
@@ -1,68 +1,114 @@
Release 0.6.0
Release 0.5.1
=============
Changes
-------
- Map ESC to exiting fullscreen.
- Run the vo inside its own thread.
- Enable the demuxer thread by default.
- Prefer the opengl vo over the vdpau one.
- Complete profile names in the zsh completion script.
- Raise dsound ao buffer size to 200ms and make it configurable.
- Bind ctrl+c to quit, so that it works both in the terminal and the player
window.
- Automatically load playlists without needing --load-unsafe-playlists or
--playlist. Unsafe URLs are still rejected (e.g. remote playlists can't load
local files).
- Remove quvi-format property (which never really worked).
- Wait until all Lua scripts are loaded on start.
- Use separate threads for input sources (terminal, lirc, joystick) instead of
using a central I/O loop.
- Complete values for options that take file names in the zsh completion script.
- Use libwaio for pipe input on Windows (if you want --input-file to work on
Windows you need libwaio as an additional dependency).
- Remove the --volstep option (users should change the argument to the "add"
function in input.conf instead).
- Always show the OSD message when changing volume, gamma, panscan, etc along
with the OSD bar.
- When changing a property always show it on the OSD (except for "pause" and
"fullscreen").
- Prefer the libavcodec decoder over libmpg123 for mp3 decoding (ffmpeg/libav
support for gapless audio works better for mpv's use-case).
- Allow passing number of loops to --loop-file.
- Change --keep-open option semantics to not terminate the player when playing
or seeking past the end of the file and there's no next file to be played.
- Disable the sndio ao by default and prefer other outputs even if it's enabled.
- 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
------------
- Add new framedrop mode that limits the frequency of new video frames displayed
based on the display framerate (this is enabled by default, the old
decoder-based mode can be enabled with --framedrop=decoder).
- Add --demuxer-readahead-secs option to control the readahead buffer using a
duration value.
- Add estimated-frame-count and estimated-frame-number properties.
- Add --cache-secs option which overrides the value of --demuxer-readahead-secs
if the stream cache is active.
- Add demuxer-cache-duration and demuxer-cache-idle properties.
- Make --cache-file create a temporary file if the string "TMP" is passed
instead of a file name.
- Add support for Matroska 3D (if a file is marked as 3D using the StereoMode
element, an automatic conversion filter is added).
- Add --osd-playing-msg option to show a message on the OSD when the playback
starts.
- Add --media-title option to force the content of the media-title property.
- Add --osd-msg1, --osd-msg2 and --osd-msg3 options to override the OSD message
for the corresponding OSD level (before only level 3 could be overridden with
--osd-status-message).
- Add support for digital passthrough in the pulse ao.
- Add support for opening DVD and Bluray directories directly.
- Add --input-x11-keyboard option to control whether keyboard input should be
enabled on the X11 window ot not (this is disabled by default when using the
libmpv library).
- 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 a1be3cf..61ebe61`` in
complete change log can be viewed by running ``git log cb250d4..52f2f67`` in
the git repository.
+2 -2
View File
@@ -5,8 +5,8 @@
conv() {
echo
identify -format "icon: %w %h" "$1"
convert "$1" -depth 8 rgba:-
identify -format "icon: %w %h" $1
convert $1 -depth 8 rgba:-
}
(echo "# File generated by gen-x11-icon.sh" ;
+53 -54
View File
@@ -1,15 +1,23 @@
#!/bin/sh
: "${MPV:=mpv}"
: "${ILDETECT_MPV:=$MPV}"
: "${ILDETECT_MPVFLAGS:=--start=35% --length=35}"
: "${ILDETECT_DRY_RUN:=}"
: "${ILDETECT_QUIET:=}"
: "${ILDETECT_RUN_INTERLACED_ONLY:=}"
: "${ILDETECT_FORCE_RUN:=}"
case "$0" in
*/*)
MYDIR=${0%/*}
;;
*)
MYDIR=.
;;
esac
# This script uses ffmpeg's "idet" filter for interlace detection. In the
# long run this should replace ildetect.sh+ildetect.so.
: ${MPV:=mpv}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPV:=$MPV}
: ${ILDETECT_MPVFLAGS:=--start=35% --length=35}
: ${ILDETECT_DRY_RUN:=}
: ${ILDETECT_QUIET:=}
: ${ILDETECT_RUN_INTERLACED_ONLY:=}
: ${ILDETECT_FORCE_RUN:=}
: ${MAKE:=make}
# exit status:
# 0 progressive
@@ -26,66 +34,57 @@ testfun()
--o= --vo=null --no-audio --untimed \
$ILDETECT_MPVFLAGS \
| { if [ -n "$ILDETECT_QUIET" ]; then cat; else tee /dev/stderr; fi } \
| grep "Parsed_idet_0: Multi frame detection: "
| grep "Parsed_idet_0: Multi frame detection: " | tail -n 1
}
judge()
{
tff=0
bff=0
progressive=0
undetermined=0
while IFS= read -r out; do
tff1=${out##* TFF:}; tff1=${tff1%% *}
bff1=${out##* BFF:}; bff1=${bff1%% *}
progressive1=${out##* Progressive:}; progressive1=${progressive1%% *}
undetermined1=${out##* Undetermined:}; undetermined1=${undetermined1%% *}
case "$tff1$bff1$progressive1$undetermined1" in
*[!0-9]*)
printf >&2 'ERROR: Unrecognized idet output: %s\n' "$out"
exit 16
;;
esac
tff=$((tff + tff1))
bff=$((bff + bff1))
progressive=$((progressive + progressive1))
undetermined=$((undetermined + undetermined1))
done <<EOF
$(testfun "$@")
EOF
out=`testfun "$@"`
tff=${out##* TFF:}; tff=${tff%% *}
bff=${out##* BFF:}; bff=${bff%% *}
progressive=${out##* Progressive:}; progressive=${progressive%% *}
undetermined=${out##* Undetermined:}; undetermined=${undetermined%% *}
case "$tff$bff$progressive$undetermined" in
*[!0-9]*)
echo >&2 "ERROR: Unrecognized idet output: $out"
exit 16
;;
esac
interlaced=$((bff + tff))
determined=$((interlaced + progressive))
if [ "$undetermined" -gt "$determined" ] || [ "$determined" -lt 250 ]; then
if [ $undetermined -gt $determined ] || [ $determined -lt 250 ]; then
echo >&2 "ERROR: Less than 50% or 250 frames are determined."
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
echo >&2 "Assuming interlacing."
if [ "$tff" -gt $((bff * 10)) ]; then
verdict="interlaced-tff"
elif [ "$bff" -gt $((tff * 10)) ]; then
verdict="interlaced-bff"
if [ $tff -gt $((bff * 10)) ]; then
verdict=interlaced-tff
elif [ $bff -gt $((tff * 10)) ]; then
verdict=interlaced-bff
else
verdict="interlaced"
verdict=interlaced
fi
elif [ $((interlaced * 20)) -gt "$progressive" ]; then
elif [ $((interlaced * 20)) -gt $progressive ]; then
# At least 5% of the frames are interlaced!
if [ "$tff" -gt $((bff * 10)) ]; then
verdict="interlaced-tff"
elif [ "$bff" -gt $((tff * 10)) ]; then
verdict="interlaced-bff"
if [ $tff -gt $((bff * 10)) ]; then
verdict=interlaced-tff
elif [ $bff -gt $((tff * 10)) ]; then
verdict=interlaced-bff
else
echo >&2 "ERROR: Content is interlaced, but can't determine field order."
[ -n "$ILDETECT_FORCE_RUN" ] || exit 8
echo >&2 "Assuming interlacing with default field order."
verdict="interlaced"
verdict=interlaced
fi
else
# Likely progressive
verdict="progressive"
# Likely progrssive.
verdict=progressive
fi
printf '%s\n' "$verdict"
echo "$verdict"
}
judge "$@" --vf-clr
@@ -95,7 +94,7 @@ case "$verdict" in
[ -n "$ILDETECT_RUN_INTERLACED_ONLY" ] || \
$ILDETECT_MPV "$@"
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 0
;;
interlaced-tff)
@@ -105,14 +104,14 @@ case "$verdict" in
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 2
;;
esac
@@ -124,14 +123,14 @@ case "$verdict" in
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 2
;;
esac
@@ -143,14 +142,14 @@ case "$verdict" in
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=pullup
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=yadif
r=$?
[ $r -eq 0 ] || exit $((r | 16))
[ $r -eq 0 ] || exit $(($r | 16))
exit 2
;;
esac
-1
View File
@@ -265,7 +265,6 @@ sub define_matroska {
elem('DisplayUnit', '54b2', 'uint'),
elem('FrameRate', '2383e3', 'float'),
elem('ColourSpace', '2eb524', 'binary'),
elem('StereoMode', '53b8', 'uint'),
}),
elem('Audio', 'e1', {
elem('SamplingFrequency', 'b5', 'float'),
+150 -127
View File
@@ -17,134 +17,157 @@
# When multiple files were specified, their info will be put into FOO_* for the
# first file, FOO_1_* for the second file, FOO_2_* for the third file, etc.
__midentify__main() {
case "$0" in
mpv_identify.sh|*/mpv_identify.sh)
# we are NOT being sourced
[ -n "$1" ] && set -- '' "$@"
;;
esac
if [ "$#" -lt 2 ]; then
cat >&2 <<EOF
Usage 1 (for humans only): $0 filename.mkv
will print all property values.
Note that this output really shouldn't be parsed, as the
format is subject to change.
Usage 2 (for use by scripts): see top of this file
NOTE: for mkv with ordered chapters, this may
not always identify the specified file, but the
file providing the first chapter. Specify
--no-ordered-chapters to prevent this.
EOF
return 2
fi
local LF="
"
local nextprefix="$1"
shift
if [ -n "$nextprefix" ]; then
# in case of error, we always want this unset
unset "${nextprefix}path"
fi
local allprops="
filename
path
stream-start
stream-end
stream-length
demuxer
length
chapters
editions
titles
audio
audio-bitrate
audio-codec
audio-format
channels
samplerate
video
angle
video-bitrate
video-codec
video-format
video-aspect
fps
width
height
dwidth
dheight
sub
"
# TODO add metadata support once mpv can do it
local propstr="X-MIDENTIFY-START:$LF"
local key
for key in $allprops; do
propstr="${propstr}X-MIDENTIFY: $key \${=$key}$LF"
key="$(printf '%s\n' "$key" | tr - _)"
unset "$nextprefix$key"
done
local fileindex=0
local prefix=
local line
while IFS= read -r line; do
case "$line" in
X-MIDENTIFY-START:)
if [ -n "$nextprefix" ]; then
prefix="$nextprefix"
if [ "$fileindex" -gt 0 ]; then
nextprefix="${prefix%${fileindex}_}"
fi
fileindex="$((fileindex+1))"
nextprefix="${nextprefix}${fileindex}_"
for key in $allprops; do
key="$(printf '%s\n' "$key" | tr - _)"
unset "$nextprefix$key"
done
else
if [ "$fileindex" -gt 0 ]; then
printf '\n'
fi
fileindex="$((fileindex+1))"
fi
case "$0" in
mpv_identify.sh|*/mpv_identify.sh)
# we are NOT being sourced
case "$1" in
'')
;;
X-MIDENTIFY:\ *)
local key="${line#X-MIDENTIFY: }"
local value="${key#* }"
key="${key%% *}"
key="$(printf '%s\n' "$key" | tr - _)"
if [ -n "$nextprefix" ]; then
if [ -z "$prefix" ]; then
echo >&2 "Got X-MIDENTIFY: without X-MIDENTIFY-START:"
elif [ -n "$value" ]; then
eval "$prefix$key"='"$value"'
fi
else
if [ -n "$value" ]; then
printf '%s=%s\n' "$key" "$value"
fi
fi
*)
set -- '' "$@"
;;
esac
done <<EOF
$(${MPV:-mpv} --term-playing-msg="$propstr" --vo=null --ao=null \
--frames=1 --quiet --no-cache --no-config -- "$@")
EOF
}
;;
esac
__midentify__main "$@"
if [ $# -lt 2 ]; then
echo >&2 "Usage 1 (for humans only): $0 filename.mkv"
echo >&2 "will print all property values."
echo >&2 "Note that this output really shouldn't be parsed, as the"
echo >&2 "format is subject to change."
echo >&2
echo >&2 "Usage 2 (for use by scripts): see top of this file"
echo >&2
echo >&2 "NOTE: for mkv with ordered chapters, this may"
echo >&2 "not always identify the specified file, but the"
echo >&2 "file providing the first chapter. Specify"
echo >&2 "--no-ordered-chapters to prevent this."
exit 1
fi
if [ -z "$MPV" ]; then
MPV="mpv"
fi
__midentify__LF="
"
__midentify__nextprefix=$1
shift
if [ -n "$__midentify__nextprefix" ]; then
# in case of error, we always want this unset
eval unset $__midentify__nextprefix'path'
fi
__midentify__allprops="
filename
path
stream-start
stream-end
stream-length
demuxer
length
chapters
editions
titles
audio
audio-bitrate
audio-codec
audio-format
channels
samplerate
video
angle
video-bitrate
video-codec
video-format
video-aspect
fps
width
height
dwidth
dheight
sub
"
# TODO add metadata support once mpv can do it
__midentify__propstr="X-MIDENTIFY-START:$__midentify__LF"
for __midentify__key in $__midentify__allprops; do
__midentify__propstr=$__midentify__propstr"X-MIDENTIFY: $__midentify__key \${=$__midentify__key}$__midentify__LF"
__midentify__key=`echo "$__midentify__key" | tr - _`
eval unset $__midentify__nextprefix$__midentify__key
done
__midentify__output=`$MPV --term-playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet --no-cache --no-config "$@"`
__midentify__fileindex=0
__midentify__prefix=
while :; do
case "$__midentify__output" in
'')
break
;;
*$__midentify__LF*)
__midentify__line=${__midentify__output%%$__midentify__LF*}
__midentify__output=${__midentify__output#*$__midentify__LF}
;;
*)
__midentify__line=$__midentify__output
__midentify__output=
;;
esac
case "$__midentify__line" in
X-MIDENTIFY-START:)
if [ -n "$__midentify__nextprefix" ]; then
__midentify__prefix=$__midentify__nextprefix
if [ $__midentify__fileindex -gt 0 ]; then
__midentify__nextprefix=${__midentify__prefix%$__midentify__fileindex\_}
fi
__midentify__fileindex=$(($__midentify__fileindex+1))
__midentify__nextprefix=$__midentify__nextprefix$__midentify__fileindex\_
for __midentify__key in $__midentify__allprops; do
__midentify__key=`echo "$__midentify__key" | tr - _`
eval unset $__midentify__nextprefix$__midentify__key
done
else
if [ $__midentify__fileindex -gt 0 ]; then
echo
fi
__midentify__fileindex=$(($__midentify__fileindex+1))
fi
;;
X-MIDENTIFY:\ *)
__midentify__key=${__midentify__line#X-MIDENTIFY:\ }
__midentify__value=${__midentify__key#* }
__midentify__key=${__midentify__key%% *}
__midentify__key=`echo "$__midentify__key" | tr - _`
if [ -n "$__midentify__nextprefix" ]; then
if [ -z "$__midentify__prefix" ]; then
echo >&2 "Got X-MIDENTIFY: without X-MIDENTIFY-START:"
elif [ -n "$__midentify__value" ]; then
eval $__midentify__prefix$__midentify__key=\$__midentify__value
fi
else
if [ -n "$__midentify__value" ]; then
echo "$__midentify__key=$__midentify__value"
fi
fi
;;
esac
done
unset __midentify__fileindex
unset __midentify__allprops
unset __midentify__key
unset __midentify__LF
unset __midentify__line
unset __midentify__output
unset __midentify__nextprefix
unset __midentify__prefix
unset __midentify__propstr
unset __midentify__value
+18 -31
View File
@@ -18,11 +18,10 @@ e.g.:
Currently, the following event types are supported:
'start' <name> start of the named event
'end' <name> end of the named event
'value' <float> <name> a normal value (as opposed to event)
'event-timed' <ts> <name> singular event at the given timestamp
<name> singular event
'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
"""
@@ -30,32 +29,19 @@ class G:
events = {}
sevents = [] # events, deterministically sorted
start = None
# http://matplotlib.org/api/markers_api.html#module-matplotlib.markers
markers = ["o", "8", "s", "p", "*", "h", "+", "x", "D"]
def find_marker():
if len(G.markers) == 0:
return "o"
m = G.markers[0]
G.markers = G.markers[1:]
return m
class Event:
pass
def get_event(event, evtype):
def get_event(event):
if event not in G.events:
e = Event()
G.events[event] = e
e.name = event
e.vals = []
e.type = evtype
e.marker = "o"
e.numid = len(G.events)
e.type = "unknown"
G.sevents = list(G.events.values())
G.sevents.sort(key=lambda x: x.name)
if e.type == "event-signal":
e.marker = find_marker()
return G.events[event]
for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
@@ -68,29 +54,30 @@ for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
G.start = ts
ts = ts - G.start
if event.startswith("start "):
e = get_event(event[6:], "event")
e = get_event(event[6:])
e.type = "event"
e.vals.append((ts, 0))
e.vals.append((ts, 1))
elif event.startswith("end "):
e = get_event(event[4:], "event")
e = get_event(event[4:])
e.type = "event"
e.vals.append((ts, 1))
e.vals.append((ts, 0))
elif event.startswith("value "):
_, val, name = event.split(" ", 2)
val = float(val)
e = get_event(name, "value")
e = get_event(name)
e.type = "value"
e.vals.append((ts, val))
elif event.startswith("event-timed "):
_, val, name = event.split(" ", 2)
val = int(val) / 1000 - G.start
e = get_event(name, "event-signal")
e.vals.append((val, 1))
else:
e = get_event(event, "event-signal")
e = get_event(event)
e.type = "event-signal"
e.vals.append((ts, 1))
ao_events = ["ao fill", "audio wait"]
for e in G.sevents:
e.vals = [(x, y * e.numid / len(G.events)) for (x, y) in e.vals]
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)
@@ -102,7 +89,7 @@ for e in G.sevents:
plot.subplot(2, 1, 1)
pl, = plot.plot([x for x,y in e.vals], [y for x,y in e.vals], label=e.name)
if e.type == "event-signal":
plot.setp(pl, marker = e.marker, linestyle = "None")
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])
+20 -15
View File
@@ -23,11 +23,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 mpv path and options with the MPV environment
variable. The environment variable will be split on whitespace, and the
first item is used as path to mpv binary and the rest is passed as options
_if_ the script starts mpv. If mpv is not started by the script (i.e. mpv
is already running), this will be ignored.
Note: you can supply custom options with the UMPV_OPTIONS environment variable.
The environment variable will be split on whitespace, and each item is
passed as option to mpv _if_ the script starts mpv. If mpv is not started
by the script (i.e. mpv is already running), the options will be ignored.
Warning:
@@ -46,17 +45,21 @@ import fcntl
import stat
import string
if len(sys.argv) < 1:
sys.exit(1)
files = sys.argv[1:]
# this is the same method mpv uses to decide this
# this is about the same method mpv uses to decide this
def is_url(filename):
parts = filename.split("://", 1)
parts = filename.split(":", 1)
if len(parts) < 2:
return False
# protocol prefix has no special characters => it's an URL
allowed_symbols = string.ascii_letters + string.digits + '_'
prefix = parts[0]
return all(map(lambda c: c in allowed_symbols, prefix))
for c in prefix:
if string.ascii_letters.find(c) < 0:
return False
return True
# make them absolute; also makes them safe against interpretation as options
def make_abs(filename):
@@ -65,6 +68,9 @@ def make_abs(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 []
FIFO = "/tmp/umpv-fifo-" + os.getenv("USER")
fifo_fd = -1
@@ -83,8 +89,7 @@ if fifo_fd >= 0:
if (((st.st_mode & (stat.S_IRWXG | stat.S_IRWXO)) != 0) or
(not stat.S_ISFIFO(st.st_mode)) or
(st.st_uid != os.getuid())):
sys.stderr.write("error: command FIFO is not a FIFO or has bogus "
"permissions\n")
print("error: command FIFO is not a FIFO or has bogus permissions")
sys.exit(1)
if fifo_fd >= 0:
@@ -107,11 +112,11 @@ else:
pass
else:
raise e
os.mkfifo(FIFO, 0o600)
os.mkfifo(FIFO, int("0600", 8))
opts = (os.getenv("MPV") or "mpv").split()
opts.extend(["--no-terminal", "--force-window", "--input-file=" + FIFO,
"--"])
opts = ["mpv", "--no-terminal", "--force-window", "--input-file=" + FIFO]
opts.extend(opts_env)
opts.append("--")
opts.extend(files)
subprocess.check_call(opts)
+2 -1
View File
@@ -90,7 +90,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
if (argc != 1 && argc != 2)
return -1;
framestep_data_t *framestep = calloc(1,sizeof(framestep_data_t));
framestep_data_t *framestep = malloc(sizeof(framestep_data_t));
memset(framestep, 0, sizeof(*framestep));
framestep->step = atoi(argv[0]);
framestep->pos = (argc >= 2) ? atoi(argv[1]) : 0;
+2 -1
View File
@@ -267,7 +267,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
(void) argc;
(void) argv;
ildetect_data_t *il = calloc(1,sizeof(ildetect_data_t));
ildetect_data_t *il = malloc(sizeof(ildetect_data_t));
memset(il, 0, sizeof(*il));
#define A(i,d) ((argc>(i) && *argv[i]) ? atof(argv[i]) : (d))
il->method = A(0, 0);
+2 -1
View File
@@ -348,7 +348,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
{ "yuv420p", "yuv420p" },
{ NULL, NULL }
};
privdata *priv = calloc(1,sizeof(privdata));
privdata *priv = malloc(sizeof(privdata));
memset(priv, 0, sizeof(*priv));
priv->step = 8;
if(argc >= 1)
priv->w = atoi(argv[0]);
+2 -1
View File
@@ -237,7 +237,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
if (!a0[0] || a0[1] || !a1[0] || argc > 2)
return -1;
tc_data_t *tc = calloc(1,sizeof(tc_data_t));
tc_data_t *tc = malloc(sizeof(tc_data_t));
memset(tc, 0, sizeof(*tc));
if (a0[0] == 't')
tc->firstfield = 0;
+2 -1
View File
@@ -150,7 +150,8 @@ int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **a
if (argc != 2)
return -1;
tile_data_t *tile = calloc(1,sizeof(tile_data_t));
tile_data_t *tile = malloc(sizeof(tile_data_t));
memset(tile, 0, sizeof(*tile));
tile->cols = atoi(argv[0]);
tile->rows = atoi(argv[1]);
+5 -4
View File
@@ -10,13 +10,14 @@ video_url="$(youtube-dl \
--user-agent="$user_agent" \
--cookies="$cookies_file" \
--get-url \
"$@")"
"$1")"
set -f
${MPV:-mpv} \
shift
mpv \
--cookies \
--cookies-file="$cookies_file" \
--user-agent="$user_agent" \
-- $video_url
"$@" -- $video_url
rm -rf "$cookies_dir"
-43
View File
@@ -37,36 +37,6 @@ chomp $vf_str;
$protos_str .= qq{$_ } foreach (@protos);
chomp $protos_str;
my $profile_comp = <<'EOS';
local -a profiles
local current
for current in "${(@f)$($words[1] --profile=help)}"; do
current=${current//\*/\\\*}
current=${current//\:/\\\:}
current=${current//\[/\\\[}
current=${current//\]/\\\]}
if [[ $current =~ $'\t'([^$'\t']*)$'\t'(.*) ]]; then
if [[ -n $match[2] ]]; then
current="$match[1][$match[2]]"
else
current="$match[1]"
fi
profiles=($profiles $current)
fi
done
if [[ $state == profile ]]; then
# For --show-profile, only one allowed
if (( ${#profiles} > 0 )); then
_values 'profile' $profiles && rc=0
fi
else
# For --profile, multiple allowed
profiles=($profiles 'help[list profiles]')
_values -s , 'profile(s)' $profiles && rc=0
fi
EOS
chomp $profile_comp;
my $tmpl = <<"EOS";
#compdef mpv
@@ -118,16 +88,6 @@ $vf_str
_describe -t values 'video filters' values && rc=0
;;
profile|profiles)
$profile_comp
;;
files)
compset -P '*,'
compset -S ',*'
_files -r ',/ \\t\\n\\-' && rc=0
;;
mfiles)
local expl
_tags files urls
@@ -181,9 +141,6 @@ sub parse_opts {
$entry .= '->vo' if ($1 eq '--vo');
$entry .= '->af' if ($1 eq '--af');
$entry .= '->vf' if ($1 eq '--vf');
$entry .= '->profiles' if ($1 eq '--profile');
$entry .= '->profile' if ($1 eq '--show-profile');
$entry .= '->files' if ($line =~ /\[file\]/);
}
push @list, $entry
+1 -1
View File
@@ -1 +1 @@
0.6.0
0.5.1
+1 -1
View File
@@ -20,7 +20,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include "misc/bstr.h"
#include "bstr/bstr.h"
#define MP_NUM_CHANNELS 8
+98 -7
View File
@@ -37,6 +37,8 @@
#include "ad.h"
#include "audio/fmt-conversion.h"
#include "compat/libav.h"
struct priv {
AVCodecContext *avctx;
AVFrame *avframe;
@@ -71,6 +73,74 @@ const struct m_sub_options ad_lavc_conf = {
},
};
struct pcm_map
{
int tag;
const char *codecs[6]; // {any, 1byte, 2bytes, 3bytes, 4bytes, 8bytes}
};
// NOTE: these are needed to make rawaudio with demux_mkv work.
static const struct pcm_map tag_map[] = {
// Microsoft PCM
{0x0, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
{0x1, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
// MS PCM, Extended
{0xfffe, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
// IEEE float
{0x3, {"pcm_f32le", [5] = "pcm_f64le"}},
// 'raw '
{0x20776172, {"pcm_s16be", [1] = "pcm_u8"}},
// 'twos', used by demux_mkv.c internally
{MKTAG('t', 'w', 'o', 's'),
{NULL, "pcm_s8", "pcm_s16be", "pcm_s24be", "pcm_s32be"}},
{-1},
};
// For demux_rawaudio.c; needed because ffmpeg doesn't have these sample
// formats natively.
static const struct pcm_map af_map[] = {
{AF_FORMAT_U8, {"pcm_u8"}},
{AF_FORMAT_S8, {"pcm_u8"}},
{AF_FORMAT_U16_LE, {"pcm_u16le"}},
{AF_FORMAT_U16_BE, {"pcm_u16be"}},
{AF_FORMAT_S16_LE, {"pcm_s16le"}},
{AF_FORMAT_S16_BE, {"pcm_s16be"}},
{AF_FORMAT_U24_LE, {"pcm_u24le"}},
{AF_FORMAT_U24_BE, {"pcm_u24be"}},
{AF_FORMAT_S24_LE, {"pcm_s24le"}},
{AF_FORMAT_S24_BE, {"pcm_s24be"}},
{AF_FORMAT_U32_LE, {"pcm_u32le"}},
{AF_FORMAT_U32_BE, {"pcm_u32be"}},
{AF_FORMAT_S32_LE, {"pcm_s32le"}},
{AF_FORMAT_S32_BE, {"pcm_s32be"}},
{AF_FORMAT_FLOAT_LE, {"pcm_f32le"}},
{AF_FORMAT_FLOAT_BE, {"pcm_f32be"}},
{AF_FORMAT_DOUBLE_LE, {"pcm_f64le"}},
{AF_FORMAT_DOUBLE_BE, {"pcm_f64be"}},
{-1},
};
static const char *find_pcm_decoder(const struct pcm_map *map, int format,
int bits_per_sample)
{
int bytes = (bits_per_sample + 7) / 8;
if (bytes == 8)
bytes = 5; // 64 bit entry
for (int n = 0; map[n].tag != -1; n++) {
const struct pcm_map *entry = &map[n];
if (entry->tag == format) {
const char *dec = NULL;
if (bytes >= 1 && bytes <= 5)
dec = entry->codecs[bytes];
if (!dec)
dec = entry->codecs[0];
if (dec)
return dec;
}
}
return NULL;
}
static void set_data_from_avframe(struct dec_audio *da)
{
struct priv *priv = da->priv;
@@ -102,6 +172,18 @@ static void set_data_from_avframe(struct dec_audio *da)
da->decoded.planes[n] = priv->avframe->data[n];
}
static void set_from_wf(AVCodecContext *avctx, MP_WAVEFORMATEX *wf)
{
avctx->channels = wf->nChannels;
avctx->sample_rate = wf->nSamplesPerSec;
avctx->bit_rate = wf->nAvgBytesPerSec * 8;
avctx->block_align = wf->nBlockAlign;
avctx->bits_per_coded_sample = wf->wBitsPerSample;
if (wf->cbSize > 0)
mp_lavc_set_extradata(avctx, wf + 1, wf->cbSize);
}
static int init(struct dec_audio *da, const char *decoder)
{
struct MPOpts *mpopts = da->opts;
@@ -114,7 +196,13 @@ static int init(struct dec_audio *da, const char *decoder)
struct priv *ctx = talloc_zero(NULL, struct priv);
da->priv = ctx;
ctx->force_channel_map = sh_audio->force_channels;
if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
decoder = find_pcm_decoder(tag_map, sh->format,
sh_audio->wf->wBitsPerSample);
} else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
decoder = find_pcm_decoder(af_map, sh->format, 0);
ctx->force_channel_map = true;
}
lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec) {
@@ -144,13 +232,12 @@ static int init(struct dec_audio *da, const char *decoder)
lavc_context->codec_tag = sh->format;
lavc_context->sample_rate = sh_audio->samplerate;
lavc_context->bit_rate = sh_audio->bitrate;
lavc_context->block_align = sh_audio->block_align;
lavc_context->bits_per_coded_sample = sh_audio->bits_per_coded_sample;
lavc_context->channels = sh_audio->channels.num;
if (!mp_chmap_is_unknown(&sh_audio->channels))
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
// demux_mkv
if (sh_audio->wf)
set_from_wf(lavc_context, sh_audio->wf);
// demux_mkv, demux_mpg
if (sh_audio->codecdata_len && sh_audio->codecdata &&
!lavc_context->extradata) {
mp_lavc_set_extradata(lavc_context, sh_audio->codecdata,
@@ -171,6 +258,8 @@ static int init(struct dec_audio *da, const char *decoder)
if (lavc_context->bit_rate != 0)
da->bitrate = lavc_context->bit_rate;
else if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
da->bitrate = sh_audio->wf->nAvgBytesPerSec * 8;
return 1;
}
@@ -273,6 +362,8 @@ static int decode_packet(struct dec_audio *da)
static void add_decoders(struct mp_decoder_list *list)
{
mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
mp_add_decoder(list, "lavc", "pcm", "pcm", "Raw PCM");
mp_add_decoder(list, "lavc", "mp-pcm", "mp-pcm", "Raw PCM");
}
const struct ad_functions ad_lavc = {
+7 -7
View File
@@ -117,13 +117,13 @@ static int init(struct dec_audio *da, const char *decoder)
switch (stream->codec->codec_id) {
case AV_CODEC_ID_AAC:
spdif_ctx->iec61937_packet_size = 16384;
sample_format = AF_FORMAT_S_AAC;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_AC3:
spdif_ctx->iec61937_packet_size = 6144;
sample_format = AF_FORMAT_S_AC3;
sample_format = AF_FORMAT_AC3_LE;
samplerate = 48000;
num_channels = 2;
break;
@@ -131,31 +131,31 @@ static int init(struct dec_audio *da, const char *decoder)
if (da->opts->dtshd) {
av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_S_DTSHD;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 192000;
num_channels = 2*4;
} else {
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_S_DTS;
sample_format = AF_FORMAT_AC3_LE;
samplerate = 48000;
num_channels = 2;
}
break;
case AV_CODEC_ID_EAC3:
spdif_ctx->iec61937_packet_size = 24576;
sample_format = AF_FORMAT_S_EAC3;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 192000;
num_channels = 2;
break;
case AV_CODEC_ID_MP3:
spdif_ctx->iec61937_packet_size = 4608;
sample_format = AF_FORMAT_S_MP3;
sample_format = AF_FORMAT_MPEG2;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_TRUEHD:
spdif_ctx->iec61937_packet_size = 61440;
sample_format = AF_FORMAT_S_TRUEHD;
sample_format = AF_FORMAT_IEC61937_LE;
samplerate = 192000;
num_channels = 8;
break;
+2 -2
View File
@@ -28,7 +28,7 @@
#include "config.h"
#include "common/codecs.h"
#include "common/msg.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "stream/stream.h"
#include "demux/demux.h"
@@ -48,10 +48,10 @@ extern const struct ad_functions ad_lavc;
extern const struct ad_functions ad_spdif;
static const struct ad_functions * const ad_drivers[] = {
&ad_lavc,
#if HAVE_MPG123
&ad_mpg123,
#endif
&ad_lavc,
&ad_spdif,
NULL
};
+49 -20
View File
@@ -48,12 +48,20 @@ static int filter_##name(struct af_instance *af, struct mp_audio *data, int f) \
}
FILTER(f, float)
FILTER(s32, int32_t)
FILTER(u32, uint32_t)
FILTER(s24, bs2b_int24_t)
FILTER(u24, bs2b_uint24_t)
FILTER(s16, int16_t)
FILTER(u16, uint16_t)
FILTER(fbe, float)
FILTER(fle, float)
FILTER(s32be, int32_t)
FILTER(u32be, uint32_t)
FILTER(s32le, int32_t)
FILTER(u32le, uint32_t)
FILTER(s24be, bs2b_int24_t)
FILTER(u24be, bs2b_uint24_t)
FILTER(s24le, bs2b_int24_t)
FILTER(u24le, bs2b_uint24_t)
FILTER(s16be, int16_t)
FILTER(u16be, uint16_t)
FILTER(s16le, int16_t)
FILTER(u16le, uint16_t)
FILTER(s8, int8_t)
FILTER(u8, uint8_t)
@@ -77,26 +85,47 @@ static int control(struct af_instance *af, int cmd, void *arg)
/* check for formats supported by libbs2b
and assign corresponding handlers */
switch (format) {
case AF_FORMAT_FLOAT:
af->filter = filter_f;
case AF_FORMAT_FLOAT_BE:
af->filter = filter_fbe;
break;
case AF_FORMAT_S32:
af->filter = filter_s32;
case AF_FORMAT_FLOAT_LE:
af->filter = filter_fle;
break;
case AF_FORMAT_U32:
af->filter = filter_u32;
case AF_FORMAT_S32_BE:
af->filter = filter_s32be;
break;
case AF_FORMAT_S24:
af->filter = filter_s24;
case AF_FORMAT_U32_BE:
af->filter = filter_u32be;
break;
case AF_FORMAT_U24:
af->filter = filter_u24;
case AF_FORMAT_S32_LE:
af->filter = filter_s32le;
break;
case AF_FORMAT_S16:
af->filter = filter_s16;
case AF_FORMAT_U32_LE:
af->filter = filter_u32le;
break;
case AF_FORMAT_U16:
af->filter = filter_u16;
case AF_FORMAT_S24_BE:
af->filter = filter_s24be;
break;
case AF_FORMAT_U24_BE:
af->filter = filter_u24be;
break;
case AF_FORMAT_S24_LE:
af->filter = filter_s24le;
break;
case AF_FORMAT_U24_LE:
af->filter = filter_u24le;
break;
case AF_FORMAT_S16_BE:
af->filter = filter_s16be;
break;
case AF_FORMAT_U16_BE:
af->filter = filter_u16be;
break;
case AF_FORMAT_S16_LE:
af->filter = filter_s16le;
break;
case AF_FORMAT_U16_LE:
af->filter = filter_u16le;
break;
case AF_FORMAT_S8:
af->filter = filter_s8;
-1
View File
@@ -20,7 +20,6 @@
#include "audio/format.h"
#include "af.h"
#include "osdep/endian.h"
static bool test_conversion(int src_format, int dst_format)
{
+41 -9
View File
@@ -20,16 +20,21 @@
#include "af.h"
#include "audio/format.h"
#include "osdep/endian.h"
#include "compat/mpbswap.h"
static bool test_conversion(int src_format, int dst_format)
{
if ((src_format & AF_FORMAT_PLANAR) ||
(dst_format & AF_FORMAT_PLANAR))
return false;
if (((src_format & ~AF_FORMAT_SIGN_MASK) ==
(dst_format & ~AF_FORMAT_SIGN_MASK)) &&
((src_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_I))
int src_noend = src_format & ~AF_FORMAT_END_MASK;
int dst_noend = dst_format & ~AF_FORMAT_END_MASK;
// We can swap endian for all formats, but sign only for integer formats.
if (src_noend == dst_noend)
return true;
if (((src_noend & ~AF_FORMAT_SIGN_MASK) ==
(dst_noend & ~AF_FORMAT_SIGN_MASK)) &&
((src_noend & AF_FORMAT_POINT_MASK) == AF_FORMAT_I))
return true;
return false;
}
@@ -58,11 +63,34 @@ static int control(struct af_instance *af, int cmd, void *arg)
return AF_UNKNOWN;
}
static void si2us(void *data, int len, int bps)
static void endian(void *data, int len, int bps)
{
switch (bps) {
case 2:
for (int i = 0; i < len; i++) {
((uint16_t*)data)[i] = bswap_16(((uint16_t *)data)[i]);
}
break;
case 3:
for(int i = 0; i < len; i++) {
uint8_t s = ((uint8_t *)data)[3 * i];
((uint8_t *)data)[3 * i] = ((uint8_t *)data)[3 * i + 2];
((uint8_t *)data)[3 * i + 2] = s;
}
break;
case 4:
for(int i = 0; i < len; i++) {
((uint32_t*)data)[i] = bswap_32(((uint32_t *)data)[i]);
}
break;
}
}
static void si2us(void *data, int len, int bps, bool le)
{
ptrdiff_t i = -(len * bps);
uint8_t *p = &((uint8_t *)data)[len * bps];
if (BYTE_ORDER == LITTLE_ENDIAN && bps > 1)
if (le && bps > 1)
p += bps - 1;
if (len <= 0)
return;
@@ -77,8 +105,12 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
int outfmt = af->data->format;
size_t len = data->samples * data->nch;
if ((infmt & AF_FORMAT_END_MASK) != (outfmt & AF_FORMAT_END_MASK))
endian(data->planes[0], len, data->bps);
if ((infmt & AF_FORMAT_SIGN_MASK) != (outfmt & AF_FORMAT_SIGN_MASK))
si2us(data->planes[0], len, data->bps);
si2us(data->planes[0], len, data->bps,
(outfmt & AF_FORMAT_END_MASK) == AF_FORMAT_LE);
mp_audio_set_format(data, outfmt);
return 0;
@@ -92,8 +124,8 @@ static int af_open(struct af_instance *af)
}
const struct af_info af_info_convertsignendian = {
.info = "Convert between sample format sign",
.name = "convertsign",
.info = "Convert between sample format sign/endian",
.name = "convertsignendian",
.open = af_open,
.test_conversion = test_conversion,
};
+17 -35
View File
@@ -284,27 +284,6 @@ static inline void update_ch(af_hrtf_t *s, short *in, const int k)
s->ba_r[k] = in[4] + in[1] + in[3];
}
static void clear_coeff(af_hrtf_t *s, float *c)
{
memset(c, 0, s->dlbuflen * sizeof(float));
}
static void reset(af_hrtf_t *s)
{
clear_coeff(s, s->lf);
clear_coeff(s, s->rf);
clear_coeff(s, s->lr);
clear_coeff(s, s->rr);
clear_coeff(s, s->cf);
clear_coeff(s, s->cr);
clear_coeff(s, s->ba_l);
clear_coeff(s, s->ba_r);
clear_coeff(s, s->fwrbuf_l);
clear_coeff(s, s->fwrbuf_r);
clear_coeff(s, s->fwrbuf_lr);
clear_coeff(s, s->fwrbuf_rr);
}
/* Initialization and runtime control */
static int control(struct af_instance *af, int cmd, void* arg)
{
@@ -313,27 +292,30 @@ static int control(struct af_instance *af, int cmd, void* arg)
switch(cmd) {
case AF_CONTROL_REINIT:
reset(s);
af->data->rate = 48000;
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
/* Default behavior is stereo mixing. */
s->decode_mode = HRTF_MIX_STEREO;
}
} else if (af->data->nch < 5) {
mp_audio_set_channels_old(af->data, 5);
af->data->rate = ((struct mp_audio*)arg)->rate;
if(af->data->rate != 48000) {
// automatic samplerate adjustment in the filter chain
// is not yet supported.
MP_ERR(af, "ERROR: Sampling rate is not 48000 Hz (%d)!\n",
af->data->rate);
return AF_ERROR;
}
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
/* Default behavior is stereo mixing. */
s->decode_mode = HRTF_MIX_STEREO;
}
}
else if (af->data->nch < 5)
mp_audio_set_channels_old(af->data, 5);
mp_audio_set_format(af->data, AF_FORMAT_S16);
test_output_res = af_test_output(af, (struct mp_audio*)arg);
// after testing input set the real output format
mp_audio_set_num_channels(af->data, 2);
s->print_flag = 1;
return test_output_res;
case AF_CONTROL_RESET:
reset(s);
return AF_OK;
}
return AF_UNKNOWN;
+6 -15
View File
@@ -30,7 +30,6 @@
#include <libavutil/audioconvert.h>
#include <libavutil/intreadwrite.h>
#include <libavutil/common.h>
#include <libavutil/bswap.h>
#include <libavutil/mem.h>
#include "common/common.h"
@@ -88,7 +87,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (in->nch > AC3_MAX_CHANNELS)
mp_audio_set_num_channels(in, AC3_MAX_CHANNELS);
mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
mp_audio_set_format(af->data, AF_FORMAT_AC3_BE);
mp_audio_set_num_channels(af->data, 2);
if (!mp_audio_config_equals(in, &orig_in))
@@ -151,12 +150,6 @@ static void uninit(struct af_instance* af)
}
}
static void swap_16(uint16_t *ptr, size_t size)
{
for (size_t n = 0; n < size; n++)
ptr[n] = av_bswap16(ptr[n]);
}
// Filter data through filter
static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
{
@@ -230,11 +223,11 @@ static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
frame_size = AC3_FRAME_SIZE * 2 * 2;
header_len = 8;
AV_WL16(hdr, 0xF872); // iec 61937 syncword 1
AV_WL16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
AV_WB16(hdr, 0xF872); // iec 61937 syncword 1
AV_WB16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
hdr[4] = bsmod; // bsmod
hdr[5] = 0x01; // data-type ac3
AV_WL16(hdr + 6, len << 3); // number of bits in payload
AV_WB16(hdr + 6, len << 3); // number of bits in payload
}
size_t max_size = (max_out_samples - out->samples) * out->sstride;
@@ -246,7 +239,6 @@ static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
memcpy(buf + header_len, s->pkt.data, s->pkt.size);
memset(buf + header_len + s->pkt.size, 0,
frame_size - (header_len + s->pkt.size));
swap_16((uint16_t *)(buf + header_len), s->pkt.size / 2);
out->samples += frame_size / out->sstride;
}
@@ -320,13 +312,12 @@ const struct af_info af_info_lavcac3enc = {
.priv_size = sizeof(struct af_ac3enc_s),
.priv_defaults = &(const struct af_ac3enc_s){
.cfg_add_iec61937_header = 1,
.cfg_bit_rate = 640,
.cfg_min_channel_num = 3,
.cfg_min_channel_num = 5,
},
.options = (const struct m_option[]) {
OPT_FLAG("tospdif", cfg_add_iec61937_header, 0),
OPT_CHOICE_OR_INT("bitrate", cfg_bit_rate, 0, 32, 640,
({"auto", 0}, {"default", 0})),
({"default", 0})),
OPT_INTRANGE("minch", cfg_min_channel_num, 0, 2, 6),
{0}
},
+6 -5
View File
@@ -214,7 +214,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
if (avresample_open(s->avrctx) < 0 ||
avresample_open(s->avrctx_out) < 0)
{
MP_ERR(af, "Cannot open Libavresample Context. \n");
MP_ERR(af, "Cannot open "
"Libavresample Context. \n");
return AF_ERROR;
}
return AF_OK;
@@ -338,7 +339,7 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
if (needs_reorder(s->reorder_out, out->nch)) {
if (af_fmt_is_planar(out->format)) {
reorder_planes(data, s->reorder_out);
} else if (out->samples) {
} else {
int out_size = out->samples * out->sstride;
if (talloc_get_size(s->reorder_buffer) < out_size)
s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
@@ -346,8 +347,7 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
int out_samples = avresample_convert(s->avrctx_out,
(uint8_t **) data->planes, out_size, out->samples,
(uint8_t **) out->planes, out_size, out->samples);
if (out_samples < 0)
MP_ERR(af, "Reordering failed.\n");
assert(out_samples == data->samples);
}
}
@@ -371,7 +371,8 @@ static int af_open(struct af_instance *af)
if (s->avrctx && s->avrctx_out) {
return AF_OK;
} else {
MP_ERR(af, "Cannot initialize Libavresample Context. \n");
MP_ERR(af, "Cannot initialize "
"Libavresample Context. \n");
uninit(af);
return AF_ERROR;
}
+38 -26
View File
@@ -30,6 +30,9 @@
int af_fmt2bps(int format)
{
if (AF_FORMAT_IS_AC3(format)) return 2;
if (format == AF_FORMAT_UNKNOWN)
return 0;
switch (format & AF_FORMAT_BITS_MASK) {
case AF_FORMAT_8BIT: return 1;
case AF_FORMAT_16BIT: return 2;
@@ -59,7 +62,7 @@ static int bits_to_mask(int bits)
int af_fmt_change_bits(int format, int bits)
{
if (!af_fmt_is_valid(format))
if (!af_fmt_is_valid(format) || (format & AF_FORMAT_SPECIAL_MASK))
return 0;
int mask = bits_to_mask(bits);
format = (format & ~AF_FORMAT_BITS_MASK) | mask;
@@ -106,31 +109,35 @@ bool af_fmt_is_planar(int format)
return !!(format & AF_FORMAT_PLANAR);
}
#define FMT(string, id) \
{string, id},
#define FMT_ENDIAN(string, id) \
{string, id}, \
{string "le", MP_CONCAT(id, _LE)}, \
{string "be", MP_CONCAT(id, _BE)}, \
const struct af_fmt_entry af_fmtstr_table[] = {
{"u8", AF_FORMAT_U8},
{"s8", AF_FORMAT_S8},
{"u16", AF_FORMAT_U16},
{"s16", AF_FORMAT_S16},
{"u24", AF_FORMAT_U24},
{"s24", AF_FORMAT_S24},
{"u32", AF_FORMAT_U32},
{"s32", AF_FORMAT_S32},
{"float", AF_FORMAT_FLOAT},
{"double", AF_FORMAT_DOUBLE},
FMT("mpeg2", AF_FORMAT_MPEG2)
FMT_ENDIAN("ac3", AF_FORMAT_AC3)
FMT_ENDIAN("iec61937", AF_FORMAT_IEC61937)
{"u8p", AF_FORMAT_U8P},
{"s16p", AF_FORMAT_S16P},
{"s32p", AF_FORMAT_S32P},
{"floatp", AF_FORMAT_FLOATP},
{"doublep", AF_FORMAT_DOUBLEP},
FMT("u8", AF_FORMAT_U8)
FMT("s8", AF_FORMAT_S8)
FMT_ENDIAN("u16", AF_FORMAT_U16)
FMT_ENDIAN("s16", AF_FORMAT_S16)
FMT_ENDIAN("u24", AF_FORMAT_U24)
FMT_ENDIAN("s24", AF_FORMAT_S24)
FMT_ENDIAN("u32", AF_FORMAT_U32)
FMT_ENDIAN("s32", AF_FORMAT_S32)
FMT_ENDIAN("float", AF_FORMAT_FLOAT)
FMT_ENDIAN("double", AF_FORMAT_DOUBLE)
{"spdif-aac", AF_FORMAT_S_AAC},
{"spdif-ac3", AF_FORMAT_S_AC3},
{"spdif-dts", AF_FORMAT_S_DTS},
{"spdif-dtshd", AF_FORMAT_S_DTSHD},
{"spdif-eac3", AF_FORMAT_S_EAC3},
{"spdif-mp3", AF_FORMAT_S_MP3},
{"spdif-truehd",AF_FORMAT_S_TRUEHD},
FMT("u8p", AF_FORMAT_U8P)
FMT("s16p", AF_FORMAT_S16P)
FMT("s32p", AF_FORMAT_S32P)
FMT("floatp", AF_FORMAT_FLOATP)
FMT("doublep", AF_FORMAT_DOUBLEP)
{0}
};
@@ -192,17 +199,22 @@ int af_format_conversion_score(int dst_format, int src_format)
return INT_MIN;
if (dst_format == src_format)
return 1024;
// Just endian swapping (separate because it works for special formats)
if ((dst_format & ~AF_FORMAT_END_MASK) == (src_format & ~AF_FORMAT_END_MASK))
return 1024 - 2;
// Can't be normally converted
if (AF_FORMAT_IS_SPECIAL(dst_format) || AF_FORMAT_IS_SPECIAL(src_format))
return INT_MIN;
int score = 1024;
if (FMT_DIFF(AF_FORMAT_INTERLEAVING_MASK, dst_format, src_format))
score -= 1; // has to (de-)planarize
if (FMT_DIFF(AF_FORMAT_END_MASK, dst_format, src_format))
score -= 2; // has to swap endian
if (FMT_DIFF(AF_FORMAT_SIGN_MASK, dst_format, src_format))
score -= 4; // has to swap sign
if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) {
if (FMT_DIFF(AF_FORMAT_POINT_MASK, dst_format, src_format)) {
int dst_bits = dst_format & AF_FORMAT_BITS_MASK;
if ((dst_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F) {
if ((dst_format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F) {
// For int->float, always prefer 32 bit float.
score -= dst_bits == AF_FORMAT_32BIT ? 8 : 0;
} else {
@@ -218,7 +230,7 @@ int af_format_conversion_score(int dst_format, int src_format)
}
}
// Consider this the worst case.
if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format))
if (FMT_DIFF(AF_FORMAT_POINT_MASK, dst_format, src_format))
score -= 2048; // has to convert float<->int
return score;
}
+91 -47
View File
@@ -25,77 +25,121 @@
#include <stdbool.h>
#include "misc/bstr.h"
#include "osdep/endian.h"
#include "bstr/bstr.h"
#if BYTE_ORDER == BIG_ENDIAN
#define AF_SELECT_LE_BE(LE, BE) BE
#else
#define AF_SELECT_LE_BE(LE, BE) LE
#endif
// Endianness
#define AF_FORMAT_BE (0<<0) // Big Endian
#define AF_FORMAT_LE (1<<0) // Little Endian
#define AF_FORMAT_END_MASK (1<<0)
#define AF_FORMAT_NE AF_SELECT_LE_BE(AF_FORMAT_LE, AF_FORMAT_BE)
// Signed/unsigned
#define AF_FORMAT_SI (0<<0) // Signed
#define AF_FORMAT_US (1<<0) // Unsigned
#define AF_FORMAT_SIGN_MASK (1<<0)
#define AF_FORMAT_SI (0<<1) // Signed
#define AF_FORMAT_US (1<<1) // Unsigned
#define AF_FORMAT_SIGN_MASK (1<<1)
// Bits used
// Some code assumes they're sorted by size.
#define AF_FORMAT_8BIT (0<<1)
#define AF_FORMAT_16BIT (1<<1)
#define AF_FORMAT_24BIT (2<<1)
#define AF_FORMAT_32BIT (3<<1)
#define AF_FORMAT_64BIT (4<<1)
#define AF_FORMAT_BITS_MASK (7<<1)
#define AF_FORMAT_8BIT (0<<3)
#define AF_FORMAT_16BIT (1<<3)
#define AF_FORMAT_24BIT (2<<3)
#define AF_FORMAT_32BIT (3<<3)
#define AF_FORMAT_64BIT (4<<3)
#define AF_FORMAT_BITS_MASK (7<<3)
// Fixed/floating point/special
#define AF_FORMAT_I (1<<4) // Int
#define AF_FORMAT_F (2<<4) // Foating point
#define AF_FORMAT_S (4<<4) // special (IEC61937)
#define AF_FORMAT_TYPE_MASK (7<<4)
// Special flags refering to non pcm data (note: 1<<6, 2<<6, 5<<6 unused)
#define AF_FORMAT_S_MPEG2 (3<<6) // MPEG(2) audio
#define AF_FORMAT_S_AC3 (4<<6) // Dolby Digital AC3
#define AF_FORMAT_S_IEC61937 (6<<6)
#define AF_FORMAT_SPECIAL_MASK (7<<6)
// Fixed or floating point
#define AF_FORMAT_I (1<<9) // Int
#define AF_FORMAT_F (2<<9) // Foating point
#define AF_FORMAT_POINT_MASK (3<<9)
// Interleaving (planar formats have data for each channel in separate planes)
#define AF_FORMAT_INTERLEAVED (0<<7) // must be 0
#define AF_FORMAT_PLANAR (1<<7)
#define AF_FORMAT_INTERLEAVING_MASK (1<<7)
#define AF_FORMAT_S_CODEC(n) ((n)<<8)
#define AF_FORMAT_S_CODEC_MASK (15 <<8) // 16 codecs max.
#define AF_FORMAT_INTERLEAVED (0<<11) // must be 0
#define AF_FORMAT_PLANAR (1<<11)
#define AF_FORMAT_INTERLEAVING_MASK (1<<11)
#define AF_FORMAT_MASK ((1<<12)-1)
#define AF_INTP (AF_FORMAT_I|AF_FORMAT_PLANAR)
#define AF_FLTP (AF_FORMAT_F|AF_FORMAT_PLANAR)
#define AF_FORMAT_S_(n) (AF_FORMAT_S_CODEC(n)|AF_FORMAT_S|AF_FORMAT_16BIT)
// actual sample formats
enum af_format {
AF_FORMAT_UNKNOWN = 0,
AF_FORMAT_U8 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_8BIT),
AF_FORMAT_S8 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_8BIT),
AF_FORMAT_U16 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_16BIT),
AF_FORMAT_S16 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_16BIT),
AF_FORMAT_U24 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_24BIT),
AF_FORMAT_S24 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_24BIT),
AF_FORMAT_U32 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_32BIT),
AF_FORMAT_S32 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_32BIT),
AF_FORMAT_U8 = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_8BIT|AF_FORMAT_NE),
AF_FORMAT_S8 = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_8BIT|AF_FORMAT_NE),
AF_FORMAT_U16_LE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_U16_BE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_S16_LE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_S16_BE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_U24_LE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_24BIT|AF_FORMAT_LE),
AF_FORMAT_U24_BE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_24BIT|AF_FORMAT_BE),
AF_FORMAT_S24_LE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_24BIT|AF_FORMAT_LE),
AF_FORMAT_S24_BE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_24BIT|AF_FORMAT_BE),
AF_FORMAT_U32_LE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_32BIT|AF_FORMAT_LE),
AF_FORMAT_U32_BE = (AF_FORMAT_I|AF_FORMAT_US|AF_FORMAT_32BIT|AF_FORMAT_BE),
AF_FORMAT_S32_LE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_LE),
AF_FORMAT_S32_BE = (AF_FORMAT_I|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_BE),
AF_FORMAT_FLOAT = (AF_FORMAT_F|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLE = (AF_FORMAT_F|AF_FORMAT_64BIT),
AF_FORMAT_FLOAT_LE = (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_LE),
AF_FORMAT_FLOAT_BE = (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_BE),
AF_FORMAT_DOUBLE_LE = (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_LE),
AF_FORMAT_DOUBLE_BE = (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_BE),
AF_FORMAT_AC3_LE = (AF_FORMAT_S_AC3|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_AC3_BE = (AF_FORMAT_S_AC3|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_IEC61937_LE = (AF_FORMAT_S_IEC61937|AF_FORMAT_16BIT|AF_FORMAT_LE),
AF_FORMAT_IEC61937_BE = (AF_FORMAT_S_IEC61937|AF_FORMAT_16BIT|AF_FORMAT_BE),
AF_FORMAT_MPEG2 = (AF_FORMAT_S_MPEG2),
// Planar variants
AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT),
AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT),
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_32BIT),
AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_64BIT),
AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT|AF_FORMAT_NE),
AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_NE),
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_NE),
AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT|AF_FORMAT_NE),
AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_64BIT|AF_FORMAT_NE),
// All of these use IEC61937 framing, and otherwise pretend to be like PCM.
AF_FORMAT_S_AAC = AF_FORMAT_S_(0),
AF_FORMAT_S_AC3 = AF_FORMAT_S_(1),
AF_FORMAT_S_DTS = AF_FORMAT_S_(2),
AF_FORMAT_S_DTSHD = AF_FORMAT_S_(3),
AF_FORMAT_S_EAC3 = AF_FORMAT_S_(4),
AF_FORMAT_S_MP3 = AF_FORMAT_S_(5),
AF_FORMAT_S_TRUEHD = AF_FORMAT_S_(6),
// Native endian variants
AF_FORMAT_U16 = AF_SELECT_LE_BE(AF_FORMAT_U16_LE, AF_FORMAT_U16_BE),
AF_FORMAT_S16 = AF_SELECT_LE_BE(AF_FORMAT_S16_LE, AF_FORMAT_S16_BE),
AF_FORMAT_U24 = AF_SELECT_LE_BE(AF_FORMAT_U24_LE, AF_FORMAT_U24_BE),
AF_FORMAT_S24 = AF_SELECT_LE_BE(AF_FORMAT_S24_LE, AF_FORMAT_S24_BE),
AF_FORMAT_U32 = AF_SELECT_LE_BE(AF_FORMAT_U32_LE, AF_FORMAT_U32_BE),
AF_FORMAT_S32 = AF_SELECT_LE_BE(AF_FORMAT_S32_LE, AF_FORMAT_S32_BE),
AF_FORMAT_FLOAT = AF_SELECT_LE_BE(AF_FORMAT_FLOAT_LE, AF_FORMAT_FLOAT_BE),
AF_FORMAT_DOUBLE = AF_SELECT_LE_BE(AF_FORMAT_DOUBLE_LE, AF_FORMAT_DOUBLE_BE),
AF_FORMAT_AC3 = AF_SELECT_LE_BE(AF_FORMAT_AC3_LE, AF_FORMAT_AC3_BE),
AF_FORMAT_IEC61937 = AF_SELECT_LE_BE(AF_FORMAT_IEC61937_LE, AF_FORMAT_IEC61937_BE),
};
#define AF_FORMAT_IS_IEC61937(f) (((f) & AF_FORMAT_TYPE_MASK) == AF_FORMAT_S)
#define AF_FORMAT_IS_SPECIAL(f) AF_FORMAT_IS_IEC61937(f)
#define AF_FORMAT_IS_AC3(fmt) \
(((fmt) & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_S_AC3)
#define AF_FORMAT_IS_IEC61937(fmt) \
(AF_FORMAT_IS_AC3(fmt) || \
((fmt) & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_S_IEC61937)
#define AF_FORMAT_IS_SPECIAL(fmt) \
((fmt & AF_FORMAT_SPECIAL_MASK) != 0)
struct af_fmt_entry {
const char *name;
+6 -8
View File
@@ -37,7 +37,6 @@ struct mixer {
struct af_stream *af;
// Static, dependent on ao/softvol settings
bool softvol; // use AO (true) or af_volume (false)
bool ao_softvol; // AO has private or per-app volume
bool emulate_mute; // if true, emulate mute with volume=0
// Last known values (possibly out of sync with reality)
float vol_l, vol_r;
@@ -246,13 +245,11 @@ char *mixer_get_volume_restore_data(struct mixer *mixer)
static void probe_softvol(struct mixer *mixer)
{
mixer->ao_softvol =
ao_control(mixer->ao, AOCONTROL_HAS_SOFT_VOLUME, 0) == 1 ||
ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) == 1;
if (mixer->opts->softvol == SOFTVOL_AUTO) {
// No system-wide volume => fine with AO volume control.
mixer->softvol = !mixer->ao_softvol;
mixer->softvol =
ao_control(mixer->ao, AOCONTROL_HAS_TEMP_VOLUME, 0) != 1 ||
ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) != 1;
} else {
mixer->softvol = mixer->opts->softvol == SOFTVOL_YES;
}
@@ -285,7 +282,8 @@ static void restore_volume(struct mixer *mixer)
const char *prev_driver = mixer->driver;
mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao);
bool restore = mixer->softvol || mixer->ao_softvol;
bool restore =
mixer->softvol || ao_control(ao, AOCONTROL_HAS_TEMP_VOLUME, 0) == 1;
// Restore old parameters if volume won't survive reinitialization.
// But not if volume scale is possibly different.
@@ -363,7 +361,7 @@ void mixer_uninit_audio(struct mixer *mixer)
return;
checkvolume(mixer);
if (mixer->muted_by_us && !mixer->softvol && !mixer->ao_softvol) {
if (mixer->muted_by_us) {
/* Current audio output API combines playing the remaining buffered
* audio and uninitializing the AO into one operation, even though
* ideally unmute would happen between those two steps. We can't do
+15 -7
View File
@@ -60,6 +60,9 @@ static const struct ao_driver * const audio_out_drivers[] = {
#if HAVE_PULSE
&audio_out_pulse,
#endif
#if HAVE_SNDIO
&audio_out_sndio,
#endif
#if HAVE_ALSA
&audio_out_alsa,
#endif
@@ -84,9 +87,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
#endif
#if HAVE_SDL1 || HAVE_SDL2
&audio_out_sdl,
#endif
#if HAVE_SNDIO
&audio_out_sndio,
#endif
&audio_out_null,
// should not be auto-selected:
@@ -152,7 +152,6 @@ static struct ao *ao_create(bool probing, struct mpv_global *global,
.channels = channels,
.format = format,
.log = mp_log_new(ao, log, name),
.def_buffer = global->opts->audio_buffer,
};
if (ao->driver->encode != !!ao->encode_lavc_ctx)
goto error;
@@ -188,7 +187,7 @@ static struct ao *ao_create(bool probing, struct mpv_global *global,
ao->device_buffer = ao->driver->get_space(ao);
MP_VERBOSE(ao, "device buffer: %d samples.\n", ao->device_buffer);
}
ao->buffer = MPMAX(ao->device_buffer, ao->def_buffer * ao->samplerate);
ao->buffer = MPMAX(ao->device_buffer, MIN_BUFFER * ao->samplerate);
MP_VERBOSE(ao, "using soft-buffer of %d samples.\n", ao->buffer);
if (ao->api->init(ao) < 0)
@@ -259,7 +258,16 @@ int ao_play(struct ao *ao, void **data, int samples, int flags)
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg)
{
return ao->api->control ? ao->api->control(ao, cmd, arg) : CONTROL_UNKNOWN;
switch (cmd) {
case AOCONTROL_HAS_TEMP_VOLUME:
return !ao->no_persistent_volume;
case AOCONTROL_HAS_PER_APP_VOLUME:
return !!ao->per_application_mixer;
default:
if (ao->api->control)
return ao->api->control(ao, cmd, arg);
}
return CONTROL_UNKNOWN;
}
// Return size of the buffered data in seconds. Can include the device latency.
@@ -313,7 +321,7 @@ void ao_drain(struct ao *ao)
bool ao_eof_reached(struct ao *ao)
{
return ao->api->get_eof ? ao->api->get_eof(ao) : true;
return ao_get_delay(ao) < AO_EOF_DELAY;
}
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
+2 -4
View File
@@ -21,7 +21,7 @@
#include <stdbool.h>
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "common/common.h"
#include "audio/chmap.h"
#include "audio/chmap_sel.h"
@@ -36,9 +36,7 @@ enum aocontrol {
AOCONTROL_SET_MUTE,
// Has char* as argument, which contains the desired stream title.
AOCONTROL_UPDATE_STREAM_TITLE,
// the AO does the equivalent of af_volume (return CONTROL_TRUE if yes)
AOCONTROL_HAS_SOFT_VOLUME,
// like above, but volume persists (per app), mpv won't restore volume
AOCONTROL_HAS_TEMP_VOLUME,
AOCONTROL_HAS_PER_APP_VOLUME,
};
+29 -25
View File
@@ -38,7 +38,6 @@
#include "options/options.h"
#include "options/m_option.h"
#include "common/msg.h"
#include "osdep/endian.h"
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
@@ -100,7 +99,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
long get_vol, set_vol;
float f_multi;
if (AF_FORMAT_IS_SPECIAL(ao->format))
if (AF_FORMAT_IS_IEC61937(ao->format))
return CONTROL_FALSE;
//allocate simple id
@@ -209,15 +208,25 @@ alsa_error:
static const int mp_to_alsa_format[][2] = {
{AF_FORMAT_S8, SND_PCM_FORMAT_S8},
{AF_FORMAT_U8, SND_PCM_FORMAT_U8},
{AF_FORMAT_U16, SND_PCM_FORMAT_U16},
{AF_FORMAT_S16, SND_PCM_FORMAT_S16},
{AF_FORMAT_U32, SND_PCM_FORMAT_U32},
{AF_FORMAT_S32, SND_PCM_FORMAT_S32},
{AF_FORMAT_U24,
MP_SELECT_LE_BE(SND_PCM_FORMAT_U24_3LE, SND_PCM_FORMAT_U24_3BE)},
{AF_FORMAT_S24,
MP_SELECT_LE_BE(SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3BE)},
{AF_FORMAT_FLOAT, SND_PCM_FORMAT_FLOAT},
{AF_FORMAT_U16_LE, SND_PCM_FORMAT_U16_LE},
{AF_FORMAT_U16_BE, SND_PCM_FORMAT_U16_BE},
{AF_FORMAT_S16_LE, SND_PCM_FORMAT_S16_LE},
{AF_FORMAT_S16_BE, SND_PCM_FORMAT_S16_BE},
{AF_FORMAT_U32_LE, SND_PCM_FORMAT_U32_LE},
{AF_FORMAT_U32_BE, SND_PCM_FORMAT_U32_BE},
{AF_FORMAT_S32_LE, SND_PCM_FORMAT_S32_LE},
{AF_FORMAT_S32_BE, SND_PCM_FORMAT_S32_BE},
{AF_FORMAT_U24_LE, SND_PCM_FORMAT_U24_3LE},
{AF_FORMAT_U24_BE, SND_PCM_FORMAT_U24_3BE},
{AF_FORMAT_S24_LE, SND_PCM_FORMAT_S24_3LE},
{AF_FORMAT_S24_BE, SND_PCM_FORMAT_S24_3BE},
{AF_FORMAT_FLOAT_LE, SND_PCM_FORMAT_FLOAT_LE},
{AF_FORMAT_FLOAT_BE, SND_PCM_FORMAT_FLOAT_BE},
{AF_FORMAT_AC3_LE, SND_PCM_FORMAT_S16_LE},
{AF_FORMAT_AC3_BE, SND_PCM_FORMAT_S16_BE},
{AF_FORMAT_IEC61937_LE, SND_PCM_FORMAT_S16_LE},
{AF_FORMAT_IEC61937_BE, SND_PCM_FORMAT_S16_BE},
{AF_FORMAT_MPEG2, SND_PCM_FORMAT_MPEG},
{AF_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN},
};
@@ -400,15 +409,7 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to get initial parameters");
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (ao->format == AF_FORMAT_S_MP3) {
p->alsa_fmt = SND_PCM_FORMAT_MPEG;
} else {
p->alsa_fmt = SND_PCM_FORMAT_S16;
}
} else {
p->alsa_fmt = find_alsa_format(ao->format);
}
p->alsa_fmt = find_alsa_format(ao->format);
if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) {
p->alsa_fmt = SND_PCM_FORMAT_S16;
ao->format = AF_FORMAT_S16;
@@ -416,12 +417,15 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt);
if (err < 0) {
if (AF_FORMAT_IS_IEC61937(ao->format))
CHECK_ALSA_ERROR("Unable to set IEC61937 format");
MP_INFO(ao, "Format %s is not supported by hardware, trying default.\n",
af_fmt_to_str(ao->format));
p->alsa_fmt = SND_PCM_FORMAT_S16;
ao->format = AF_FORMAT_S16;
p->alsa_fmt = SND_PCM_FORMAT_S16_LE;
if (AF_FORMAT_IS_AC3(ao->format))
ao->format = AF_FORMAT_AC3_LE;
else if (AF_FORMAT_IS_IEC61937(ao->format))
ao->format = AF_FORMAT_IEC61937_LE;
else
ao->format = AF_FORMAT_S16_LE;
}
err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt);
@@ -671,7 +675,7 @@ static int get_space(struct ao *ao)
unsigned space = snd_pcm_status_get_avail(status);
if (space > p->buffersize) // Buffer underrun?
space = p->buffersize;
return space / p->outburst * p->outburst;
return space;
alsa_error:
return 0;
+3 -4
View File
@@ -136,10 +136,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return get_volume(ao, arg);
case AOCONTROL_SET_VOLUME:
return set_volume(ao, arg);
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
case AOCONTROL_HAS_PER_APP_VOLUME:
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
@@ -153,6 +149,9 @@ static int init(struct ao *ao)
if (p->opt_list) ca_print_device_list(ao);
ao->per_application_mixer = true;
ao->no_persistent_volume = true;
OSStatus err = ca_select_device(ao, p->opt_device_id, &p->device);
CHECK_CA_ERROR("failed to select device");
+10 -4
View File
@@ -410,9 +410,8 @@ static int init(struct ao *ao)
ao->format = af_fmt_from_planar(ao->format);
bool supports_digital = false;
/* Probe whether device support S/PDIF stream output if input is AC3 stream,
* or anything else IEC61937-framed. */
if (AF_FORMAT_IS_IEC61937(ao->format)) {
/* Probe whether device support S/PDIF stream output if input is AC3 stream. */
if (AF_FORMAT_IS_AC3(ao->format)) {
if (ca_device_supports_digital(ao, p->device))
supports_digital = true;
}
@@ -522,7 +521,14 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
err = ca_enable_device_listener(p->device, changed);
CHECK_CA_ERROR("cannot install format change listener during init");
if (p->stream_asbd.mFormatFlags & kAudioFormatFlagIsBigEndian)
#if BYTE_ORDER == BIG_ENDIAN
if (!(p->stream_asdb.mFormatFlags & kAudioFormatFlagIsBigEndian))
#else
/* tell mplayer that we need a byteswap on AC3 streams, */
if (p->stream_asbd.mFormatID & kAudioFormat60958AC3)
ao->format = AF_FORMAT_AC3_LE;
else if (p->stream_asbd.mFormatFlags & kAudioFormatFlagIsBigEndian)
#endif
MP_WARN(ao, "stream has non-native byte order, output may fail\n");
ao->samplerate = p->stream_asbd.mSampleRate;
+3 -5
View File
@@ -25,7 +25,6 @@
#include "audio/out/ao_coreaudio_utils.h"
#include "audio/out/ao_coreaudio_properties.h"
#include "osdep/timer.h"
#include "osdep/endian.h"
#include "audio/format.h"
void ca_print_device_list(struct ao *ao)
@@ -130,21 +129,20 @@ bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message)
void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd)
{
asbd->mSampleRate = ao->samplerate;
// Set "AC3" for other spdif formats too - unknown if that works.
asbd->mFormatID = AF_FORMAT_IS_IEC61937(ao->format) ?
asbd->mFormatID = AF_FORMAT_IS_AC3(ao->format) ?
kAudioFormat60958AC3 :
kAudioFormatLinearPCM;
asbd->mChannelsPerFrame = ao->channels.num;
asbd->mBitsPerChannel = af_fmt2bits(ao->format);
asbd->mFormatFlags = kAudioFormatFlagIsPacked;
if ((ao->format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F)
if ((ao->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F)
asbd->mFormatFlags |= kAudioFormatFlagIsFloat;
if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI)
asbd->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
if (BYTE_ORDER == BIG_ENDIAN)
if ((ao->format & AF_FORMAT_END_MASK) == AF_FORMAT_BE)
asbd->mFormatFlags |= kAudioFormatFlagIsBigEndian;
asbd->mFramesPerPacket = 1;
+13 -16
View File
@@ -98,7 +98,6 @@ struct priv {
int outburst; ///play in multiple of chunks of this size
int cfg_device;
int cfg_buffersize;
};
static float get_delay(struct ao *ao);
@@ -351,8 +350,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
IDirectSoundBuffer_SetVolume(p->hdsbuf, volume);
return CONTROL_OK;
}
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
@@ -373,6 +370,7 @@ static int init(struct ao *ao)
if (!InitDirectSound(ao))
return -1;
ao->no_persistent_volume = true;
p->audio_volume = 100;
// ok, now create the buffers
@@ -382,33 +380,34 @@ static int init(struct ao *ao)
int format = af_fmt_from_planar(ao->format);
int rate = ao->samplerate;
if (!AF_FORMAT_IS_IEC61937(format)) {
if (AF_FORMAT_IS_AC3(format))
format = AF_FORMAT_AC3;
else {
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
}
switch (format) {
case AF_FORMAT_S24:
case AF_FORMAT_S16:
case AF_FORMAT_AC3:
case AF_FORMAT_S24_LE:
case AF_FORMAT_S16_LE:
case AF_FORMAT_U8:
break;
default:
if (AF_FORMAT_IS_IEC61937(format))
break;
MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n",
af_fmt_to_str(format));
format = AF_FORMAT_S16;
format = AF_FORMAT_S16_LE;
}
//set our audio parameters
ao->samplerate = rate;
ao->format = format;
ao->bps = ao->channels.num * rate * af_fmt2bps(format);
int buffersize = ao->bps * p->cfg_buffersize / 1000;
int buffersize = ao->bps * 0.100; // space for 100ms
MP_VERBOSE(ao, "Samplerate:%iHz Channels:%i Format:%s\n", rate,
ao->channels.num, af_fmt_to_str(format));
MP_VERBOSE(ao, "Buffersize:%d bytes (%f msec)\n",
buffersize, buffersize * 1000.0 / ao->bps);
MP_VERBOSE(ao, "Buffersize:%d bytes (%d msec)\n",
buffersize, buffersize / ao->bps * 1000);
//fill waveformatex
ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
@@ -416,8 +415,7 @@ static int init(struct ao *ao)
? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = ao->channels.num;
wformat.Format.nSamplesPerSec = rate;
if (AF_FORMAT_IS_IEC61937(format)) {
// Whether it also works with e.g. DTS is unknown, but probably does.
if (AF_FORMAT_IS_AC3(format)) {
wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
wformat.Format.wBitsPerSample = 16;
wformat.Format.nBlockAlign = 4;
@@ -585,7 +583,7 @@ static int get_space(struct ao *ao)
int space = check_free_buffer_size(ao);
if (space < p->min_free_space)
return 0;
return (space - p->min_free_space) / p->outburst * p->outburst / ao->sstride;
return (space - p->min_free_space) / ao->sstride;
}
/**
@@ -638,7 +636,6 @@ const struct ao_driver audio_out_dsound = {
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_INT("device", cfg_device, 0),
OPT_INTRANGE("buffersize", cfg_buffersize, 0, 1, 10000, OPTDEF_INT(200)),
{0}
},
};
+1
View File
@@ -28,6 +28,7 @@
#include <libavutil/common.h>
#include <libavutil/audioconvert.h>
#include "compat/libav.h"
#include "config.h"
#include "options/options.h"
#include "common/common.h"
+1 -2
View File
@@ -148,8 +148,7 @@ static int get_space(struct ao *ao)
struct priv *priv = ao->priv;
drain(ao);
int samples = priv->buffersize - priv->latency - priv->buffered;
return samples / priv->outburst * priv->outburst;
return priv->buffersize - priv->latency - priv->buffered;
}
static int play(struct ao *ao, void **data, int samples, int flags)
+1 -2
View File
@@ -76,8 +76,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
vol->left = vol->right = volume * 100;
return CONTROL_TRUE;
}
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
}
@@ -134,6 +132,7 @@ static int init(struct ao *ao)
return -1;
}
ao_data = ao;
ao->no_persistent_volume = true;
struct mp_chmap_sel sel = {0};
for (i = 0; speaker_pos[i].id != -1; i++)
mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id);
+297 -321
View File
@@ -31,7 +31,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
@@ -39,8 +38,6 @@
#include "config.h"
#include "options/options.h"
#include "common/msg.h"
#include "osdep/timer.h"
#include "osdep/endian.h"
#if HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
@@ -55,20 +52,14 @@
#include "ao.h"
#include "internal.h"
// Define to 0 if the device must be reopened to reset it (stop all playback,
// clear the buffer), and the device should be closed when unused.
// Define to 1 if SNDCTL_DSP_RESET should be used to reset without close.
#define KEEP_DEVICE (defined(SNDCTL_DSP_RESET) && !defined(__NetBSD__))
struct priv {
int audio_fd;
int prepause_samples;
int prepause_space;
int oss_mixer_channel;
audio_buf_info zz;
int audio_delay_method;
int buffersize;
int outburst;
bool device_failed;
double audio_end;
char *dsp;
char *oss_mixer_device;
@@ -90,60 +81,53 @@ static const struct mp_chmap oss_layouts[MP_NUM_CHANNELS + 1] = {
MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), // 7.1
};
#if !defined(AFMT_S16_NE) && defined(AFMT_S16_LE) && defined(AFMT_S16_BE)
#define AFMT_S16_NE MP_SELECT_LE_BE(AFMT_S16_LE, AFMT_S16_BE)
#endif
#if !defined(AFMT_U16_NE) && defined(AFMT_U16_LE) && defined(AFMT_U16_BE)
#define AFMT_U16_NE MP_SELECT_LE_BE(AFMT_U16_LE, AFMT_U16_BE)
#endif
#if !defined(AFMT_U24_NE) && defined(AFMT_U24_LE) && defined(AFMT_U24_BE)
#define AFMT_U24_NE MP_SELECT_LE_BE(AFMT_U24_LE, AFMT_U24_BE)
#endif
#if !defined(AFMT_S24_NE) && defined(AFMT_S24_LE) && defined(AFMT_S24_BE)
#define AFMT_S24_NE MP_SELECT_LE_BE(AFMT_S24_LE, AFMT_S24_BE)
#endif
#if !defined(AFMT_U32_NE) && defined(AFMT_U32_LE) && defined(AFMT_U32_BE)
#define AFMT_U32MP_SELECT_LE_BE(AFMT_U32_LE, AFMT_U32_BE)
#endif
#if !defined(AFMT_S32_NE) && defined(AFMT_S32_LE) && defined(AFMT_S32_BE)
#define AFMT_S32MP_SELECT_LE_BE(AFMT_S32_LE, AFMT_S32_BE)
#endif
static const int format_table[][2] = {
{AFMT_U8, AF_FORMAT_U8},
{AFMT_S8, AF_FORMAT_S8},
{AFMT_U16_NE, AF_FORMAT_U16},
{AFMT_S16_NE, AF_FORMAT_S16},
#ifdef AFMT_U24_NE
{AFMT_U24_NE, AF_FORMAT_U24},
{AFMT_U16_LE, AF_FORMAT_U16_LE},
{AFMT_U16_BE, AF_FORMAT_U16_BE},
{AFMT_S16_LE, AF_FORMAT_S16_LE},
{AFMT_S16_BE, AF_FORMAT_S16_BE},
#ifdef AFMT_S24_PACKED
{AFMT_S24_PACKED, AF_FORMAT_S24_LE},
#endif
#ifdef AFMT_S24_NE
{AFMT_S24_NE, AF_FORMAT_S24},
#ifdef AFMT_U24_LE
{AFMT_U24_LE, AF_FORMAT_U24_LE},
#endif
#ifdef AFMT_U32_NE
{AFMT_U32_NE, AF_FORMAT_U32},
#ifdef AFMT_U24_BE
{AFMT_U24_BE, AF_FORMAT_U24_BE},
#endif
#ifdef AFMT_S32_NE
{AFMT_S32_NE, AF_FORMAT_S32},
#ifdef AFMT_S24_LE
{AFMT_S24_LE, AF_FORMAT_S24_LE},
#endif
#ifdef AFMT_S24_BE
{AFMT_S24_BE, AF_FORMAT_S24_BE},
#endif
#ifdef AFMT_U32_LE
{AFMT_U32_LE, AF_FORMAT_U32_LE},
#endif
#ifdef AFMT_U32_BE
{AFMT_U32_BE, AF_FORMAT_U32_BE},
#endif
#ifdef AFMT_S32_LE
{AFMT_S32_LE, AF_FORMAT_S32_LE},
#endif
#ifdef AFMT_S32_BE
{AFMT_S32_BE, AF_FORMAT_S32_BE},
#endif
#ifdef AFMT_FLOAT
{AFMT_FLOAT, AF_FORMAT_FLOAT},
#endif
// SPECIALS
#ifdef AFMT_MPEG
{AFMT_MPEG, AF_FORMAT_S_MP3},
{AFMT_MPEG, AF_FORMAT_MPEG2},
#endif
#ifdef AFMT_AC3
{AFMT_AC3, AF_FORMAT_AC3},
#endif
{-1, -1}
};
#ifndef AFMT_AC3
#define AFMT_AC3 -1
#endif
static int format2oss(int format)
{
for (int n = 0; format_table[n][0] != -1; n++) {
@@ -159,7 +143,7 @@ static int oss2format(int format)
if (format_table[n][0] == format)
return format_table[n][1];
}
return 0;
return -1;
}
@@ -194,7 +178,8 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
struct priv *p = ao->priv;
switch (cmd) {
case AOCONTROL_GET_VOLUME:
case AOCONTROL_SET_VOLUME: {
case AOCONTROL_SET_VOLUME:
{
ao_control_vol_t *vol = (ao_control_vol_t *)arg;
int fd, v, devs;
@@ -204,7 +189,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return CONTROL_OK;
#endif
if (AF_FORMAT_IS_SPECIAL(ao->format))
if (AF_FORMAT_IS_AC3(ao->format))
return CONTROL_TRUE;
if ((fd = open(p->oss_mixer_device, O_RDONLY)) != -1) {
@@ -225,203 +210,22 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
close(fd);
return CONTROL_OK;
}
}
return CONTROL_ERROR;
}
#ifdef SNDCTL_DSP_GETPLAYVOL
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
#endif
}
return CONTROL_UNKNOWN;
}
// 1: ok, 0: not writable, -1: error
static int device_writable(struct ao *ao)
{
struct priv *p = ao->priv;
struct pollfd fd = {.fd = p->audio_fd, .events = POLLOUT};
return poll(&fd, 1, 0);
}
static void close_device(struct ao *ao)
{
struct priv *p = ao->priv;
p->device_failed = false;
if (p->audio_fd == -1)
return;
#if defined(SNDCTL_DSP_RESET)
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#endif
close(p->audio_fd);
p->audio_fd = -1;
}
// close audio device
static void uninit(struct ao *ao)
{
close_device(ao);
}
static bool try_format(struct ao *ao, int *format)
{
struct priv *p = ao->priv;
int oss_format = format2oss(*format);
if (oss_format == -1 && AF_FORMAT_IS_IEC61937(*format))
oss_format = AFMT_AC3;
if (oss_format == -1) {
MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n",
af_fmt_to_str(*format));
*format = 0;
return false;
}
int actual_format = oss_format;
if (ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &actual_format) < 0)
actual_format = -1;
if (actual_format == oss_format)
return true;
MP_WARN(ao, "Can't set audio device to %s output.\n", af_fmt_to_str(*format));
*format = oss2format(actual_format);
if (actual_format != -1 && !*format)
MP_ERR(ao, "Unknown/Unsupported OSS format: 0x%x.\n", actual_format);
return false;
}
static int reopen_device(struct ao *ao, bool allow_format_changes)
{
struct priv *p = ao->priv;
int samplerate = ao->samplerate;
int format = ao->format;
struct mp_chmap channels = ao->channels;
#ifdef __linux__
p->audio_fd = open(p->dsp, O_WRONLY | O_NONBLOCK);
#else
p->audio_fd = open(p->dsp, O_WRONLY);
#endif
if (p->audio_fd < 0) {
MP_ERR(ao, "Can't open audio device %s: %s\n", p->dsp, strerror(errno));
goto fail;
}
#ifdef __linux__
/* Remove the non-blocking flag */
if (fcntl(p->audio_fd, F_SETFL, 0) < 0) {
MP_ERR(ao, "Can't make file descriptor blocking: %s\n", strerror(errno));
goto fail;
}
#endif
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
if (AF_FORMAT_IS_IEC61937(format)) {
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate);
// Probably could be fixed by setting number of channels; needs testing.
if (channels.num != 2) {
MP_ERR(ao, "Format %s not implemented.\n", af_fmt_to_str(format));
goto fail;
}
}
int try_formats[] = {format, AF_FORMAT_S32, AF_FORMAT_S24, AF_FORMAT_S16, 0};
for (int n = 0; try_formats[n]; n++) {
format = try_formats[n];
if (try_format(ao, &format))
break;
}
if (!format) {
MP_ERR(ao, "Can't set sample format.\n");
goto fail;
}
MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(format));
if (!AF_FORMAT_IS_IEC61937(format)) {
struct mp_chmap_sel sel = {0};
for (int n = 0; n < MP_NUM_CHANNELS + 1; n++)
mp_chmap_sel_add_map(&sel, &oss_layouts[n]);
if (!ao_chmap_sel_adjust(ao, &sel, &channels))
goto fail;
int reqchannels = channels.num;
// We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
if (reqchannels > 2) {
int nchannels = reqchannels;
if (ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1 ||
nchannels != reqchannels)
{
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
goto fail;
}
} else {
int c = reqchannels - 1;
if (ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
goto fail;
}
if (!ao_chmap_sel_get_def(ao, &sel, &channels, c + 1))
goto fail;
}
MP_VERBOSE(ao, "using %d channels (requested: %d)\n",
channels.num, reqchannels);
// set rate
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate);
MP_VERBOSE(ao, "using %d Hz samplerate\n", samplerate);
}
audio_buf_info zz = {0};
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &zz) == -1) {
int r = 0;
MP_WARN(ao, "driver doesn't support SNDCTL_DSP_GETOSPACE\n");
if (ioctl(p->audio_fd, SNDCTL_DSP_GETBLKSIZE, &r) == -1)
MP_VERBOSE(ao, "%d bytes/frag (config.h)\n", p->outburst);
else {
p->outburst = r;
MP_VERBOSE(ao, "%d bytes/frag (GETBLKSIZE)\n", p->outburst);
}
} else {
MP_VERBOSE(ao, "frags: %3d/%d (%d bytes/frag) free: %6d\n",
zz.fragments, zz.fragstotal, zz.fragsize, zz.bytes);
p->buffersize = zz.bytes;
p->outburst = zz.fragsize;
}
if (allow_format_changes) {
ao->format = format;
ao->samplerate = samplerate;
ao->channels = channels;
} else {
if (format != ao->format || samplerate != ao->samplerate ||
!mp_chmap_equals(&channels, &ao->channels))
{
MP_ERR(ao, "Could not reselect previous audio format.\n");
goto fail;
}
}
p->outburst -= p->outburst % (channels.num * af_fmt2bps(format)); // round down
return 0;
fail:
close_device(ao);
return -1;
}
// open & setup audio device
// return: 0=success -1=fail
static int init(struct ao *ao)
{
struct priv *p = ao->priv;
int oss_format;
#ifdef SNDCTL_DSP_GETPLAYVOL
ao->no_persistent_volume = true;
#endif
const char *mchan = NULL;
if (p->cfg_oss_mixer_channel && p->cfg_oss_mixer_channel[0])
@@ -462,36 +266,178 @@ static int init(struct ao *ao)
MP_VERBOSE(ao, "using '%s' mixer device\n", p->oss_mixer_device);
MP_VERBOSE(ao, "using '%s' mixer device\n", mixer_channels[p->oss_mixer_channel]);
#ifdef __linux__
p->audio_fd = open(p->dsp, O_WRONLY | O_NONBLOCK);
#else
p->audio_fd = open(p->dsp, O_WRONLY);
#endif
if (p->audio_fd < 0) {
MP_ERR(ao, "Can't open audio device %s: %s\n", p->dsp, strerror(errno));
return -1;
}
#ifdef __linux__
/* Remove the non-blocking flag */
if (fcntl(p->audio_fd, F_SETFL, 0) < 0) {
MP_ERR(ao, "Can't make file descriptor blocking: %s\n", strerror(errno));
return -1;
}
#endif
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
ao->format = af_fmt_from_planar(ao->format);
if (reopen_device(ao, true) < 0)
goto fail;
if (AF_FORMAT_IS_AC3(ao->format)) {
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
}
ac3_retry:
if (AF_FORMAT_IS_AC3(ao->format))
ao->format = AF_FORMAT_AC3;
oss_format = format2oss(ao->format);
if (oss_format == -1) {
MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n",
af_fmt_to_str(ao->format));
#if defined(AFMT_S32_LE) && defined(AFMT_S32_BE)
#if BYTE_ORDER == BIG_ENDIAN
oss_format = AFMT_S32_BE;
#else
oss_format = AFMT_S32_LE;
#endif
ao->format = AF_FORMAT_S32;
#elif defined(AFMT_S24_LE) && defined(AFMT_S24_BE)
#if BYTE_ORDER == BIG_ENDIAN
oss_format = AFMT_S24_BE;
#else
oss_format = AFMT_S24_LE;
#endif
ao->format = AF_FORMAT_S24;
#else
#if BYTE_ORDER == BIG_ENDIAN
oss_format = AFMT_S16_BE;
#else
oss_format = AFMT_S16_LE;
#endif
ao->format = AF_FORMAT_S16;
#endif
}
if (ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &oss_format) < 0 ||
oss_format != format2oss(ao->format))
{
MP_WARN(ao, "Can't set audio device %s to %s output, trying %s...\n",
p->dsp, af_fmt_to_str(ao->format),
af_fmt_to_str(AF_FORMAT_S16));
ao->format = AF_FORMAT_S16;
goto ac3_retry;
}
ao->format = oss2format(oss_format);
if (ao->format == -1) {
MP_ERR(ao, "Unknown/Unsupported OSS format: %x.\n", oss_format);
return -1;
}
MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(ao->format));
if (!AF_FORMAT_IS_AC3(ao->format)) {
struct mp_chmap_sel sel = {0};
for (int n = 0; n < MP_NUM_CHANNELS + 1; n++)
mp_chmap_sel_add_map(&sel, &oss_layouts[n]);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
int reqchannels = ao->channels.num;
// We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
if (reqchannels > 2) {
int nchannels = reqchannels;
if (ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1 ||
nchannels != reqchannels)
{
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
return -1;
}
} else {
int c = reqchannels - 1;
if (ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
MP_ERR(ao, "Failed to set audio device to %d channels.\n",
reqchannels);
return -1;
}
if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, c + 1))
return -1;
}
MP_VERBOSE(ao, "using %d channels (requested: %d)\n",
ao->channels.num, reqchannels);
// set rate
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
MP_VERBOSE(ao, "using %d Hz samplerate\n", ao->samplerate);
}
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) == -1) {
int r = 0;
MP_WARN(ao, "driver doesn't support SNDCTL_DSP_GETOSPACE\n");
if (ioctl(p->audio_fd, SNDCTL_DSP_GETBLKSIZE, &r) == -1)
MP_VERBOSE(ao, "%d bytes/frag (config.h)\n", p->outburst);
else {
p->outburst = r;
MP_VERBOSE(ao, "%d bytes/frag (GETBLKSIZE)\n", p->outburst);
}
} else {
MP_VERBOSE(ao, "frags: %3d/%d (%d bytes/frag) free: %6d\n",
p->zz.fragments, p->zz.fragstotal, p->zz.fragsize, p->zz.bytes);
p->buffersize = p->zz.bytes;
p->outburst = p->zz.fragsize;
}
if (p->buffersize == -1) {
// Measuring buffer size:
void *data = malloc(p->outburst);
if (!data) {
MP_ERR(ao, "Out of memory, or broken outburst size.\n");
goto fail;
}
void *data;
p->buffersize = 0;
#if HAVE_AUDIO_SELECT
data = malloc(p->outburst);
memset(data, 0, p->outburst);
while (p->buffersize < 0x40000 && device_writable(ao) > 0) {
while (p->buffersize < 0x40000) {
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(p->audio_fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
if (!select(p->audio_fd + 1, NULL, &rfds, NULL, &tv))
break;
write(p->audio_fd, data, p->outburst);
p->buffersize += p->outburst;
}
free(data);
if (p->buffersize == 0) {
MP_ERR(ao, "Your OSS audio driver DOES NOT support poll().\n");
goto fail;
MP_ERR(ao, "*** Your audio driver DOES NOT support select() ***\n");
MP_ERR(ao, "Recompile mpv with #define HAVE_AUDIO_SELECT 0 in config.h!\n");
return -1;
}
#endif
}
return 0;
ao->bps = ao->channels.num * af_fmt2bps(ao->format);
p->outburst -= p->outburst % ao->bps; // round down
ao->bps *= ao->samplerate;
fail:
uninit(ao);
return -1;
return 0;
}
// close audio device
static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->audio_fd == -1)
return;
#ifdef SNDCTL_DSP_RESET
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#endif
close(p->audio_fd);
p->audio_fd = -1;
}
static void drain(struct ao *ao)
@@ -504,39 +450,104 @@ static void drain(struct ao *ao)
#endif
}
#ifndef SNDCTL_DSP_RESET
static void close_device(struct ao *ao)
{
struct priv *p = ao->priv;
close(p->audio_fd);
p->audio_fd = -1;
}
#endif
// stop playing and empty buffers (for seeking/pause)
static void reset(struct ao *ao)
{
#if KEEP_DEVICE
struct priv *p = ao->priv;
int oss_format;
#ifdef SNDCTL_DSP_RESET
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
p->audio_fd = open(p->dsp, O_WRONLY);
if (p->audio_fd < 0) {
MP_ERR(ao, "Fatal error: *** CANNOT "
"RE-OPEN / RESET AUDIO DEVICE *** %s\n", strerror(errno));
return;
}
#if defined(FD_CLOEXEC) && defined(F_SETFD)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
#endif
oss_format = format2oss(ao->format);
if (AF_FORMAT_IS_AC3(ao->format))
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
ioctl(p->audio_fd, SNDCTL_DSP_SETFMT, &oss_format);
if (!AF_FORMAT_IS_AC3(ao->format)) {
int c = ao->channels.num;
if (ao->channels.num > 2)
ioctl(p->audio_fd, SNDCTL_DSP_CHANNELS, &c);
else {
c--;
ioctl(p->audio_fd, SNDCTL_DSP_STEREO, &c);
}
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &ao->samplerate);
}
}
// return: how many bytes can be played without blocking
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
int playsize = p->outburst;
#ifdef SNDCTL_DSP_GETOSPACE
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) != -1) {
// calculate exact buffer space:
playsize = p->zz.fragments * p->zz.fragsize;
return playsize / ao->sstride;
}
#endif
// check buffer
#if HAVE_AUDIO_SELECT
{
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(p->audio_fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
if (!select(p->audio_fd + 1, NULL, &rfds, NULL, &tv))
return 0; // not block!
}
#endif
return p->outburst / ao->sstride;
}
// stop playing, keep buffers (for pause)
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
p->prepause_space = get_space(ao) * ao->sstride;
#ifdef SNDCTL_DSP_RESET
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
#endif
}
// plays 'len' samples of 'data'
// plays 'len' bytes of 'data'
// it should round it down to outburst*n
// return: number of samples played
// return: number of bytes played
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
int len = samples * ao->sstride;
if (len == 0)
return len;
if (p->audio_fd < 0 && !p->device_failed && reopen_device(ao, false) < 0)
MP_ERR(ao, "Fatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n");
if (p->audio_fd < 0) {
// Let playback continue normally, even with a closed device.
p->device_failed = true;
double now = mp_time_sec();
if (p->audio_end < now)
p->audio_end = now;
p->audio_end += samples / (double)ao->samplerate;
return samples;
}
if (len > p->outburst || !(flags & AOPLAY_FINAL_CHUNK)) {
len /= p->outburst;
len *= p->outburst;
@@ -545,16 +556,22 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return len / ao->sstride;
}
// resume playing, after audio_pause()
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
#ifndef SNDCTL_DSP_RESET
reset(ao);
#endif
int fillframes = get_space(ao) - p->prepause_space / ao->sstride;
if (fillframes > 0)
ao_play_silence(ao, fillframes);
}
// return: delay in seconds between first and last sample in buffer
static float get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->audio_fd < 0) {
double rest = p->audio_end - mp_time_sec();
if (rest > 0)
return rest;
return 0;
}
/* Calculate how many bytes/second is sent out */
if (p->audio_delay_method == 2) {
#ifdef SNDCTL_DSP_GETODELAY
@@ -565,57 +582,16 @@ static float get_delay(struct ao *ao)
p->audio_delay_method = 1; // fallback if not supported
}
if (p->audio_delay_method == 1) {
audio_buf_info zz = {0};
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &zz) != -1) {
return ((float)(p->buffersize - zz.bytes)) / (float)ao->bps;
// SNDCTL_DSP_GETOSPACE
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &p->zz) != -1) {
return ((float)(p->buffersize -
p->zz.bytes)) / (float)ao->bps;
}
p->audio_delay_method = 0; // fallback if not supported
}
return ((float)p->buffersize) / (float)ao->bps;
}
// return: how many samples can be played without blocking
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
audio_buf_info zz = {0};
if (ioctl(p->audio_fd, SNDCTL_DSP_GETOSPACE, &zz) != -1) {
// calculate exact buffer space:
return zz.fragments * zz.fragsize / ao->sstride;
}
if (p->audio_fd < 0 && p->device_failed && get_delay(ao) > 0.2)
return 0;
if (p->audio_fd < 0 || device_writable(ao) > 0)
return p->outburst / ao->sstride;
return 0;
}
// stop playing, keep buffers (for pause)
static void audio_pause(struct ao *ao)
{
struct priv *p = ao->priv;
p->prepause_samples = get_delay(ao) * ao->samplerate;
#if KEEP_DEVICE
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
#endif
}
// resume playing, after audio_pause()
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
p->audio_end = 0;
if (p->prepause_samples > 0)
ao_play_silence(ao, p->prepause_samples);
}
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_oss = {
+9 -16
View File
@@ -35,7 +35,6 @@
#include "ao.h"
#include "internal.h"
#include "common/msg.h"
#include "osdep/endian.h"
#ifdef __MINGW32__
// for GetFileType to detect pipes
@@ -73,7 +72,8 @@ static void fput32le(uint32_t val, FILE *fp)
static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length)
{
bool use_waveex = true;
uint16_t fmt = ao->format == AF_FORMAT_FLOAT ? WAV_ID_FLOAT_PCM : WAV_ID_PCM;
uint16_t fmt = ao->format == AF_FORMAT_FLOAT_LE ?
WAV_ID_FLOAT_PCM : WAV_ID_PCM;
uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
int bits = af_fmt2bits(ao->format);
@@ -124,23 +124,16 @@ static int init(struct ao *ao)
if (priv->waveheader) {
// WAV files must have one of the following formats
// And they don't work in big endian; fixing it would be simple, but
// nobody cares.
if (BYTE_ORDER == BIG_ENDIAN) {
MP_FATAL(ao, "Not supported on big endian.\n");
return -1;
}
switch (ao->format) {
case AF_FORMAT_U8:
case AF_FORMAT_S16:
case AF_FORMAT_S24:
case AF_FORMAT_S32:
case AF_FORMAT_FLOAT:
case AF_FORMAT_S16_LE:
case AF_FORMAT_S24_LE:
case AF_FORMAT_S32_LE:
case AF_FORMAT_FLOAT_LE:
case AF_FORMAT_AC3_LE:
break;
default:
if (!AF_FORMAT_IS_IEC61937(ao->format))
ao->format = AF_FORMAT_S16;
ao->format = AF_FORMAT_S16_LE;
break;
}
}
@@ -210,7 +203,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
fwrite(data[0], len, 1, priv->fp);
priv->data_length += len;
return samples;
return len / ao->sstride;
}
#define OPT_BASE_STRUCT struct priv
+32 -74
View File
@@ -169,31 +169,16 @@ static const struct format_map {
int mp_format;
pa_sample_format_t pa_format;
} format_maps[] = {
{AF_FORMAT_S16, PA_SAMPLE_S16NE},
{AF_FORMAT_S32, PA_SAMPLE_S32NE},
{AF_FORMAT_FLOAT, PA_SAMPLE_FLOAT32NE},
{AF_FORMAT_S16_LE, PA_SAMPLE_S16LE},
{AF_FORMAT_S16_BE, PA_SAMPLE_S16BE},
{AF_FORMAT_S32_LE, PA_SAMPLE_S32LE},
{AF_FORMAT_S32_BE, PA_SAMPLE_S32BE},
{AF_FORMAT_FLOAT_LE, PA_SAMPLE_FLOAT32LE},
{AF_FORMAT_FLOAT_BE, PA_SAMPLE_FLOAT32BE},
{AF_FORMAT_U8, PA_SAMPLE_U8},
{AF_FORMAT_UNKNOWN, 0}
};
static pa_encoding_t map_digital_format(int format)
{
switch (format) {
case AF_FORMAT_S_AC3: return PA_ENCODING_AC3_IEC61937;
case AF_FORMAT_S_EAC3: return PA_ENCODING_EAC3_IEC61937;
case AF_FORMAT_S_MP3: return PA_ENCODING_MPEG_IEC61937;
case AF_FORMAT_S_DTS:
case AF_FORMAT_S_DTSHD: return PA_ENCODING_DTS_IEC61937;
#ifdef PA_ENCODING_MPEG2_AAC_IEC61937
case AF_FORMAT_S_AAC: return PA_ENCODING_MPEG2_AAC_IEC61937;
#endif
default:
if (AF_FORMAT_IS_IEC61937(format))
return PA_ENCODING_ANY;
return PA_ENCODING_PCM;
}
}
static const int speaker_map[][2] = {
{PA_CHANNEL_POSITION_FRONT_LEFT, MP_SPEAKER_ID_FL},
{PA_CHANNEL_POSITION_FRONT_RIGHT, MP_SPEAKER_ID_FR},
@@ -289,9 +274,9 @@ static void uninit(struct ao *ao)
static int init(struct ao *ao)
{
struct pa_sample_spec ss;
struct pa_channel_map map;
pa_proplist *proplist = NULL;
pa_format_info *format = NULL;
struct priv *priv = ao->priv;
char *host = priv->cfg_host && priv->cfg_host[0] ? priv->cfg_host : NULL;
char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : NULL;
@@ -299,6 +284,8 @@ static int init(struct ao *ao)
pthread_mutex_init(&priv->wakeup_lock, NULL);
pthread_cond_init(&priv->wakeup, NULL);
ao->per_application_mixer = true;
if (!(priv->mainloop = pa_threaded_mainloop_new())) {
MP_ERR(ao, "Failed to allocate main loop\n");
goto fail;
@@ -310,12 +297,6 @@ static int init(struct ao *ao)
goto fail;
}
MP_VERBOSE(ao, "Library version: %s\n", pa_get_library_version());
MP_VERBOSE(ao, "Proto: %lu\n",
(long)pa_context_get_protocol_version(priv->context));
MP_VERBOSE(ao, "Server proto: %lu\n",
(long)pa_context_get_server_protocol_version(priv->context));
pa_context_set_state_callback(priv->context, context_state_cb, ao);
if (pa_context_connect(priv->context, host, 0, NULL) < 0)
@@ -332,26 +313,26 @@ static int init(struct ao *ao)
if (pa_context_get_state(priv->context) != PA_CONTEXT_READY)
goto unlock_and_fail;
if (!(format = pa_format_info_new()))
goto unlock_and_fail;
ss.channels = ao->channels.num;
ss.rate = ao->samplerate;
ao->format = af_fmt_from_planar(ao->format);
format->encoding = map_digital_format(ao->format);
if (format->encoding == PA_ENCODING_PCM) {
const struct format_map *fmt_map = format_maps;
while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
MP_VERBOSE(ao, "Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
fmt_map++;
const struct format_map *fmt_map = format_maps;
while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
MP_VERBOSE(ao, "Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
ao->format = fmt_map->mp_format;
fmt_map++;
}
ao->format = fmt_map->mp_format;
ss.format = fmt_map->pa_format;
pa_format_info_set_sample_format(format, fmt_map->pa_format);
if (!pa_sample_spec_valid(&ss)) {
MP_ERR(ao, "Invalid sample spec\n");
goto unlock_and_fail;
}
if (!select_chmap(ao, &map))
@@ -365,28 +346,14 @@ static int init(struct ao *ao)
(void)pa_proplist_sets(proplist, PA_PROP_MEDIA_ICON_NAME,
PULSE_CLIENT_NAME);
pa_format_info_set_rate(format, ao->samplerate);
pa_format_info_set_channels(format, ao->channels.num);
pa_format_info_set_channel_map(format, &map);
if (!pa_format_info_valid(format)) {
MP_ERR(ao, "Invalid audio format\n");
goto unlock_and_fail;
}
if (!(priv->stream = pa_stream_new_extended(priv->context, "audio stream",
&format, 1, proplist)))
if (!(priv->stream = pa_stream_new_with_proplist(priv->context,
"audio stream", &ss,
&map, proplist)))
goto unlock_and_fail;
pa_proplist_free(proplist);
proplist = NULL;
pa_sample_spec ss;
pa_channel_map map2;
if (pa_format_info_to_sample_spec(format, &ss, &map2) < 0)
goto unlock_and_fail;
pa_stream_set_state_callback(priv->stream, stream_state_cb, ao);
pa_stream_set_write_callback(priv->stream, stream_request_cb, ao);
pa_stream_set_latency_update_callback(priv->stream,
@@ -409,14 +376,10 @@ static int init(struct ao *ao)
goto unlock_and_fail;
/* Wait until the stream is ready */
while (1) {
int state = pa_stream_get_state(priv->stream);
if (state == PA_STREAM_READY)
break;
if (!PA_STREAM_IS_GOOD(state))
goto unlock_and_fail;
pa_threaded_mainloop_wait(priv->mainloop);
}
pa_threaded_mainloop_wait(priv->mainloop);
if (pa_stream_get_state(priv->stream) != PA_STREAM_READY)
goto unlock_and_fail;
pa_threaded_mainloop_unlock(priv->mainloop);
@@ -428,8 +391,6 @@ unlock_and_fail:
pa_threaded_mainloop_unlock(priv->mainloop);
fail:
if (format)
pa_format_info_free(format);
if (priv->context) {
if (!(pa_context_errno(priv->context) == PA_ERR_CONNECTIONREFUSED
&& ao->probing))
@@ -620,7 +581,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
pa_threaded_mainloop_lock(priv->mainloop);
if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx,
info_func, ao))) {
GENERIC_ERR_MSG("pa_context_get_sink_input_info() failed");
GENERIC_ERR_MSG("pa_stream_get_sink_input_info() failed");
return CONTROL_ERROR;
}
// Warning: some information in pi might be unaccessible, because
@@ -683,9 +644,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return CONTROL_OK;
}
case AOCONTROL_HAS_PER_APP_VOLUME:
return CONTROL_TRUE;
case AOCONTROL_UPDATE_STREAM_TITLE: {
char *title = (char *)arg;
pa_threaded_mainloop_lock(priv->mainloop);
+28 -14
View File
@@ -52,26 +52,40 @@ static int set_format(struct ao *ao)
case AF_FORMAT_S8:
rsd_format = RSD_S8;
break;
case AF_FORMAT_S16:
rsd_format = RSD_S16_NE;
case AF_FORMAT_S16_LE:
rsd_format = RSD_S16_LE;
break;
case AF_FORMAT_U16:
rsd_format = RSD_U16_NE;
case AF_FORMAT_S16_BE:
rsd_format = RSD_S16_BE;
break;
case AF_FORMAT_S24:
case AF_FORMAT_U24:
rsd_format = RSD_S32_NE;
ao->format = AF_FORMAT_S32;
case AF_FORMAT_U16_LE:
rsd_format = RSD_U16_LE;
break;
case AF_FORMAT_S32:
rsd_format = RSD_S32_NE;
case AF_FORMAT_U16_BE:
rsd_format = RSD_U16_BE;
break;
case AF_FORMAT_U32:
rsd_format = RSD_U32_NE;
case AF_FORMAT_S24_LE:
case AF_FORMAT_S24_BE:
case AF_FORMAT_U24_LE:
case AF_FORMAT_U24_BE:
rsd_format = RSD_S32_LE;
ao->format = AF_FORMAT_S32_LE;
break;
case AF_FORMAT_S32_LE:
rsd_format = RSD_S32_LE;
break;
case AF_FORMAT_S32_BE:
rsd_format = RSD_S32_BE;
break;
case AF_FORMAT_U32_LE:
rsd_format = RSD_U32_LE;
break;
case AF_FORMAT_U32_BE:
rsd_format = RSD_U32_BE;
break;
default:
rsd_format = RSD_S16_NE;
ao->format = AF_FORMAT_S16;
rsd_format = RSD_S16_LE;
ao->format = AF_FORMAT_S16_LE;
}
return rsd_format;
+44 -32
View File
@@ -38,20 +38,6 @@ struct priv
float buflen;
};
static int fmtmap[][2] = {
{AF_FORMAT_U8, AUDIO_U8},
{AF_FORMAT_S8, AUDIO_S8},
{AF_FORMAT_U16, AUDIO_U16SYS},
{AF_FORMAT_S16, AUDIO_S16SYS},
#ifdef AUDIO_S32SYS
{AF_FORMAT_S32, AUDIO_S32SYS},
#endif
#ifdef AUDIO_F32SYS
{AF_FORMAT_FLOAT, AUDIO_F32SYS},
#endif
{0}
};
static void audio_callback(void *userdata, Uint8 *stream, int len)
{
struct ao *ao = userdata;
@@ -118,12 +104,26 @@ static int init(struct ao *ao)
SDL_AudioSpec desired, obtained;
desired.format = AUDIO_S16SYS;
for (int n = 0; fmtmap[n][0]; n++) {
if (ao->format == fmtmap[n][0]) {
desired.format = fmtmap[n][1];
break;
}
switch (ao->format) {
case AF_FORMAT_U8: desired.format = AUDIO_U8; break;
case AF_FORMAT_S8: desired.format = AUDIO_S8; break;
case AF_FORMAT_U16_LE: desired.format = AUDIO_U16LSB; break;
case AF_FORMAT_U16_BE: desired.format = AUDIO_U16MSB; break;
default:
case AF_FORMAT_S16_LE: desired.format = AUDIO_S16LSB; break;
case AF_FORMAT_S16_BE: desired.format = AUDIO_S16MSB; break;
#ifdef AUDIO_S32LSB
case AF_FORMAT_S32_LE: desired.format = AUDIO_S32LSB; break;
#endif
#ifdef AUDIO_S32MSB
case AF_FORMAT_S32_BE: desired.format = AUDIO_S32MSB; break;
#endif
#ifdef AUDIO_F32LSB
case AF_FORMAT_FLOAT_LE: desired.format = AUDIO_F32LSB; break;
#endif
#ifdef AUDIO_F32MSB
case AF_FORMAT_FLOAT_BE: desired.format = AUDIO_F32MSB; break;
#endif
}
desired.freq = ao->samplerate;
desired.channels = ao->channels.num;
@@ -156,18 +156,30 @@ static int init(struct ao *ao)
// large, this will help.
ao->device_buffer = 3 * obtained.samples;
ao->format = 0;
for (int n = 0; fmtmap[n][0]; n++) {
if (obtained.format == fmtmap[n][1]) {
ao->format = fmtmap[n][0];
break;
}
}
if (!ao->format) {
if (!ao->probing)
MP_ERR(ao, "could not find matching format\n");
uninit(ao);
return -1;
switch (obtained.format) {
case AUDIO_U8: ao->format = AF_FORMAT_U8; break;
case AUDIO_S8: ao->format = AF_FORMAT_S8; break;
case AUDIO_S16LSB: ao->format = AF_FORMAT_S16_LE; break;
case AUDIO_S16MSB: ao->format = AF_FORMAT_S16_BE; break;
case AUDIO_U16LSB: ao->format = AF_FORMAT_U16_LE; break;
case AUDIO_U16MSB: ao->format = AF_FORMAT_U16_BE; break;
#ifdef AUDIO_S32LSB
case AUDIO_S32LSB: ao->format = AF_FORMAT_S32_LE; break;
#endif
#ifdef AUDIO_S32MSB
case AUDIO_S32MSB: ao->format = AF_FORMAT_S32_BE; break;
#endif
#ifdef AUDIO_F32LSB
case AUDIO_F32LSB: ao->format = AF_FORMAT_FLOAT_LE; break;
#endif
#ifdef AUDIO_F32MSB
case AUDIO_F32MSB: ao->format = AF_FORMAT_FLOAT_BE; break;
#endif
default:
if (!ao->probing)
MP_ERR(ao, "could not find matching format\n");
uninit(ao);
return -1;
}
if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) {
+54 -59
View File
@@ -33,7 +33,6 @@ struct priv {
struct sio_hdl *hdl;
struct sio_par par;
int delay;
bool playing;
int vol;
int havevol;
#define SILENCE_NMAX 0x1000
@@ -61,8 +60,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return CONTROL_FALSE;
sio_setvol(p->hdl, vol->left * SIO_MAXVOL / 100);
break;
case AOCONTROL_HAS_SOFT_VOLUME:
return CONTROL_TRUE;
default:
return CONTROL_UNKNOWN;
}
@@ -75,7 +72,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
static void movecb(void *addr, int delta)
{
struct priv *p = addr;
p->delay -= delta;
p->delay -= delta * (int)(p->par.bps * p->par.pchan);
}
/*
@@ -110,20 +107,26 @@ static int init(struct ao *ao)
struct priv *p = ao->priv;
struct af_to_par {
int format, bits, sig;
int format, bits, sig, le;
} static const af_to_par[] = {
{AF_FORMAT_U8, 8, 0},
{AF_FORMAT_S8, 8, 1},
{AF_FORMAT_U16, 16, 0},
{AF_FORMAT_S16, 16, 1},
{AF_FORMAT_U24, 24, 0},
{AF_FORMAT_S24, 24, 1},
{AF_FORMAT_U32, 32, 0},
{AF_FORMAT_S32, 32, 1},
{AF_FORMAT_U8, 8, 0, 0},
{AF_FORMAT_S8, 8, 1, 0},
{AF_FORMAT_U16_LE, 16, 0, 1},
{AF_FORMAT_U16_BE, 16, 0, 0},
{AF_FORMAT_S16_LE, 16, 1, 1},
{AF_FORMAT_S16_BE, 16, 1, 0},
{AF_FORMAT_U24_LE, 16, 0, 1},
{AF_FORMAT_U24_BE, 24, 0, 0},
{AF_FORMAT_S24_LE, 24, 1, 1},
{AF_FORMAT_S24_BE, 24, 1, 0},
{AF_FORMAT_U32_LE, 32, 0, 1},
{AF_FORMAT_U32_BE, 32, 0, 0},
{AF_FORMAT_S32_LE, 32, 1, 1},
{AF_FORMAT_S32_BE, 32, 1, 0}
}, *ap;
int i;
p->hdl = sio_open(p->dev, SIO_PLAY, 1);
p->hdl = sio_open(p->dev, SIO_PLAY, 0);
if (p->hdl == NULL) {
MP_ERR(ao, "can't open sndio %s\n", p->dev);
goto error;
@@ -144,7 +147,7 @@ static int init(struct ao *ao)
p->par.bits = ap->bits;
p->par.sig = ap->sig;
if (ap->bits > 8)
p->par.le = SIO_LE_NATIVE;
p->par.le = ap->le;
if (ap->bits != SIO_BPS(ap->bits))
p->par.bps = ap->bits / 8;
break;
@@ -170,25 +173,30 @@ static int init(struct ao *ao)
MP_ERR(ao, "couldn't get params\n");
goto error;
}
if (p->par.bps > 1 && p->par.le != SIO_LE_NATIVE) {
MP_ERR(ao, "swapped endian output not supported\n");
goto error;
}
if (p->par.bits == 8 && p->par.bps == 1) {
ao->format = p->par.sig ? AF_FORMAT_S8 : AF_FORMAT_U8;
} else if (p->par.bits == 16 && p->par.bps == 2) {
ao->format = p->par.sig ? AF_FORMAT_S16 : AF_FORMAT_U16;
ao->format = p->par.sig ?
(p->par.le ? AF_FORMAT_S16_LE : AF_FORMAT_S16_BE) :
(p->par.le ? AF_FORMAT_U16_LE : AF_FORMAT_U16_BE);
} else if ((p->par.bits == 24 || p->par.msb) && p->par.bps == 3) {
ao->format = p->par.sig ? AF_FORMAT_S24 : AF_FORMAT_U24;
ao->format = p->par.sig ?
(p->par.le ? AF_FORMAT_S24_LE : AF_FORMAT_S24_BE) :
(p->par.le ? AF_FORMAT_U24_LE : AF_FORMAT_U24_BE);
} else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4) {
ao->format = p->par.sig ? AF_FORMAT_S32 : AF_FORMAT_U32;
ao->format = p->par.sig ?
(p->par.le ? AF_FORMAT_S32_LE : AF_FORMAT_S32_BE) :
(p->par.le ? AF_FORMAT_U32_LE : AF_FORMAT_U32_BE);
} else {
MP_ERR(ao, "couldn't set format\n");
goto error;
}
ao->bps = p->par.bps * p->par.pchan * p->par.rate;
ao->no_persistent_volume = true;
p->havevol = sio_onvol(p->hdl, volcb, p);
sio_onmove(p->hdl, movecb, p);
p->delay = 0;
if (!sio_start(p->hdl))
MP_ERR(ao, "init: couldn't start\n");
@@ -225,56 +233,46 @@ static void reset(struct ao *ao)
{
struct priv *p = ao->priv;
if (p->playing) {
MP_WARN(ao, "Blocking until remaining audio is played... (sndio design bug).\n");
p->playing = false;
if (!sio_stop(p->hdl))
MP_ERR(ao, "reset: couldn't stop\n");
p->delay = 0;
if (!sio_start(p->hdl))
MP_ERR(ao, "reset: couldn't start\n");
}
if (!sio_stop(p->hdl))
MP_ERR(ao, "reset: couldn't stop\n");
p->delay = 0;
if (!sio_start(p->hdl))
MP_ERR(ao, "reset: couldn't start\n");
}
/*
* play given number of samples until sio_write() blocks
* play given number of bytes until sio_write() blocks
*/
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
int n;
n = sio_write(p->hdl, data[0], samples * ao->sstride) / ao->sstride;
n = sio_write(p->hdl, data[0], samples * ao->sstride);
p->delay += n;
p->playing = true;
/* on AOPLAY_FINAL_CHUNK, just let it underrun */
return n;
if (flags & AOPLAY_FINAL_CHUNK)
reset(ao);
return n / ao->sstride;
}
/*
* make libsndio call movecb()
*/
static void update(struct ao *ao)
{
struct priv *p = ao->priv;
int n = sio_pollfd(p->hdl, p->pfd, POLLOUT);
while (poll(p->pfd, n, 0) < 0 && errno == EINTR) {}
sio_revents(p->hdl, p->pfd);
}
/*
* how many samples can be played without blocking
* how many bytes can be played without blocking
*/
static int get_space(struct ao *ao)
{
struct priv *p = ao->priv;
int n;
update(ao);
/*
* call poll() and sio_revents(), so the
* delay counter is updated
*/
n = sio_pollfd(p->hdl, p->pfd, POLLOUT);
while (poll(p->pfd, n, 0) < 0 && errno == EINTR)
; /* nothing */
sio_revents(p->hdl, p->pfd);
int samples = p->par.bufsz - p->delay;
return samples / p->par.round * p->par.round;
return (p->par.bufsz * p->par.pchan * p->par.bps - p->delay) / ao->sstride;
}
/*
@@ -283,10 +281,7 @@ static int get_space(struct ao *ao)
static float get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
update(ao);
return p->delay / (double)p->par.rate;
return (float)p->delay / (p->par.bps * p->par.pchan * p->par.rate);
}
/*
@@ -306,8 +301,8 @@ static void audio_resume(struct ao *ao)
int n, count, todo;
/*
* we want to start with buffers full, because mpv uses
* get_delay() as clock, which would cause video to
* we want to start with buffers full, because mplayer uses
* get_space() pointer as clock, which would cause video to
* accelerate while buffers are filled.
*/
todo = p->par.bufsz * p->par.pchan * p->par.bps;
+1 -2
View File
@@ -194,6 +194,7 @@ static int init(struct ao *ao)
wasapi_enumerate_devices(state->log);
}
ao->per_application_mixer = true;
if (state->opt_exclusive) {
state->share_mode = AUDCLNT_SHAREMODE_EXCLUSIVE;
} else {
@@ -283,8 +284,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
ISimpleAudioVolume_SetMute(state->pAudioVolumeProxy, mute, NULL);
return CONTROL_OK;
case AOCONTROL_HAS_PER_APP_VOLUME:
return CONTROL_TRUE;
case AOCONTROL_UPDATE_STREAM_TITLE: {
MP_VERBOSE(state, "Updating stream title to \"%s\"\n", (char*)arg);
wchar_t *title = mp_from_utf8(NULL, (char*)arg);
+1 -1
View File
@@ -28,7 +28,7 @@
#include <mmdeviceapi.h>
#include <avrt.h>
#include "osdep/atomics.h"
#include "compat/atomics.h"
typedef struct wasapi_state {
struct mp_log *log;
+33 -23
View File
@@ -142,36 +142,47 @@ static void set_format(WAVEFORMATEXTENSIBLE *wformat, WORD bytepersample,
wformat->dwChannelMask = chanmask;
}
static int format_set_bits(int old_format, int bits, int fp)
{
if (fp) {
switch (bits) {
case 64: return AF_FORMAT_DOUBLE;
case 32: return AF_FORMAT_FLOAT;
default: return 0;
}
static int format_set_bits(int old_format, int bits, int fp) {
int format = old_format;
format &= (~AF_FORMAT_BITS_MASK) & (~AF_FORMAT_POINT_MASK) & (~AF_FORMAT_SIGN_MASK);
format |= AF_FORMAT_SI;
switch (bits) {
case 32:
format |= AF_FORMAT_32BIT;
break;
case 24:
format |= AF_FORMAT_24BIT;
break;
case 16:
format |= AF_FORMAT_16BIT;
break;
default:
abort(); // (should be) unreachable
}
return af_fmt_change_bits(old_format, bits);
if (fp) {
format |= AF_FORMAT_F;
} else {
format |= AF_FORMAT_I;
}
return format;
}
static int set_ao_format(struct wasapi_state *state,
struct ao *const ao,
WAVEFORMATEXTENSIBLE wformat)
{
WAVEFORMATEXTENSIBLE wformat) {
// .Data1 == 1 is PCM, .Data1 == 3 is IEEE_FLOAT
int format = format_set_bits(ao->format,
wformat.Format.wBitsPerSample, wformat.SubFormat.Data1 == 3);
if (wformat.SubFormat.Data1 != 1 && wformat.SubFormat.Data1 != 3) {
MP_ERR(ao, "unknown SubFormat %"PRIu32"\n",
(uint32_t)wformat.SubFormat.Data1);
return 0;
}
// .Data1 == 1 is PCM, .Data1 == 3 is IEEE_FLOAT
int format = format_set_bits(ao->format,
wformat.Format.wBitsPerSample, wformat.SubFormat.Data1 == 3);
if (!format)
return 0;
ao->samplerate = wformat.Format.nSamplesPerSec;
ao->bps = wformat.Format.nAvgBytesPerSec;
ao->format = format;
@@ -193,8 +204,6 @@ static int try_format(struct wasapi_state *state,
set_format(&wformat, bits / 8, samplerate, channels.num, mp_chmap_to_waveext(&channels));
int af_format = format_set_bits(ao->format, bits, bits == 32);
if (!af_format)
return 0;
MP_VERBOSE(ao, "trying %dch %s @ %dhz\n",
channels.num, af_fmt_to_str(af_format), samplerate);
@@ -283,13 +292,14 @@ static int try_passthrough(struct wasapi_state *state,
union WAVEFMT u;
u.extensible = &wformat;
MP_VERBOSE(ao, "trying passthrough for %s...\n", af_fmt_to_str(ao->format));
MP_VERBOSE(ao, "trying passthrough for %s...\n",
af_fmt_to_str((ao->format&~AF_FORMAT_END_MASK) | AF_FORMAT_LE));
HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient,
state->share_mode,
u.ex, NULL);
if (!FAILED(hr)) {
ao->format = ao->format;
ao->format = (ao->format&~AF_FORMAT_END_MASK) | AF_FORMAT_LE;
state->format = wformat;
return 1;
}
@@ -300,7 +310,7 @@ static int find_formats(struct ao *const ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (AF_FORMAT_IS_IEC61937(ao->format) || ao->format == AF_FORMAT_MPEG2) {
if (try_passthrough(state, ao))
return 0;
+5 -3
View File
@@ -25,6 +25,9 @@
#include "audio/chmap.h"
#include "audio/chmap_sel.h"
// Minimum buffer size in seconds.
#define MIN_BUFFER 0.2
// If ao_get_delay() reaches this value after ao_play() was called with the
// AOPLAY_FINAL_CHUNK flag set, the playback core expects that the audio has
// all been played.
@@ -41,6 +44,8 @@ struct ao {
int num_planes;
bool probing; // if true, don't fail loudly on init
bool untimed; // don't assume realtime playback
bool no_persistent_volume; // the AO does the equivalent of af_volume
bool per_application_mixer; // like above, but volume persists (per app)
int device_buffer; // device buffer in samples (guessed by
// common init code if not set by driver)
const struct ao_driver *api; // entrypoints to the wrapper (push.c/pull.c)
@@ -51,7 +56,6 @@ struct ao {
struct mp_log *log; // Using e.g. "[ao/coreaudio]" as prefix
int buffer;
double def_buffer;
void *api_priv;
};
@@ -130,8 +134,6 @@ struct ao_driver {
float (*get_delay)(struct ao *ao);
// push based: block until all queued audio is played (optional)
void (*drain)(struct ao *ao);
// Optional. Return true if audio has stopped in any way.
bool (*get_eof)(struct ao *ao);
// Wait until the audio buffer needs to be refilled. The lock is the
// internal mutex usually protecting the internal AO state (and used to
// protect driver calls), and must be temporarily unlocked while waiting.
+1 -10
View File
@@ -30,7 +30,7 @@
#include "osdep/timer.h"
#include "osdep/threads.h"
#include "osdep/atomics.h"
#include "compat/atomics.h"
#include "misc/ring.h"
/*
@@ -201,14 +201,6 @@ static void drain(struct ao *ao)
reset(ao);
}
static bool get_eof(struct ao *ao)
{
struct ao_pull_state *p = ao->api_priv;
// For simplicity, ignore the latency. Otherwise, we would have to run an
// extra thread to time it.
return mp_ring_buffered(p->buffers[0]) == 0;
}
static void uninit(struct ao *ao)
{
ao->driver->uninit(ao);
@@ -233,7 +225,6 @@ const struct ao_driver ao_api_pull = {
.get_space = get_space,
.play = play,
.get_delay = get_delay,
.get_eof = get_eof,
.pause = pause,
.resume = resume,
.priv_size = sizeof(struct ao_pull_state),
+60 -101
View File
@@ -35,7 +35,7 @@
#include "osdep/threads.h"
#include "osdep/timer.h"
#include "osdep/atomics.h"
#include "compat/atomics.h"
#include "audio/audio.h"
#include "audio/audio_buffer.h"
@@ -52,9 +52,10 @@ struct ao_push_state {
bool terminate;
bool drain;
bool wait_on_ao;
bool still_playing;
bool buffers_full;
bool avoid_ao_wait;
bool need_wakeup;
bool requested_data;
bool paused;
// Whether the current buffer contains the complete audio.
@@ -86,13 +87,15 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return r;
}
static double unlocked_get_delay(struct ao *ao)
static float get_delay(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
double driver_delay = 0;
if (ao->driver->get_delay)
driver_delay = ao->driver->get_delay(ao);
double delay = driver_delay + mp_audio_buffer_seconds(p->buffer);
pthread_mutex_unlock(&p->lock);
if (delay >= AO_EOF_DELAY && p->expected_end_time) {
if (mp_time_sec() > p->expected_end_time) {
MP_ERR(ao, "Audio device EOF reporting is broken!\n");
@@ -103,15 +106,6 @@ static double unlocked_get_delay(struct ao *ao)
return delay;
}
static float get_delay(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
float delay = unlocked_get_delay(ao);
pthread_mutex_unlock(&p->lock);
return delay;
}
static void reset(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
@@ -120,9 +114,7 @@ static void reset(struct ao *ao)
ao->driver->reset(ao);
mp_audio_buffer_clear(p->buffer);
p->paused = false;
if (p->still_playing)
wakeup_playthread(ao);
p->still_playing = false;
wakeup_playthread(ao);
pthread_mutex_unlock(&p->lock);
}
@@ -176,17 +168,13 @@ static int unlocked_get_space(struct ao *ao)
int space = mp_audio_buffer_get_write_available(p->buffer);
if (ao->driver->get_space) {
// The following code attempts to keep the total buffered audio to
// ao->buffer in order to improve latency.
// MIN_BUFFER/2+device_buffer in order to improve latency.
int device_space = ao->driver->get_space(ao);
int device_buffered = ao->device_buffer - device_space;
int soft_buffered = mp_audio_buffer_samples(p->buffer);
// The extra margin helps avoiding too many wakeups if the AO is fully
// byte based and doesn't do proper chunked processing.
int min_buffer = ao->buffer + 64;
int missing = min_buffer - device_buffered - soft_buffered;
// But always keep the device's buffer filled as much as we can.
int device_missing = device_space - soft_buffered;
missing = MPMAX(missing, device_missing);
int min_buffer = MIN_BUFFER / 2 * ao->samplerate + ao->device_buffer;
int total_buffer = device_buffered + soft_buffered;
int missing = min_buffer - total_buffer;
space = MPMIN(space, missing);
space = MPMAX(0, space);
}
@@ -202,15 +190,6 @@ static int get_space(struct ao *ao)
return space;
}
static bool get_eof(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
pthread_mutex_lock(&p->lock);
bool eof = !p->still_playing;
pthread_mutex_unlock(&p->lock);
return eof;
}
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct ao_push_state *p = ao->api_priv;
@@ -220,8 +199,6 @@ static int play(struct ao *ao, void **data, int samples, int flags)
int write_samples = mp_audio_buffer_get_write_available(p->buffer);
write_samples = MPMIN(write_samples, samples);
MP_TRACE(ao, "samples=%d flags=%d r=%d\n", samples, flags, write_samples);
if (write_samples < samples)
flags = flags & ~AOPLAY_FINAL_CHUNK;
bool is_final = flags & AOPLAY_FINAL_CHUNK;
@@ -238,12 +215,13 @@ static int play(struct ao *ao, void **data, int samples, int flags)
p->expected_end_time = 0;
p->final_chunk = is_final;
p->paused = false;
p->still_playing |= write_samples > 0;
// If we don't have new data, the decoder thread basically promises it
// will send new data as soon as it's available.
if (got_data)
if (got_data) {
p->requested_data = false;
wakeup_playthread(ao);
}
pthread_mutex_unlock(&p->lock);
return write_samples;
}
@@ -273,8 +251,8 @@ static void ao_play_data(struct ao *ao)
}
r = MPMAX(r, 0);
// Probably can't copy the rest of the buffer due to period alignment.
bool stuck_eof = r <= 0 && space >= max && data.samples > 0;
if ((flags & AOPLAY_FINAL_CHUNK) && stuck_eof) {
bool stuck = r <= 0 && space >= max && data.samples > 0;
if ((flags & AOPLAY_FINAL_CHUNK) && stuck) {
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
r = max;
}
@@ -284,23 +262,26 @@ static void ao_play_data(struct ao *ao)
if (ao->driver->get_delay)
p->expected_end_time += ao->driver->get_delay(ao);
}
// Nothing written, but more input data than space - this must mean the
// AO's get_space() doesn't do period alignment correctly.
bool stuck = r == 0 && max >= space && space > 0;
if (stuck)
MP_ERR(ao, "Audio output is reporting incorrect buffer status.\n");
// Wait until space becomes available. Also wait if we actually wrote data,
// so the AO wakes us up properly if it needs more data.
p->wait_on_ao = space == 0 || r > 0 || stuck;
p->still_playing |= r > 0;
// If we just filled the AO completely (r == space), don't refill for a
// while. Prevents wakeup feedback with byte-granular AOs.
int needed = unlocked_get_space(ao);
bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck;
if (more)
mp_input_wakeup(ao->input_ctx); // request more data
MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa=%d needed=%d more=%d\n",
max, flags, space, r, p->wait_on_ao, needed, more);
// In both cases, we have to account for space!=0, but the AO not accepting
// any new data (due to rounding to period boundaries).
p->buffers_full = max >= space && r <= 0;
p->avoid_ao_wait = (max == 0 && space > 0) || p->paused || stuck;
MP_TRACE(ao, "in=%d, space=%d r=%d flags=%d aw=%d full=%d f=%d\n", max,
space, r, flags, p->avoid_ao_wait, p->buffers_full, p->final_chunk);
}
// Estimate when the AO needs data again.
static double ao_estimate_timeout(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
double timeout = 0;
if (p->buffers_full && ao->driver->get_delay) {
timeout = ao->driver->get_delay(ao) - 0.050;
// Keep extra safety margin if the buffers are large
if (timeout > 0.100)
timeout = MPMAX(timeout - 0.200, 0.100);
}
return MPMAX(timeout, ao->device_buffer * 0.75 / ao->samplerate);
}
static void *playthread(void *arg)
@@ -312,7 +293,16 @@ static void *playthread(void *arg)
if (!p->paused)
ao_play_data(ao);
if (p->drain && (!p->wait_on_ao || p->paused)) {
// Request new data from decoder if buffer goes below "full".
// Allow a small margin of missing data for AOs that use timeouts.
double margin = ao->driver->wait ? 0 : ao->device_buffer / 8;
if (!p->buffers_full && unlocked_get_space(ao) > margin) {
if (!p->requested_data)
mp_input_wakeup(ao->input_ctx);
p->requested_data = true;
}
if (p->drain && (p->avoid_ao_wait || p->paused)) {
if (ao->driver->drain)
ao->driver->drain(ao);
p->drain = false;
@@ -321,7 +311,7 @@ static void *playthread(void *arg)
if (!p->need_wakeup) {
MP_STATS(ao, "start audio wait");
if (!p->wait_on_ao || p->paused) {
if (p->avoid_ao_wait || p->paused) {
// Avoid busy waiting, because the audio API will still report
// that it needs new data, even if we're not ready yet, or if
// get_space() decides that the amount of audio buffered in the
@@ -329,30 +319,12 @@ static void *playthread(void *arg)
// The most important part is that the decoder is woken up, so
// that the decoder will wake up us in turn.
MP_TRACE(ao, "buffer inactive.\n");
bool was_playing = p->still_playing;
double timeout = -1;
if (p->still_playing && !p->paused) {
timeout = unlocked_get_delay(ao);
if (timeout < AO_EOF_DELAY)
p->still_playing = false;
}
if (was_playing && !p->still_playing)
mp_input_wakeup(ao->input_ctx);
if (p->still_playing && timeout > 0) {
mpthread_cond_timedwait_rel(&p->wakeup, &p->lock, timeout);
} else {
pthread_cond_wait(&p->wakeup, &p->lock);
}
mp_input_wakeup(ao->input_ctx);
pthread_cond_wait(&p->wakeup, &p->lock);
} else {
if (!ao->driver->wait || ao->driver->wait(ao, &p->lock) < 0) {
// Fallback to guessing.
double timeout = 0;
if (ao->driver->get_delay)
timeout = ao->driver->get_delay(ao);
timeout *= 0.25; // wake up if 25% played
double timeout = ao_estimate_timeout(ao);
mpthread_cond_timedwait_rel(&p->wakeup, &p->lock, timeout);
}
}
@@ -364,20 +336,6 @@ static void *playthread(void *arg)
return NULL;
}
static void destroy_no_thread(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
ao->driver->uninit(ao);
for (int n = 0; n < 2; n++)
close(p->wakeup_pipe[n]);
pthread_cond_destroy(&p->wakeup);
pthread_cond_destroy(&p->wakeup_drain);
pthread_mutex_destroy(&p->lock);
}
static void uninit(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
@@ -389,7 +347,14 @@ static void uninit(struct ao *ao)
pthread_join(p->thread, NULL);
destroy_no_thread(ao);
ao->driver->uninit(ao);
for (int n = 0; n < 2; n++)
close(p->wakeup_pipe[n]);
pthread_cond_destroy(&p->wakeup);
pthread_cond_destroy(&p->wakeup_drain);
pthread_mutex_destroy(&p->lock);
}
static int init(struct ao *ao)
@@ -401,11 +366,6 @@ static int init(struct ao *ao)
pthread_cond_init(&p->wakeup_drain, NULL);
mp_make_wakeup_pipe(p->wakeup_pipe);
if (ao->device_buffer <= 0) {
MP_FATAL(ao, "Couldn't probe device buffer size.\n");
goto err;
}
p->buffer = mp_audio_buffer_create(ao);
mp_audio_buffer_reinit_fmt(p->buffer, ao->format,
&ao->channels, ao->samplerate);
@@ -414,7 +374,7 @@ static int init(struct ao *ao)
goto err;
return 0;
err:
destroy_no_thread(ao);
ao->driver->uninit(ao);
return -1;
}
@@ -429,7 +389,6 @@ const struct ao_driver ao_api_push = {
.pause = audio_pause,
.resume = resume,
.drain = drain,
.get_eof = get_eof,
.priv_size = sizeof(struct ao_push_state),
};
+1 -1
View File
@@ -29,7 +29,7 @@
#include "common/common.h"
#include "misc/ctype.h"
#include "bstr.h"
#include "bstr/bstr.h"
int bstrcmp(struct bstr str1, struct bstr str2)
{
+1 -1
View File
@@ -26,7 +26,7 @@
#include <stdarg.h>
#include "talloc.h"
#include "osdep/compiler.h"
#include "compat/compiler.h"
/* NOTE: 'len' is size_t, but most string-handling functions below assume
* that input size has been sanity checked and len fits in an int.
-2
View File
@@ -117,8 +117,6 @@ void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb)
if (mpkt && mpkt->avpacket) {
dst->side_data = mpkt->avpacket->side_data;
dst->side_data_elems = mpkt->avpacket->side_data_elems;
if (dst->data == mpkt->avpacket->data)
dst->buf = mpkt->avpacket->buf;
}
if (mpkt && tb && tb->num > 0 && tb->den > 0)
dst->duration = mpkt->duration / av_q2d(*tb);
+1 -1
View File
@@ -17,7 +17,7 @@
#include <assert.h>
#include "talloc.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "common/msg.h"
#include "codecs.h"
+1 -1
View File
@@ -22,7 +22,7 @@
#include <libavutil/common.h>
#include "talloc.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "common/common.h"
#define appendf(ptr, ...) \
+1 -1
View File
@@ -24,7 +24,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "osdep/compiler.h"
#include "compat/compiler.h"
#include "talloc.h"
// double should be able to represent this exactly
+3
View File
@@ -7,6 +7,9 @@
struct mpv_global {
struct MPOpts *opts;
struct mp_log *log;
int (*stream_interrupt_cb)(void *ctx);
void *stream_interrupt_cb_ctx;
};
#endif
+31 -40
View File
@@ -27,8 +27,8 @@
#include "talloc.h"
#include "misc/bstr.h"
#include "osdep/atomics.h"
#include "bstr/bstr.h"
#include "compat/atomics.h"
#include "common/common.h"
#include "common/global.h"
#include "misc/ring.h"
@@ -158,10 +158,16 @@ static void prepare_status_line(struct mp_log_root *root, char *new_status)
size_t clear_lines = MPMIN(MPMAX(new_lines, old_lines), root->blank_lines);
// clear the status line itself
fprintf(f, "\r\033[K");
if (terminal_erase_to_end_of_line[0]) {
fprintf(f, "\r%s", terminal_erase_to_end_of_line);
} else {
// This code is for MS windows (no ANSI control sequences)
get_screen_size();
fprintf(f, "\r%*s\r", screen_width - 1, "");
}
// and clear all previous old lines
for (size_t n = 1; n < clear_lines; n++)
fprintf(f, "\033[A\r\033[K");
fprintf(f, "%s\r%s", terminal_cursor_up, terminal_erase_to_end_of_line);
// skip "unused" blank lines, so that status is aligned to term bottom
for (size_t n = new_lines; n < clear_lines; n++)
fprintf(f, "\n");
@@ -194,20 +200,10 @@ bool mp_msg_has_status_line(struct mpv_global *global)
return r;
}
static void set_term_color(FILE *stream, int c)
{
if (c == -1) {
fprintf(stream, "\033[0m");
} else {
fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
}
}
static void set_msg_color(FILE* stream, int lev)
{
static const int v_colors[] = {9, 1, 3, -1, -1, 2, 8, 8, 8, -1};
set_term_color(stream, v_colors[lev]);
terminal_set_foreground_color(stream, v_colors[lev]);
}
static void pretty_print_module(FILE* stream, const char *prefix, bool use_color, int lev)
@@ -218,12 +214,12 @@ static void pretty_print_module(FILE* stream, const char *prefix, bool use_color
unsigned int mod = 0;
for (int i = 0; i < prefix_len; ++i)
mod = mod * 33 + prefix[i];
set_term_color(stream, (mod + 1) % 15 + 1);
terminal_set_foreground_color(stream, (mod + 1) % 15 + 1);
}
fprintf(stream, "%10s", prefix);
if (use_color)
set_term_color(stream, -1);
terminal_set_foreground_color(stream, -1);
fprintf(stream, ": ");
if (use_color)
set_msg_color(stream, lev);
@@ -295,7 +291,7 @@ static void print_msg_on_terminal(struct mp_log *log, int lev, char *text)
fprintf(stream, "%s", terminate);
if (root->color)
set_term_color(stream, -1);
terminal_set_foreground_color(stream, -1);
fflush(stream);
}
@@ -367,39 +363,34 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va)
// parent's name. If the name starts with "/", the parent's name is not
// prefixed (except in verbose mode), and if it starts with "!", the name is
// not printed at all (except in verbose mode).
// If name is NULL, the parent's name/prefix is used.
// Thread-safety: fully thread-safe, but keep in mind that talloc is not (so
// talloc_ctx must be owned by the current thread).
struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent,
const char *name)
{
assert(parent);
assert(name);
struct mp_log *log = talloc_zero(talloc_ctx, struct mp_log);
if (!parent->root)
return log; // same as null_log
log->root = parent->root;
if (name) {
if (name[0] == '!') {
name = &name[1];
} else if (name[0] == '/') {
name = &name[1];
log->prefix = talloc_strdup(log, name);
} else {
log->prefix = parent->prefix
? talloc_asprintf(log, "%s/%s", parent->prefix, name)
: talloc_strdup(log, name);
}
log->verbose_prefix = parent->prefix
if (name[0] == '!') {
name = &name[1];
} else if (name[0] == '/') {
name = &name[1];
log->prefix = talloc_strdup(log, name);
} else {
log->prefix = parent->prefix
? talloc_asprintf(log, "%s/%s", parent->prefix, name)
: talloc_strdup(log, name);
if (log->prefix && !log->prefix[0])
log->prefix = NULL;
if (!log->verbose_prefix[0])
log->verbose_prefix = "global";
} else {
log->prefix = talloc_strdup(log, parent->prefix);
log->verbose_prefix = talloc_strdup(log, parent->verbose_prefix);
}
log->verbose_prefix = parent->prefix
? talloc_asprintf(log, "%s/%s", parent->prefix, name)
: talloc_strdup(log, name);
if (log->prefix && !log->prefix[0])
log->prefix = NULL;
if (!log->verbose_prefix[0])
log->verbose_prefix = "global";
return log;
}
@@ -437,8 +428,8 @@ void mp_msg_update_msglevels(struct mpv_global *global)
root->use_terminal = opts->use_terminal;
root->show_time = opts->msg_time;
if (root->use_terminal) {
root->color = opts->msg_color && isatty(STDOUT_FILENO);
root->termosd = isatty(STDERR_FILENO);
root->color = opts->msg_color && isatty(fileno(stdout));
root->termosd = isatty(fileno(stderr));
}
talloc_free(root->msglevels);
+1 -1
View File
@@ -24,7 +24,7 @@
#include <stdlib.h>
#include <stdint.h>
#include "osdep/compiler.h"
#include "compat/compiler.h"
struct mp_log;
+5 -11
View File
@@ -30,8 +30,7 @@
struct playlist_entry *playlist_entry_new(const char *filename)
{
struct playlist_entry *e = talloc_zero(NULL, struct playlist_entry);
char *local_filename = mp_file_url_to_filename(e, bstr0(filename));
e->filename = local_filename ? local_filename : talloc_strdup(e, filename);
e->filename = talloc_strdup(e, filename);
return e;
}
@@ -106,18 +105,10 @@ static void playlist_unlink(struct playlist *pl, struct playlist_entry *entry)
entry->pl = NULL;
}
void playlist_entry_unref(struct playlist_entry *e)
{
e->reserved--;
if (e->reserved < 0)
talloc_free(e);
}
void playlist_remove(struct playlist *pl, struct playlist_entry *entry)
{
playlist_unlink(pl, entry);
entry->removed = true;
playlist_entry_unref(entry);
talloc_free(entry);
}
void playlist_clear(struct playlist *pl)
@@ -295,6 +286,9 @@ struct playlist *playlist_parse_file(const char *file, struct mpv_global *global
if (ret && !ret->first)
mp_warn(log, "Warning: empty playlist\n");
if (ret)
playlist_add_base_path(ret, mp_dirname(file));
talloc_free(log);
return ret;
}
+1 -14
View File
@@ -19,7 +19,7 @@
#define MPLAYER_PLAYLIST_H
#include <stdbool.h>
#include "misc/bstr.h"
#include "bstr/bstr.h"
struct playlist_param {
bstr name, value;
@@ -41,17 +41,6 @@ struct playlist_entry {
bool playback_short : 1;
// Set to true if not at least 1 frame (audio or video) could be played.
bool init_failed : 1;
// Entry was removed with playlist_remove (etc.), but not deallocated.
bool removed : 1;
// Additional refcount. Normally (reserved==0), the entry is owned by the
// playlist, and this can be used to keep the entry alive.
int reserved;
// Used to reject loading of unsafe entries from external playlists.
// Can have any of the following bit flags set:
// STREAM_SAFE_ONLY: only allow streams marked with is_safe
// STREAM_NETWORK_ONLY: only allow streams marked with is_network
// The value 0 allows everything.
int stream_flags;
};
struct playlist {
@@ -94,6 +83,4 @@ struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index)
struct mpv_global;
struct playlist *playlist_parse_file(const char *file, struct mpv_global *global);
void playlist_entry_unref(struct playlist_entry *e);
#endif
+1 -1
View File
@@ -17,7 +17,7 @@
#include <libavutil/dict.h>
#include "tags.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
void mp_tags_set_str(struct mp_tags *tags, const char *key, const char *value)
{
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef MP_TAGS_H
#define MP_TAGS_H
#include "misc/bstr.h"
#include "bstr/bstr.h"
struct mp_tags {
char **keys;
File renamed without changes.
File renamed without changes.
+8 -10
View File
@@ -1,26 +1,24 @@
/*
* This file is part of mpv video player.
* Copyright © 2014 Alexander Preisinger <alexander.preisinger@gmail.com>
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_WAYLAND_MEMFILE_H
#define MPLAYER_WAYLAND_MEMFILE_H
#ifndef MPV_LIBAV_COMPAT_H
#define MPV_LIBAV_COMPAT_H
// create file decsriptor to memory space without filesystem representation
// truncates to size immediately
int memfile_create(off_t size);
// There's nothing here. But for how long?
#endif /* MPLAYER_WAYLAND_MEMFILE_H */
#endif /* MPV_LIBAV_COMPAT_H */
+32
View File
@@ -0,0 +1,32 @@
/*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_MPBSWAP_H
#define MPLAYER_MPBSWAP_H
#include <libavutil/bswap.h>
#define bswap_16(x) av_bswap16(x)
#define bswap_32(x) av_bswap32(x)
#define be2me_16(x) av_be2ne16(x)
#define be2me_32(x) av_be2ne32(x)
#define le2me_16(x) av_le2ne16(x)
#define le2me_32(x) av_le2ne32(x)
#define le2me_64(x) av_le2ne64(x)
#endif /* MPLAYER_MPBSWAP_H */
+6 -44
View File
@@ -97,6 +97,12 @@ static const struct mp_codec_tag mp_audio_codec_tags[] = {
{MKTAG('s', 'a', 'm', 'r'), "amr_nb"},
{MKTAG('s', 'a', 'w', 'b'), "amr_wb"},
{MKTAG('v', 'r', 'b', 's'), "vorbis"},
// Special cased in ad_lavc:
{0 , "pcm"},
{0x1 , "pcm"}, // lavf: pcm_s16le
{0x3 , "pcm"}, // lavf: pcm_f32le
{0xfffe , "pcm"},
{MKTAG('t', 'w', 'o', 's'), "pcm"},
// ------- internal mplayer FourCCs ------
{MKTAG('O', 'p', 'u', 's'), "opus"}, // demux_mkv.c
{MKTAG('a', 'L', 'a', 'C'), "alac"}, // demux_mkv.c
@@ -352,28 +358,6 @@ static const char *lookup_tag(const struct mp_codec_tag *mp_table,
return id == AV_CODEC_ID_NONE ? NULL : mp_codec_from_av_codec_id(id);
}
static const char *pcm_le[] = {"pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"};
static const char *pcm_be[] = {"pcm_s8", "pcm_s16be", "pcm_s24be", "pcm_s32be"};
static const char *map_audio_pcm_tag(uint32_t tag, int bits)
{
int bytes = (bits + 7) / 8;
switch (tag) {
case 0x0: // Microsoft PCM
case 0x1:
case 0xfffe: // MS PCM, Extended
return bytes >= 1 && bytes <= 4 ? pcm_le[bytes - 1] : NULL;
case 0x3: // IEEE float
return bits == 64 ? "pcm_f64le" : "pcm_f32le";
case 0x20776172:// 'raw '
return bits == 8 ? "pcm_u8" : "pcm_s16be";
case MKTAG('t', 'w', 'o', 's'): // demux_mkv.c internal
return bytes >= 1 && bytes <= 4 ? pcm_be[bytes - 1] : NULL;
default:
return NULL;
}
}
void mp_set_codec_from_tag(struct sh_stream *sh)
{
switch (sh->type) {
@@ -386,12 +370,6 @@ void mp_set_codec_from_tag(struct sh_stream *sh)
sh->codec = lookup_tag(mp_audio_codec_tags,
avformat_get_riff_audio_tags(),
sh->format);
if (sh->audio && sh->audio->bits_per_coded_sample) {
const char *codec =
map_audio_pcm_tag(sh->format, sh->audio->bits_per_coded_sample);
if (codec)
sh->codec = codec;
}
break;
default: ;
}
@@ -405,19 +383,3 @@ uint32_t mp_video_fourcc_alias(uint32_t fourcc)
}
return fourcc;
}
void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
bool is_be)
{
// This uses libavcodec pcm codec names, e.g. "pcm_u16le".
char codec[64] = "pcm_";
if (is_float) {
mp_snprintf_cat(codec, sizeof(codec), "f");
} else {
mp_snprintf_cat(codec, sizeof(codec), sign ? "s" : "u");
}
mp_snprintf_cat(codec, sizeof(codec), "%d", bits);
if (bits != 8)
mp_snprintf_cat(codec, sizeof(codec), is_be ? "be" : "le");
sh->codec = talloc_strdup(sh->audio, codec);
}
-4
View File
@@ -19,7 +19,6 @@
#define MP_CODEC_TAGS_H
#include <stdint.h>
#include <stdbool.h>
uint32_t mp_video_fourcc_alias(uint32_t fourcc);
@@ -27,7 +26,4 @@ struct sh_stream;
void mp_set_codec_from_tag(struct sh_stream *sh);
void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
bool is_be);
#endif
+21 -57
View File
@@ -109,9 +109,7 @@ struct demux_internal {
bool warned_queue_overflow;
bool last_eof; // last actual global EOF status
bool eof; // whether we're in EOF state (reset for retry)
bool idle;
bool autoselect;
double min_secs;
int min_packs;
int min_bytes;
@@ -139,16 +137,10 @@ struct demux_stream {
bool eof; // end of demuxed stream? (true if all buffer empty)
size_t packs; // number of packets in buffer
size_t bytes; // total bytes of packets in buffer
double base_ts; // timestamp of the last packet returned to decoder
double last_ts; // timestamp of the last packet added to queue
struct demux_packet *head;
struct demux_packet *tail;
};
// If one of the values is NOPTS, always pick the other one.
#define MP_PTS_MIN(a, b) ((a) == MP_NOPTS_VALUE || ((a) > (b)) ? (b) : (a))
#define MP_PTS_MAX(a, b) ((a) == MP_NOPTS_VALUE || ((a) < (b)) ? (b) : (a))
static void demuxer_sort_chapters(demuxer_t *demuxer);
static void *demux_thread(void *pctx);
static void update_cache(struct demux_internal *in);
@@ -165,7 +157,6 @@ static void ds_flush(struct demux_stream *ds)
ds->head = ds->tail = NULL;
ds->packs = 0;
ds->bytes = 0;
ds->last_ts = ds->base_ts = MP_NOPTS_VALUE;
ds->eof = false;
ds->active = false;
}
@@ -303,7 +294,6 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
// first packet in stream
ds->head = ds->tail = dp;
}
// obviously not true anymore
ds->eof = false;
in->last_eof = in->eof = false;
@@ -313,17 +303,11 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
if (stream->type != STREAM_VIDEO && dp->pts == MP_NOPTS_VALUE)
dp->pts = dp->dts;
double ts = dp->dts == MP_NOPTS_VALUE ? dp->pts : dp->dts;
if (ts != MP_NOPTS_VALUE && (ts > ds->last_ts || ts + 10 < ds->last_ts))
ds->last_ts = ts;
if (ds->base_ts == MP_NOPTS_VALUE)
ds->base_ts = ds->last_ts;
MP_DBG(in, "append packet to %s: size=%d pts=%f dts=%f pos=%"PRIi64" "
"[num=%zd size=%zd]\n", stream_type_name(stream->type),
dp->len, dp->pts, dp->dts, dp->pos, ds->packs, ds->bytes);
if (ds->in->wakeup_cb && !ds->head->next)
if (ds->in->wakeup_cb)
ds->in->wakeup_cb(ds->in->wakeup_cb_ctx);
pthread_cond_signal(&in->wakeup);
pthread_mutex_unlock(&in->lock);
@@ -334,7 +318,6 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
static bool read_packet(struct demux_internal *in)
{
in->eof = false;
in->idle = true;
// Check if we need to read a new packet. We do this if all queues are below
// the minimum, or if a stream explicitly needs new packets. Also includes
@@ -343,12 +326,10 @@ static bool read_packet(struct demux_internal *in)
size_t packs = 0, bytes = 0;
for (int n = 0; n < in->d_buffer->num_streams; n++) {
struct demux_stream *ds = in->d_buffer->streams[n]->ds;
active |= ds->active;
active |= ds->selected && ds->active;
read_more |= ds->active && !ds->head;
packs += ds->packs;
bytes += ds->bytes;
if (ds->active && ds->last_ts != MP_NOPTS_VALUE && in->min_secs > 0)
read_more |= ds->last_ts - ds->base_ts < in->min_secs;
}
MP_DBG(in, "packets=%zd, bytes=%zd, active=%d, more=%d\n",
packs, bytes, active, read_more);
@@ -379,7 +360,6 @@ static bool read_packet(struct demux_internal *in)
// Actually read a packet. Drop the lock while doing so, because waiting
// for disk or network I/O can take time.
in->idle = false;
pthread_mutex_unlock(&in->lock);
struct demuxer *demux = in->d_thread;
bool eof = !demux->desc->fill_buffer || demux->desc->fill_buffer(demux) <= 0;
@@ -495,12 +475,8 @@ static struct demux_packet *dequeue_packet(struct demux_stream *ds)
ds->bytes -= pkt->len;
ds->packs--;
double ts = pkt->dts == MP_NOPTS_VALUE ? pkt->pts : pkt->dts;
if (ts != MP_NOPTS_VALUE)
ds->base_ts = ts;
// This implies this function is actually called from "the" user thread.
if (pkt->pos >= ds->in->d_user->filepos)
if (pkt && pkt->pos >= 0)
ds->in->d_user->filepos = pkt->pos;
return pkt;
@@ -582,6 +558,18 @@ bool demux_has_packet(struct sh_stream *sh)
return has_packet;
}
// Return whether EOF was returned with an earlier packet read.
bool demux_stream_eof(struct sh_stream *sh)
{
bool eof = false;
if (sh) {
pthread_mutex_lock(&sh->ds->in->lock);
eof = sh->ds->eof && !sh->ds->head;
pthread_mutex_unlock(&sh->ds->in->lock);
}
return eof;
}
// Read and return any packet we find.
struct demux_packet *demux_read_any_packet(struct demuxer *demuxer)
{
@@ -815,8 +803,6 @@ static struct demuxer *open_given_type(struct mpv_global *global,
.d_thread = talloc(demuxer, struct demuxer),
.d_buffer = talloc(demuxer, struct demuxer),
.d_user = demuxer,
.min_secs = stream->uncached_stream ? demuxer->opts->demuxer_min_secs_cache
: demuxer->opts->demuxer_min_secs,
.min_packs = demuxer->opts->demuxer_min_packs,
.min_bytes = demuxer->opts->demuxer_min_bytes,
};
@@ -925,8 +911,6 @@ static void flush_locked(demuxer_t *demuxer)
demuxer->in->warned_queue_overflow = false;
demuxer->in->eof = false;
demuxer->in->last_eof = false;
demuxer->in->idle = true;
demuxer->filepos = -1; // implicitly synchronized
}
// clear the packet queues
@@ -966,6 +950,11 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
return 1;
}
char *demux_info_get(demuxer_t *demuxer, const char *opt)
{
return mp_tags_get_str(demuxer->metadata, opt);
}
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
enum stream_type t, int id)
{
@@ -1117,10 +1106,6 @@ static void update_cache(struct demux_internal *in)
// must be called locked
static int cached_stream_control(struct demux_internal *in, int cmd, void *arg)
{
// If the cache is active, wake up the thread to possibly update cache state.
if (in->stream_cache_size >= 0)
pthread_cond_signal(&in->wakeup);
switch (cmd) {
case STREAM_CTRL_GET_CACHE_SIZE:
if (in->stream_cache_size < 0)
@@ -1165,29 +1150,7 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
}
case DEMUXER_CTRL_SWITCHED_TRACKS:
in->tracks_switched = true;
pthread_cond_signal(&in->wakeup);
return DEMUXER_CTRL_OK;
case DEMUXER_CTRL_GET_READER_STATE: {
struct demux_ctrl_reader_state *r = arg;
*r = (struct demux_ctrl_reader_state){
.eof = in->last_eof,
.ts_range = {MP_NOPTS_VALUE, MP_NOPTS_VALUE},
.ts_duration = -1,
};
for (int n = 0; n < in->d_user->num_streams; n++) {
struct demux_stream *ds = in->d_user->streams[n]->ds;
if (ds->active) {
r->underrun |= !ds->head;
r->ts_range[0] = MP_PTS_MAX(r->ts_range[0], ds->base_ts);
r->ts_range[1] = MP_PTS_MIN(r->ts_range[1], ds->last_ts);
}
}
r->idle = (in->idle && !r->underrun) || r->eof;
r->underrun &= !r->idle;
if (r->ts_range[0] != MP_NOPTS_VALUE && r->ts_range[1] != MP_NOPTS_VALUE)
r->ts_duration = r->ts_range[1] - r->ts_range[0];
return DEMUXER_CTRL_OK;
}
}
return DEMUXER_CTRL_DONTKNOW;
}
@@ -1198,6 +1161,7 @@ int demux_control(demuxer_t *demuxer, int cmd, void *arg)
if (in->threading) {
pthread_mutex_lock(&in->lock);
pthread_cond_signal(&in->wakeup);
int cr = cached_demux_control(in, cmd, arg);
pthread_mutex_unlock(&in->lock);
if (cr != DEMUXER_CTRL_DONTKNOW)
+9 -8
View File
@@ -25,7 +25,7 @@
#include <string.h>
#include <stdbool.h>
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "common/common.h"
#include "common/tags.h"
#include "packet.h"
@@ -35,6 +35,11 @@
// and the demuxer pretends EOF was reached.
#define MAX_PACKS 16000
#define MAX_PACK_BYTES (400 * 1024 * 1024)
// Minimum total size of packets queued - the demuxer thread will read more
// packets, until either number or total size of the packets exceed the minimum.
// This can actually be configured with command line options.
#define MIN_PACKS 64
#define MIN_PACK_BYTES (5 * 1024 * 1024)
enum demuxer_type {
DEMUXER_TYPE_GENERIC = 0,
@@ -54,13 +59,6 @@ enum demux_ctrl {
DEMUXER_CTRL_RESYNC,
DEMUXER_CTRL_IDENTIFY_PROGRAM,
DEMUXER_CTRL_STREAM_CTRL,
DEMUXER_CTRL_GET_READER_STATE,
};
struct demux_ctrl_reader_state {
bool eof, underrun, idle;
double ts_range[2]; // start, end
double ts_duration;
};
struct demux_ctrl_stream_ctrl {
@@ -241,6 +239,7 @@ int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt)
bool demux_stream_is_selected(struct sh_stream *stream);
double demux_get_next_pts(struct sh_stream *sh);
bool demux_has_packet(struct sh_stream *sh);
bool demux_stream_eof(struct sh_stream *sh);
struct demux_packet *demux_read_any_packet(struct demuxer *demuxer);
struct sh_stream *new_sh_stream(struct demuxer *demuxer, enum stream_type type);
@@ -256,6 +255,8 @@ void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *c
void demux_flush(struct demuxer *demuxer);
int demux_seek(struct demuxer *demuxer, float rel_seek_secs, int flags);
char *demux_info_get(struct demuxer *demuxer, const char *opt);
int demux_control(struct demuxer *demuxer, int cmd, void *arg);
void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
+1 -1
View File
@@ -22,7 +22,7 @@
#include <stdbool.h>
#include <string.h>
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "demux.h"
#include "stream/stream.h"
+2 -11
View File
@@ -135,23 +135,20 @@ static void add_streams(demuxer_t *demuxer)
}
}
struct sh_stream *sh = new_sh_stream(demuxer, src->type);
if (!sh)
break;
assert(p->num_streams == n); // directly mapped
MP_TARRAY_APPEND(p, p->streams, p->num_streams, sh);
// Copy all stream fields that might be relevant
sh->codec = talloc_strdup(sh, src->codec);
sh->format = src->format;
sh->lav_headers = src->lav_headers;
if (src->video) {
if (sh && src->video) {
double ar;
if (stream_control(demuxer->stream, STREAM_CTRL_GET_ASPECT_RATIO, &ar)
== STREAM_OK)
sh->video->aspect = ar;
}
if (src->audio)
if (sh && src->audio)
sh->audio = src->audio;
get_disc_lang(demuxer->stream, sh);
}
reselect_streams(demuxer);
}
@@ -311,12 +308,6 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
// Can be seekable even if the stream isn't.
demuxer->seekable = true;
// With cache enabled, the stream can be seekable. This causes demux_lavf.c
// (actually libavformat/mpegts.c) to seek sometimes when reading a packet.
// It does this to seek back a bit in case the current file position points
// into the middle of a packet.
demuxer->stream->seekable = false;
add_dvd_streams(demuxer);
add_streams(demuxer);
add_stream_chapters(demuxer);
+40 -70
View File
@@ -39,12 +39,13 @@
# include <libavutil/display.h>
#endif
#include <libavutil/opt.h>
#include "compat/libav.h"
#include "options/options.h"
#include "common/msg.h"
#include "common/tags.h"
#include "common/av_common.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "stream/stream.h"
#include "demux.h"
@@ -233,7 +234,7 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
priv->filename = remove_prefix(priv->filename, prefixes);
char *avdevice_format = NULL;
if (s->uncached_type == STREAMTYPE_AVDEVICE) {
if (s->type == STREAMTYPE_AVDEVICE) {
// always require filename in the form "format:filename"
char *sep = strchr(priv->filename, ':');
if (!sep) {
@@ -429,19 +430,6 @@ static void export_replaygain(demuxer_t *demuxer, sh_audio_t *sh, AVStream *st)
#endif
}
// Return a dictionary entry as (decimal) integer.
static int dict_get_decimal(AVDictionary *dict, const char *entry, int def)
{
AVDictionaryEntry *e = av_dict_get(dict, entry, NULL, 0);
if (e && e->value) {
char *end = NULL;
long int r = strtol(e->value, &end, 10);
if (end && !end[0] && r >= INT_MIN && r <= INT_MAX)
return r;
}
return def;
}
static void handle_stream(demuxer_t *demuxer, int i)
{
lavf_priv_t *priv = demuxer->priv;
@@ -460,7 +448,7 @@ static void handle_stream(demuxer_t *demuxer, int i)
sh->format = codec->codec_tag;
// probably unneeded
mp_chmap_set_unknown(&sh_audio->channels, codec->channels);
mp_chmap_from_channels(&sh_audio->channels, codec->channels);
if (codec->channel_layout)
mp_chmap_from_lavc(&sh_audio->channels, codec->channel_layout);
sh_audio->samplerate = codec->sample_rate;
@@ -479,11 +467,9 @@ static void handle_stream(demuxer_t *demuxer, int i)
if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
sh->attached_picture = new_demux_packet_from(st->attached_pic.data,
st->attached_pic.size);
if (sh->attached_picture) {
sh->attached_picture->pts = 0;
talloc_steal(sh, sh->attached_picture);
sh->attached_picture->keyframe = true;
}
sh->attached_picture->pts = 0;
talloc_steal(sh, sh->attached_picture);
sh->attached_picture->keyframe = true;
}
sh->format = codec->codec_tag;
@@ -520,9 +506,13 @@ static void handle_stream(demuxer_t *demuxer, int i)
if (sd)
sh_video->rotate = -av_display_rotation_get((uint32_t *)sd);
#else
int rot = dict_get_decimal(st->metadata, "rotate", -1);
if (rot >= 0)
sh_video->rotate = rot;
AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0);
if (rot && rot->value) {
char *end = NULL;
long int r = strtol(rot->value, &end, 10);
if (end && !end[0])
sh_video->rotate = r;
}
#endif
sh_video->rotate = ((sh_video->rotate % 360) + 360) % 360;
@@ -600,9 +590,6 @@ static void handle_stream(demuxer_t *demuxer, int i)
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
if (lang && lang->value)
sh->lang = talloc_strdup(sh, lang->value);
sh->hls_bitrate = dict_get_decimal(st->metadata, "variant_bitrate", 0);
if (!sh->title && sh->hls_bitrate > 0)
sh->title = talloc_asprintf(sh, "bitrate %d", sh->hls_bitrate);
}
select_tracks(demuxer, i);
@@ -619,29 +606,10 @@ static void add_new_streams(demuxer_t *demuxer)
static void update_metadata(demuxer_t *demuxer, AVPacket *pkt)
{
#if HAVE_AVFORMAT_METADATA_UPDATE_FLAG
lavf_priv_t *priv = demuxer->priv;
if (priv->avfc->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) {
mp_tags_copy_from_av_dictionary(demuxer->metadata, priv->avfc->metadata);
priv->avfc->event_flags = 0;
demux_changed(demuxer, DEMUX_EVENT_METADATA);
}
if (priv->merge_track_metadata) {
for (int n = 0; n < priv->num_streams; n++) {
AVStream *st = priv->streams[n] ? priv->avfc->streams[n] : NULL;
if (st && st->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
mp_tags_copy_from_av_dictionary(demuxer->metadata, st->metadata);
st->event_flags = 0;
demux_changed(demuxer, DEMUX_EVENT_METADATA);
}
}
}
#elif HAVE_AVCODEC_METADATA_UPDATE_SIDE_DATA
#if HAVE_AVCODEC_METADATA_UPDATE_SIDE_DATA
lavf_priv_t *priv = demuxer->priv;
int md_size;
const uint8_t *md;
if (!pkt)
return;
md = av_packet_get_side_data(pkt, AV_PKT_DATA_METADATA_UPDATE, &md_size);
if (md && priv->merge_track_metadata) {
AVDictionary *dict = NULL;
@@ -772,6 +740,8 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
add_new_streams(demuxer);
mp_tags_copy_from_av_dictionary(demuxer->metadata, avfc->metadata);
// Often useful with OGG audio-only files, which have metadata in the audio
// track metadata instead of the main metadata.
if (demuxer->num_streams == 1) {
@@ -782,9 +752,6 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
}
}
mp_tags_copy_from_av_dictionary(demuxer->metadata, avfc->metadata);
update_metadata(demuxer, NULL);
demuxer->ts_resets_possible = priv->avif->flags & AVFMT_TS_DISCONT;
demuxer->start_time = priv->avfc->start_time == AV_NOPTS_VALUE ?
@@ -793,21 +760,23 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
return 0;
}
static void destroy_avpacket(void *pkt)
{
av_free_packet(pkt);
}
static int demux_lavf_fill_buffer(demuxer_t *demux)
{
lavf_priv_t *priv = demux->priv;
demux_packet_t *dp;
AVPacket *pkt = &(AVPacket){0};
AVPacket *pkt = talloc(NULL, AVPacket);
int r = av_read_frame(priv->avfc, pkt);
if (r < 0) {
av_free_packet(pkt);
if (r == AVERROR(EAGAIN))
return 1;
if (r == AVERROR_EOF)
return 0;
MP_WARN(demux, "error reading packet.\n");
return -1;
talloc_free(pkt);
return r == AVERROR(EAGAIN) ? 1 : -1; // eof
}
talloc_set_destructor(pkt, destroy_avpacket);
add_new_streams(demux);
update_metadata(demux, pkt);
@@ -817,15 +786,18 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
AVStream *st = priv->avfc->streams[pkt->stream_index];
if (!demux_stream_is_selected(stream)) {
av_free_packet(pkt);
talloc_free(pkt);
return 1; // don't signal EOF if skipping a packet
}
struct demux_packet *dp = new_demux_packet_from_avpacket(pkt);
if (!dp) {
av_free_packet(pkt);
return 1;
}
// If the packet has pointers to temporary fields that could be
// overwritten/freed by next av_read_frame(), copy them to persistent
// allocations so we can safely queue the packet for any length of time.
if (av_dup_packet(pkt) < 0)
abort();
dp = new_demux_packet_fromdata(pkt->data, pkt->size);
dp->avpacket = talloc_steal(dp, pkt);
if (pkt->pts != AV_NOPTS_VALUE)
dp->pts = pkt->pts * av_q2d(st->time_base);
@@ -841,7 +813,6 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
} else if (dp->dts != MP_NOPTS_VALUE) {
priv->last_pts = dp->dts * AV_TIME_BASE;
}
av_free_packet(pkt);
demux_add_packet(stream, dp);
return 1;
}
@@ -1010,13 +981,12 @@ redo:
* call the new API instead of relying on av_seek_frame() to do this
* for us.
*/
// avio_flush() is designed for write-only streams, and does the wrong
// thing when reading. Flush it manually instead.
stream_drop_buffers(demuxer->stream);
priv->avfc->pb->buf_ptr = priv->avfc->pb->buf_end = priv->avfc->pb->buffer;
priv->avfc->pb->pos = stream_tell(demuxer->stream);
av_seek_frame(priv->avfc, 0, stream_tell(demuxer->stream),
AVSEEK_FLAG_BYTE);
// avio_flush() is designed for write-only streams, and does the wrong
// thing when reading. Flush it manually instead.
priv->avfc->pb->buf_ptr = priv->avfc->pb->buf_end;
stream_drop_buffers(demuxer->stream);
return DEMUXER_CTRL_OK;
default:
return DEMUXER_CTRL_NOTIMPL;
+4 -6
View File
@@ -77,12 +77,10 @@ static int demux_mf_fill_buffer(demuxer_t *demuxer)
bstr data = stream_read_complete(stream, NULL, MF_MAX_FILE_SIZE);
if (data.len) {
demux_packet_t *dp = new_demux_packet(data.len);
if (dp) {
memcpy(dp->buffer, data.start, data.len);
dp->pts = mf->curr_frame / mf->sh->fps;
dp->keyframe = true;
demux_add_packet(demuxer->streams[0], dp);
}
memcpy(dp->buffer, data.start, data.len);
dp->pts = mf->curr_frame / mf->sh->fps;
dp->keyframe = true;
demux_add_packet(demuxer->streams[0], dp);
}
talloc_free(data.start);
}
+141 -133
View File
@@ -44,15 +44,13 @@
#include "talloc.h"
#include "common/av_common.h"
#include "options/options.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
#include "stream/stream.h"
#include "video/csputils.h"
#include "demux.h"
#include "stheader.h"
#include "ebml.h"
#include "matroska.h"
#include "codec_tags.h"
#include "video/img_fourcc.h"
#include "common/msg.h"
@@ -104,7 +102,6 @@ typedef struct mkv_track {
bool v_dwidth_set, v_dheight_set;
double v_frate;
uint32_t colorspace;
int stereo_mode;
uint32_t a_formattag;
uint32_t a_channels, a_bps;
@@ -507,15 +504,6 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
MP_VERBOSE(demuxer, "| + Colorspace: %#x\n",
(unsigned int)track->colorspace);
}
if (video->n_stereo_mode) {
const char *name = MP_STEREO3D_NAME(video->stereo_mode);
if (name) {
track->stereo_mode = video->stereo_mode;
MP_VERBOSE(demuxer, "| + StereoMode: %s\n", name);
} else {
MP_WARN(demuxer, "Unknown StereoMode: %d\n", (int)video->stereo_mode);
}
}
}
/**
@@ -588,7 +576,7 @@ static void parse_trackentry(struct demuxer *demuxer,
track->codec_id = "";
}
if (entry->n_codec_private && entry->codec_private.len <= 0x10000000) {
if (entry->n_codec_private && entry->codec_private.len <= 0x1000000) {
int len = entry->codec_private.len;
track->private_data = talloc_size(track, len + AV_LZO_INPUT_PADDING);
memcpy(track->private_data, entry->codec_private.start, len);
@@ -1149,34 +1137,45 @@ static const videocodec_info_t vinfo[] = {
static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
{
MP_BITMAPINFOHEADER *bih = &(MP_BITMAPINFOHEADER){0};
unsigned char *extradata;
unsigned int extradata_size = 0;
struct sh_stream *sh;
sh_video_t *sh_v;
bool raw = false;
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
if (!sh)
return 1;
track->stream = sh;
sh_video_t *sh_v = sh->video;
sh->demuxer_id = track->tnum;
sh->title = talloc_strdup(sh_v, track->name);
if (track->ms_compat) { /* MS compatibility mode */
// The private_data contains a BITMAPINFOHEADER struct
if (track->private_data == NULL || track->private_size < 40)
MP_BITMAPINFOHEADER *src;
if (track->private_data == NULL
|| track->private_size < sizeof(*bih))
return 1;
unsigned char *h = track->private_data;
if (track->v_width == 0)
track->v_width = AV_RL32(h + 4); // biWidth
if (track->v_height == 0)
track->v_height = AV_RL32(h + 8); // biHeight
sh_v->bits_per_coded_sample = AV_RL16(h + 14); // biBitCount
sh->format = AV_RL32(h + 16); // biCompression
src = (MP_BITMAPINFOHEADER *) track->private_data;
bih->biSize = le2me_32(src->biSize);
bih->biWidth = le2me_32(src->biWidth);
bih->biHeight = le2me_32(src->biHeight);
bih->biPlanes = le2me_16(src->biPlanes);
bih->biBitCount = le2me_16(src->biBitCount);
bih->biCompression = le2me_32(src->biCompression);
bih->biSizeImage = le2me_32(src->biSizeImage);
bih->biXPelsPerMeter = le2me_32(src->biXPelsPerMeter);
bih->biYPelsPerMeter = le2me_32(src->biYPelsPerMeter);
bih->biClrUsed = le2me_32(src->biClrUsed);
bih->biClrImportant = le2me_32(src->biClrImportant);
extradata = track->private_data + sizeof(*bih);
extradata_size = track->private_size - sizeof(*bih);
extradata = track->private_data + 40;
extradata_size = track->private_size - 40;
if (track->v_width == 0)
track->v_width = bih->biWidth;
if (track->v_height == 0)
track->v_height = bih->biHeight;
} else {
sh_v->bits_per_coded_sample = 24;
bih->biSize = sizeof(*bih);
bih->biWidth = track->v_width;
bih->biHeight = track->v_height;
bih->biBitCount = 24;
bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount / 8;
if (track->private_size >= RVPROPERTIES_SIZE
&& (!strcmp(track->codec_id, MKV_V_REALV10)
@@ -1190,26 +1189,30 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
src = (uint8_t *) track->private_data + RVPROPERTIES_SIZE;
cnt = track->private_size - RVPROPERTIES_SIZE;
bih->biSize = 48 + cnt;
bih->biPlanes = 1;
type2 = AV_RB32(src - 4);
if (type2 == 0x10003000 || type2 == 0x10003001)
sh->format = MP_FOURCC('R', 'V', '1', '3');
bih->biCompression = MP_FOURCC('R', 'V', '1', '3');
else
sh->format = MP_FOURCC('R', 'V', track->codec_id[9], '0');
bih->biCompression =
MP_FOURCC('R', 'V', track->codec_id[9], '0');
// copy type1 and type2 info from rv properties
extradata_size = cnt + 8;
extradata = src - 8;
track->realmedia = 1;
} else if (strcmp(track->codec_id, MKV_V_UNCOMPRESSED) == 0) {
// raw video, "like AVI" - this is a FourCC
sh->format = track->colorspace;
bih->biCompression = track->colorspace;
raw = true;
} else {
const videocodec_info_t *vi = vinfo;
while (vi->id && strcmp(vi->id, track->codec_id))
vi++;
sh->format = vi->fourcc;
bih->biCompression = vi->fourcc;
if (vi->extradata && track->private_data
&& (track->private_size > 0)) {
bih->biSize += track->private_size;
extradata = track->private_data;
extradata_size = track->private_size;
}
@@ -1229,10 +1232,22 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
return 1;
}
sh_v->coded_width = track->v_width;
sh_v->coded_height = track->v_height;
sh_v->extradata = talloc_memdup(sh_v, extradata, extradata_size);
sh_v->extradata_len = extradata_size;
sh = new_sh_stream(demuxer, STREAM_VIDEO);
if (!sh)
return 1;
track->stream = sh;
sh_v = sh->video;
sh->demuxer_id = track->tnum;
sh->title = talloc_strdup(sh_v, track->name);
sh_v->bih = talloc_size(sh_v, sizeof(MP_BITMAPINFOHEADER) + extradata_size);
if (!sh_v->bih) {
MP_FATAL(demuxer, "Memory allocation failure!\n");
abort();
}
*sh_v->bih = *bih;
if (extradata_size)
memcpy(sh_v->bih + 1, extradata, extradata_size);
sh->format = sh_v->bih->biCompression;
if (raw) {
sh->codec = "rawvideo";
} else {
@@ -1261,7 +1276,6 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
}
MP_VERBOSE(demuxer, "Aspect: %f\n", sh_v->aspect);
sh_v->avi_dts = track->ms_compat;
sh_v->stereo_mode = track->stereo_mode;
return 0;
}
@@ -1304,6 +1318,15 @@ static const struct mkv_audio_tag {
{ NULL },
};
static void copy_audio_private_data(sh_audio_t *sh, mkv_track_t *track)
{
if (!track->ms_compat && track->private_size) {
sh->codecdata = talloc_size(sh, track->private_size);
sh->codecdata_len = track->private_size;
memcpy(sh->codecdata, track->private_data, track->private_size);
}
}
static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
{
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_AUDIO);
@@ -1312,9 +1335,6 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
track->stream = sh;
sh_audio_t *sh_a = sh->audio;
unsigned char *extradata = NULL;
int extradata_len = 0;
if (track->language && (strcmp(track->language, "und") != 0))
sh->lang = talloc_strdup(sh_a, track->language);
sh->demuxer_id = track->tnum;
@@ -1322,25 +1342,30 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
sh->default_track = track->default_track;
if (!track->a_osfreq)
track->a_osfreq = track->a_sfreq;
if (track->ms_compat) {
// The private_data contains a WAVEFORMATEX struct
if (track->private_size < 18)
if (track->private_size < sizeof(*sh_a->wf))
goto error;
MP_VERBOSE(demuxer, "track with MS compat audio.\n");
unsigned char *h = track->private_data;
track->a_formattag = AV_RL16(h + 0); // wFormatTag
if (track->a_channels == 0)
track->a_channels = AV_RL16(h + 2); // nChannels
MP_WAVEFORMATEX *wf = (MP_WAVEFORMATEX *) track->private_data;
sh_a->wf = talloc_zero_size(sh_a, track->private_size);
sh_a->wf->wFormatTag = le2me_16(wf->wFormatTag);
sh_a->wf->nChannels = le2me_16(wf->nChannels);
sh_a->wf->nSamplesPerSec = le2me_32(wf->nSamplesPerSec);
sh_a->wf->nAvgBytesPerSec = le2me_32(wf->nAvgBytesPerSec);
sh_a->wf->nBlockAlign = le2me_16(wf->nBlockAlign);
sh_a->wf->wBitsPerSample = le2me_16(wf->wBitsPerSample);
sh_a->wf->cbSize = track->private_size - sizeof(*sh_a->wf);
memcpy(sh_a->wf + 1, wf + 1,
track->private_size - sizeof(*sh_a->wf));
if (track->a_osfreq == 0.0)
track->a_osfreq = AV_RL32(h + 4); // nSamplesPerSec
sh_a->bitrate = AV_RL32(h + 8) * 8; // nAvgBytesPerSec
sh_a->block_align = AV_RL16(h + 12); // nBlockAlign
track->a_osfreq = sh_a->wf->nSamplesPerSec;
if (track->a_channels == 0)
track->a_channels = sh_a->wf->nChannels;
if (track->a_bps == 0)
track->a_bps = AV_RL16(h + 14); // wBitsPerSample
extradata = track->private_data + 18;
extradata_len = track->private_size - 18;
track->a_bps = sh_a->wf->wBitsPerSample;
track->a_formattag = sh_a->wf->wFormatTag;
} else {
sh_a->wf = talloc_zero(sh_a, MP_WAVEFORMATEX);
for (int i = 0; ; i++) {
const struct mkv_audio_tag *t = mkv_audio_tags + i;
if (t->id == NULL)
@@ -1359,21 +1384,23 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
}
sh->format = track->a_formattag;
mp_chmap_set_unknown(&sh_a->channels, track->a_channels);
sh_a->wf->wFormatTag = track->a_formattag;
mp_chmap_from_channels(&sh_a->channels, track->a_channels);
sh_a->wf->nChannels = track->a_channels;
sh_a->samplerate = (uint32_t) track->a_osfreq;
sh_a->wf->nSamplesPerSec = (uint32_t) track->a_osfreq;
if (track->a_bps == 0)
sh_a->bits_per_coded_sample = 16;
sh_a->wf->wBitsPerSample = 16;
else
sh_a->bits_per_coded_sample = track->a_bps;
sh_a->wf->wBitsPerSample = track->a_bps;
if (track->a_formattag == 0x0055) { /* MP3 || MP2 */
sh_a->bitrate = 16000 * 8;
sh_a->block_align = 1152;
sh_a->wf->nAvgBytesPerSec = 16000;
sh_a->wf->nBlockAlign = 1152;
} else if ((track->a_formattag == 0x2000) /* AC3 */
|| track->a_formattag == MP_FOURCC('E', 'A', 'C', '3')
|| (track->a_formattag == 0x2001)) { /* DTS */
sh_a->bits_per_coded_sample = 0;
sh_a->bitrate = 0;
sh_a->block_align = 0;
talloc_free(sh_a->wf);
sh_a->wf = NULL;
} else if (track->a_formattag == 0x0001) { /* PCM || PCM_BE */
if (!strcmp(track->codec_id, MKV_A_PCM_BE))
sh->format = MP_FOURCC('t', 'w', 'o', 's');
@@ -1381,23 +1408,17 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
/* ok */
} else if (!strcmp(track->codec_id, MKV_A_QDMC)
|| !strcmp(track->codec_id, MKV_A_QDMC2)) {
sh_a->bitrate = 16000 * 8;
sh_a->block_align = 1486;
if (!extradata_len) {
extradata = track->private_data;
extradata_len = track->private_size;
}
sh_a->wf->nAvgBytesPerSec = 16000;
sh_a->wf->nBlockAlign = 1486;
copy_audio_private_data(sh_a, track);
} else if (track->a_formattag == MP_FOURCC('M', 'P', '4', 'A')) {
int profile, srate_idx;
sh_a->bitrate = 16000 * 8;
sh_a->block_align = 1024;
sh_a->wf->nAvgBytesPerSec = 16000;
sh_a->wf->nBlockAlign = 1024;
if (!strcmp(track->codec_id, MKV_A_AAC) && track->private_data) {
if (!extradata_len) {
extradata = track->private_data;
extradata_len = track->private_size;
}
copy_audio_private_data(sh_a, track);
} else {
/* Recreate the 'private data' */
/* which faad2 uses in its initialization */
@@ -1419,6 +1440,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
/* HE-AAC (aka SBR AAC) */
sh_a->codecdata_len = 5;
sh_a->samplerate = sh_a->wf->nSamplesPerSec = track->a_osfreq;
srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
sh_a->codecdata[2] = AAC_SYNC_EXTENSION_TYPE >> 3;
sh_a->codecdata[3] = ((AAC_SYNC_EXTENSION_TYPE & 0x07) << 5) | 5;
@@ -1431,19 +1453,21 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
}
} else if (track->a_formattag == MP_FOURCC('v', 'r', 'b', 's')) {
/* VORBIS */
if (track->private_size == 0 || (track->ms_compat && !extradata_len))
if (track->private_size == 0 || track->ms_compat && !sh_a->wf->cbSize)
goto error;
if (!track->ms_compat) {
extradata = track->private_data;
extradata_len = track->private_size;
if (track->private_size > 0x1000000)
goto error;
sh_a->wf->cbSize = track->private_size;
sh_a->wf = talloc_realloc_size(sh_a, sh_a->wf,
sizeof(*sh_a->wf) + sh_a->wf->cbSize);
memcpy((unsigned char *) (sh_a->wf + 1), track->private_data,
sh_a->wf->cbSize);
}
} else if (!strcmp(track->codec_id, MKV_A_OPUS)
|| !strcmp(track->codec_id, MKV_A_OPUS_EXP)) {
sh->format = MP_FOURCC('O', 'p', 'u', 's');
if (!track->ms_compat) {
extradata = track->private_data;
extradata_len = track->private_size;
}
copy_audio_private_data(sh_a, track);
} else if (!strncmp(track->codec_id, MKV_A_REALATRC, 7)) {
if (track->private_size < RAPROPERTIES4_SIZE)
goto error;
@@ -1452,13 +1476,13 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
int codecdata_length, version;
int flavor;
sh_a->bitrate = 0; /* FIXME !? */
sh_a->wf->nAvgBytesPerSec = 0; /* FIXME !? */
version = AV_RB16(src + 4);
flavor = AV_RB16(src + 22);
track->coded_framesize = AV_RB32(src + 24);
track->sub_packet_h = AV_RB16(src + 40);
sh_a->block_align = track->audiopk_size = AV_RB16(src + 42);
sh_a->wf->nBlockAlign = track->audiopk_size = AV_RB16(src + 42);
track->sub_packet_size = AV_RB16(src + 44);
if (version == 4) {
src += RAPROPERTIES4_SIZE;
@@ -1481,25 +1505,27 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
if (codecdata_length < 0 || codecdata_length > 0x1000000)
goto error;
src += 4;
extradata_len = codecdata_length;
extradata = src;
sh_a->wf->cbSize = codecdata_length;
sh_a->wf = talloc_realloc_size(sh_a, sh_a->wf,
sizeof(*sh_a->wf) + sh_a->wf->cbSize);
memcpy(((char *) (sh_a->wf + 1)), src, codecdata_length);
switch (track->a_formattag) {
case MP_FOURCC('a', 't', 'r', 'c'):
sh_a->bitrate = atrc_fl2bps[flavor] * 8;
sh_a->block_align = track->sub_packet_size;
sh_a->wf->nAvgBytesPerSec = atrc_fl2bps[flavor];
sh_a->wf->nBlockAlign = track->sub_packet_size;
goto audiobuf;
case MP_FOURCC('c', 'o', 'o', 'k'):
sh_a->bitrate = cook_fl2bps[flavor] * 8;
sh_a->block_align = track->sub_packet_size;
sh_a->wf->nAvgBytesPerSec = cook_fl2bps[flavor];
sh_a->wf->nBlockAlign = track->sub_packet_size;
goto audiobuf;
case MP_FOURCC('s', 'i', 'p', 'r'):
sh_a->bitrate = sipr_fl2bps[flavor] * 8;
sh_a->block_align = track->coded_framesize;
sh_a->wf->nAvgBytesPerSec = sipr_fl2bps[flavor];
sh_a->wf->nBlockAlign = track->coded_framesize;
goto audiobuf;
case MP_FOURCC('2', '8', '_', '8'):
sh_a->bitrate = 3600 * 8;
sh_a->block_align = track->coded_framesize;
sh_a->wf->nAvgBytesPerSec = 3600;
sh_a->wf->nBlockAlign = track->coded_framesize;
audiobuf:
track->audio_buf =
talloc_array_size(track, track->sub_packet_h, track->audiopk_size);
@@ -1513,17 +1539,16 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|| (track->a_formattag == 0xf1ac)) {
unsigned char *ptr;
int size;
sh_a->bits_per_coded_sample = 0;
sh_a->bitrate = 0;
sh_a->block_align = 0;
talloc_free(sh_a->wf);
sh_a->wf = NULL;
if (!track->ms_compat) {
ptr = track->private_data;
size = track->private_size;
} else {
sh->format = MP_FOURCC('f', 'L', 'a', 'C');
ptr = extradata;
size = extradata_len;
ptr = track->private_data + sizeof(*sh_a->wf);
size = track->private_size - sizeof(*sh_a->wf);
}
if (size < 4 || ptr[0] != 'f' || ptr[1] != 'L' || ptr[2] != 'a'
|| ptr[3] != 'C') {
@@ -1547,10 +1572,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
}
} else if (track->a_formattag == MP_FOURCC('W', 'V', 'P', 'K') ||
track->a_formattag == MP_FOURCC('T', 'R', 'H', 'D')) {
if (!track->ms_compat) {
extradata = track->private_data;
extradata_len = track->private_size;
}
copy_audio_private_data(sh_a, track);
} else if (track->a_formattag == MP_FOURCC('T', 'T', 'A', '1')) {
sh_a->codecdata_len = 30;
sh_a->codecdata = talloc_zero_size(sh_a, sh_a->codecdata_len);
@@ -1560,7 +1582,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
memcpy(data + 0, "TTA1", 4);
AV_WL16(data + 4, 1);
AV_WL16(data + 6, sh_a->channels.num);
AV_WL16(data + 8, sh_a->bits_per_coded_sample);
AV_WL16(data + 8, sh_a->wf->wBitsPerSample);
AV_WL32(data + 10, track->a_osfreq);
// Bogus: last frame won't be played.
AV_WL32(data + 14, 0);
@@ -1576,14 +1598,6 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
mp_set_codec_from_tag(sh);
if (track->private_size > 0x1000000 || extradata_len > 0x1000000)
goto error;
if (!sh_a->codecdata && extradata) {
sh_a->codecdata = talloc_memdup(sh_a, extradata, extradata_len);
sh_a->codecdata_len = extradata_len;
}
return 0;
error:
@@ -1938,7 +1952,11 @@ static int64_t real_fix_timestamp(unsigned char *buf, int len, int64_t timestamp
*kf_base = timestamp;
*kf_pts = pts;
} else {
timestamp = *kf_base - ((*kf_pts - pts) & 0x1FFF);
if (pict_type != 3) {
timestamp = *kf_base + ((pts - *kf_pts) & 0x1FFF);
} else {
timestamp = *kf_base - ((*kf_pts - pts) & 0x1FFF);
}
}
return timestamp;
@@ -1952,8 +1970,6 @@ static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
int64_t timestamp = mkv_d->last_pts * 1000;
dp = new_demux_packet_from(data.start, data.len);
if (!dp)
return;
if (mkv_d->v_skip_to_keyframe) {
dp->pts = mkv_d->last_pts;
@@ -1962,7 +1978,7 @@ static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
} else {
dp->pts =
real_fix_timestamp(dp->buffer, dp->len, timestamp,
track->stream->format,
track->stream->video->bih->biCompression,
&track->rv_kf_base, &track->rv_kf_pts) * 0.001;
}
dp->pos = mkv_d->last_filepos;
@@ -2065,15 +2081,13 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
if (++(track->sub_packet_cnt) == sph) {
track->sub_packet_cnt = 0;
// apk_usize has same range as coded_framesize in worst case
uint32_t apk_usize = track->stream->audio->block_align;
uint32_t apk_usize = track->stream->audio->wf->nBlockAlign;
if (apk_usize > audiobuf_size)
goto error;
// Release all the audio packets
for (int x = 0; x < sph * w / apk_usize; x++) {
dp = new_demux_packet_from(track->audio_buf + x * apk_usize,
apk_usize);
if (!dp)
goto error;
/* Put timestamp only on packets that correspond to original
* audio packets in file */
dp->pts = (x * apk_usize % w) ? MP_NOPTS_VALUE :
@@ -2085,8 +2099,6 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
}
} else { // Not a codec that requires reordering
dp = new_demux_packet_from(buffer, size);
if (!dp)
goto error;
if (track->ra_pts == mkv_d->last_pts && !mkv_d->a_skip_to_keyframe)
dp->pts = MP_NOPTS_VALUE;
else
@@ -2099,7 +2111,7 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
}
return;
error:
MP_ERR(demuxer, "RealAudio packet extraction or decryption error.\n");
MP_ERR(demuxer, "RealAudio decrypting error.\n");
}
static void mkv_seek_reset(demuxer_t *demuxer)
@@ -2404,21 +2416,17 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
while (raw.start && mkv_parse_packet(track, &raw, &buffer)) {
demux_packet_t *dp =
new_demux_packet_from(buffer.start, buffer.len);
if (!dp)
break;
dp->keyframe = keyframe;
/* If default_duration is 0, assume no pts value is known
* for packets after the first one (rather than all pts
* values being the same). Also, don't use it for extra
* packets resulting from parsing. */
if (p == 0 || (p == i && track->default_duration))
* values being the same) */
if (p == 0 || track->default_duration)
dp->pts = mkv_d->last_pts + p * track->default_duration;
p++;
if (track->ms_compat)
MPSWAP(double, dp->pts, dp->dts);
if (p == 0)
dp->duration = block_duration / 1e9;
dp->duration = block_duration / 1e9;
demux_add_packet(stream, dp);
p++;
}
talloc_free_children(track->parser_tmp);
}
+18 -44
View File
@@ -29,62 +29,33 @@
#include "stream/stream.h"
#include "demux.h"
#include "stheader.h"
#include "codec_tags.h"
#include "audio/format.h"
#include "video/img_format.h"
#include "video/img_fourcc.h"
#include "osdep/endian.h"
struct demux_rawaudio_opts {
struct mp_chmap channels;
int samplerate;
int aformat;
};
// Ad-hoc schema to systematically encode the format as int
#define PCM(sign, is_float, bits, is_be) \
((sign) | ((is_float) << 1) | ((is_be) << 2) | ((bits) << 3))
#define NE (BYTE_ORDER == BIG_ENDIAN)
#define OPT_BASE_STRUCT struct demux_rawaudio_opts
const struct m_sub_options demux_rawaudio_conf = {
.opts = (const m_option_t[]) {
OPT_CHMAP("channels", channels, CONF_MIN, .min = 1),
OPT_INTRANGE("rate", samplerate, 0, 1000, 8 * 48000),
OPT_CHOICE("format", aformat, 0,
({"u8", PCM(0, 0, 8, 0)},
{"s8", PCM(1, 0, 8, 0)},
{"u16le", PCM(0, 0, 16, 0)}, {"u16be", PCM(0, 0, 16, 1)},
{"s16le", PCM(1, 0, 16, 0)}, {"u16be", PCM(1, 0, 16, 1)},
{"u24le", PCM(0, 0, 24, 0)}, {"u24be", PCM(0, 0, 24, 1)},
{"s24le", PCM(1, 0, 24, 0)}, {"s24be", PCM(1, 0, 24, 1)},
{"u32le", PCM(0, 0, 32, 0)}, {"u32be", PCM(0, 0, 32, 1)},
{"s32le", PCM(1, 0, 32, 0)}, {"s32be", PCM(1, 0, 32, 1)},
{"floatle", PCM(0, 1, 32, 0)}, {"floatbe", PCM(0, 1, 32, 1)},
{"doublele",PCM(0, 1, 64, 0)}, {"doublebe", PCM(0, 1, 64, 1)},
{"u16", PCM(0, 0, 16, NE)},
{"s16", PCM(1, 0, 16, NE)},
{"u24", PCM(0, 0, 24, NE)},
{"s24", PCM(1, 0, 24, NE)},
{"u32", PCM(0, 0, 32, NE)},
{"s32", PCM(1, 0, 32, NE)},
{"float", PCM(0, 1, 32, NE)},
{"double", PCM(0, 1, 64, NE)})),
OPT_AUDIOFORMAT("format", aformat, 0),
{0}
},
.size = sizeof(struct demux_rawaudio_opts),
.defaults = &(const struct demux_rawaudio_opts){
// Note that currently, stream_cdda expects exactly these parameters!
.channels = MP_CHMAP_INIT_STEREO,
.samplerate = 44100,
.aformat = PCM(1, 0, 16, 0), // s16le
.aformat = AF_FORMAT_S16,
},
};
#undef PCM
#undef NE
struct demux_rawvideo_opts {
int vformat;
int mp_format;
@@ -128,20 +99,28 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
struct demux_rawaudio_opts *opts = demuxer->opts->demux_rawaudio;
struct sh_stream *sh;
sh_audio_t *sh_audio;
MP_WAVEFORMATEX *w;
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
return -1;
if ((opts->aformat & AF_FORMAT_SPECIAL_MASK) != 0)
return -1;
sh = new_sh_stream(demuxer, STREAM_AUDIO);
sh_audio = sh->audio;
sh->codec = "mp-pcm";
sh->format = opts->aformat;
sh_audio->wf = w = talloc_zero(sh, MP_WAVEFORMATEX);
w->wFormatTag = 0;
sh_audio->channels = opts->channels;
sh_audio->force_channels = true;
sh_audio->samplerate = opts->samplerate;
int f = opts->aformat;
// See PCM(): sign float bits endian
mp_set_pcm_codec(sh, f & 1, f & 2, f >> 3, f & 4);
int samplesize = ((f >> 3) + 7) / 8;
w->nChannels = sh_audio->channels.num;
w->nSamplesPerSec = sh_audio->samplerate = opts->samplerate;
int samplesize = af_fmt2bps(opts->aformat);
w->nAvgBytesPerSec = sh_audio->samplerate * samplesize * w->nChannels;
w->nBlockAlign = w->nChannels * samplesize;
w->wBitsPerSample = 8 * samplesize;
w->cbSize = 0;
struct priv *p = talloc_ptrtype(demuxer, p);
demuxer->priv = p;
@@ -248,11 +227,6 @@ static int raw_fill_buffer(demuxer_t *demuxer)
return 0;
struct demux_packet *dp = new_demux_packet(p->frame_size * p->read_frames);
if (!dp) {
MP_ERR(demuxer, "Can't read packet.\n");
return 1;
}
dp->pos = stream_tell(demuxer->stream);
dp->pts = (dp->pos / p->frame_size) / p->frame_rate;
+38 -21
View File
@@ -8,11 +8,9 @@
#include "options/options.h"
#include "demux.h"
#include "codec_tags.h"
#include "audio/format.h"
#include "video/img_fourcc.h"
#include "osdep/endian.h"
#include "stream/stream.h"
#include "stream/tv.h"
@@ -106,9 +104,16 @@ static int demux_open_tv(demuxer_t *demuxer, enum demux_check check)
switch(audio_format)
{
// This is the only format any of the current inputs generate.
case AF_FORMAT_S16:
case AF_FORMAT_U8:
case AF_FORMAT_S8:
case AF_FORMAT_U16_LE:
case AF_FORMAT_U16_BE:
case AF_FORMAT_S16_LE:
case AF_FORMAT_S16_BE:
case AF_FORMAT_S32_LE:
case AF_FORMAT_S32_BE:
break;
case AF_FORMAT_MPEG2:
default:
MP_ERR(tvh, "Audio type '%s' unsupported!\n",
af_fmt_to_str(audio_format));
@@ -125,11 +130,27 @@ static int demux_open_tv(demuxer_t *demuxer, enum demux_check check)
&nchannels);
mp_chmap_from_channels(&sh_audio->channels, nchannels);
// s16ne
mp_set_pcm_codec(sh_a, true, false, 16, BYTE_ORDER == BIG_ENDIAN);
sh_a->codec = "mp-pcm";
sh_a->format = audio_format;
int samplesize = af_fmt2bps(audio_format);
int block_align = samplesize * sh_audio->channels.num;
int bytes_per_second = sh_audio->samplerate * block_align;
sh_audio->bitrate = bytes_per_second * 8;
// emulate WF for win32 codecs:
sh_audio->wf = talloc_zero(sh_audio, MP_WAVEFORMATEX);
sh_audio->wf->wFormatTag = sh_a->format;
sh_audio->wf->nChannels = sh_audio->channels.num;
sh_audio->wf->wBitsPerSample = samplesize * 8;
sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
sh_audio->wf->nBlockAlign = block_align;
sh_audio->wf->nAvgBytesPerSec = bytes_per_second;
MP_VERBOSE(tvh, " TV audio: %d channels, %d bits, %d Hz\n",
nchannels, 16, sh_audio->samplerate);
sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
sh_audio->wf->nSamplesPerSec);
}
no_audio:
@@ -183,30 +204,26 @@ static int demux_tv_fill_buffer(demuxer_t *demux)
if (want_audio && tvh->tv_param->audio &&
tvh->functions->control(tvh->priv,
TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE)
{
{
len = tvh->functions->get_audio_framesize(tvh->priv);
dp=new_demux_packet(len);
if (dp) {
dp->keyframe = true;
dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len);
demux_add_packet(want_audio, dp);
dp->keyframe = true;
dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len);
demux_add_packet(want_audio, dp);
}
}
/* ================== ADD VIDEO PACKET =================== */
if (want_video && tvh->functions->control(tvh->priv,
TVI_CONTROL_IS_VIDEO, 0) == TVI_CONTROL_TRUE)
{
len = tvh->functions->get_video_framesize(tvh->priv);
{
len = tvh->functions->get_video_framesize(tvh->priv);
dp=new_demux_packet(len);
if (dp) {
dp->keyframe = true;
dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len);
demux_add_packet(want_video, dp);
}
}
dp->keyframe = true;
dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len);
demux_add_packet(want_video, dp);
}
if (tvh->tv_param->scan) tv_scan(tvh);
return 1;
+4 -7
View File
@@ -34,6 +34,7 @@
#include "talloc.h"
#include "ebml.h"
#include "stream/stream.h"
#include "compat/mpbswap.h"
#include "common/msg.h"
// Whether the id is a known Matroska level 1 element (allowed as element on
@@ -419,16 +420,12 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
if (num_elems[i] && type->fields[i].multiple) {
char *ptr = s + type->fields[i].offset;
switch (type->fields[i].desc->type) {
case EBML_TYPE_SUBELEMENTS: {
size_t max = 1000000000 / type->fields[i].desc->size;
if (num_elems[i] > max) {
MP_ERR(ctx, "Too many subelements.\n");
num_elems[i] = max;
}
case EBML_TYPE_SUBELEMENTS:
num_elems[i] = FFMIN(num_elems[i],
1000000000 / type->fields[i].desc->size);
int sz = num_elems[i] * type->fields[i].desc->size;
*(generic_struct **) ptr = talloc_zero_size(ctx->talloc_ctx, sz);
break;
}
case EBML_TYPE_UINT:
*(uint64_t **) ptr = talloc_zero_array(ctx->talloc_ctx,
uint64_t, num_elems[i]);
+1 -1
View File
@@ -24,7 +24,7 @@
#include <stdbool.h>
#include "stream/stream.h"
#include "misc/bstr.h"
#include "bstr/bstr.h"
struct mp_log;
+52
View File
@@ -0,0 +1,52 @@
/*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_MS_HDR_H
#define MPLAYER_MS_HDR_H
#include "compat/mpbswap.h"
#include "video/img_fourcc.h"
// These structs must be binary-compatible to the native win32 types,
// because demux_mkv.c uses them directly.
typedef struct __attribute__((__packed__)) MP_WAVEFORMATEX {
unsigned short wFormatTag;
unsigned short nChannels;
unsigned int nSamplesPerSec;
unsigned int nAvgBytesPerSec;
unsigned short nBlockAlign;
unsigned short wBitsPerSample;
unsigned short cbSize;
} MP_WAVEFORMATEX;
typedef struct __attribute__((__packed__)) MP_BITMAPINFOHEADER {
int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
} MP_BITMAPINFOHEADER;
#endif /* MPLAYER_MS_HDR_H */
+50 -43
View File
@@ -29,60 +29,55 @@
static void packet_destroy(void *ptr)
{
struct demux_packet *dp = ptr;
av_packet_unref(dp->avpacket);
talloc_free(dp->avpacket);
av_free(dp->allocation);
}
// This actually preserves only data and side data, not PTS/DTS/pos/etc.
// It also allows avpkt->data==NULL with avpkt->size!=0 - the libavcodec API
// does not allow it, but we do it to simplify new_demux_packet().
struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt)
static struct demux_packet *create_packet(size_t len)
{
if (avpkt->size > 1000000000)
return NULL;
if (len > 1000000000) {
fprintf(stderr, "Attempt to allocate demux packet over 1 GB!\n");
abort();
}
struct demux_packet *dp = talloc(NULL, struct demux_packet);
talloc_set_destructor(dp, packet_destroy);
*dp = (struct demux_packet) {
.len = len,
.pts = MP_NOPTS_VALUE,
.dts = MP_NOPTS_VALUE,
.duration = -1,
.pos = -1,
.stream = -1,
.avpacket = talloc_zero(dp, AVPacket),
};
av_init_packet(dp->avpacket);
int r = -1;
if (avpkt->data) {
// We hope that this function won't need/access AVPacket input padding,
// because otherwise new_demux_packet_from() wouldn't work.
r = av_packet_ref(dp->avpacket, avpkt);
} else {
r = av_new_packet(dp->avpacket, avpkt->size);
}
if (r < 0) {
*dp->avpacket = (AVPacket){0};
talloc_free(dp);
return NULL;
}
dp->buffer = dp->avpacket->data;
dp->len = dp->avpacket->size;
return dp;
}
// Input data doesn't need to be padded.
struct demux_packet *new_demux_packet_from(void *data, size_t len)
{
if (len > INT_MAX)
return NULL;
AVPacket pkt = { .data = data, .size = len };
return new_demux_packet_from_avpacket(&pkt);
}
struct demux_packet *new_demux_packet(size_t len)
{
if (len > INT_MAX)
return NULL;
AVPacket pkt = { .data = NULL, .size = len };
return new_demux_packet_from_avpacket(&pkt);
struct demux_packet *dp = create_packet(len);
dp->buffer = av_malloc(len + FF_INPUT_BUFFER_PADDING_SIZE);
if (!dp->buffer) {
fprintf(stderr, "Memory allocation failure!\n");
abort();
}
memset(dp->buffer + len, 0, FF_INPUT_BUFFER_PADDING_SIZE);
dp->allocation = dp->buffer;
return dp;
}
// data must already have suitable padding, and does not copy the data
struct demux_packet *new_demux_packet_fromdata(void *data, size_t len)
{
struct demux_packet *dp = create_packet(len);
dp->buffer = data;
return dp;
}
struct demux_packet *new_demux_packet_from(void *data, size_t len)
{
struct demux_packet *dp = new_demux_packet(len);
memcpy(dp->buffer, data, len);
return dp;
}
void demux_packet_shorten(struct demux_packet *dp, size_t len)
@@ -97,17 +92,29 @@ void free_demux_packet(struct demux_packet *dp)
talloc_free(dp);
}
static void destroy_avpacket(void *pkt)
{
av_free_packet(pkt);
}
struct demux_packet *demux_copy_packet(struct demux_packet *dp)
{
struct demux_packet *new = NULL;
if (dp->avpacket) {
new = new_demux_packet_from_avpacket(dp->avpacket);
} else {
// Some packets might be not created by new_demux_packet*().
new = new_demux_packet_from(dp->buffer, dp->len);
assert(dp->buffer == dp->avpacket->data);
assert(dp->len == dp->avpacket->size);
AVPacket *newavp = talloc_zero(NULL, AVPacket);
talloc_set_destructor(newavp, destroy_avpacket);
av_init_packet(newavp);
if (av_packet_ref(newavp, dp->avpacket) < 0)
abort();
new = new_demux_packet_fromdata(newavp->data, newavp->size);
new->avpacket = newavp;
}
if (!new) {
new = new_demux_packet(dp->len);
memcpy(new->buffer, dp->buffer, new->len);
}
if (!new)
return NULL;
new->pts = dp->pts;
new->dts = dp->dts;
new->duration = dp->duration;
+4 -2
View File
@@ -34,11 +34,13 @@ typedef struct demux_packet {
bool keyframe;
int stream; // source stream index
struct demux_packet *next;
struct AVPacket *avpacket; // keep the buffer allocation
void *allocation;
struct AVPacket *avpacket; // original libavformat packet (demux_lavf)
} demux_packet_t;
struct demux_packet *new_demux_packet(size_t len);
struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt);
// data must already have suitable padding
struct demux_packet *new_demux_packet_fromdata(void *data, size_t len);
struct demux_packet *new_demux_packet_from(void *data, size_t len);
void demux_packet_shorten(struct demux_packet *dp, size_t len);
void free_demux_packet(struct demux_packet *dp);
Loaded 100 of 262 files, more files were not shown because too many files have changed in this diff. Show more