2004-04-11 14:26:04 +00:00
|
|
|
/*
|
2008-05-14 18:01:51 +00:00
|
|
|
* Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2004-04-11 14:26:04 +00:00
|
|
|
|
|
|
|
// #include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
// #include <unistd.h>
|
2006-08-31 21:26:02 +00:00
|
|
|
#include <limits.h>
|
2009-03-19 03:25:12 +00:00
|
|
|
#include <stdbool.h>
|
2010-11-05 10:50:11 +00:00
|
|
|
#include <string.h>
|
core: fix DVD subtitle selection
Add all subtitle tracks as reported by libdvdread at playback start.
Display language for subtitle and audio tracks. This commit restores
these features to the state when demux_mpg was default for DVD playback,
and makes them work with demux_lavf and the recent changes to subtitle
selection in the frontend.
demux_mpg, which was the default demuxer for DVD playback, reordered
the subtitle streams according to the "logical" subtitle track number,
which conforms to the track layout reported by libdvdread, and is what
stream_dvd expects for the STREAM_CTRL_GET_LANG call. demux_lavf, on
the other hand, adds the streams in the order it encounters them in
the MPEG stream. It seems this order is essentially random, and can't
be mapped easily to what stream_dvd expects.
Solve this by making demux_lavf hand out the MPEG stream IDs (using the
demuxer_id field). The MPEG IDs are mapped by mplayer.c by special
casing DVD playback (map_id_from/to_demuxer() functions). This mapping
is essentially the same what demux_mpg did. Making demux_lavf reorder
the streams is out of the question, because its stream handling is
already messy enough.
(Note that demux_lavf doesn't export stream IDs for other formats,
because most time libavformat demuxers do not set AVStream.id, and we
don't know which demuxers do. But we know that MPEG is safe.)
Another major complication is that subtitle tracks are added lazily, as
soon as the demuxer encounters the first subtitle packet for a given
subtitle stream. Add the streams in advance. If a yet non-existent
stream is selected, demux_lavf must be made to auto-select that subtitle
stream as soon as it is added. Otherwise, the first subtitle packet
would be lost. This is done by DEMUXER_CTRL_PRESELECT_SUBTITLE.
demux_mpg didn't need this: the frontend code could just set ds->id to
the desired stream number. But demux_lavf's stream IDs don't map
directly to the stream number as used by libdvdread, which is why this
hack is needed.
2012-08-30 14:43:31 +00:00
|
|
|
#include <assert.h>
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2012-01-28 11:41:36 +00:00
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
#include <libavformat/avio.h>
|
|
|
|
#include <libavutil/avutil.h>
|
|
|
|
#include <libavutil/avstring.h>
|
|
|
|
#include <libavutil/mathematics.h>
|
|
|
|
#include <libavutil/opt.h>
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "compat/libav.h"
|
2012-01-28 11:41:36 +00:00
|
|
|
|
2004-04-11 14:26:04 +00:00
|
|
|
#include "config.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
|
|
|
#include "common/av_opts.h"
|
|
|
|
#include "common/av_common.h"
|
|
|
|
#include "bstr/bstr.h"
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2007-03-15 18:36:36 +00:00
|
|
|
#include "stream/stream.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "demux.h"
|
2004-04-11 14:26:04 +00:00
|
|
|
#include "stheader.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_option.h"
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2010-03-22 19:38:42 +00:00
|
|
|
#define INITIAL_PROBE_SIZE STREAM_BUFFER_SIZE
|
2013-05-25 13:00:03 +00:00
|
|
|
#define PROBE_BUF_SIZE FFMIN(STREAM_MAX_BUFFER_SIZE, 2 * 1024 * 1024)
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-03-01 10:27:59 +00:00
|
|
|
#define OPT_BASE_STRUCT struct MPOpts
|
|
|
|
|
2013-08-04 21:25:54 +00:00
|
|
|
// Should correspond to IO_BUFFER_SIZE in libavformat/aviobuf.c (not public)
|
|
|
|
// libavformat (almost) always reads data in blocks of this size.
|
|
|
|
#define BIO_BUFFER_SIZE 32768
|
|
|
|
|
2007-12-02 21:26:23 +00:00
|
|
|
const m_option_t lavfdopts_conf[] = {
|
2010-04-23 19:08:18 +00:00
|
|
|
OPT_INTRANGE("probesize", lavfdopts.probesize, 0, 32, INT_MAX),
|
|
|
|
OPT_STRING("format", lavfdopts.format, 0),
|
2013-05-27 21:26:22 +00:00
|
|
|
OPT_FLOATRANGE("analyzeduration", lavfdopts.analyzeduration, 0, 0, 3600),
|
2013-08-04 21:25:54 +00:00
|
|
|
OPT_INTRANGE("buffersize", lavfdopts.buffersize, 0, 1, 10 * 1024 * 1024,
|
|
|
|
OPTDEF_INT(BIO_BUFFER_SIZE)),
|
2013-05-27 20:48:04 +00:00
|
|
|
OPT_FLAG("allow-mimetype", lavfdopts.allow_mimetype, 0),
|
2012-12-08 19:14:13 +00:00
|
|
|
OPT_INTRANGE("probescore", lavfdopts.probescore, 0, 0, 100),
|
2010-04-23 19:08:18 +00:00
|
|
|
OPT_STRING("cryptokey", lavfdopts.cryptokey, 0),
|
2013-07-14 21:44:50 +00:00
|
|
|
OPT_CHOICE("genpts-mode", lavfdopts.genptsmode, 0,
|
2013-11-25 22:13:46 +00:00
|
|
|
({"lavf", 1}, {"no", 0})),
|
2010-04-23 19:08:18 +00:00
|
|
|
OPT_STRING("o", lavfdopts.avopt, 0),
|
|
|
|
{NULL, NULL, 0, 0, 0, 0, NULL}
|
2006-08-30 22:25:40 +00:00
|
|
|
};
|
|
|
|
|
2013-07-14 21:44:50 +00:00
|
|
|
#define MAX_PKT_QUEUE 50
|
|
|
|
|
2010-04-23 20:50:34 +00:00
|
|
|
typedef struct lavf_priv {
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
char *filename;
|
2013-05-27 21:26:22 +00:00
|
|
|
const struct format_hack *format_hack;
|
2004-04-11 14:26:04 +00:00
|
|
|
AVInputFormat *avif;
|
|
|
|
AVFormatContext *avfc;
|
2011-12-22 00:06:52 +00:00
|
|
|
AVIOContext *pb;
|
2004-04-11 17:20:52 +00:00
|
|
|
int64_t last_pts;
|
2013-04-14 18:53:03 +00:00
|
|
|
struct sh_stream **streams; // NULL for unknown streams
|
|
|
|
int num_streams;
|
2007-10-27 19:12:59 +00:00
|
|
|
int cur_program;
|
2012-12-10 00:28:20 +00:00
|
|
|
char *mime_type;
|
2011-07-03 12:42:04 +00:00
|
|
|
} lavf_priv_t;
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-05-27 21:26:22 +00:00
|
|
|
struct format_hack {
|
|
|
|
const char *ff_name;
|
|
|
|
const char *mime_type;
|
|
|
|
int probescore;
|
|
|
|
float analyzeduration;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct format_hack format_hacks[] = {
|
|
|
|
{"aac", "audio/aacp", 25, 0.5},
|
2013-06-24 22:55:20 +00:00
|
|
|
{"aac", "audio/aac", 25, 0.5},
|
2013-05-27 21:27:59 +00:00
|
|
|
{"mp3", "audio/mpeg", 25, 0.5},
|
2012-12-10 00:28:20 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
2013-08-07 21:15:11 +00:00
|
|
|
static const char *format_blacklist[] = {
|
|
|
|
"tty", // Useless non-sense, sometimes breaks MLP2 subreader.c fallback
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2013-05-27 21:26:22 +00:00
|
|
|
static const struct format_hack *find_format_from_mime_type(char *mime_type)
|
2012-12-10 00:28:20 +00:00
|
|
|
{
|
2013-05-27 21:26:22 +00:00
|
|
|
for (int n = 0; format_hacks[n].ff_name; n++) {
|
|
|
|
if (strcasecmp(format_hacks[n].mime_type, mime_type) == 0)
|
|
|
|
return &format_hacks[n];
|
2012-12-10 00:28:20 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
static int mp_read(void *opaque, uint8_t *buf, int size)
|
|
|
|
{
|
2010-04-23 20:50:34 +00:00
|
|
|
struct demuxer *demuxer = opaque;
|
|
|
|
struct stream *stream = demuxer->stream;
|
2004-04-11 14:51:10 +00:00
|
|
|
int ret;
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
ret = stream_read(stream, buf, size);
|
2004-04-11 15:04:54 +00:00
|
|
|
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_DBG(demuxer, "%d=mp_read(%p, %p, %d), pos: %"PRId64", eof:%d\n",
|
2010-06-05 16:14:56 +00:00
|
|
|
ret, stream, buf, size, stream_tell(stream), stream->eof);
|
2004-04-11 14:51:10 +00:00
|
|
|
return ret;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
static int64_t mp_seek(void *opaque, int64_t pos, int whence)
|
|
|
|
{
|
2010-04-23 20:50:34 +00:00
|
|
|
struct demuxer *demuxer = opaque;
|
|
|
|
struct stream *stream = demuxer->stream;
|
2008-10-03 14:54:22 +00:00
|
|
|
int64_t current_pos;
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_DBG(demuxer, "mp_seek(%p, %"PRId64", %d)\n",
|
2011-07-03 12:42:04 +00:00
|
|
|
stream, pos, whence);
|
|
|
|
if (whence == SEEK_CUR)
|
|
|
|
pos += stream_tell(stream);
|
|
|
|
else if (whence == SEEK_END && stream->end_pos > 0)
|
2004-04-11 14:26:04 +00:00
|
|
|
pos += stream->end_pos;
|
2011-07-03 12:42:04 +00:00
|
|
|
else if (whence == SEEK_SET)
|
2007-03-04 16:23:18 +00:00
|
|
|
pos += stream->start_pos;
|
2012-02-26 03:53:13 +00:00
|
|
|
else if (whence == AVSEEK_SIZE && stream->end_pos > 0) {
|
2012-11-18 20:23:17 +00:00
|
|
|
stream_update_size(stream);
|
2007-08-20 09:27:47 +00:00
|
|
|
return stream->end_pos - stream->start_pos;
|
2012-02-26 03:53:13 +00:00
|
|
|
} else
|
2004-04-11 14:26:04 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
if (pos < 0)
|
2007-08-19 21:22:27 +00:00
|
|
|
return -1;
|
2008-08-13 00:01:31 +00:00
|
|
|
current_pos = stream_tell(stream);
|
2011-07-03 12:42:04 +00:00
|
|
|
if (stream_seek(stream, pos) == 0) {
|
2008-08-13 00:01:31 +00:00
|
|
|
stream_seek(stream, current_pos);
|
2004-04-11 14:26:04 +00:00
|
|
|
return -1;
|
2008-08-13 00:01:31 +00:00
|
|
|
}
|
2004-04-11 15:04:54 +00:00
|
|
|
|
2007-03-04 16:23:18 +00:00
|
|
|
return pos - stream->start_pos;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
|
|
|
|
2010-04-23 20:50:34 +00:00
|
|
|
static int64_t mp_read_seek(void *opaque, int stream_idx, int64_t ts, int flags)
|
|
|
|
{
|
|
|
|
struct demuxer *demuxer = opaque;
|
|
|
|
struct stream *stream = demuxer->stream;
|
|
|
|
struct lavf_priv *priv = demuxer->priv;
|
|
|
|
|
|
|
|
AVStream *st = priv->avfc->streams[stream_idx];
|
|
|
|
double pts = (double)ts * st->time_base.num / st->time_base.den;
|
|
|
|
int ret = stream_control(stream, STREAM_CTRL_SEEK_TO_TIME, &pts);
|
|
|
|
if (ret < 0)
|
|
|
|
ret = AVERROR(ENOSYS);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-12-21 19:24:20 +00:00
|
|
|
static void list_formats(struct demuxer *demuxer)
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_INFO(demuxer, "Available lavf input formats:\n");
|
2010-11-06 02:00:10 +00:00
|
|
|
AVInputFormat *fmt = NULL;
|
2011-07-07 21:41:42 +00:00
|
|
|
while ((fmt = av_iformat_next(fmt)))
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_INFO(demuxer, "%15s : %s\n", fmt->name, fmt->long_name);
|
2007-02-06 22:15:20 +00:00
|
|
|
}
|
|
|
|
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
static char *remove_prefix(char *s, const char **prefixes)
|
|
|
|
{
|
|
|
|
for (int n = 0; prefixes[n]; n++) {
|
|
|
|
int len = strlen(prefixes[n]);
|
|
|
|
if (strncmp(s, prefixes[n], len) == 0)
|
|
|
|
return s + len;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *prefixes[] =
|
|
|
|
{"ffmpeg://", "lavf://", "avdevice://", "av://", NULL};
|
|
|
|
|
2013-07-12 19:58:11 +00:00
|
|
|
static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
2010-04-23 19:08:18 +00:00
|
|
|
struct MPOpts *opts = demuxer->opts;
|
|
|
|
struct lavfdopts *lavfdopts = &opts->lavfdopts;
|
2013-05-25 13:00:03 +00:00
|
|
|
struct stream *s = demuxer->stream;
|
2004-04-11 14:26:04 +00:00
|
|
|
lavf_priv_t *priv;
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2012-12-08 19:14:13 +00:00
|
|
|
assert(!demuxer->priv);
|
|
|
|
demuxer->priv = talloc_zero(NULL, lavf_priv_t);
|
2011-07-03 12:42:04 +00:00
|
|
|
priv = demuxer->priv;
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-05-25 13:00:03 +00:00
|
|
|
priv->filename = s->url;
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
if (!priv->filename) {
|
|
|
|
priv->filename = "mp:unknown";
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_WARN(demuxer, "Stream url is not set!\n");
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
priv->filename = remove_prefix(priv->filename, prefixes);
|
|
|
|
|
|
|
|
char *avdevice_format = NULL;
|
2013-05-25 13:00:03 +00:00
|
|
|
if (s->type == STREAMTYPE_AVDEVICE) {
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
// always require filename in the form "format:filename"
|
|
|
|
char *sep = strchr(priv->filename, ':');
|
|
|
|
if (!sep) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_FATAL(demuxer, "Must specify filename in 'format:filename' form\n");
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
}
|
|
|
|
avdevice_format = talloc_strndup(priv, priv->filename,
|
|
|
|
sep - priv->filename);
|
|
|
|
priv->filename = sep + 1;
|
|
|
|
}
|
|
|
|
|
2013-05-27 21:26:22 +00:00
|
|
|
const char *expected_format = NULL;
|
|
|
|
int expected_format_probescore = AVPROBE_SCORE_MAX;
|
|
|
|
char *mime_type = demuxer->stream->mime_type;
|
|
|
|
|
|
|
|
if (lavfdopts->allow_mimetype && mime_type) {
|
|
|
|
priv->format_hack = find_format_from_mime_type(mime_type);
|
|
|
|
if (priv->format_hack) {
|
|
|
|
expected_format = priv->format_hack->ff_name;
|
|
|
|
expected_format_probescore = priv->format_hack->probescore;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *format = lavfdopts->format;
|
2010-04-23 19:57:25 +00:00
|
|
|
if (!format)
|
2013-05-25 13:00:03 +00:00
|
|
|
format = s->lavf_type;
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
if (!format)
|
|
|
|
format = avdevice_format;
|
2010-04-23 19:57:25 +00:00
|
|
|
if (format) {
|
|
|
|
if (strcmp(format, "help") == 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
list_formats(demuxer);
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2007-02-06 22:15:20 +00:00
|
|
|
}
|
2010-04-23 19:57:25 +00:00
|
|
|
priv->avif = av_find_input_format(format);
|
2007-02-06 22:15:20 +00:00
|
|
|
if (!priv->avif) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_FATAL(demuxer, "Unknown lavf format %s\n", format);
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2007-02-06 22:15:20 +00:00
|
|
|
}
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_INFO(demuxer, "Forced lavf %s demuxer\n",
|
2011-07-03 12:42:04 +00:00
|
|
|
priv->avif->long_name);
|
2012-12-08 19:14:13 +00:00
|
|
|
goto success;
|
2007-02-06 22:15:20 +00:00
|
|
|
}
|
2009-06-01 09:39:02 +00:00
|
|
|
|
2012-12-13 11:47:19 +00:00
|
|
|
// AVPROBE_SCORE_MAX/4 + 1 is the "recommended" limit. Below that, the user
|
2012-12-08 19:14:13 +00:00
|
|
|
// is supposed to retry with larger probe sizes until a higher value is
|
|
|
|
// reached.
|
2012-12-13 11:47:19 +00:00
|
|
|
int min_probe = AVPROBE_SCORE_MAX/4 + 1;
|
2012-12-08 19:14:13 +00:00
|
|
|
if (lavfdopts->probescore)
|
|
|
|
min_probe = lavfdopts->probescore;
|
|
|
|
|
2013-05-25 13:00:03 +00:00
|
|
|
AVProbeData avpd = {
|
2013-07-12 19:58:11 +00:00
|
|
|
// Disable file-extension matching with normal checks
|
|
|
|
.filename = check <= DEMUX_CHECK_REQUEST ? priv->filename : NULL,
|
2013-05-25 13:00:03 +00:00
|
|
|
.buf_size = 0,
|
|
|
|
.buf = av_mallocz(PROBE_BUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE),
|
|
|
|
};
|
|
|
|
|
|
|
|
while (avpd.buf_size < PROBE_BUF_SIZE) {
|
|
|
|
int nsize = av_clip(avpd.buf_size * 2, INITIAL_PROBE_SIZE,
|
|
|
|
PROBE_BUF_SIZE);
|
2013-06-21 19:14:38 +00:00
|
|
|
bstr buf = stream_peek(s, nsize);
|
|
|
|
if (buf.len <= avpd.buf_size)
|
2013-05-25 13:00:03 +00:00
|
|
|
break;
|
2013-06-21 19:14:38 +00:00
|
|
|
memcpy(avpd.buf, buf.start, buf.len);
|
|
|
|
avpd.buf_size = buf.len;
|
2013-05-25 13:00:03 +00:00
|
|
|
|
|
|
|
int score = 0;
|
|
|
|
priv->avif = av_probe_input_format2(&avpd, avpd.buf_size > 0, &score);
|
2012-12-08 19:14:13 +00:00
|
|
|
|
|
|
|
if (priv->avif) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "Found '%s' at score=%d size=%d.\n",
|
2013-05-25 13:00:03 +00:00
|
|
|
priv->avif->name, score, avpd.buf_size);
|
2012-12-08 19:14:13 +00:00
|
|
|
|
2013-05-25 13:00:03 +00:00
|
|
|
if (score >= min_probe)
|
2013-05-27 21:26:22 +00:00
|
|
|
break;
|
2013-05-25 13:00:03 +00:00
|
|
|
|
|
|
|
if (expected_format) {
|
|
|
|
if (strcmp(priv->avif->name, expected_format) == 0 &&
|
|
|
|
score >= expected_format_probescore)
|
|
|
|
break;
|
|
|
|
}
|
2013-05-27 21:26:22 +00:00
|
|
|
}
|
2012-12-08 19:14:13 +00:00
|
|
|
|
|
|
|
priv->avif = NULL;
|
2013-05-25 13:00:03 +00:00
|
|
|
}
|
|
|
|
|
2010-02-12 20:38:29 +00:00
|
|
|
av_free(avpd.buf);
|
|
|
|
|
2013-08-07 21:15:11 +00:00
|
|
|
if (priv->avif && !format) {
|
|
|
|
for (int n = 0; format_blacklist[n]; n++) {
|
|
|
|
if (strcmp(format_blacklist[n], priv->avif->name) == 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "Format blacklisted.\n");
|
2013-08-07 21:15:11 +00:00
|
|
|
priv->avif = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-08 19:14:13 +00:00
|
|
|
if (!priv->avif) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "No format found, try lowering probescore or forcing the format.\n");
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2012-12-08 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
success:
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2010-11-10 13:38:36 +00:00
|
|
|
demuxer->filetype = priv->avif->long_name;
|
|
|
|
if (!demuxer->filetype)
|
|
|
|
demuxer->filetype = priv->avif->name;
|
|
|
|
|
2013-07-11 18:08:12 +00:00
|
|
|
return 0;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
2007-04-14 10:03:42 +00:00
|
|
|
|
2010-11-05 10:50:11 +00:00
|
|
|
static bool matches_avinputformat_name(struct lavf_priv *priv,
|
|
|
|
const char *name)
|
|
|
|
{
|
2013-05-04 00:09:47 +00:00
|
|
|
// At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
|
|
|
|
// on "," in general.
|
2010-11-05 10:50:11 +00:00
|
|
|
const char *avifname = priv->avif->name;
|
|
|
|
while (1) {
|
|
|
|
const char *next = strchr(avifname, ',');
|
|
|
|
if (!next)
|
|
|
|
return !strcmp(avifname, name);
|
|
|
|
int len = next - avifname;
|
|
|
|
if (len == strlen(name) && !memcmp(avifname, name, len))
|
|
|
|
return true;
|
|
|
|
avifname = next + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
static uint8_t char2int(char c)
|
|
|
|
{
|
2007-10-14 12:11:28 +00:00
|
|
|
if (c >= '0' && c <= '9') return c - '0';
|
|
|
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
|
|
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
static void parse_cryptokey(AVFormatContext *avfc, const char *str)
|
|
|
|
{
|
2007-10-14 12:11:28 +00:00
|
|
|
int len = strlen(str) / 2;
|
|
|
|
uint8_t *key = av_mallocz(len);
|
|
|
|
int i;
|
|
|
|
avfc->keylen = len;
|
|
|
|
avfc->key = key;
|
|
|
|
for (i = 0; i < len; i++, str += 2)
|
|
|
|
*key++ = (char2int(str[0]) << 4) | char2int(str[1]);
|
|
|
|
}
|
|
|
|
|
2013-07-11 17:23:31 +00:00
|
|
|
static void select_tracks(struct demuxer *demuxer, int start)
|
|
|
|
{
|
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
|
|
|
for (int n = start; n < priv->num_streams; n++) {
|
|
|
|
struct sh_stream *stream = priv->streams[n];
|
|
|
|
AVStream *st = priv->avfc->streams[n];
|
core: completely change handling of attached picture pseudo video
Before this commit, we tried to play along with libavformat and tried
to pretend that attached pictures are video streams with a single
frame, and that the frame magically appeared at the seek position when
seeking. The playback core would then switch to a mode where the video
has ended, and the "remaining" audio is played.
This didn't work very well:
- we needed a hack in demux.c, because we tried to read more packets in
order to find the "next" video frame (libavformat doesn't tell us if
a stream has ended)
- switching the video stream didn't work, because we can't tell
libavformat to send the packet again
- seeking and resuming after was hacky (for some reason libavformat sets
the returned packet's PTS to that of the previously returned audio
packet in generic code not related to attached pictures, and this
happened to work)
- if the user did something stupid and e.g. inserted a deinterlacer by
default, a picture was never displayed, only an inactive VO window)
- same when using a command that reconfigured the VO (like switching
aspect or video filters)
- hr-seek didn't work
For this reason, handle attached pictures as separate case with a
separate video decoding function, which doesn't read packets. Also,
do not synchronize audio to video start in this case.
2013-07-11 17:23:56 +00:00
|
|
|
bool selected = stream && demuxer_stream_is_selected(demuxer, stream) &&
|
|
|
|
!stream->attached_picture;
|
2013-07-11 17:23:31 +00:00
|
|
|
st->discard = selected ? AVDISCARD_DEFAULT : AVDISCARD_ALL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
static void handle_stream(demuxer_t *demuxer, int i)
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
2013-04-14 18:53:03 +00:00
|
|
|
AVFormatContext *avfc = priv->avfc;
|
2011-07-03 12:42:04 +00:00
|
|
|
AVStream *st = avfc->streams[i];
|
|
|
|
AVCodecContext *codec = st->codec;
|
2013-02-09 14:15:28 +00:00
|
|
|
struct sh_stream *sh = NULL;
|
2012-07-29 19:04:57 +00:00
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
switch (codec->codec_type) {
|
|
|
|
case AVMEDIA_TYPE_AUDIO: {
|
2013-04-14 18:53:03 +00:00
|
|
|
sh = new_sh_stream(demuxer, STREAM_AUDIO);
|
|
|
|
if (!sh)
|
2007-10-27 19:00:07 +00:00
|
|
|
break;
|
2013-04-14 18:53:03 +00:00
|
|
|
sh_audio_t *sh_audio = sh->audio;
|
|
|
|
|
2013-11-23 20:37:56 +00:00
|
|
|
sh->format = codec->codec_tag;
|
demux_lavf, ad_lavc, vd_lavc: pass codec header data directly
Instead of putting codec header data into WAVEFORMATEX and
BITMAPINFOHEADER, pass it directly via AVCodecContext. To do this, we
add mp_copy_lav_codec_headers(), which copies the codec header data
from one AVCodecContext to another (originally, the plan was to use
avcodec_copy_context() for this, but it looks like this would turn
decoder initialization into an even worse mess).
Get rid of the silly CodecID <-> codec_tag mapping. This was originally
needed for codecs.conf: codec tags were used to identify codecs, but
libavformat didn't always return useful codec tags (different file
formats can have different, overlapping tag numbers). Since we don't
go through WAVEFORMATEX etc. and pass all header data directly via
AVCodecContext, we can be absolutely sure that the codec tag mapping is
not needed anymore.
Note that this also destroys the "standard" MPlayer method of exporting
codec header data. WAVEFORMATEX and BITMAPINFOHEADER made sure that
other non-libavcodec decoders could be initialized. However, all these
decoders have been removed, so this is just cruft full of old hacks that
are not needed anymore. There's still ad_spdif and ad_mpg123, bu neither
of these need codec header data. Should we ever add non-libavcodec
decoders, better data structures without the past hacks could be added
to export the headers.
2013-02-09 14:15:37 +00:00
|
|
|
|
|
|
|
// probably unneeded
|
2013-04-06 20:43:12 +00:00
|
|
|
mp_chmap_from_channels(&sh_audio->channels, codec->channels);
|
|
|
|
if (codec->channel_layout)
|
|
|
|
mp_chmap_from_lavc(&sh_audio->channels, codec->channel_layout);
|
2011-07-03 12:42:04 +00:00
|
|
|
sh_audio->samplerate = codec->sample_rate;
|
|
|
|
sh_audio->i_bps = codec->bit_rate / 8;
|
demux_lavf, ad_lavc, vd_lavc: pass codec header data directly
Instead of putting codec header data into WAVEFORMATEX and
BITMAPINFOHEADER, pass it directly via AVCodecContext. To do this, we
add mp_copy_lav_codec_headers(), which copies the codec header data
from one AVCodecContext to another (originally, the plan was to use
avcodec_copy_context() for this, but it looks like this would turn
decoder initialization into an even worse mess).
Get rid of the silly CodecID <-> codec_tag mapping. This was originally
needed for codecs.conf: codec tags were used to identify codecs, but
libavformat didn't always return useful codec tags (different file
formats can have different, overlapping tag numbers). Since we don't
go through WAVEFORMATEX etc. and pass all header data directly via
AVCodecContext, we can be absolutely sure that the codec tag mapping is
not needed anymore.
Note that this also destroys the "standard" MPlayer method of exporting
codec header data. WAVEFORMATEX and BITMAPINFOHEADER made sure that
other non-libavcodec decoders could be initialized. However, all these
decoders have been removed, so this is just cruft full of old hacks that
are not needed anymore. There's still ad_spdif and ad_mpg123, bu neither
of these need codec header data. Should we ever add non-libavcodec
decoders, better data structures without the past hacks could be added
to export the headers.
2013-02-09 14:15:37 +00:00
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case AVMEDIA_TYPE_VIDEO: {
|
2013-04-14 18:53:03 +00:00
|
|
|
sh = new_sh_stream(demuxer, STREAM_VIDEO);
|
|
|
|
if (!sh)
|
2007-10-27 19:00:07 +00:00
|
|
|
break;
|
2013-04-14 18:53:03 +00:00
|
|
|
sh_video_t *sh_video = sh->video;
|
|
|
|
|
core: completely change handling of attached picture pseudo video
Before this commit, we tried to play along with libavformat and tried
to pretend that attached pictures are video streams with a single
frame, and that the frame magically appeared at the seek position when
seeking. The playback core would then switch to a mode where the video
has ended, and the "remaining" audio is played.
This didn't work very well:
- we needed a hack in demux.c, because we tried to read more packets in
order to find the "next" video frame (libavformat doesn't tell us if
a stream has ended)
- switching the video stream didn't work, because we can't tell
libavformat to send the packet again
- seeking and resuming after was hacky (for some reason libavformat sets
the returned packet's PTS to that of the previously returned audio
packet in generic code not related to attached pictures, and this
happened to work)
- if the user did something stupid and e.g. inserted a deinterlacer by
default, a picture was never displayed, only an inactive VO window)
- same when using a command that reconfigured the VO (like switching
aspect or video filters)
- hr-seek didn't work
For this reason, handle attached pictures as separate case with a
separate video decoding function, which doesn't read packets. Also,
do not synchronize audio to video start in this case.
2013-07-11 17:23:56 +00:00
|
|
|
if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
|
|
|
|
sh->attached_picture = new_demux_packet_from(st->attached_pic.data,
|
|
|
|
st->attached_pic.size);
|
|
|
|
sh->attached_picture->pts = 0;
|
|
|
|
talloc_steal(sh, sh->attached_picture);
|
2013-07-24 17:42:02 +00:00
|
|
|
sh->attached_picture->keyframe = true;
|
core: completely change handling of attached picture pseudo video
Before this commit, we tried to play along with libavformat and tried
to pretend that attached pictures are video streams with a single
frame, and that the frame magically appeared at the seek position when
seeking. The playback core would then switch to a mode where the video
has ended, and the "remaining" audio is played.
This didn't work very well:
- we needed a hack in demux.c, because we tried to read more packets in
order to find the "next" video frame (libavformat doesn't tell us if
a stream has ended)
- switching the video stream didn't work, because we can't tell
libavformat to send the packet again
- seeking and resuming after was hacky (for some reason libavformat sets
the returned packet's PTS to that of the previously returned audio
packet in generic code not related to attached pictures, and this
happened to work)
- if the user did something stupid and e.g. inserted a deinterlacer by
default, a picture was never displayed, only an inactive VO window)
- same when using a command that reconfigured the VO (like switching
aspect or video filters)
- hr-seek didn't work
For this reason, handle attached pictures as separate case with a
separate video decoding function, which doesn't read packets. Also,
do not synchronize audio to video start in this case.
2013-07-11 17:23:56 +00:00
|
|
|
}
|
demux_lavf, ad_lavc, vd_lavc: pass codec header data directly
Instead of putting codec header data into WAVEFORMATEX and
BITMAPINFOHEADER, pass it directly via AVCodecContext. To do this, we
add mp_copy_lav_codec_headers(), which copies the codec header data
from one AVCodecContext to another (originally, the plan was to use
avcodec_copy_context() for this, but it looks like this would turn
decoder initialization into an even worse mess).
Get rid of the silly CodecID <-> codec_tag mapping. This was originally
needed for codecs.conf: codec tags were used to identify codecs, but
libavformat didn't always return useful codec tags (different file
formats can have different, overlapping tag numbers). Since we don't
go through WAVEFORMATEX etc. and pass all header data directly via
AVCodecContext, we can be absolutely sure that the codec tag mapping is
not needed anymore.
Note that this also destroys the "standard" MPlayer method of exporting
codec header data. WAVEFORMATEX and BITMAPINFOHEADER made sure that
other non-libavcodec decoders could be initialized. However, all these
decoders have been removed, so this is just cruft full of old hacks that
are not needed anymore. There's still ad_spdif and ad_mpg123, bu neither
of these need codec header data. Should we ever add non-libavcodec
decoders, better data structures without the past hacks could be added
to export the headers.
2013-02-09 14:15:37 +00:00
|
|
|
|
2013-11-23 20:37:56 +00:00
|
|
|
sh->format = codec->codec_tag;
|
2011-07-03 12:42:04 +00:00
|
|
|
sh_video->disp_w = codec->width;
|
|
|
|
sh_video->disp_h = codec->height;
|
2012-04-13 23:43:40 +00:00
|
|
|
/* Try to make up some frame rate value, even if it's not reliable.
|
|
|
|
* FPS information is needed to support subtitle formats which base
|
|
|
|
* timing on frame numbers.
|
|
|
|
* Libavformat seems to report no "reliable" FPS value for AVI files,
|
|
|
|
* while they are typically constant enough FPS that the value this
|
|
|
|
* heuristic makes up works with subtitles in practice.
|
|
|
|
*/
|
|
|
|
double fps;
|
2013-03-09 07:52:53 +00:00
|
|
|
if (st->avg_frame_rate.num)
|
|
|
|
fps = av_q2d(st->avg_frame_rate);
|
2012-04-13 23:43:40 +00:00
|
|
|
else
|
|
|
|
fps = 1.0 / FFMAX(av_q2d(st->time_base),
|
|
|
|
av_q2d(st->codec->time_base) *
|
|
|
|
st->codec->ticks_per_frame);
|
|
|
|
sh_video->fps = fps;
|
2011-07-03 12:42:04 +00:00
|
|
|
if (st->sample_aspect_ratio.num)
|
|
|
|
sh_video->aspect = codec->width * st->sample_aspect_ratio.num
|
|
|
|
/ (float)(codec->height * st->sample_aspect_ratio.den);
|
|
|
|
else
|
|
|
|
sh_video->aspect = codec->width * codec->sample_aspect_ratio.num
|
|
|
|
/ (float)(codec->height * codec->sample_aspect_ratio.den);
|
|
|
|
sh_video->i_bps = codec->bit_rate / 8;
|
2013-02-09 14:15:28 +00:00
|
|
|
|
video: add insane hack to work around FFmpeg/Libav insanity
So, FFmpeg/Libav requires us to figure out video timestamps ourselves
(see last 10 commits or so), but the methods it provides for this aren't
even sufficient. In particular, everything that uses AVI-style DTS (avi,
vfw-muxed mkv, possibly mpeg4-in-ogm) with a codec that has an internal
frame delay is broken. In this case, libavcodec will shift the packet-
to-image correspondence by the codec delay, meaning that with a delay=1,
the first AVFrame.pkt_dts is not 0, but that of the second packet. All
timestamps will appear shifted. The start time (e.g. the time displayed
when doing "mpv file.avi --pause") will not be exactly 0.
(According to Libav developers, this is how it's supposed to work; just
that the first DTS values are normally negative with formats that use
DTS "properly". Who cares if it doesn't work at all with very common
video formats? There's no indication that they'll fix this soon,
either. An elegant workaround is missing too.)
Add a hack to re-enable the old PTS code for AVI and vfw-muxed MKV.
Since these timestamps are not reorderd, we wouldn't need to sort them,
but it's less code this way (and possibly more robust, should a demuxer
unexpectedly output PTS).
The original intention of all the timestamp changes recently was
actually to get rid of demuxer-specific hacks and the old timestamp
sorting code, but it looks like this didn't work out. Yet another case
where trying to replace native MPlayer functionality with FFmpeg/Libav
led to disadvantages and bugs. (Note that the old PTS sorting code
doesn't and can't handle frame dropping correctly, though.)
Bug reports:
https://trac.ffmpeg.org/ticket/3178
https://bugzilla.libav.org/show_bug.cgi?id=600
2013-11-28 14:10:45 +00:00
|
|
|
// This also applies to vfw-muxed mkv, but we can't detect these easily.
|
|
|
|
sh_video->avi_dts = matches_avinputformat_name(priv, "avi");
|
|
|
|
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_DBG(demuxer, "aspect= %d*%d/(%d*%d)\n",
|
2011-07-03 12:42:04 +00:00
|
|
|
codec->width, codec->sample_aspect_ratio.num,
|
|
|
|
codec->height, codec->sample_aspect_ratio.den);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case AVMEDIA_TYPE_SUBTITLE: {
|
|
|
|
sh_sub_t *sh_sub;
|
2013-04-14 18:53:03 +00:00
|
|
|
sh = new_sh_stream(demuxer, STREAM_SUB);
|
|
|
|
if (!sh)
|
2008-01-30 08:10:25 +00:00
|
|
|
break;
|
2013-04-14 18:53:03 +00:00
|
|
|
sh_sub = sh->sub;
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
if (codec->extradata_size) {
|
2014-01-06 23:55:33 +00:00
|
|
|
sh_sub->extradata = talloc_size(sh, codec->extradata_size);
|
2011-07-03 12:42:04 +00:00
|
|
|
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
|
|
|
|
sh_sub->extradata_len = codec->extradata_size;
|
2008-01-30 08:10:25 +00:00
|
|
|
}
|
2014-01-09 23:02:06 +00:00
|
|
|
|
|
|
|
// Hack for MicroDVD: if time_base matches the ffmpeg microdvd reader's
|
|
|
|
// default FPS (23.976), assume the MicroDVD file did not declare a
|
|
|
|
// FPS, and the MicroDVD file uses frame based timing.
|
|
|
|
if (codec->time_base.num == 125 && codec->time_base.den == 2997)
|
|
|
|
sh_sub->frame_based = true;
|
2011-07-03 12:42:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case AVMEDIA_TYPE_ATTACHMENT: {
|
2011-12-22 00:06:52 +00:00
|
|
|
AVDictionaryEntry *ftag = av_dict_get(st->metadata, "filename",
|
2011-07-03 12:42:04 +00:00
|
|
|
NULL, 0);
|
|
|
|
char *filename = ftag ? ftag->value : NULL;
|
2013-03-09 07:49:56 +00:00
|
|
|
if (st->codec->codec_id == AV_CODEC_ID_TTF)
|
2012-07-28 21:47:42 +00:00
|
|
|
demuxer_add_attachment(demuxer, bstr0(filename),
|
|
|
|
bstr0("application/x-truetype-font"),
|
2011-07-03 12:42:04 +00:00
|
|
|
(struct bstr){codec->extradata,
|
|
|
|
codec->extradata_size});
|
|
|
|
break;
|
|
|
|
}
|
2013-04-14 18:53:03 +00:00
|
|
|
default: ;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
2013-04-14 18:53:03 +00:00
|
|
|
|
|
|
|
assert(priv->num_streams == i); // directly mapped
|
|
|
|
MP_TARRAY_APPEND(priv, priv->streams, priv->num_streams, sh);
|
|
|
|
|
2013-02-09 14:15:28 +00:00
|
|
|
if (sh) {
|
demux_lavf, ad_lavc, vd_lavc: pass codec header data directly
Instead of putting codec header data into WAVEFORMATEX and
BITMAPINFOHEADER, pass it directly via AVCodecContext. To do this, we
add mp_copy_lav_codec_headers(), which copies the codec header data
from one AVCodecContext to another (originally, the plan was to use
avcodec_copy_context() for this, but it looks like this would turn
decoder initialization into an even worse mess).
Get rid of the silly CodecID <-> codec_tag mapping. This was originally
needed for codecs.conf: codec tags were used to identify codecs, but
libavformat didn't always return useful codec tags (different file
formats can have different, overlapping tag numbers). Since we don't
go through WAVEFORMATEX etc. and pass all header data directly via
AVCodecContext, we can be absolutely sure that the codec tag mapping is
not needed anymore.
Note that this also destroys the "standard" MPlayer method of exporting
codec header data. WAVEFORMATEX and BITMAPINFOHEADER made sure that
other non-libavcodec decoders could be initialized. However, all these
decoders have been removed, so this is just cruft full of old hacks that
are not needed anymore. There's still ad_spdif and ad_mpg123, bu neither
of these need codec header data. Should we ever add non-libavcodec
decoders, better data structures without the past hacks could be added
to export the headers.
2013-02-09 14:15:37 +00:00
|
|
|
sh->codec = mp_codec_from_av_codec_id(codec->codec_id);
|
2013-05-21 20:06:45 +00:00
|
|
|
sh->lav_headers = codec;
|
demux_lavf, ad_lavc, vd_lavc: pass codec header data directly
Instead of putting codec header data into WAVEFORMATEX and
BITMAPINFOHEADER, pass it directly via AVCodecContext. To do this, we
add mp_copy_lav_codec_headers(), which copies the codec header data
from one AVCodecContext to another (originally, the plan was to use
avcodec_copy_context() for this, but it looks like this would turn
decoder initialization into an even worse mess).
Get rid of the silly CodecID <-> codec_tag mapping. This was originally
needed for codecs.conf: codec tags were used to identify codecs, but
libavformat didn't always return useful codec tags (different file
formats can have different, overlapping tag numbers). Since we don't
go through WAVEFORMATEX etc. and pass all header data directly via
AVCodecContext, we can be absolutely sure that the codec tag mapping is
not needed anymore.
Note that this also destroys the "standard" MPlayer method of exporting
codec header data. WAVEFORMATEX and BITMAPINFOHEADER made sure that
other non-libavcodec decoders could be initialized. However, all these
decoders have been removed, so this is just cruft full of old hacks that
are not needed anymore. There's still ad_spdif and ad_mpg123, bu neither
of these need codec header data. Should we ever add non-libavcodec
decoders, better data structures without the past hacks could be added
to export the headers.
2013-02-09 14:15:37 +00:00
|
|
|
|
2013-02-09 14:15:28 +00:00
|
|
|
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
|
|
|
sh->default_track = 1;
|
2013-05-04 00:09:47 +00:00
|
|
|
if (matches_avinputformat_name(priv, "mpeg") ||
|
|
|
|
matches_avinputformat_name(priv, "mpegts"))
|
2013-02-09 14:15:28 +00:00
|
|
|
sh->demuxer_id = st->id;
|
|
|
|
AVDictionaryEntry *title = av_dict_get(st->metadata, "title", NULL, 0);
|
2010-05-03 22:45:00 +00:00
|
|
|
if (title && title->value)
|
2013-02-09 14:15:28 +00:00
|
|
|
sh->title = talloc_strdup(sh, title->value);
|
|
|
|
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
|
|
|
if (lang && lang->value)
|
|
|
|
sh->lang = talloc_strdup(sh, lang->value);
|
2010-05-03 22:45:00 +00:00
|
|
|
}
|
2013-07-11 17:22:24 +00:00
|
|
|
|
2013-07-11 17:23:31 +00:00
|
|
|
select_tracks(demuxer, i);
|
2007-10-27 19:00:07 +00:00
|
|
|
}
|
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
// Add any new streams that might have been added
|
|
|
|
static void add_new_streams(demuxer_t *demuxer)
|
|
|
|
{
|
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
|
|
|
while (priv->num_streams < priv->avfc->nb_streams)
|
|
|
|
handle_stream(demuxer, priv->num_streams);
|
|
|
|
}
|
|
|
|
|
2013-06-15 15:53:15 +00:00
|
|
|
static void add_metadata(demuxer_t *demuxer, AVDictionary *metadata)
|
|
|
|
{
|
|
|
|
AVDictionaryEntry *t = NULL;
|
|
|
|
while ((t = av_dict_get(metadata, "", t, AV_DICT_IGNORE_SUFFIX)))
|
|
|
|
demux_info_add(demuxer, t->key, t->value);
|
|
|
|
}
|
|
|
|
|
2013-07-12 19:58:11 +00:00
|
|
|
static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
2008-04-16 04:11:12 +00:00
|
|
|
struct MPOpts *opts = demuxer->opts;
|
2010-04-23 19:08:18 +00:00
|
|
|
struct lavfdopts *lavfdopts = &opts->lavfdopts;
|
2007-10-27 19:00:07 +00:00
|
|
|
AVFormatContext *avfc;
|
2011-12-22 00:06:52 +00:00
|
|
|
AVDictionaryEntry *t = NULL;
|
2013-05-27 21:26:22 +00:00
|
|
|
float analyze_duration = 0;
|
2007-10-30 15:49:53 +00:00
|
|
|
int i;
|
2007-10-27 19:00:07 +00:00
|
|
|
|
2013-07-12 19:58:11 +00:00
|
|
|
if (lavf_check_file(demuxer, check) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
|
|
|
if (!priv)
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2012-12-08 19:14:13 +00:00
|
|
|
|
2009-11-22 14:15:41 +00:00
|
|
|
avfc = avformat_alloc_context();
|
2007-10-27 19:00:07 +00:00
|
|
|
|
2010-04-23 19:08:18 +00:00
|
|
|
if (lavfdopts->cryptokey)
|
|
|
|
parse_cryptokey(avfc, lavfdopts->cryptokey);
|
2013-11-25 22:13:46 +00:00
|
|
|
if (lavfdopts->genptsmode)
|
|
|
|
avfc->flags |= AVFMT_FLAG_GENPTS;
|
2013-07-07 21:54:11 +00:00
|
|
|
if (opts->index_mode == 0)
|
2007-10-27 19:00:07 +00:00
|
|
|
avfc->flags |= AVFMT_FLAG_IGNIDX;
|
|
|
|
|
2010-04-23 19:08:18 +00:00
|
|
|
if (lavfdopts->probesize) {
|
2012-01-28 11:41:36 +00:00
|
|
|
if (av_opt_set_int(avfc, "probesize", lavfdopts->probesize, 0) < 0)
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(demuxer, "demux_lavf, couldn't set option probesize to %u\n",
|
2011-07-03 12:42:04 +00:00
|
|
|
lavfdopts->probesize);
|
2007-10-27 19:00:07 +00:00
|
|
|
}
|
2013-05-27 21:26:22 +00:00
|
|
|
|
|
|
|
if (priv->format_hack && priv->format_hack->analyzeduration)
|
|
|
|
analyze_duration = priv->format_hack->analyzeduration;
|
|
|
|
if (lavfdopts->analyzeduration)
|
|
|
|
analyze_duration = lavfdopts->analyzeduration;
|
|
|
|
if (analyze_duration > 0) {
|
2012-01-28 11:41:36 +00:00
|
|
|
if (av_opt_set_int(avfc, "analyzeduration",
|
2013-05-27 21:26:22 +00:00
|
|
|
analyze_duration * AV_TIME_BASE, 0) < 0)
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(demuxer, "demux_lavf, couldn't set option "
|
2013-05-27 21:26:22 +00:00
|
|
|
"analyzeduration to %f\n", analyze_duration);
|
2007-10-27 19:00:07 +00:00
|
|
|
}
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
if (lavfdopts->avopt) {
|
|
|
|
if (parse_avopts(avfc, lavfdopts->avopt) < 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(demuxer, "Your options /%s/ look like gibberish to me pal\n",
|
2011-07-03 12:42:04 +00:00
|
|
|
lavfdopts->avopt);
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2008-05-10 19:29:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-03 18:21:47 +00:00
|
|
|
if ((priv->avif->flags & AVFMT_NOFILE) ||
|
|
|
|
demuxer->stream->type == STREAMTYPE_AVDEVICE)
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
{
|
2013-11-03 18:21:47 +00:00
|
|
|
// This might be incorrect.
|
|
|
|
demuxer->seekable = true;
|
|
|
|
} else {
|
2013-08-04 21:25:54 +00:00
|
|
|
void *buffer = av_malloc(lavfdopts->buffersize);
|
2013-08-04 21:21:50 +00:00
|
|
|
if (!buffer)
|
|
|
|
return -1;
|
2013-08-04 21:25:54 +00:00
|
|
|
priv->pb = avio_alloc_context(buffer, lavfdopts->buffersize, 0,
|
2011-12-22 00:06:52 +00:00
|
|
|
demuxer, mp_read, NULL, mp_seek);
|
2013-08-04 21:21:50 +00:00
|
|
|
if (!priv->pb) {
|
|
|
|
av_free(buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
2011-06-21 20:28:53 +00:00
|
|
|
priv->pb->read_seek = mp_read_seek;
|
2013-11-03 18:21:47 +00:00
|
|
|
priv->pb->seekable = demuxer->seekable ? AVIO_SEEKABLE_NORMAL : 0;
|
2011-12-22 00:06:52 +00:00
|
|
|
avfc->pb = priv->pb;
|
2011-06-21 20:28:53 +00:00
|
|
|
}
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2013-09-22 00:40:29 +00:00
|
|
|
AVDictionary *dopts = NULL;
|
|
|
|
|
|
|
|
if (matches_avinputformat_name(priv, "rtsp")) {
|
|
|
|
const char *transport = NULL;
|
|
|
|
switch (opts->network_rtsp_transport) {
|
|
|
|
case 1: transport = "udp"; break;
|
|
|
|
case 2: transport = "tcp"; break;
|
|
|
|
case 3: transport = "http"; break;
|
|
|
|
}
|
|
|
|
if (transport)
|
|
|
|
av_dict_set(&dopts, "rtsp_transport", transport, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(demuxer, "LAVF_header: avformat_open_input() failed\n");
|
2013-09-22 00:40:29 +00:00
|
|
|
av_dict_free(&dopts);
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2007-10-27 19:00:07 +00:00
|
|
|
}
|
|
|
|
|
2013-09-22 00:40:29 +00:00
|
|
|
t = NULL;
|
|
|
|
while ((t = av_dict_get(dopts, "", t, AV_DICT_IGNORE_SUFFIX))) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "[lavf] Could not set demux option %s=%s\n",
|
2013-09-22 00:40:29 +00:00
|
|
|
t->key, t->value);
|
|
|
|
}
|
|
|
|
av_dict_free(&dopts);
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
priv->avfc = avfc;
|
2012-01-28 11:41:36 +00:00
|
|
|
if (avformat_find_stream_info(avfc, NULL) < 0) {
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_ERR(demuxer, "LAVF_header: av_find_stream_info() failed\n");
|
2013-07-11 18:08:12 +00:00
|
|
|
return -1;
|
2007-10-27 19:00:07 +00:00
|
|
|
}
|
2013-05-24 10:00:44 +00:00
|
|
|
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "demux_lavf: avformat_find_stream_info() "
|
2013-05-24 10:00:44 +00:00
|
|
|
"finished after %"PRId64" bytes.\n", stream_tell(demuxer->stream));
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
for (i = 0; i < avfc->nb_chapters; i++) {
|
2008-06-16 15:54:29 +00:00
|
|
|
AVChapter *c = avfc->chapters[i];
|
2011-07-03 12:42:04 +00:00
|
|
|
uint64_t start = av_rescale_q(c->start, c->time_base,
|
|
|
|
(AVRational){1, 1000000000});
|
|
|
|
uint64_t end = av_rescale_q(c->end, c->time_base,
|
|
|
|
(AVRational){1, 1000000000});
|
2011-12-22 00:06:52 +00:00
|
|
|
t = av_dict_get(c->metadata, "title", NULL, 0);
|
2012-07-28 21:47:42 +00:00
|
|
|
demuxer_add_chapter(demuxer, t ? bstr0(t->value) : bstr0(NULL),
|
2013-09-08 05:42:05 +00:00
|
|
|
start, end, i);
|
2013-11-01 12:00:15 +00:00
|
|
|
t = NULL;
|
2013-09-08 05:42:05 +00:00
|
|
|
while ((t = av_dict_get(c->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
|
|
|
|
demuxer_add_chapter_info(demuxer, i, bstr0(t->key),
|
|
|
|
bstr0(t->value));
|
|
|
|
}
|
2008-06-16 15:54:29 +00:00
|
|
|
}
|
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
add_new_streams(demuxer);
|
2010-10-04 18:12:36 +00:00
|
|
|
|
2013-06-15 15:53:15 +00:00
|
|
|
add_metadata(demuxer, 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) {
|
|
|
|
for (int n = 0; n < priv->num_streams; n++) {
|
|
|
|
if (priv->streams[n])
|
|
|
|
add_metadata(demuxer, avfc->streams[n]->metadata);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
if (avfc->nb_programs) {
|
2009-11-07 11:15:26 +00:00
|
|
|
int p;
|
|
|
|
for (p = 0; p < avfc->nb_programs; p++) {
|
2007-10-27 19:12:59 +00:00
|
|
|
AVProgram *program = avfc->programs[p];
|
2011-12-22 00:06:52 +00:00
|
|
|
t = av_dict_get(program->metadata, "title", NULL, 0);
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_INFO(demuxer, "LAVF: Program %d %s\n",
|
2011-07-03 12:42:04 +00:00
|
|
|
program->id, t ? t->value : "");
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "PROGRAM_ID=%d\n", program->id);
|
2009-11-07 11:15:26 +00:00
|
|
|
}
|
2009-09-08 08:55:05 +00:00
|
|
|
}
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_VERBOSE(demuxer, "LAVF: build %d\n", LIBAVFORMAT_BUILD);
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-03-01 12:20:33 +00:00
|
|
|
demuxer->ts_resets_possible = priv->avif->flags & AVFMT_TS_DISCONT;
|
|
|
|
|
2013-07-11 18:08:12 +00:00
|
|
|
return 0;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
|
|
|
|
2013-10-12 23:16:30 +00:00
|
|
|
static void destroy_avpacket(void *pkt)
|
2011-08-19 01:59:01 +00:00
|
|
|
{
|
|
|
|
av_free_packet(pkt);
|
|
|
|
}
|
|
|
|
|
2013-11-25 22:13:46 +00:00
|
|
|
static int demux_lavf_fill_buffer(demuxer_t *demux)
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
|
|
|
lavf_priv_t *priv = demux->priv;
|
2013-11-25 22:13:46 +00:00
|
|
|
demux_packet_t *dp;
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_DBG(demux, "demux_lavf_fill_buffer()\n");
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2011-08-19 01:59:01 +00:00
|
|
|
AVPacket *pkt = talloc(NULL, AVPacket);
|
|
|
|
if (av_read_frame(priv->avfc, pkt) < 0) {
|
|
|
|
talloc_free(pkt);
|
2013-11-25 22:13:46 +00:00
|
|
|
return 0; // eof
|
2011-08-19 01:59:01 +00:00
|
|
|
}
|
|
|
|
talloc_set_destructor(pkt, destroy_avpacket);
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
add_new_streams(demux);
|
2010-10-04 18:12:36 +00:00
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
assert(pkt->stream_index >= 0 && pkt->stream_index < priv->num_streams);
|
|
|
|
struct sh_stream *stream = priv->streams[pkt->stream_index];
|
2013-11-25 22:13:46 +00:00
|
|
|
AVStream *st = priv->avfc->streams[pkt->stream_index];
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
if (!demuxer_stream_is_selected(demux, stream)) {
|
2011-08-19 01:59:01 +00:00
|
|
|
talloc_free(pkt);
|
2013-11-25 22:13:46 +00:00
|
|
|
return 1; // don't signal EOF if skipping a packet
|
2005-01-30 09:13:28 +00:00
|
|
|
}
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2011-08-21 18:55:32 +00:00
|
|
|
// 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();
|
2013-07-14 21:44:50 +00:00
|
|
|
|
2011-08-19 01:59:01 +00:00
|
|
|
dp = new_demux_packet_fromdata(pkt->data, pkt->size);
|
2013-07-14 21:44:50 +00:00
|
|
|
dp->avpacket = talloc_steal(dp, pkt);
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-12-12 22:36:52 +00:00
|
|
|
if (pkt->pts != AV_NOPTS_VALUE)
|
2013-11-25 22:13:01 +00:00
|
|
|
dp->pts = pkt->pts * av_q2d(st->time_base);
|
2013-12-12 22:36:52 +00:00
|
|
|
if (pkt->dts != AV_NOPTS_VALUE)
|
2013-11-25 22:13:01 +00:00
|
|
|
dp->dts = pkt->dts * av_q2d(st->time_base);
|
|
|
|
dp->duration = pkt->duration * av_q2d(st->time_base);
|
|
|
|
if (pkt->convergence_duration > 0)
|
|
|
|
dp->duration = pkt->convergence_duration * av_q2d(st->time_base);
|
2013-11-16 20:04:28 +00:00
|
|
|
dp->pos = pkt->pos;
|
2012-07-24 21:23:27 +00:00
|
|
|
dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY;
|
2013-05-03 18:30:08 +00:00
|
|
|
// Use only one stream for stream_pts, otherwise PTS might be jumpy.
|
|
|
|
if (stream->type == STREAM_VIDEO) {
|
|
|
|
double pts;
|
|
|
|
if (stream_control(demux->stream, STREAM_CTRL_GET_CURRENT_TIME, &pts) > 0)
|
|
|
|
dp->stream_pts = pts;
|
|
|
|
}
|
2013-12-12 22:36:52 +00:00
|
|
|
if (dp->pts != MP_NOPTS_VALUE) {
|
|
|
|
priv->last_pts = dp->pts * AV_TIME_BASE;
|
|
|
|
} else if (dp->dts != MP_NOPTS_VALUE) {
|
|
|
|
priv->last_pts = dp->dts * AV_TIME_BASE;
|
|
|
|
}
|
2013-04-14 18:53:03 +00:00
|
|
|
demuxer_add_packet(demux, stream, dp);
|
2004-04-11 14:26:04 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-08-22 17:13:29 +00:00
|
|
|
static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
2004-04-11 17:20:52 +00:00
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
2006-10-05 21:25:22 +00:00
|
|
|
int avsflags = 0;
|
2013-12-21 19:24:20 +00:00
|
|
|
MP_DBG(demuxer, "demux_seek_lavf(%p, %f, %d)\n",
|
2013-08-22 17:13:29 +00:00
|
|
|
demuxer, rel_seek_secs, flags);
|
2006-07-13 23:02:03 +00:00
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
if (flags & SEEK_ABSOLUTE)
|
|
|
|
priv->last_pts = 0;
|
|
|
|
else if (rel_seek_secs < 0)
|
|
|
|
avsflags = AVSEEK_FLAG_BACKWARD;
|
2013-03-01 12:20:33 +00:00
|
|
|
|
2009-03-19 03:25:12 +00:00
|
|
|
if (flags & SEEK_FORWARD)
|
|
|
|
avsflags = 0;
|
|
|
|
else if (flags & SEEK_BACKWARD)
|
|
|
|
avsflags = AVSEEK_FLAG_BACKWARD;
|
2013-03-01 12:20:33 +00:00
|
|
|
|
2008-01-29 15:11:38 +00:00
|
|
|
if (flags & SEEK_FACTOR) {
|
2013-11-03 17:50:00 +00:00
|
|
|
struct stream *s = demuxer->stream;
|
|
|
|
if (s->end_pos > 0 && demuxer->ts_resets_possible &&
|
2013-03-01 12:20:33 +00:00
|
|
|
!(priv->avif->flags & AVFMT_NO_BYTE_SEEK))
|
|
|
|
{
|
|
|
|
avsflags |= AVSEEK_FLAG_BYTE;
|
2013-11-03 17:50:00 +00:00
|
|
|
priv->last_pts = (s->end_pos - s->start_pos) * rel_seek_secs;
|
2013-03-01 12:20:33 +00:00
|
|
|
} else if (priv->avfc->duration != 0 &&
|
|
|
|
priv->avfc->duration != AV_NOPTS_VALUE)
|
|
|
|
{
|
|
|
|
priv->last_pts = rel_seek_secs * priv->avfc->duration;
|
|
|
|
}
|
|
|
|
} else {
|
2011-07-03 12:42:04 +00:00
|
|
|
priv->last_pts += rel_seek_secs * AV_TIME_BASE;
|
2013-03-01 12:20:33 +00:00
|
|
|
}
|
2012-12-08 12:12:46 +00:00
|
|
|
|
|
|
|
if (!priv->avfc->iformat->read_seek2) {
|
|
|
|
// Normal seeking.
|
2013-02-19 00:43:26 +00:00
|
|
|
int r = av_seek_frame(priv->avfc, -1, priv->last_pts, avsflags);
|
|
|
|
if (r < 0 && (avsflags & AVSEEK_FLAG_BACKWARD)) {
|
|
|
|
// When seeking before the beginning of the file, and seeking fails,
|
|
|
|
// try again without the backwards flag to make it seek to the
|
|
|
|
// beginning.
|
|
|
|
avsflags &= ~AVSEEK_FLAG_BACKWARD;
|
|
|
|
av_seek_frame(priv->avfc, -1, priv->last_pts, avsflags);
|
|
|
|
}
|
2012-12-08 12:12:46 +00:00
|
|
|
} else {
|
|
|
|
// av_seek_frame() won't work. Use "new" seeking API. We don't use this
|
|
|
|
// API by default, because there are some major issues.
|
|
|
|
// Set max_ts==ts, so that demuxing starts from an earlier position in
|
|
|
|
// the worst case.
|
2013-09-07 00:46:19 +00:00
|
|
|
// To make this horrible situation even worse, some lavf demuxers have
|
|
|
|
// broken timebase handling (everything that uses
|
|
|
|
// ff_subtitles_queue_seek()), and always uses the stream timebase. So
|
|
|
|
// we use the timebase and stream index of the first enabled stream
|
|
|
|
// (i.e. a stream which can participate in seeking).
|
|
|
|
int stream_index = -1;
|
|
|
|
AVRational time_base = {1, AV_TIME_BASE};
|
|
|
|
for (int n = 0; n < priv->num_streams; n++) {
|
|
|
|
struct sh_stream *stream = priv->streams[n];
|
|
|
|
AVStream *st = priv->avfc->streams[n];
|
|
|
|
if (stream && st->discard != AVDISCARD_ALL) {
|
|
|
|
stream_index = n;
|
|
|
|
time_base = st->time_base;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int64_t pts = priv->last_pts;
|
|
|
|
if (pts != AV_NOPTS_VALUE)
|
|
|
|
pts = pts / (double)AV_TIME_BASE * av_q2d(av_inv_q(time_base));
|
|
|
|
int r = avformat_seek_file(priv->avfc, stream_index, INT64_MIN,
|
|
|
|
pts, pts, avsflags);
|
demux_lavf: fix subtitle seeking before start of the file
When trying to seek before the start of the file, which usually happens
when using the arrow keys to seek to the start of the file, external
libavformat demuxed subtitles will be invisible. This is because seeking
in the external subtitle file fails, so the subtitle demuxer is left in
a random state.
This is actually similar to the normal seeking path, which has some
fallback code to handle this situation. Add such code to the subtitle
seeking path too.
(Normally, all demuxer support av_seek_frame(), except subtitles, which
support avformat_seek_file() only. The latter was meant to be the "new"
seeking API, but this never really took off, and using it normally seems
to cause worse seeking behavior. Or maybe we just use it incorrectly,
nobody really knows.)
2013-04-20 22:21:23 +00:00
|
|
|
// Similar issue as in the normal seeking codepath.
|
|
|
|
if (r < 0) {
|
2013-09-07 00:46:19 +00:00
|
|
|
avformat_seek_file(priv->avfc, stream_index, INT64_MIN,
|
|
|
|
pts, INT64_MAX, avsflags);
|
demux_lavf: fix subtitle seeking before start of the file
When trying to seek before the start of the file, which usually happens
when using the arrow keys to seek to the start of the file, external
libavformat demuxed subtitles will be invisible. This is because seeking
in the external subtitle file fails, so the subtitle demuxer is left in
a random state.
This is actually similar to the normal seeking path, which has some
fallback code to handle this situation. Add such code to the subtitle
seeking path too.
(Normally, all demuxer support av_seek_frame(), except subtitles, which
support avformat_seek_file() only. The latter was meant to be the "new"
seeking API, but this never really took off, and using it normally seems
to cause worse seeking behavior. Or maybe we just use it incorrectly,
nobody really knows.)
2013-04-20 22:21:23 +00:00
|
|
|
}
|
2009-09-30 08:19:49 +00:00
|
|
|
}
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
|
|
|
|
2005-08-05 19:57:47 +00:00
|
|
|
static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg)
|
2004-04-11 14:26:04 +00:00
|
|
|
{
|
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2004-04-11 14:26:04 +00:00
|
|
|
switch (cmd) {
|
2010-11-10 05:17:51 +00:00
|
|
|
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
2011-07-03 12:42:04 +00:00
|
|
|
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
|
|
|
return DEMUXER_CTRL_DONTKNOW;
|
2008-01-26 21:45:31 +00:00
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
*((double *)arg) = (double)priv->avfc->duration / AV_TIME_BASE;
|
|
|
|
return DEMUXER_CTRL_OK;
|
2004-04-11 14:26:04 +00:00
|
|
|
|
2013-02-25 23:38:36 +00:00
|
|
|
case DEMUXER_CTRL_GET_START_TIME:
|
2013-03-01 11:55:55 +00:00
|
|
|
*((double *)arg) = priv->avfc->start_time == AV_NOPTS_VALUE ?
|
|
|
|
0 : (double)priv->avfc->start_time / AV_TIME_BASE;
|
2011-07-03 12:42:04 +00:00
|
|
|
return DEMUXER_CTRL_OK;
|
2013-02-25 23:38:36 +00:00
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
case DEMUXER_CTRL_SWITCHED_TRACKS:
|
2011-07-03 12:42:04 +00:00
|
|
|
{
|
2013-07-11 17:23:31 +00:00
|
|
|
select_tracks(demuxer, 0);
|
2013-04-14 18:53:03 +00:00
|
|
|
return DEMUXER_CTRL_OK;
|
2011-07-03 12:42:04 +00:00
|
|
|
}
|
|
|
|
case DEMUXER_CTRL_IDENTIFY_PROGRAM:
|
|
|
|
{
|
|
|
|
demux_program_t *prog = arg;
|
|
|
|
AVProgram *program;
|
|
|
|
int p, i;
|
|
|
|
int start;
|
|
|
|
|
2013-04-14 18:53:03 +00:00
|
|
|
add_new_streams(demuxer);
|
|
|
|
|
2011-07-03 12:42:04 +00:00
|
|
|
prog->vid = prog->aid = prog->sid = -2;
|
|
|
|
if (priv->avfc->nb_programs < 1)
|
|
|
|
return DEMUXER_CTRL_DONTKNOW;
|
|
|
|
|
|
|
|
if (prog->progid == -1) {
|
|
|
|
p = 0;
|
|
|
|
while (p < priv->avfc->nb_programs && priv->avfc->programs[p]->id != priv->cur_program)
|
|
|
|
p++;
|
|
|
|
p = (p + 1) % priv->avfc->nb_programs;
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < priv->avfc->nb_programs; i++)
|
|
|
|
if (priv->avfc->programs[i]->id == prog->progid)
|
|
|
|
break;
|
|
|
|
if (i == priv->avfc->nb_programs)
|
2009-11-07 11:09:23 +00:00
|
|
|
return DEMUXER_CTRL_DONTKNOW;
|
2011-07-03 12:42:04 +00:00
|
|
|
p = i;
|
|
|
|
}
|
|
|
|
start = p;
|
2007-10-27 19:15:43 +00:00
|
|
|
redo:
|
2013-04-14 18:53:03 +00:00
|
|
|
prog->vid = prog->aid = prog->sid = -2;
|
2011-07-03 12:42:04 +00:00
|
|
|
program = priv->avfc->programs[p];
|
|
|
|
for (i = 0; i < program->nb_stream_indexes; i++) {
|
2013-04-14 18:53:03 +00:00
|
|
|
struct sh_stream *stream = priv->streams[program->stream_index[i]];
|
|
|
|
if (stream) {
|
|
|
|
switch (stream->type) {
|
|
|
|
case STREAM_VIDEO:
|
|
|
|
if (prog->vid == -2)
|
|
|
|
prog->vid = stream->demuxer_id;
|
|
|
|
break;
|
|
|
|
case STREAM_AUDIO:
|
|
|
|
if (prog->aid == -2)
|
|
|
|
prog->aid = stream->demuxer_id;
|
|
|
|
break;
|
|
|
|
case STREAM_SUB:
|
|
|
|
if (prog->sid == -2)
|
|
|
|
prog->sid = stream->demuxer_id;
|
|
|
|
break;
|
|
|
|
}
|
2007-10-27 19:15:43 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-03 12:42:04 +00:00
|
|
|
if (prog->progid == -1 && prog->vid == -2 && prog->aid == -2) {
|
|
|
|
p = (p + 1) % priv->avfc->nb_programs;
|
|
|
|
if (p == start)
|
|
|
|
return DEMUXER_CTRL_DONTKNOW;
|
|
|
|
goto redo;
|
|
|
|
}
|
|
|
|
priv->cur_program = prog->progid = program->id;
|
|
|
|
return DEMUXER_CTRL_OK;
|
|
|
|
}
|
2013-01-07 16:39:55 +00:00
|
|
|
case DEMUXER_CTRL_RESYNC:
|
|
|
|
/* NOTE:
|
|
|
|
*
|
|
|
|
* We actually want to call ff_read_frame_flush() here, but it is
|
|
|
|
* internal.
|
|
|
|
*
|
|
|
|
* This function call seems to do the same for now.
|
|
|
|
*
|
|
|
|
* Once ff_read_frame_flush() is exported in some way, change this to
|
|
|
|
* call the new API instead of relying on av_seek_frame() to do this
|
|
|
|
* for us.
|
|
|
|
*/
|
2013-12-13 23:51:00 +00:00
|
|
|
stream_drop_buffers(demuxer->stream);
|
2013-01-10 11:36:13 +00:00
|
|
|
avio_flush(priv->avfc->pb);
|
2013-05-03 19:32:34 +00:00
|
|
|
av_seek_frame(priv->avfc, 0, stream_tell(demuxer->stream),
|
2013-01-07 16:39:55 +00:00
|
|
|
AVSEEK_FLAG_BYTE);
|
2013-01-10 11:36:13 +00:00
|
|
|
avio_flush(priv->avfc->pb);
|
2013-01-07 16:39:55 +00:00
|
|
|
return DEMUXER_CTRL_OK;
|
2011-07-03 12:42:04 +00:00
|
|
|
default:
|
|
|
|
return DEMUXER_CTRL_NOTIMPL;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-05 19:57:47 +00:00
|
|
|
static void demux_close_lavf(demuxer_t *demuxer)
|
2004-04-11 14:26:04 +00:00
|
|
|
{
|
2011-07-03 12:42:04 +00:00
|
|
|
lavf_priv_t *priv = demuxer->priv;
|
|
|
|
if (priv) {
|
|
|
|
if (priv->avfc) {
|
|
|
|
av_freep(&priv->avfc->key);
|
2012-01-28 11:41:36 +00:00
|
|
|
avformat_close_input(&priv->avfc);
|
2004-04-26 19:55:55 +00:00
|
|
|
}
|
2013-08-04 21:21:50 +00:00
|
|
|
if (priv->pb)
|
|
|
|
av_freep(&priv->pb->buffer);
|
2007-12-22 16:22:54 +00:00
|
|
|
av_freep(&priv->pb);
|
demux_lavf: add support for libavdevice
libavdevice supports various "special" video and audio inputs, such
as screen-capture or libavfilter filter graphs.
libavdevice inputs are implemented as demuxers. They don't use the
custom stream callbacks (in AVFormatContext.pb). Instead, input
parameters are passed as filename. This means the mpv stream layer has
to be disabled. Do this by adding the pseudo stream handler avdevice://,
whose only purpose is passing the filename to demux_lavf, without
actually doing anything.
Change the logic how the filename is passed to libavformat. Remove
handling of the filename from demux_open_lavf() and move it to
lavf_check_file(). (This also fixes a possible bug when skipping the
"lavf://" prefix.)
libavdevice now can be invoked by specifying demuxer and args as in:
mpv avdevice://demuxer:args
The args are passed as filename to libavformat. When using libavdevice
demuxers, their actual meaning is highly implementation specific. They
don't refer to actual filenames.
Note:
libavdevice is disabled by default. There is one problem: libavdevice
pulls in libavfilter, which in turn causes symbol clashes with mpv
internals. The problem is that libavfilter includes a mplayer filter
bridge, which is used to interface with a set of nearly unmodified
mplayer filters copied into libavfilter. This filter bridge uses the
same symbol names as mplayer/mpv's filter chain, which results in symbol
clashes at link-time.
This can be prevented by building ffmpeg with --disable-filter=mp, but
unfortunately this is not the default.
This means linking to libavdevice (which in turn forces linking with
libavfilter by default) must be disabled. We try doing this by compiling
a test file that defines one of the clashing symbols (vf_mpi_clear).
To enable libavdevice input, ffmpeg should be built with the options:
--disable-filter=mp
and mpv with:
--enable-libavdevice
Originally, I tried to auto-detect it. But the resulting complications
in configure did't seem worth the trouble.
2012-11-30 17:41:04 +00:00
|
|
|
talloc_free(priv);
|
2011-07-03 12:42:04 +00:00
|
|
|
demuxer->priv = NULL;
|
2004-04-11 14:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-05 19:57:47 +00:00
|
|
|
|
2008-01-13 16:00:39 +00:00
|
|
|
const demuxer_desc_t demuxer_desc_lavf = {
|
2013-07-11 18:08:12 +00:00
|
|
|
.name = "lavf",
|
2013-07-12 20:12:02 +00:00
|
|
|
.desc = "libavformat",
|
2013-07-11 18:08:12 +00:00
|
|
|
.fill_buffer = demux_lavf_fill_buffer,
|
|
|
|
.open = demux_open_lavf,
|
|
|
|
.close = demux_close_lavf,
|
|
|
|
.seek = demux_seek_lavf,
|
|
|
|
.control = demux_lavf_control,
|
2007-04-14 10:03:42 +00:00
|
|
|
};
|