Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
777295ce28 | ||
|
|
d50be0a2a6 | ||
|
|
2d8e26bb72 | ||
|
|
7ee275095f | ||
|
|
5a5b219853 | ||
|
|
608bed1aed | ||
|
|
636b62fc1a | ||
|
|
78195cd742 | ||
|
|
e7fc048eca | ||
|
|
0ab7d01425 | ||
|
|
bd0b661183 | ||
|
|
0989d8358c | ||
|
|
c979ee34e1 | ||
|
|
bb00774514 | ||
|
|
ef41a98a79 | ||
|
|
b18c2d9fe2 | ||
|
|
8f5ebdbe59 | ||
|
|
e8616fea50 | ||
|
|
00997484f1 | ||
|
|
ea556e5398 | ||
|
|
a3fc0b2015 | ||
|
|
2db094203d | ||
|
|
958858f920 | ||
|
|
bd271ae1cc | ||
|
|
c71644b595 | ||
|
|
9b18ed8d8b | ||
|
|
5dce714dfe | ||
|
|
25a0709972 | ||
|
|
6cf2f634b3 | ||
|
|
e165ccbf3b | ||
|
|
f78c0692e2 | ||
|
|
59f456cdd3 | ||
|
|
0e35c230f4 | ||
|
|
9ae80929ea | ||
|
|
98d1358e6e | ||
|
|
e71d68cdae | ||
|
|
950ef5b75b | ||
|
|
0075f8e0cf | ||
|
|
49275b2879 |
No files matched your search
@@ -193,6 +193,8 @@ List of Input Commands
|
||||
Stop playback of the current file, and play the new file immediately.
|
||||
<append>
|
||||
Append the file to the playlist.
|
||||
<append-play>
|
||||
Append the file, and if nothing is currently playing, start playback.
|
||||
|
||||
The third argument is a list of options and values which should be set
|
||||
while the file is playing. It is of the form ``opt1=value1,opt2=value2,..``.
|
||||
|
||||
@@ -1366,13 +1366,13 @@ OPTIONS
|
||||
example files or playlists loaded with the ``loadfile`` or ``loadlist``
|
||||
commands.
|
||||
|
||||
``--mf=<option1:option2:...>``
|
||||
Used when decoding from multiple PNG or JPEG files with ``mf://``.
|
||||
``--mf-fps=<value>``
|
||||
Framerate used when decoding from multiple PNG or JPEG files with ``mf://``
|
||||
(default: 1).
|
||||
|
||||
Available options are:
|
||||
|
||||
:fps=<value>: output fps (default: 1)
|
||||
:type=<value>: input file type (available: jpeg, png, tga, sgi)
|
||||
``--mf-type=<value>``
|
||||
Input file type for ``mf://`` (available: jpeg, png, tga, sgi). By default,
|
||||
this is guessed from the file extension.
|
||||
|
||||
``--monitoraspect=<ratio>``
|
||||
Set the aspect ratio of your monitor or TV screen. A value of 0 disables a
|
||||
|
||||
@@ -136,4 +136,4 @@ To contact the `mpv` team in private write to `mpv-team@googlegroups.com`.
|
||||
[mpv-users]: https://groups.google.com/forum/?hl=en#!forum/mpv-users
|
||||
[mpv-devel]: https://groups.google.com/forum/?hl=en#!forum/mpv-devel
|
||||
[ffmpeg_vs_libav]: https://github.com/mpv-player/mpv/wiki/FFmpeg-versus-Libav
|
||||
[release-policy]: https://github.com/mpv-player/mpv/blob/master/release-policy.md
|
||||
[release-policy]: https://github.com/mpv-player/mpv/blob/master/DOCS/release-policy.md
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
Release 0.4.2
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Include changes from point releases in the release notes.
|
||||
- Fix --cache-file operation when file size is unknown (e.g. when playing from
|
||||
a pipe).
|
||||
- Don't sleep if playback is stopped when reconnecting for remote stream.
|
||||
- Suspend read on vts change even if the requested title is not found when
|
||||
using dvdnav (dvd://) (this fixes a bug where the DVD menu was not shown
|
||||
properly after a DVD track ended).
|
||||
- Avoid draining if the audio output is paused (this fixes a bug where mpv would
|
||||
hang when switching tracks when paused).
|
||||
- Drop buffered audio when switching tracks or filters (this fixes a possible
|
||||
regression when using gapless audio).
|
||||
- Reverse video rotation direction.
|
||||
- Fix initialization of the input when playing from a pipe.
|
||||
- Fix description of the --mf option in the manpage (the --mf syntax changed a
|
||||
while ago, but was not documented).
|
||||
- Actually append entries to the end of the playlist instead of after the
|
||||
current entry with the "loadlist append" command.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Add "append-play" mode for the loadfile command.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log bb00774..d50be0a`` in
|
||||
the git repository.
|
||||
|
||||
Release 0.4.1
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix af_volume bug that caused negative ReplayGain values to increase volume
|
||||
instead of decreasing it in some situations.
|
||||
- Actually use "weak" as --gapless-audio default value (as documented in the
|
||||
0.4.0 release notes).
|
||||
- Fix cache resizing bug that caused seeking to not work anymore.
|
||||
- Escape all colons in the options descriptions in the zsh completion script.
|
||||
- Don't consume an extra argument with --ao/af and --vo/vf options in the zsh
|
||||
completion script (as side effect, the completion now uses --opt=val instead
|
||||
of --opt val).
|
||||
- Allow client applications to call mpv_terminate_destroy(NULL).
|
||||
- Make sure seeking bounds are within range with dvdnav://.
|
||||
- Check the length of the last title too with dvdnav://longest.
|
||||
- Properly flush buffers on DVD seek (this fixes some seeking problems when
|
||||
playing DVDs).
|
||||
- Allow compilation without atomics (for compilers that don't support atomic
|
||||
operations).
|
||||
- Disable ao_null latency emulation.
|
||||
- Restore ability to combine mouse buttons.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log 0075f8e..b18c2d9`` in
|
||||
the git repository.
|
||||
|
||||
Release 0.4.0
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Drop support for Libav 9 and earlier FFmpeg releases. At least FFmpeg 2.1.4 or
|
||||
Libav 10 are now required.
|
||||
- Change cache options to take kilobytes instead of percentages, and raise the
|
||||
default values.
|
||||
- Lower --auto-pause/resume defaults values to improve web streams playback.
|
||||
- Use dvdnav support instead of the internal dvd implementation for dvd:// URLs
|
||||
(the old implementation is available under dvdread://).
|
||||
- DVD (dvd://) tracks IDs now start from 0 instead of 1.
|
||||
- Play the longest track by default with dvd://.
|
||||
- Rename some options to make them more consistent. Here's a partial list of
|
||||
renamed options:
|
||||
|
||||
+ Audio-related:
|
||||
|
||||
* --audiofile → --audio-file
|
||||
* --audiofile-cache → --audio-file-cache
|
||||
* --channels → --audio-channels
|
||||
* --format → --audio-format
|
||||
* --srate → --audio-samplerate
|
||||
|
||||
+ Input-related:
|
||||
|
||||
* --ar → --input-appleremote
|
||||
* --consolecontrols → --input-terminal
|
||||
* --media-keys → --input-media-keys
|
||||
* --joystick → --input-joystick
|
||||
* --lirc → --input-lirc
|
||||
* --lircconf → --input-lirc-conf
|
||||
* --mouse-movements → --input-cursor
|
||||
* --right-alt-gr → --input-right-alt-gr
|
||||
|
||||
+ Terminal-related:
|
||||
|
||||
* --msgcolor → --msg-color
|
||||
* --msglevel → --msg-level
|
||||
* --msgmodule → --msg-module
|
||||
* --msgtime → --msg-time
|
||||
* --playing-msg → --term-playing-msg
|
||||
* --status-msg → --term-status-msg
|
||||
|
||||
+ Subtitle-related:
|
||||
|
||||
* --ass → --sub-ass
|
||||
* --autosub → --sub-auto
|
||||
* --autosub-match → --sub-auto-match
|
||||
* --sub → --sub-file
|
||||
* --subcp → --sub-codepage
|
||||
* --subfps → --sub-fps
|
||||
|
||||
+ Video-related:
|
||||
|
||||
* --aspect → --video-aspect
|
||||
* --fstype → --x11-fstype
|
||||
* --native-fs → --fs-missioncontrol
|
||||
* --name → --x11-name
|
||||
|
||||
- Remove global options variables for --tv, --pvr, --dvb and --cdda.
|
||||
- Move post-processing support to a separate filter (vdpaupp) for the vdpau vo,
|
||||
and deprecate the old vdpau post-processing options.
|
||||
- Remove radio:// support.
|
||||
- Remove support for ASX, SMIL and NSC playlist formats.
|
||||
- Re-introduce pretty-printing for module names with --msg-module.
|
||||
- Load Lua scripts under `$MPV_HOME/lua/` (default `~/.mpv/lua/`) automatically
|
||||
(this can be disabled by using `--load-scripts=no`).
|
||||
- Corrupt/broken frames are not shown by default anymore (this can be re-enabled
|
||||
by using --vd-lavc-show-all=yes).
|
||||
- Automatically copy metadata from the input file to the output when encoding
|
||||
(this can be disabled by using --no-ometadata).
|
||||
- Change --sub-file semantics: if multiple --sub-file are used, the subtitle
|
||||
tracks can be cycled at runtime and used with --sid and --secondary-sid.
|
||||
- Make the subtitle font size relative to the window, instead of the video, when
|
||||
--sub-scale-with-window=yes is used.
|
||||
- Change default ao from wasapi to dsound on Windows.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix tv:// playback with missing timestamps.
|
||||
- Fix display of cover art inside audio files with the vdpau vo.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Add client API in the form of the libmpv library, which is intended to be a
|
||||
stable API to get some rough control over the player (this is not supported on
|
||||
Mac OS X).
|
||||
- Add option for approximating BT.709 gamma for the opengl vo (similarly to many
|
||||
programs in the Apple ecosystem).
|
||||
- Add support for non-BT.709 primaries.
|
||||
- Add support for BT.2020 colorspace.
|
||||
- Generate and install zsh completion script (disabled by default since it may
|
||||
interfere with cross-compilation).
|
||||
- Add support for looping a single file (instead of the whole playlist) with the
|
||||
--loop-file option.
|
||||
- Add VapourSynth video filter (this has various restrictions, which are listed
|
||||
in the manpage).
|
||||
- Add support for ReplayGain in the volume audio filter.
|
||||
- Add a --config-dir option to force config directory.
|
||||
- Add support for GPU switching on Mac OS X.
|
||||
- Add support for automatic selection of color profiles on Mac OS X.
|
||||
- Add support for binding commands to sequences of keys.
|
||||
- Add support for passing options to Lua scripts with --lua-opts.
|
||||
- Add some filesystem utility functions to the Lua API.
|
||||
- Add functions for observing property changes to the Lua API .
|
||||
- Add support for creating a cache file on the filesystem with --cache-file.
|
||||
- Add support for window dragging by grabbing with the x11 vo.
|
||||
- Add option to write file name to watch later file.
|
||||
- Add support for a "weak" gapless mode, and make it default (the old mode can
|
||||
be enabled with --gapless-audio or --gapless-audio=yes).
|
||||
- Automatically detect network filesystems on Linux and Windows.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log 56ce2a3..8bb7d42`` in
|
||||
the git repository.
|
||||
+28
-11
@@ -7,7 +7,7 @@ use warnings;
|
||||
|
||||
my $mpv = $ARGV[0] || 'mpv';
|
||||
|
||||
my @opts = parse_opts("$mpv --list-options", '^ (\-\-[^\s\*]*)\*?\s*(.*)');
|
||||
my @opts = parse_opts("$mpv --list-options", '^ (\-\-[^\s\*]*)\*?\s*(.*)', 1);
|
||||
|
||||
my @ao = parse_opts("$mpv --ao=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
my @vo = parse_opts("$mpv --vo=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
@@ -17,7 +17,7 @@ my @vf = parse_opts("$mpv --vf=help", '^ ([^\s\:]*)\s*: (.*)');
|
||||
|
||||
my ($opts_str, $ao_str, $vo_str, $af_str, $vf_str);
|
||||
|
||||
$opts_str .= qq{ '$_': \\\n} foreach (@opts);
|
||||
$opts_str .= qq{ '$_' \\\n} foreach (@opts);
|
||||
chomp $opts_str;
|
||||
|
||||
$ao_str .= qq{ '$_' \\\n} foreach (@ao);
|
||||
@@ -98,7 +98,7 @@ EOS
|
||||
print $tmpl;
|
||||
|
||||
sub parse_opts {
|
||||
my ($cmd, $regex) = @_;
|
||||
my ($cmd, $regex, $parsing_main_options) = @_;
|
||||
|
||||
my @list;
|
||||
my @lines = split /\n/, `$cmd`;
|
||||
@@ -108,21 +108,38 @@ sub parse_opts {
|
||||
next;
|
||||
}
|
||||
|
||||
my $entry = "$1:";
|
||||
my $entry = $1;
|
||||
|
||||
if ($parsing_main_options) {
|
||||
$entry .= '=-';
|
||||
}
|
||||
|
||||
if (defined $2) {
|
||||
my $desc = $2;
|
||||
$desc =~ s/\:/\\:/;
|
||||
$desc =~ s/\:/\\:/g;
|
||||
|
||||
$entry .= $desc;
|
||||
$entry .= ':' . $desc;
|
||||
}
|
||||
|
||||
$entry .= ':->ao' if ($1 eq '--ao');
|
||||
$entry .= ':->vo' if ($1 eq '--vo');
|
||||
$entry .= ':->af' if ($1 eq '--af');
|
||||
$entry .= ':->vf' if ($1 eq '--vf');
|
||||
if ($parsing_main_options) {
|
||||
$entry .= ':';
|
||||
|
||||
push @list, $entry if ($line =~ /^$regex/)
|
||||
$entry .= '->ao' if ($1 eq '--ao');
|
||||
$entry .= '->vo' if ($1 eq '--vo');
|
||||
$entry .= '->af' if ($1 eq '--af');
|
||||
$entry .= '->vf' if ($1 eq '--vf');
|
||||
}
|
||||
|
||||
push @list, $entry
|
||||
}
|
||||
|
||||
if ($parsing_main_options) {
|
||||
@list = sort {
|
||||
$a =~ /(.*?)\:/; my $ma = $1;
|
||||
$b =~ /(.*?)\:/; my $mb = $1;
|
||||
|
||||
length($mb) <=> length($ma)
|
||||
} @list;
|
||||
}
|
||||
|
||||
return @list;
|
||||
|
||||
@@ -79,7 +79,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
if (!s->rgain_clip) // clipping prevention
|
||||
s->rgain = MPMIN(s->rgain, 1.0 / peak);
|
||||
}
|
||||
if (s->detach && fabs(s->level + s->rgain - 2.0) < 0.00001)
|
||||
if (s->detach && fabs(s->level * s->rgain - 1.0) < 0.00001)
|
||||
return AF_DETACH;
|
||||
return af_test_output(af, in);
|
||||
}
|
||||
@@ -97,7 +97,7 @@ static void filter_plane(struct af_instance *af, void *ptr, int num_samples)
|
||||
{
|
||||
struct priv *s = af->priv;
|
||||
|
||||
float level = s->level + s->rgain - 1.0;
|
||||
float level = s->level * s->rgain;
|
||||
|
||||
if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16) {
|
||||
int16_t *a = ptr;
|
||||
|
||||
+1
-13
@@ -31,7 +31,6 @@
|
||||
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/common.h"
|
||||
#include "common/global.h"
|
||||
@@ -309,22 +308,11 @@ void ao_resume(struct ao *ao)
|
||||
ao->api->resume(ao);
|
||||
}
|
||||
|
||||
// Be careful with locking
|
||||
void ao_wait_drain(struct ao *ao)
|
||||
{
|
||||
// This is probably not entirely accurate, but good enough.
|
||||
mp_sleep_us(ao_get_delay(ao) * 1000000);
|
||||
ao_reset(ao);
|
||||
}
|
||||
|
||||
// Block until the current audio buffer has played completely.
|
||||
void ao_drain(struct ao *ao)
|
||||
{
|
||||
if (ao->api->drain) {
|
||||
if (ao->api->drain)
|
||||
ao->api->drain(ao);
|
||||
} else {
|
||||
ao_wait_drain(ao);
|
||||
}
|
||||
}
|
||||
|
||||
bool ao_eof_reached(struct ao *ao)
|
||||
|
||||
@@ -210,7 +210,6 @@ const struct ao_driver audio_out_null = {
|
||||
.priv_size = sizeof(struct priv),
|
||||
.priv_defaults = &(const struct priv) {
|
||||
.bufferlen = 0.2,
|
||||
.latency_sec = 0.5,
|
||||
.outburst = 256,
|
||||
.speed = 1,
|
||||
},
|
||||
|
||||
@@ -158,7 +158,6 @@ struct ao_driver {
|
||||
// These functions can be called by AOs.
|
||||
|
||||
int ao_play_silence(struct ao *ao, int samples);
|
||||
void ao_wait_drain(struct ao *ao);
|
||||
int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us);
|
||||
struct pollfd;
|
||||
int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds,
|
||||
|
||||
@@ -193,6 +193,14 @@ static void resume(struct ao *ao)
|
||||
ao->driver->resume(ao);
|
||||
}
|
||||
|
||||
static void drain(struct ao *ao)
|
||||
{
|
||||
struct ao_pull_state *p = ao->api_priv;
|
||||
if (atomic_load(&p->state) == AO_STATE_PLAY)
|
||||
mp_sleep_us(get_delay(ao) * 1000000);
|
||||
reset(ao);
|
||||
}
|
||||
|
||||
static void uninit(struct ao *ao)
|
||||
{
|
||||
ao->driver->uninit(ao);
|
||||
@@ -212,6 +220,7 @@ const struct ao_driver ao_api_pull = {
|
||||
.init = init,
|
||||
.control = control,
|
||||
.uninit = uninit,
|
||||
.drain = drain,
|
||||
.reset = reset,
|
||||
.get_space = get_space,
|
||||
.play = play,
|
||||
|
||||
+6
-1
@@ -146,6 +146,10 @@ static void drain(struct ao *ao)
|
||||
struct ao_push_state *p = ao->api_priv;
|
||||
|
||||
pthread_mutex_lock(&p->lock);
|
||||
if (p->paused) {
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
return;
|
||||
}
|
||||
p->final_chunk = true;
|
||||
p->drain = true;
|
||||
wakeup_playthread(ao);
|
||||
@@ -154,7 +158,8 @@ static void drain(struct ao *ao)
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
|
||||
if (!ao->driver->drain)
|
||||
ao_wait_drain(ao);
|
||||
mp_sleep_us(get_delay(ao) * 1000000);
|
||||
reset(ao);
|
||||
}
|
||||
|
||||
static int unlocked_get_space(struct ao *ao)
|
||||
|
||||
@@ -469,6 +469,10 @@ struct mp_log_buffer *mp_msg_log_buffer_new(struct mpv_global *global,
|
||||
{
|
||||
struct mp_log_root *root = global->log->root;
|
||||
|
||||
#if !HAVE_ATOMICS
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&mp_msg_lock);
|
||||
|
||||
struct mp_log_buffer *buffer = talloc_ptrtype(NULL, buffer);
|
||||
|
||||
@@ -215,6 +215,15 @@ void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl)
|
||||
}
|
||||
}
|
||||
|
||||
void playlist_append_entries(struct playlist *pl, struct playlist *source_pl)
|
||||
{
|
||||
while (source_pl->first) {
|
||||
struct playlist_entry *e = source_pl->first;
|
||||
playlist_unlink(source_pl, e);
|
||||
playlist_add(pl, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Return number of entries between list start and e.
|
||||
// Return -1 if e is not on the list, or if e is NULL.
|
||||
int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e)
|
||||
|
||||
@@ -74,6 +74,7 @@ void playlist_shuffle(struct playlist *pl);
|
||||
struct playlist_entry *playlist_get_next(struct playlist *pl, int direction);
|
||||
void playlist_add_base_path(struct playlist *pl, bstr base_path);
|
||||
void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl);
|
||||
void playlist_append_entries(struct playlist *pl, struct playlist *source_pl);
|
||||
|
||||
int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e);
|
||||
int playlist_entry_count(struct playlist *pl);
|
||||
|
||||
+13
-2
@@ -22,6 +22,8 @@
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
|
||||
#define HAVE_ATOMICS 1
|
||||
|
||||
#if HAVE_STDATOMIC
|
||||
#include <stdatomic.h>
|
||||
#else
|
||||
@@ -58,8 +60,17 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
|
||||
__sync_fetch_and_add(&(a)->v, b)
|
||||
|
||||
#else
|
||||
# error "this should have been a configuration error, report a bug please"
|
||||
#endif
|
||||
|
||||
// This is extremely wrong. The build system actually disables code that has
|
||||
// a serious dependency on working atomics, so this is barely ok.
|
||||
#define atomic_load(p) ((p)->v)
|
||||
#define atomic_store(p, val) ((p)->v = (val))
|
||||
#define atomic_fetch_add(a, b) (((a)->v += (b)) - (b))
|
||||
|
||||
#undef HAVE_ATOMICS
|
||||
#define HAVE_ATOMICS 0
|
||||
|
||||
#endif /* no atomics */
|
||||
|
||||
#endif /* else HAVE_STDATOMIC */
|
||||
|
||||
|
||||
@@ -583,6 +583,11 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
.filename = talloc_strdup(demuxer, stream->url),
|
||||
.metadata = talloc_zero(demuxer, struct mp_tags),
|
||||
};
|
||||
demuxer->seekable = stream->seekable;
|
||||
if (demuxer->stream->uncached_stream &&
|
||||
!demuxer->stream->uncached_stream->seekable)
|
||||
demuxer->seekable = false;
|
||||
|
||||
demuxer->params = params; // temporary during open()
|
||||
int64_t start_pos = stream_tell(stream);
|
||||
|
||||
|
||||
+8
-4
@@ -129,6 +129,9 @@ static const struct format_hack format_hacks[] = {
|
||||
|
||||
static const char *const format_blacklist[] = {
|
||||
"tty", // Useless non-sense, sometimes breaks MLP2 subreader.c fallback
|
||||
// Image demuxers, disabled in favor of demux_mf:
|
||||
"image2", "image2pipe",
|
||||
"bmp_pipe", "dpx_pipe", "exr_pipe", "j2k_pipe", "png_pipe", "tiff_pipe",
|
||||
0
|
||||
};
|
||||
|
||||
@@ -504,7 +507,7 @@ static void handle_stream(demuxer_t *demuxer, int i)
|
||||
#if HAVE_AV_DISPLAYMATRIX
|
||||
uint8_t *sd = av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, NULL);
|
||||
if (sd)
|
||||
sh_video->rotate = av_display_rotation_get((uint32_t *)sd);
|
||||
sh_video->rotate = -av_display_rotation_get((uint32_t *)sd);
|
||||
#else
|
||||
AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0);
|
||||
if (rot && rot->value) {
|
||||
@@ -1006,11 +1009,12 @@ redo:
|
||||
* call the new API instead of relying on av_seek_frame() to do this
|
||||
* for us.
|
||||
*/
|
||||
stream_drop_buffers(demuxer->stream);
|
||||
avio_flush(priv->avfc->pb);
|
||||
av_seek_frame(priv->avfc, 0, stream_tell(demuxer->stream),
|
||||
AVSEEK_FLAG_BYTE);
|
||||
avio_flush(priv->avfc->pb);
|
||||
// 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;
|
||||
|
||||
+103
-58
@@ -128,13 +128,13 @@ typedef struct mkv_track {
|
||||
double ra_pts; /* previous audio timestamp */
|
||||
|
||||
/** realaudio descrambling */
|
||||
int sub_packet_size; ///< sub packet size, per stream
|
||||
int sub_packet_h; ///< number of coded frames per block
|
||||
int coded_framesize; ///< coded frame size, per stream
|
||||
int audiopk_size; ///< audio packet size
|
||||
uint16_t sub_packet_size; ///< sub packet size, per stream
|
||||
uint16_t sub_packet_h; ///< number of coded frames per block
|
||||
uint32_t coded_framesize; ///< coded frame size, per stream
|
||||
uint16_t audiopk_size; ///< audio packet size
|
||||
unsigned char *audio_buf; ///< place to store reordered audio data
|
||||
double *audio_timestamp; ///< timestamp for each audio packet
|
||||
int sub_packet_cnt; ///< number of subpacket already received
|
||||
uint16_t sub_packet_cnt; ///< number of subpacket already received
|
||||
int audio_filepos; ///< file position of first audio packet in block
|
||||
|
||||
/* generic content encoding support */
|
||||
@@ -142,7 +142,7 @@ typedef struct mkv_track {
|
||||
int num_encodings;
|
||||
|
||||
/* latest added index entry for this track */
|
||||
int last_index_entry;
|
||||
size_t last_index_entry;
|
||||
} mkv_track_t;
|
||||
|
||||
typedef struct mkv_index {
|
||||
@@ -167,7 +167,7 @@ typedef struct mkv_demuxer {
|
||||
uint64_t cluster_end;
|
||||
|
||||
mkv_index_t *indexes;
|
||||
int num_indexes;
|
||||
size_t num_indexes;
|
||||
bool index_complete;
|
||||
uint64_t deferred_cues;
|
||||
|
||||
@@ -192,19 +192,6 @@ typedef struct mkv_demuxer {
|
||||
// (Subtitle packets added before first A/V keyframe packet is found with seek.)
|
||||
#define NUM_SUB_PREROLL_PACKETS 500
|
||||
|
||||
/**
|
||||
* \brief ensures there is space for at least one additional element
|
||||
* \param array array to grow
|
||||
* \param nelem current number of elements in array
|
||||
* \param elsize size of one array element
|
||||
*/
|
||||
static void *grow_array(void *array, int nelem, size_t elsize)
|
||||
{
|
||||
if (!(nelem & 31))
|
||||
array = realloc(array, (nelem + 32) * elsize);
|
||||
return array;
|
||||
}
|
||||
|
||||
#define AAC_SYNC_EXTENSION_TYPE 0x02b7
|
||||
static int aac_get_sample_rate_index(uint32_t sample_rate)
|
||||
{
|
||||
@@ -258,6 +245,12 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
||||
zstream.avail_out = size;
|
||||
int result;
|
||||
do {
|
||||
if (size >= INT_MAX - 4000) {
|
||||
talloc_free(dest);
|
||||
dest = NULL;
|
||||
inflateEnd(&zstream);
|
||||
goto error;
|
||||
}
|
||||
size += 4000;
|
||||
dest = talloc_realloc_size(track->parser_tmp, dest, size);
|
||||
zstream.next_out = (Bytef *) (dest + zstream.total_out);
|
||||
@@ -279,6 +272,9 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
||||
} else if (enc->comp_algo == 2) {
|
||||
/* lzo encoded track */
|
||||
int out_avail;
|
||||
int maxlen = INT_MAX - AV_LZO_OUTPUT_PADDING;
|
||||
if (size >= maxlen / 3)
|
||||
goto error;
|
||||
int dstlen = size * 3;
|
||||
|
||||
dest = NULL;
|
||||
@@ -297,6 +293,11 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
||||
goto error;
|
||||
}
|
||||
mp_dbg(log, "lzo decompression buffer too small.\n");
|
||||
if (dstlen >= maxlen / 2) {
|
||||
talloc_free(dest);
|
||||
dest = NULL;
|
||||
goto error;
|
||||
}
|
||||
dstlen *= 2;
|
||||
}
|
||||
size = dstlen - out_avail;
|
||||
@@ -311,6 +312,8 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
|
||||
error:
|
||||
if (src != dest && src != orig_src)
|
||||
talloc_free(src);
|
||||
if (!size)
|
||||
dest = NULL;
|
||||
return (bstr){dest, size};
|
||||
}
|
||||
|
||||
@@ -433,7 +436,7 @@ static void parse_trackencodings(struct demuxer *demuxer,
|
||||
if (e.order >= ce[i].order)
|
||||
break;
|
||||
}
|
||||
ce = talloc_realloc_size(track, ce, (n_enc + 1) * sizeof(*ce));
|
||||
ce = talloc_realloc(track, ce, mkv_content_encoding_t, n_enc + 1);
|
||||
memmove(ce + i + 1, ce + i, (n_enc - i) * sizeof(*ce));
|
||||
memcpy(ce + i, &e, sizeof(e));
|
||||
}
|
||||
@@ -525,8 +528,8 @@ static void parse_trackentry(struct demuxer *demuxer,
|
||||
struct ebml_track_entry *entry)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
struct mkv_track *track = talloc_zero_size(NULL, sizeof(*track));
|
||||
track->last_index_entry = -1;
|
||||
struct mkv_track *track = talloc_zero(NULL, struct mkv_track);
|
||||
track->last_index_entry = (size_t)-1;
|
||||
track->parser_tmp = talloc_new(track);
|
||||
|
||||
track->tnum = entry->track_number;
|
||||
@@ -584,7 +587,7 @@ static void parse_trackentry(struct demuxer *demuxer,
|
||||
track->codec_id = "";
|
||||
}
|
||||
|
||||
if (entry->n_codec_private) {
|
||||
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);
|
||||
@@ -640,8 +643,8 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
|
||||
if (ebml_read_element(s, &parse_ctx, &tracks, &ebml_tracks_desc) < 0)
|
||||
return -1;
|
||||
|
||||
mkv_d->tracks = talloc_size(mkv_d,
|
||||
tracks.n_track_entry * sizeof(*mkv_d->tracks));
|
||||
mkv_d->tracks = talloc_zero_array(mkv_d, struct mkv_track*,
|
||||
tracks.n_track_entry);
|
||||
for (int i = 0; i < tracks.n_track_entry; i++) {
|
||||
MP_VERBOSE(demuxer, "| + a track...\n");
|
||||
parse_trackentry(demuxer, &tracks.track_entry[i]);
|
||||
@@ -655,8 +658,8 @@ static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos,
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
|
||||
mkv_d->indexes = grow_array(mkv_d->indexes, mkv_d->num_indexes,
|
||||
sizeof(mkv_index_t));
|
||||
MP_TARRAY_GROW(mkv_d, mkv_d->indexes, mkv_d->num_indexes);
|
||||
|
||||
mkv_d->indexes[mkv_d->num_indexes].tnum = track_id;
|
||||
mkv_d->indexes[mkv_d->num_indexes].timecode = timecode;
|
||||
mkv_d->indexes[mkv_d->num_indexes].filepos = filepos;
|
||||
@@ -670,7 +673,7 @@ static void add_block_position(demuxer_t *demuxer, struct mkv_track *track,
|
||||
|
||||
if (mkv_d->index_complete || !track)
|
||||
return;
|
||||
if (track->last_index_entry >= 0) {
|
||||
if (track->last_index_entry != (size_t)-1) {
|
||||
mkv_index_t *index = &mkv_d->indexes[track->last_index_entry];
|
||||
// filepos is always the cluster position, which can contain multiple
|
||||
// blocks with different timecodes - one is enough.
|
||||
@@ -1241,6 +1244,11 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
|
||||
}
|
||||
}
|
||||
|
||||
if (extradata_size > 0x1000000) {
|
||||
MP_WARN(demuxer, "Invalid CodecPrivate\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sh = new_sh_stream(demuxer, STREAM_VIDEO);
|
||||
if (!sh)
|
||||
return 1;
|
||||
@@ -1465,6 +1473,8 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
||||
if (track->private_size == 0 || track->ms_compat && !sh_a->wf->cbSize)
|
||||
goto error;
|
||||
if (!track->ms_compat) {
|
||||
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);
|
||||
@@ -1499,10 +1509,18 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
||||
src += RAPROPERTIES5_SIZE;
|
||||
}
|
||||
|
||||
if (track->audiopk_size == 0 || track->sub_packet_size == 0 ||
|
||||
track->sub_packet_h == 0 || track->coded_framesize == 0)
|
||||
goto error;
|
||||
if (track->coded_framesize > 0x40000000)
|
||||
goto error;
|
||||
|
||||
src += 3;
|
||||
if (version == 5)
|
||||
src++;
|
||||
codecdata_length = AV_RB32(src);
|
||||
if (codecdata_length < 0 || codecdata_length > 0x1000000)
|
||||
goto error;
|
||||
src += 4;
|
||||
sh_a->wf->cbSize = codecdata_length;
|
||||
sh_a->wf = talloc_realloc_size(sh_a, sh_a->wf,
|
||||
@@ -1527,9 +1545,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
||||
sh_a->wf->nBlockAlign = track->coded_framesize;
|
||||
audiobuf:
|
||||
track->audio_buf =
|
||||
talloc_size(demuxer, track->sub_packet_h * track->audiopk_size);
|
||||
talloc_array_size(track, track->sub_packet_h, track->audiopk_size);
|
||||
track->audio_timestamp =
|
||||
talloc_size(demuxer, track->sub_packet_h * sizeof(double));
|
||||
talloc_array(track, double, track->sub_packet_h);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1631,6 +1649,9 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
|
||||
}
|
||||
}
|
||||
|
||||
if (track->private_size > 0x10000000)
|
||||
return 1;
|
||||
|
||||
bstr in = (bstr){track->private_data, track->private_size};
|
||||
struct sh_stream *sh = new_sh_stream(demuxer, STREAM_SUB);
|
||||
if (!sh)
|
||||
@@ -1989,46 +2010,63 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
||||
bstr data, bool keyframe)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
int sps = track->sub_packet_size;
|
||||
int sph = track->sub_packet_h;
|
||||
int cfs = track->coded_framesize;
|
||||
int w = track->audiopk_size;
|
||||
int spc = track->sub_packet_cnt;
|
||||
uint16_t sps = track->sub_packet_size;
|
||||
uint16_t sph = track->sub_packet_h;
|
||||
uint32_t cfs = track->coded_framesize; // restricted to [1,0x40000000]
|
||||
uint16_t w = track->audiopk_size;
|
||||
uint16_t spc = track->sub_packet_cnt;
|
||||
uint8_t *buffer = data.start;
|
||||
uint32_t size = data.len;
|
||||
demux_packet_t *dp;
|
||||
|
||||
// track->audio_buf allocation size
|
||||
size_t audiobuf_size = sph * w;
|
||||
|
||||
if ((track->a_formattag == MP_FOURCC('2', '8', '_', '8'))
|
||||
|| (track->a_formattag == MP_FOURCC('c', 'o', 'o', 'k'))
|
||||
|| (track->a_formattag == MP_FOURCC('a', 't', 'r', 'c'))
|
||||
|| (track->a_formattag == MP_FOURCC('s', 'i', 'p', 'r'))) {
|
||||
// if(!block_bref)
|
||||
// spc = track->sub_packet_cnt = 0;
|
||||
|| (track->a_formattag == MP_FOURCC('s', 'i', 'p', 'r')))
|
||||
{
|
||||
switch (track->a_formattag) {
|
||||
case MP_FOURCC('2', '8', '_', '8'):
|
||||
for (int x = 0; x < sph / 2; x++)
|
||||
memcpy(track->audio_buf + x * 2 * w + spc * cfs,
|
||||
buffer + cfs * x, cfs);
|
||||
for (int x = 0; x < sph / 2; x++) {
|
||||
uint64_t dst_offset = x * 2 * w + spc * (uint64_t)cfs;
|
||||
if (dst_offset + cfs > audiobuf_size)
|
||||
goto error;
|
||||
uint64_t src_offset = x * (uint64_t)cfs;
|
||||
if (src_offset + cfs > size)
|
||||
goto error;
|
||||
memcpy(track->audio_buf + dst_offset, buffer + src_offset, cfs);
|
||||
}
|
||||
break;
|
||||
case MP_FOURCC('c', 'o', 'o', 'k'):
|
||||
case MP_FOURCC('a', 't', 'r', 'c'):
|
||||
for (int x = 0; x < w / sps; x++)
|
||||
memcpy(track->audio_buf +
|
||||
sps * (sph * x + ((sph + 1) / 2) * (spc & 1) +
|
||||
(spc >> 1)), buffer + sps * x, sps);
|
||||
for (int x = 0; x < w / sps; x++) {
|
||||
uint32_t dst_offset = sps * (sph * x + ((sph + 1) / 2) * (spc & 1)
|
||||
+ (spc >> 1));
|
||||
if (dst_offset + sps > audiobuf_size)
|
||||
goto error;
|
||||
uint32_t src_offset = sps * x;
|
||||
if (src_offset + sps > size)
|
||||
goto error;
|
||||
memcpy(track->audio_buf + dst_offset, buffer + src_offset, sps);
|
||||
}
|
||||
break;
|
||||
case MP_FOURCC('s', 'i', 'p', 'r'):
|
||||
if (spc * w + w > audiobuf_size || w > size)
|
||||
goto error;
|
||||
memcpy(track->audio_buf + spc * w, buffer, w);
|
||||
if (spc == sph - 1) {
|
||||
int n;
|
||||
int bs = sph * w * 2 / 96; // nibbles per subpacket
|
||||
// Perform reordering
|
||||
for (n = 0; n < 38; n++) {
|
||||
int j;
|
||||
int i = bs * sipr_swaps[n][0];
|
||||
int o = bs * sipr_swaps[n][1];
|
||||
// swap nibbles of block 'i' with 'o' TODO: optimize
|
||||
for (j = 0; j < bs; j++) {
|
||||
int i = bs * sipr_swaps[n][0]; // 77 max
|
||||
int o = bs * sipr_swaps[n][1]; // 95 max
|
||||
// swap nibbles of block 'i' with 'o'
|
||||
for (int j = 0; j < bs; j++) {
|
||||
if (i / 2 >= audiobuf_size || o / 2 >= audiobuf_size)
|
||||
goto error;
|
||||
int x = (i & 1) ?
|
||||
(track->audio_buf[i >> 1] >> 4) :
|
||||
(track->audio_buf[i >> 1] & 0x0F);
|
||||
@@ -2060,8 +2098,11 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
||||
if (track->sub_packet_cnt == 0)
|
||||
track->audio_filepos = mkv_d->last_filepos;
|
||||
if (++(track->sub_packet_cnt) == sph) {
|
||||
int apk_usize = track->stream->audio->wf->nBlockAlign;
|
||||
track->sub_packet_cnt = 0;
|
||||
// apk_usize has same range as coded_framesize in worst case
|
||||
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,
|
||||
@@ -2087,6 +2128,9 @@ static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
||||
dp->keyframe = keyframe;
|
||||
demuxer_add_packet(demuxer, track->stream, dp);
|
||||
}
|
||||
return;
|
||||
error:
|
||||
MP_ERR(demuxer, "RealAudio decrypting error.\n");
|
||||
}
|
||||
|
||||
static void mkv_seek_reset(demuxer_t *demuxer)
|
||||
@@ -2154,6 +2198,9 @@ static int libav_parse_wavpack(mkv_track_t *track, uint8_t *src,
|
||||
if (blocksize > srclen)
|
||||
goto fail;
|
||||
|
||||
if (dstlen > 0x10000000 || blocksize > 0x10000000)
|
||||
goto fail;
|
||||
|
||||
tmp = talloc_realloc(track->parser_tmp, dst, uint8_t,
|
||||
dstlen + blocksize + 32);
|
||||
if (!tmp)
|
||||
@@ -2223,7 +2270,7 @@ static bool mkv_parse_packet(mkv_track_t *track, bstr *raw, bstr *out)
|
||||
int len = av_parser_parse2(track->av_parser, track->av_parser_codec,
|
||||
&data, &size, raw->start, raw->len,
|
||||
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||||
if (len < 0)
|
||||
if (len < 0 || len > 0x10000000)
|
||||
return false;
|
||||
*raw = bstr_cut(*raw, len);
|
||||
if (size) {
|
||||
@@ -2640,7 +2687,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
||||
min_diff = -min_diff;
|
||||
min_diff = FFMAX(min_diff, 1);
|
||||
|
||||
for (int i = 0; i < mkv_d->num_indexes; i++) {
|
||||
for (size_t i = 0; i < mkv_d->num_indexes; i++) {
|
||||
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
|
||||
int64_t diff =
|
||||
target_timecode -
|
||||
@@ -2661,7 +2708,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
||||
uint64_t seek_pos = index->filepos;
|
||||
if (flags & SEEK_SUBPREROLL) {
|
||||
uint64_t prev_target = 0;
|
||||
for (int i = 0; i < mkv_d->num_indexes; i++) {
|
||||
for (size_t i = 0; i < mkv_d->num_indexes; i++) {
|
||||
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
|
||||
uint64_t index_pos = mkv_d->indexes[i].filepos;
|
||||
if (index_pos > prev_target && index_pos < seek_pos)
|
||||
@@ -2745,7 +2792,6 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
||||
stream_t *s = demuxer->stream;
|
||||
uint64_t target_filepos;
|
||||
mkv_index_t *index = NULL;
|
||||
int i;
|
||||
|
||||
read_deferred_cues(demuxer);
|
||||
|
||||
@@ -2759,7 +2805,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
||||
stream_control(s, STREAM_CTRL_GET_SIZE, &size);
|
||||
|
||||
target_filepos = (uint64_t) (size * rel_seek_secs);
|
||||
for (i = 0; i < mkv_d->num_indexes; i++)
|
||||
for (size_t i = 0; i < mkv_d->num_indexes; i++)
|
||||
if (mkv_d->indexes[i].tnum == v_tnum)
|
||||
if ((index == NULL)
|
||||
|| ((mkv_d->indexes[i].filepos >= target_filepos)
|
||||
@@ -2807,7 +2853,6 @@ static void mkv_free(struct demuxer *demuxer)
|
||||
mkv_seek_reset(demuxer);
|
||||
for (int i = 0; i < mkv_d->num_tracks; i++)
|
||||
demux_mkv_free_trackentry(mkv_d->tracks[i]);
|
||||
free(mkv_d->indexes);
|
||||
}
|
||||
|
||||
const demuxer_desc_t demuxer_desc_matroska = {
|
||||
|
||||
+9
-1
@@ -364,7 +364,7 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
||||
char *s = target;
|
||||
uint8_t *end = data + size;
|
||||
uint8_t *p = data;
|
||||
int num_elems[MAX_EBML_SUBELEMENTS] = {};
|
||||
int num_elems[MAX_EBML_SUBELEMENTS] = {0};
|
||||
while (p < end) {
|
||||
uint8_t *startp = p;
|
||||
int len;
|
||||
@@ -390,6 +390,10 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
||||
if (type->fields[i].id == id) {
|
||||
field_idx = i;
|
||||
num_elems[i]++;
|
||||
if (num_elems[i] >= 0x70000000) {
|
||||
MP_ERR(ctx, "Too many EBML subelements.\n");
|
||||
goto other_error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -566,6 +570,10 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
||||
|
||||
case EBML_TYPE_STR:
|
||||
case EBML_TYPE_BINARY:;
|
||||
if (length > 0x80000000) {
|
||||
MP_ERR(ctx, "Not reading overly long EBML element.\n");
|
||||
break;
|
||||
}
|
||||
struct bstr *strptr;
|
||||
GETPTR(strptr, struct bstr);
|
||||
strptr->start = data;
|
||||
|
||||
+2
-1
@@ -111,7 +111,8 @@ const struct mp_cmd_def mp_cmds[] = {
|
||||
{ MP_CMD_LOADFILE, "loadfile", {
|
||||
ARG_STRING,
|
||||
OARG_CHOICE(0, ({"replace", 0}, {"0", 0},
|
||||
{"append", 1}, {"1", 1})),
|
||||
{"append", 1}, {"1", 1},
|
||||
{"append-play", 2})),
|
||||
OPT_KEYVALUELIST(ARG(str_list), MP_CMD_OPT_ARG),
|
||||
}},
|
||||
{ MP_CMD_LOADLIST, "loadlist", {
|
||||
|
||||
+6
-8
@@ -557,6 +557,7 @@ static void release_down_cmd(struct input_ctx *ictx, bool drop_current)
|
||||
if (!drop_current && ictx->current_down_cmd &&
|
||||
ictx->current_down_cmd->key_up_follows)
|
||||
{
|
||||
memset(ictx->key_history, 0, sizeof(ictx->key_history));
|
||||
ictx->current_down_cmd->key_up_follows = false;
|
||||
queue_add_tail(&ictx->cmd_queue, ictx->current_down_cmd);
|
||||
ictx->got_new_events = true;
|
||||
@@ -596,15 +597,10 @@ static struct mp_cmd *resolve_key(struct input_ctx *ictx, int code)
|
||||
{
|
||||
update_mouse_section(ictx);
|
||||
struct mp_cmd *cmd = get_cmd_from_keys(ictx, NULL, code);
|
||||
if (cmd && cmd->id != MP_CMD_IGNORE) {
|
||||
memset(ictx->key_history, 0, sizeof(ictx->key_history));
|
||||
if (!should_drop_cmd(ictx, cmd))
|
||||
return cmd;
|
||||
talloc_free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
talloc_free(cmd);
|
||||
key_buf_add(ictx->key_history, code);
|
||||
if (cmd && cmd->id != MP_CMD_IGNORE && !should_drop_cmd(ictx, cmd))
|
||||
return cmd;
|
||||
talloc_free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -673,6 +669,8 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale)
|
||||
return;
|
||||
}
|
||||
|
||||
memset(ictx->key_history, 0, sizeof(ictx->key_history));
|
||||
|
||||
cmd->scale = scale;
|
||||
|
||||
if (cmd->key_up_follows)
|
||||
|
||||
+1
-1
@@ -920,7 +920,6 @@ static const char *const replaced_opts =
|
||||
"|font#--osd-font"
|
||||
"|forcedsubsonly#--sub-forced-only"
|
||||
"|format#--audio-format"
|
||||
"|fstype#--x11-fstype"
|
||||
"|hardframedrop#--framedrop=hard"
|
||||
"|identify#removed; use TOOLS/mpv_identify.sh"
|
||||
"|lavdopts#--vd-lavc-..."
|
||||
@@ -969,6 +968,7 @@ static const char *const replaced_opts =
|
||||
"|lirc#--input-lirc"
|
||||
"|right-alt-gr#--input-right-alt-gr"
|
||||
"|autosub#--sub-auto"
|
||||
"|autosub-match#--sub-auto"
|
||||
"|native-fs#--fs-missioncontrol"
|
||||
"|status-msg#--term-status-msg"
|
||||
"|idx#--index"
|
||||
|
||||
@@ -540,6 +540,7 @@ const struct MPOpts mp_default_opts = {
|
||||
.mixer_init_volume = -1,
|
||||
.mixer_init_mute = -1,
|
||||
.volstep = 3,
|
||||
.gapless_audio = -1,
|
||||
.vo = {
|
||||
.video_driver_list = NULL,
|
||||
.monitor_pixel_aspect = 1.0,
|
||||
|
||||
@@ -330,6 +330,9 @@ static void get_thread(void *ptr)
|
||||
|
||||
void mpv_terminate_destroy(mpv_handle *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
mpv_command(ctx, (const char*[]){"quit", NULL});
|
||||
|
||||
if (!ctx->owner) {
|
||||
|
||||
+4
-3
@@ -2995,6 +2995,7 @@ static bool reinit_filters(MPContext *mpctx, enum stream_type mediatype)
|
||||
case STREAM_VIDEO:
|
||||
return reinit_video_filters(mpctx) >= 0;
|
||||
case STREAM_AUDIO:
|
||||
clear_audio_output_buffers(mpctx);
|
||||
return reinit_audio_filters(mpctx) >= 0;
|
||||
}
|
||||
return false;
|
||||
@@ -3549,7 +3550,7 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
|
||||
case MP_CMD_LOADFILE: {
|
||||
char *filename = cmd->args[0].v.s;
|
||||
bool append = cmd->args[1].v.i;
|
||||
int append = cmd->args[1].v.i;
|
||||
|
||||
if (!append)
|
||||
playlist_clear(mpctx->playlist);
|
||||
@@ -3564,7 +3565,7 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
}
|
||||
playlist_add(mpctx->playlist, entry);
|
||||
|
||||
if (!append)
|
||||
if (!append || (append == 2 && !mpctx->playlist->current))
|
||||
mp_set_playlist_entry(mpctx, mpctx->playlist->first);
|
||||
break;
|
||||
}
|
||||
@@ -3576,7 +3577,7 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
if (pl) {
|
||||
if (!append)
|
||||
playlist_clear(mpctx->playlist);
|
||||
playlist_transfer_entries(mpctx->playlist, pl);
|
||||
playlist_append_entries(mpctx->playlist, pl);
|
||||
talloc_free(pl);
|
||||
|
||||
if (!append && mpctx->playlist->first) {
|
||||
|
||||
@@ -598,6 +598,7 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type
|
||||
uninit |= mpctx->opts->fixed_vo && track ? 0 : INITIALIZED_VO;
|
||||
uninit_player(mpctx, uninit);
|
||||
} else if (type == STREAM_AUDIO) {
|
||||
clear_audio_output_buffers(mpctx);
|
||||
uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC);
|
||||
} else if (type == STREAM_SUB) {
|
||||
uninit_player(mpctx, INITIALIZED_SUB);
|
||||
|
||||
+1
-1
@@ -189,7 +189,7 @@ static void set_dvdsub_fake_extradata(struct dec_sub *dec_sub, struct stream *st
|
||||
color = (c[2] << 16) | (c[1] << 8) | c[0];
|
||||
|
||||
if (i != 0)
|
||||
talloc_asprintf_append(s, ", ");
|
||||
s = talloc_asprintf_append(s, ", ");
|
||||
s = talloc_asprintf_append(s, "%06x", color);
|
||||
}
|
||||
s = talloc_asprintf_append(s, "\n");
|
||||
|
||||
@@ -361,6 +361,9 @@ static int resize_cache(struct priv *s, int64_t size)
|
||||
if (s->seek_limit > s->buffer_size - FILL_LIMIT)
|
||||
s->seek_limit = s->buffer_size - FILL_LIMIT;
|
||||
|
||||
for (size_t n = 0; n < s->buffer_size / BYTE_META_CHUNK_SIZE + 2; n++)
|
||||
s->bm[n] = (struct byte_meta){.stream_pts = MP_NOPTS_VALUE};
|
||||
|
||||
return STREAM_OK;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -66,7 +66,7 @@ static int fill_buffer(stream_t *s, char *buffer, int max_len)
|
||||
if (s->pos >= p->size - BLOCK_SIZE) {
|
||||
int64_t new_size = -1;
|
||||
stream_control(s, STREAM_CTRL_GET_SIZE, &new_size);
|
||||
if (new_size != p->size)
|
||||
if (p->size >= 0 && new_size != p->size)
|
||||
set_bit(p, BLOCK_ALIGN(p->size), 0);
|
||||
p->size = MPMIN(p->max_size, new_size);
|
||||
}
|
||||
@@ -94,7 +94,8 @@ static int fill_buffer(stream_t *s, char *buffer, int max_len)
|
||||
// align/limit to blocks
|
||||
max_len = MPMIN(max_len, BLOCK_SIZE - (s->pos % BLOCK_SIZE));
|
||||
// Limit to max. known file size
|
||||
max_len = MPMIN(max_len, p->size - s->pos);
|
||||
if (p->size >= 0)
|
||||
max_len = MPMIN(max_len, p->size - s->pos);
|
||||
return fread(buffer, 1, max_len, p->cache_file);
|
||||
}
|
||||
|
||||
|
||||
@@ -388,6 +388,8 @@ static int stream_reconnect(stream_t *s)
|
||||
return 0;
|
||||
if (!s->seekable)
|
||||
return 0;
|
||||
if (stream_check_interrupt(s))
|
||||
return 0;
|
||||
int64_t pos = s->pos;
|
||||
int sleep_ms = 5;
|
||||
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
|
||||
|
||||
@@ -443,7 +443,6 @@ static int fill_buffer(stream_t *s, char *buf, int max_len)
|
||||
if (priv->title > 0 && tit != priv->title) {
|
||||
priv->next_event |= 1 << MP_NAV_EVENT_EOF;;
|
||||
MP_WARN(s, "Requested title not found\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (priv->nav_enabled)
|
||||
@@ -546,7 +545,11 @@ static int control(stream_t *stream, int cmd, void *arg)
|
||||
return STREAM_OK;
|
||||
}
|
||||
case STREAM_CTRL_SEEK_TO_TIME: {
|
||||
uint64_t tm = (uint64_t) (*((double *)arg) * 90000);
|
||||
int64_t tm = (int64_t) (*((double *)arg) * 90000);
|
||||
if (tm < 0)
|
||||
tm = 0;
|
||||
if (priv->duration && tm >= (priv->duration * 90))
|
||||
tm = priv->duration * 90 - 1;
|
||||
MP_VERBOSE(stream, "seek to PTS %"PRId64"\n", tm);
|
||||
if (dvdnav_time_search(dvdnav, tm) != DVDNAV_STATUS_OK)
|
||||
break;
|
||||
@@ -634,6 +637,8 @@ static void stream_dvdnav_close(stream_t *s)
|
||||
priv->dvdnav = NULL;
|
||||
if (priv->dvd_speed)
|
||||
dvd_set_speed(s, priv->filename, -1);
|
||||
if (priv->filename)
|
||||
free(priv->filename);
|
||||
}
|
||||
|
||||
static struct priv *new_dvdnav_stream(stream_t *stream, char *filename)
|
||||
@@ -692,7 +697,7 @@ static int open_s(stream_t *stream)
|
||||
int best_title = -1;
|
||||
int32_t num_titles;
|
||||
if (dvdnav_get_number_of_titles(dvdnav, &num_titles) == DVDNAV_STATUS_OK) {
|
||||
for (int n = 1; n < num_titles; n++) {
|
||||
for (int n = 1; n <= num_titles; n++) {
|
||||
uint64_t *parts = NULL, duration = 0;
|
||||
dvdnav_describe_title_chapters(dvdnav, n, &parts, &duration);
|
||||
if (parts) {
|
||||
|
||||
@@ -434,6 +434,7 @@ static void destroy_vs(struct vf_instance *vf)
|
||||
p->next_image = NULL;
|
||||
p->out_pts = MP_NOPTS_VALUE;
|
||||
p->out_frameno = p->in_frameno = 0;
|
||||
p->failed = false;
|
||||
|
||||
MP_DBG(vf, "uninitialized.\n");
|
||||
}
|
||||
|
||||
@@ -858,8 +858,9 @@ int vo_x11_check_events(struct vo *vo)
|
||||
get_mods(Event.xbutton.state) | MP_KEY_STATE_UP);
|
||||
break;
|
||||
case MapNotify:
|
||||
if (x11->window_hidden)
|
||||
vo_x11_clearwindow(vo, x11->window);
|
||||
x11->window_hidden = false;
|
||||
vo_x11_clearwindow(vo, x11->window);
|
||||
vo_x11_update_geometry(vo);
|
||||
break;
|
||||
case DestroyNotify:
|
||||
|
||||
@@ -138,12 +138,10 @@ main_dependencies = [
|
||||
'test = __sync_add_and_fetch(&test, 1)'),
|
||||
'deps_neg': [ 'stdatomic', 'atomic-builtins' ],
|
||||
}, {
|
||||
'name': 'thread-synchronization-builtins',
|
||||
'name': 'atomics',
|
||||
'desc': 'compiler support for usable thread synchronization built-ins',
|
||||
'func': check_true,
|
||||
'deps_any': ['stdatomic', 'atomic-builtins', 'sync-builtins'],
|
||||
'req': True,
|
||||
'fmsg': 'your compiler must support either __atomic or __sync built-ins',
|
||||
}, {
|
||||
'name': 'librt',
|
||||
'desc': 'linking with -lrt',
|
||||
@@ -419,11 +417,13 @@ audio_output_features = [
|
||||
{
|
||||
'name': '--sdl2',
|
||||
'desc': 'SDL2',
|
||||
'deps': ['atomics'],
|
||||
'func': check_pkg_config('sdl2'),
|
||||
'default': 'disable'
|
||||
}, {
|
||||
'name': '--sdl1',
|
||||
'desc': 'SDL (1.x)',
|
||||
'deps': ['atomics'],
|
||||
'deps_neg': [ 'sdl2' ],
|
||||
'func': check_pkg_config('sdl'),
|
||||
'default': 'disable'
|
||||
@@ -478,12 +478,13 @@ audio_output_features = [
|
||||
}, {
|
||||
'name': '--portaudio',
|
||||
'desc': 'PortAudio audio output',
|
||||
'deps': [ 'pthreads' ],
|
||||
'deps': [ 'atomics' ],
|
||||
'func': check_pkg_config('portaudio-2.0', '>= 19'),
|
||||
'default': 'disable',
|
||||
}, {
|
||||
'name': '--jack',
|
||||
'desc': 'JACK audio output',
|
||||
'deps': ['atomics'],
|
||||
'func': check_pkg_config('jack'),
|
||||
}, {
|
||||
'name': '--openal',
|
||||
@@ -497,6 +498,7 @@ audio_output_features = [
|
||||
}, {
|
||||
'name': '--coreaudio',
|
||||
'desc': 'CoreAudio audio output',
|
||||
'deps': ['atomics'],
|
||||
'func': check_cc(
|
||||
fragment=load_fragment('coreaudio.c'),
|
||||
framework_name=['CoreFoundation', 'CoreAudio', 'AudioUnit', 'AudioToolbox'])
|
||||
@@ -507,6 +509,7 @@ audio_output_features = [
|
||||
}, {
|
||||
'name': '--wasapi',
|
||||
'desc': 'WASAPI audio output',
|
||||
'deps': ['atomics'],
|
||||
'func': check_cc(fragment=load_fragment('wasapi.c'), lib='ole32'),
|
||||
}
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user