summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/codec_tags.c2
-rw-r--r--demux/demux.c254
-rw-r--r--demux/demux.h19
-rw-r--r--demux/demux_avi.c3
-rw-r--r--demux/demux_lavf.c264
-rw-r--r--demux/demux_mkv.c1190
-rw-r--r--demux/demux_mpg.c2
-rw-r--r--demux/demux_packet.h2
-rw-r--r--demux/demux_ts.c13
-rw-r--r--demux/ebml.c25
-rw-r--r--demux/ebml.h4
-rw-r--r--demux/matroska.h3
-rw-r--r--demux/stheader.h30
-rw-r--r--demux/video.c4
14 files changed, 854 insertions, 961 deletions
diff --git a/demux/codec_tags.c b/demux/codec_tags.c
index 70b7a9a26e..cf7e0356be 100644
--- a/demux/codec_tags.c
+++ b/demux/codec_tags.c
@@ -102,6 +102,7 @@ static const struct mp_codec_tag mp_audio_codec_tags[] = {
{0x1 , "pcm"}, // lavf: pcm_s16le
{0x3 , "pcm"}, // lavf: pcm_f32le
{0xfffe , "pcm"},
+ {MKTAG('t', 'w', 'o', 's'), "pcm"},
// ------- internal mplayer FourCCs ------
{MKTAG('O', 'p', 'u', 's'), "opus"}, // demux_mkv.c
{MKTAG('a', 'L', 'a', 'C'), "alac"}, // demux_mkv.c
@@ -310,6 +311,7 @@ static const struct mp_codec_tag mp_video_codec_tags[] = {
{MKTAG('I', 'N', 'P', 'V'), "interplayvideo"},
{MKTAG('V', 'Q', 'A', 'V'), "ws_vqa"},
{MKTAG('C', '9', '3', 'V'), "c93"},
+ {MKTAG('V', 'P', '9', '0'), "vp9"},
{0},
};
diff --git a/demux/demux.c b/demux/demux.c
index cb3d3a5efe..64c7c73b9f 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -45,7 +45,7 @@
#error MP_INPUT_BUFFER_PADDING_SIZE is too small!
#endif
-static void clear_parser(sh_common_t *sh);
+static void clear_parser(sh_audio_t *sh);
// Demuxer list
extern const struct demuxer_desc demuxer_desc_edl;
@@ -101,6 +101,18 @@ const demuxer_desc_t *const demuxer_list[] = {
NULL
};
+static void add_stream_chapters(struct demuxer *demuxer);
+
+static int packet_destroy(void *ptr)
+{
+ struct demux_packet *dp = ptr;
+ if (dp->avpacket)
+ talloc_free(dp->avpacket);
+ else
+ free(dp->buffer);
+ return 0;
+}
+
static struct demux_packet *create_packet(size_t len)
{
if (len > 1000000000) {
@@ -108,18 +120,14 @@ static struct demux_packet *create_packet(size_t len)
"over 1 GB!\n");
abort();
}
- struct demux_packet *dp = malloc(sizeof(struct demux_packet));
- dp->len = len;
- dp->next = NULL;
- dp->pts = MP_NOPTS_VALUE;
- dp->duration = -1;
- dp->stream_pts = MP_NOPTS_VALUE;
- dp->pos = 0;
- dp->keyframe = false;
- dp->refcount = 1;
- dp->master = NULL;
- dp->buffer = NULL;
- dp->avpacket = NULL;
+ struct demux_packet *dp = talloc(NULL, struct demux_packet);
+ talloc_set_destructor(dp, packet_destroy);
+ *dp = (struct demux_packet) {
+ .len = len,
+ .pts = MP_NOPTS_VALUE,
+ .duration = -1,
+ .stream_pts = MP_NOPTS_VALUE,
+ };
return dp;
}
@@ -131,11 +139,11 @@ struct demux_packet *new_demux_packet(size_t len)
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
abort();
}
- memset(dp->buffer + len, 0, 8);
+ memset(dp->buffer + len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
return dp;
}
-// data must already have suitable padding
+// data must already have suitable padding, and does not copy the data
struct demux_packet *new_demux_packet_fromdata(void *data, size_t len)
{
struct demux_packet *dp = create_packet(len);
@@ -143,6 +151,13 @@ struct demux_packet *new_demux_packet_fromdata(void *data, size_t len)
return dp;
}
+struct demux_packet *new_demux_packet_from(void *data, size_t len)
+{
+ struct demux_packet *dp = new_demux_packet(len);
+ memcpy(dp->buffer, data, len);
+ return dp;
+}
+
void resize_demux_packet(struct demux_packet *dp, size_t len)
{
if (len > 1000000000) {
@@ -155,39 +170,13 @@ void resize_demux_packet(struct demux_packet *dp, size_t len)
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
abort();
}
- memset(dp->buffer + len, 0, 8);
+ memset(dp->buffer + len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
dp->len = len;
}
-struct demux_packet *clone_demux_packet(struct demux_packet *pack)
-{
- struct demux_packet *dp = malloc(sizeof(struct demux_packet));
- while (pack->master)
- pack = pack->master; // find the master
- memcpy(dp, pack, sizeof(struct demux_packet));
- dp->next = NULL;
- dp->refcount = 0;
- dp->master = pack;
- pack->refcount++;
- return dp;
-}
-
void free_demux_packet(struct demux_packet *dp)
{
- if (dp->master == NULL) { //dp is a master packet
- dp->refcount--;
- if (dp->refcount == 0) {
- if (dp->avpacket)
- talloc_free(dp->avpacket);
- else
- free(dp->buffer);
- free(dp);
- }
- return;
- }
- // dp is a clone:
- free_demux_packet(dp->master);
- free(dp);
+ talloc_free(dp);
}
static void free_demuxer_stream(struct demux_stream *ds)
@@ -209,20 +198,6 @@ static struct demux_stream *new_demuxer_stream(struct demuxer *demuxer,
return ds;
}
-struct sh_stream *ds_gsh(struct demux_stream *ds)
-{
- // Ideally ds would have a gsh field, but since all the old demuxers set
- // ds->sh themselves and we don't want to change them, enjoy this hack.
- if (!ds->sh)
- return NULL;
- switch (ds->stream_type) {
- case STREAM_VIDEO: return ((struct sh_video *)ds->sh)->gsh;
- case STREAM_AUDIO: return ((struct sh_audio *)ds->sh)->gsh;
- case STREAM_SUB: return ((struct sh_sub *)ds->sh)->gsh;
- }
- assert(false);
-}
-
/**
* Get demuxer description structure for a given demuxer type
*
@@ -272,32 +247,21 @@ demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
return d;
}
-const char *sh_sub_type2str(int type)
+static struct sh_stream *new_sh_stream_id(demuxer_t *demuxer,
+ enum stream_type type,
+ int stream_index,
+ int demuxer_id)
{
- switch (type) {
- case 't': return "text";
- case 'm': return "movtext";
- case 'a': return "ass";
- case 'v': return "vobsub";
- case 'x': return "xsub";
- case 'b': return "dvb";
- case 'd': return "dvb-teletext";
- case 'p': return "hdmv pgs";
+ if (demuxer->num_streams > MAX_SH_STREAMS || stream_index > MAX_SH_STREAMS) {
+ mp_msg(MSGT_DEMUXER, MSGL_WARN, "Too many streams.");
+ return NULL;
}
- return "unknown";
-}
-static struct sh_stream *new_sh_stream(demuxer_t *demuxer,
- enum stream_type type,
- int stream_index,
- int tid)
-{
struct sh_stream *sh = talloc_struct(demuxer, struct sh_stream, {
.type = type,
.demuxer = demuxer,
.index = demuxer->num_streams,
- .demuxer_id = tid, // may be overwritten by demuxer
- .tid = tid,
+ .demuxer_id = demuxer_id, // may be overwritten by demuxer
.stream_index = stream_index,
.opts = demuxer->opts,
});
@@ -305,40 +269,49 @@ static struct sh_stream *new_sh_stream(demuxer_t *demuxer,
switch (sh->type) {
case STREAM_VIDEO: {
struct sh_video *sht = talloc_zero(demuxer, struct sh_video);
- sht->vid = sh->tid;
+ sht->gsh = sh;
+ sht->opts = sh->opts;
sht->ds = demuxer->video;
sh->video = sht;
- sh->common_header = (struct sh_common *) sht;
demuxer->v_streams[sh->stream_index] = sht;
break;
}
case STREAM_AUDIO: {
struct sh_audio *sht = talloc_zero(demuxer, struct sh_audio);
- sht->aid = tid;
+ sht->gsh = sh;
+ sht->opts = sh->opts;
sht->ds = demuxer->audio;
sht->samplesize = 2;
sht->sample_format = AF_FORMAT_S16_NE;
sh->audio = sht;
- sh->common_header = (struct sh_common *) sht;
demuxer->a_streams[sh->stream_index] = sht;
break;
}
case STREAM_SUB: {
struct sh_sub *sht = talloc_zero(demuxer, struct sh_sub);
- sht->sid = tid;
+ sht->gsh = sh;
+ sht->opts = sh->opts;
sht->ds = demuxer->sub;
sh->sub = sht;
- sh->common_header = (struct sh_common *) sht;
demuxer->s_streams[sh->stream_index] = sht;
break;
}
default: assert(false);
}
- sh->common_header->opts = sh->opts;
- sh->common_header->gsh = sh;
return sh;
}
+// This is what "modern" demuxers are supposed to use.
+struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
+{
+ int num = 0;
+ for (int n = 0; n < demuxer->num_streams; n++) {
+ if (demuxer->streams[n]->type == type)
+ num++;
+ }
+ return new_sh_stream_id(demuxer, type, demuxer->num_streams, num);
+}
+
static void free_sh_stream(struct sh_stream *sh)
{
if (sh->lav_headers) {
@@ -358,7 +331,7 @@ sh_sub_t *new_sh_sub_sid(demuxer_t *demuxer, int id, int sid)
if (demuxer->s_streams[id])
mp_msg(MSGT_DEMUXER, MSGL_WARN, "Sub stream %i redefined\n", id);
else {
- new_sh_stream(demuxer, STREAM_SUB, id, sid);
+ new_sh_stream_id(demuxer, STREAM_SUB, id, sid);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SUBTITLE_ID=%d\n", sid);
}
return demuxer->s_streams[id];
@@ -379,7 +352,6 @@ static void free_sh_sub(sh_sub_t *sh)
{
mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_sub at %p\n", sh);
free(sh->extradata);
- clear_parser((sh_common_t *)sh);
free_sh_stream(sh->gsh);
}
@@ -395,7 +367,7 @@ sh_audio_t *new_sh_audio_aid(demuxer_t *demuxer, int id, int aid)
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "WARNING: Audio stream header %d redefined.\n", id);
} else {
mp_tmsg(MSGT_DEMUXER, MSGL_V, "==> Found audio stream: %d\n", id);
- new_sh_stream(demuxer, STREAM_AUDIO, id, aid);
+ new_sh_stream_id(demuxer, STREAM_AUDIO, id, aid);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_ID=%d\n", aid);
}
return demuxer->a_streams[id];
@@ -408,7 +380,7 @@ static void free_sh_audio(demuxer_t *demuxer, int id)
mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_audio at %p\n", sh);
free(sh->wf);
free(sh->codecdata);
- clear_parser((sh_common_t *)sh);
+ clear_parser(sh);
free_sh_stream(sh->gsh);
}
@@ -424,7 +396,7 @@ sh_video_t *new_sh_video_vid(demuxer_t *demuxer, int id, int vid)
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "WARNING: Video stream header %d redefined.\n", id);
else {
mp_tmsg(MSGT_DEMUXER, MSGL_V, "==> Found video stream: %d\n", id);
- new_sh_stream(demuxer, STREAM_VIDEO, id, vid);
+ new_sh_stream_id(demuxer, STREAM_VIDEO, id, vid);
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_ID=%d\n", vid);
}
return demuxer->v_streams[id];
@@ -434,7 +406,6 @@ static void free_sh_video(sh_video_t *sh)
{
mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_video at %p\n", sh);
free(sh->bih);
- clear_parser((sh_common_t *)sh);
free_sh_stream(sh->gsh);
}
@@ -463,6 +434,15 @@ void free_demuxer(demuxer_t *demuxer)
talloc_free(demuxer);
}
+void demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
+ demux_packet_t *dp)
+{
+ if (!demuxer_stream_is_selected(demuxer, stream)) {
+ free_demux_packet(dp);
+ } else {
+ ds_add_packet(demuxer->ds[stream->type], dp);
+ }
+}
void ds_add_packet(demux_stream_t *ds, demux_packet_t *dp)
{
@@ -519,7 +499,7 @@ static void allocate_parser(AVCodecContext **avctx, AVCodecParserContext **parse
}
}
-static void get_parser(sh_common_t *sh, AVCodecContext **avctx, AVCodecParserContext **parser)
+static void get_parser(sh_audio_t *sh, AVCodecContext **avctx, AVCodecParserContext **parser)
{
*avctx = NULL;
*parser = NULL;
@@ -547,7 +527,7 @@ int ds_parse(demux_stream_t *ds, uint8_t **buffer, int *len, double pts, int64_t
return av_parser_parse2(parser, avctx, buffer, len, *buffer, *len, pts, pts, pos);
}
-static void clear_parser(sh_common_t *sh)
+static void clear_parser(sh_audio_t *sh)
{
av_parser_close(sh->parser);
sh->parser = NULL;
@@ -948,6 +928,13 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
opts->correct_pts =
demux_control(demuxer, DEMUXER_CTRL_CORRECT_PTS,
NULL) == DEMUXER_CTRL_OK;
+ if (stream_manages_timeline(demuxer->stream)) {
+ // Incorrect, but fixes some behavior with DVD/BD
+ demuxer->ts_resets_possible = false;
+ // Doesn't work, because stream_pts is a "guess".
+ demuxer->accurate_seek = false;
+ }
+ add_stream_chapters(demuxer);
demuxer_sort_chapters(demuxer);
return demuxer;
} else {
@@ -998,7 +985,7 @@ struct demuxer *demux_open_withparams(struct MPOpts *opts,
// format, instead of reyling on libav to auto-detect the stream's format
// correctly.
switch (file_format) {
- //case DEMUXER_TYPE_MPEG_PS:
+ case DEMUXER_TYPE_MPEG_PS:
//case DEMUXER_TYPE_MPEG_TS:
case DEMUXER_TYPE_Y4M:
case DEMUXER_TYPE_NSV:
@@ -1097,7 +1084,7 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay,
* (nothing actually implements DEMUXER_CTRL_RESYNC now).
*/
struct stream *stream = demuxer->stream;
- if (stream->type == STREAMTYPE_DVD) {
+ if (stream_manages_timeline(stream)) {
double pts;
if (flags & SEEK_ABSOLUTE)
@@ -1224,7 +1211,11 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
struct sh_stream *stream)
{
assert(!stream || stream->type == type);
- int index = stream ? stream->tid : -2;
+
+ int old_id = demuxer->ds[type]->id;
+
+ // legacy
+ int index = stream ? stream->stream_index : -2;
if (type == STREAM_AUDIO) {
if (demux_control(demuxer, DEMUXER_CTRL_SWITCH_AUDIO, &index)
== DEMUXER_CTRL_NOTIMPL)
@@ -1234,10 +1225,7 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
== DEMUXER_CTRL_NOTIMPL)
demuxer->video->id = index;
} else if (type == STREAM_SUB) {
- int index2 = stream ? stream->stream_index : -2;
- if (demuxer->ds[type]->id != index2)
- ds_free_packs(demuxer->ds[type]);
- demuxer->ds[type]->id = index2;
+ demuxer->ds[type]->id = index;
} else {
abort();
}
@@ -1252,6 +1240,16 @@ void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type,
}
}
demuxer->ds[type]->sh = new;
+
+ if (old_id != new_id) {
+ ds_free_packs(demuxer->ds[type]);
+ demux_control(demuxer, DEMUXER_CTRL_SWITCHED_TRACKS, NULL);
+ }
+}
+
+bool demuxer_stream_is_selected(struct demuxer *d, struct sh_stream *stream)
+{
+ return stream && d->ds[stream->type]->id == stream->stream_index;
}
int demuxer_add_attachment(demuxer_t *demuxer, struct bstr name,
@@ -1298,13 +1296,26 @@ int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name,
.original_index = demuxer->num_chapters,
.start = start,
.end = end,
- .name = name.len ? bstrdup0(demuxer, name)
- : talloc_strdup(demuxer, mp_gtext("unknown")),
+ .name = name.len ? bstrdup0(demuxer, name) : NULL,
};
MP_TARRAY_APPEND(demuxer, demuxer->chapters, demuxer->num_chapters, new);
return 0;
}
+static void add_stream_chapters(struct demuxer *demuxer)
+{
+ if (demuxer->num_chapters)
+ return;
+ int num_chapters = demuxer_chapter_count(demuxer);
+ for (int n = 0; n < num_chapters; n++) {
+ double p = n;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_CHAPTER_TIME, &p)
+ != STREAM_OK)
+ return;
+ demuxer_add_chapter(demuxer, bstr0(""), p * 1e9, 0);
+ }
+}
+
/**
* \brief demuxer_seek_chapter() seeks to a chapter in two possible ways:
* either using the demuxer->chapters structure set by the demuxer
@@ -1316,22 +1327,22 @@ int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name,
int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, double *seek_pts)
{
- int ris;
-
- if (!demuxer->num_chapters || !demuxer->chapters) {
- demux_flush(demuxer);
+ int ris = STREAM_UNSUPPORTED;
+ if (demuxer->num_chapters == 0)
ris = stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_CHAPTER,
&chapter);
- if (ris != STREAM_UNSUPPORTED)
- demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL);
+
+ if (ris != STREAM_UNSUPPORTED) {
+ demux_flush(demuxer);
+ demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL);
// exit status may be ok, but main() doesn't have to seek itself
// (because e.g. dvds depend on sectors, not on pts)
*seek_pts = -1.0;
- return ris != STREAM_UNSUPPORTED ? chapter : -1;
- } else { // chapters structure is set in the demuxer
+ return chapter;
+ } else {
if (chapter >= demuxer->num_chapters)
return -1;
if (chapter < 0)
@@ -1370,12 +1381,10 @@ char *demuxer_chapter_name(demuxer_t *demuxer, int chapter)
return NULL;
}
-float demuxer_chapter_time(demuxer_t *demuxer, int chapter, float *end)
+double demuxer_chapter_time(demuxer_t *demuxer, int chapter)
{
if (demuxer->num_chapters && demuxer->chapters && chapter >= 0
&& chapter < demuxer->num_chapters) {
- if (end)
- *end = demuxer->chapters[chapter].end / 1e9;
return demuxer->chapters[chapter].start / 1e9;
}
return -1.0;
@@ -1393,6 +1402,27 @@ int demuxer_chapter_count(demuxer_t *demuxer)
return demuxer->num_chapters;
}
+double demuxer_get_time_length(struct demuxer *demuxer)
+{
+ double len;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) > 0)
+ return len;
+ // <= 0 means DEMUXER_CTRL_NOTIMPL or DEMUXER_CTRL_DONTKNOW
+ if (demux_control(demuxer, DEMUXER_CTRL_GET_TIME_LENGTH, &len) > 0)
+ return len;
+ return -1;
+}
+
+double demuxer_get_start_time(struct demuxer *demuxer)
+{
+ double time;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_START_TIME, &time) > 0)
+ return time;
+ if (demux_control(demuxer, DEMUXER_CTRL_GET_START_TIME, &time) > 0)
+ return time;
+ return 0;
+}
+
int demuxer_angles_count(demuxer_t *demuxer)
{
int ris, angles = -1;
diff --git a/demux/demux.h b/demux/demux.h
index c922dc8bb5..886252fa85 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -90,6 +90,8 @@ enum timestamp_type {
#define DEMUXER_CTRL_DONTKNOW 0
#define DEMUXER_CTRL_OK 1
#define DEMUXER_CTRL_GUESS 2
+
+#define DEMUXER_CTRL_SWITCHED_TRACKS 9
#define DEMUXER_CTRL_GET_TIME_LENGTH 10
#define DEMUXER_CTRL_GET_START_TIME 11
#define DEMUXER_CTRL_SWITCH_AUDIO 12
@@ -211,6 +213,8 @@ typedef struct demux_attachment
struct demuxer_params {
unsigned char (*matroska_wanted_uids)[16];
+ int matroska_wanted_segment;
+ bool *matroska_was_valid;
};
typedef struct demuxer {
@@ -283,8 +287,8 @@ typedef struct {
struct demux_packet *new_demux_packet(size_t len);
// data must already have suitable padding
struct demux_packet *new_demux_packet_fromdata(void *data, size_t len);
+struct demux_packet *new_demux_packet_from(void *data, size_t len);
void resize_demux_packet(struct demux_packet *dp, size_t len);
-struct demux_packet *clone_demux_packet(struct demux_packet *pack);
void free_demux_packet(struct demux_packet *dp);
#ifndef SIZE_MAX
@@ -305,8 +309,8 @@ struct demuxer *new_demuxer(struct MPOpts *opts, struct stream *stream,
char *filename);
void free_demuxer(struct demuxer *demuxer);
-struct sh_stream *ds_gsh(struct demux_stream *ds);
-
+void demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
+ demux_packet_t *dp);
void ds_add_packet(struct demux_stream *ds, struct demux_packet *dp);
void ds_read_packet(struct demux_stream *ds, struct stream *stream, int len,
double pts, int64_t pos, bool keyframe);
@@ -397,12 +401,15 @@ int demuxer_seek_chapter(struct demuxer *demuxer, int chapter,
double *seek_pts);
void demuxer_sort_chapters(demuxer_t *demuxer);
+double demuxer_get_time_length(struct demuxer *demuxer);
+double demuxer_get_start_time(struct demuxer *demuxer);
+
/// Get current chapter index if available.
int demuxer_get_current_chapter(struct demuxer *demuxer, double time_now);
/// Get chapter name by index if available.
char *demuxer_chapter_name(struct demuxer *demuxer, int chapter);
-/// Get chapter start time and end time by index if available.
-float demuxer_chapter_time(struct demuxer *demuxer, int chapter, float *end);
+/// Get chapter start time by index if available.
+double demuxer_chapter_time(struct demuxer *demuxer, int chapter);
/// Get total chapter number.
int demuxer_chapter_count(struct demuxer *demuxer);
/// Get current angle index.
@@ -415,4 +422,6 @@ int demuxer_angles_count(struct demuxer *demuxer);
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
enum stream_type t, int id);
+bool demuxer_stream_is_selected(struct demuxer *d, struct sh_stream *stream);
+
#endif /* MPLAYER_DEMUXER_H */
diff --git a/demux/demux_avi.c b/demux/demux_avi.c
index fbce13f707..daf542bfac 100644
--- a/demux/demux_avi.c
+++ b/demux/demux_avi.c
@@ -652,8 +652,7 @@ static void demux_seek_avi(demuxer_t *demuxer, float rel_seek_secs,
int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
if(avi_stream_id(id)==d_video->id) ++d_video->pack_no;
}
- priv->video_pack_no=
- sh_video->num_frames=sh_video->num_frames_decoded=d_video->pack_no;
+ priv->video_pack_no=d_video->pack_no;
priv->avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
d_video->pos=video_chunk_pos;
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 9bfafe3257..279f7f7b33 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -69,16 +69,11 @@ typedef struct lavf_priv {
AVFormatContext *avfc;
AVIOContext *pb;
uint8_t buffer[BIO_BUFFER_SIZE];
- int audio_streams;
- int video_streams;
- int sub_streams;
int autoselect_sub;
int64_t last_pts;
- int astreams[MAX_A_STREAMS];
- int vstreams[MAX_V_STREAMS];
- int sstreams[MAX_S_STREAMS];
+ struct sh_stream **streams; // NULL for unknown streams
+ int num_streams;
int cur_program;
- int nb_streams_last;
bool use_dts;
bool seek_by_bytes;
int bitrate;
@@ -292,6 +287,8 @@ success:
static bool matches_avinputformat_name(struct lavf_priv *priv,
const char *name)
{
+ // At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
+ // on "," in general.
const char *avifname = priv->avif->name;
while (1) {
const char *next = strchr(avifname, ',');
@@ -323,21 +320,23 @@ static void parse_cryptokey(AVFormatContext *avfc, const char *str)
*key++ = (char2int(str[0]) << 4) | char2int(str[1]);
}
-static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
+static void handle_stream(demuxer_t *demuxer, int i)
{
lavf_priv_t *priv = demuxer->priv;
+ AVFormatContext *avfc = priv->avfc;
AVStream *st = avfc->streams[i];
AVCodecContext *codec = st->codec;
struct sh_stream *sh = NULL;
+ st->discard = AVDISCARD_ALL;
+
switch (codec->codec_type) {
case AVMEDIA_TYPE_AUDIO: {
- sh_audio_t *sh_audio = new_sh_audio_aid(demuxer, i, priv->audio_streams);
- if (!sh_audio)
+ sh = new_sh_stream(demuxer, STREAM_AUDIO);
+ if (!sh)
break;
- sh = sh_audio->gsh;
- priv->astreams[priv->audio_streams] = i;
- sh_audio->ds = demuxer->audio;
+ sh_audio_t *sh_audio = sh->audio;
+
sh_audio->format = codec->codec_tag;
// probably unneeded
@@ -347,16 +346,14 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
sh_audio->samplerate = codec->sample_rate;
sh_audio->i_bps = codec->bit_rate / 8;
- st->discard = AVDISCARD_ALL;
- priv->audio_streams++;
break;
}
case AVMEDIA_TYPE_VIDEO: {
- sh_video_t *sh_video = new_sh_video_vid(demuxer, i, priv->video_streams);
- if (!sh_video)
+ sh = new_sh_stream(demuxer, STREAM_VIDEO);
+ if (!sh)
break;
- sh = sh_video->gsh;
- priv->vstreams[priv->video_streams] = i;
+ sh_video_t *sh_video = sh->video;
+
if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
sh_video->gsh->attached_picture = true;
@@ -390,52 +387,21 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
mp_msg(MSGT_DEMUX, MSGL_DBG2, "aspect= %d*%d/(%d*%d)\n",
codec->width, codec->sample_aspect_ratio.num,
codec->height, codec->sample_aspect_ratio.den);
-
- sh_video->ds = demuxer->video;
- if (demuxer->video->id != priv->video_streams
- && demuxer->video->id != -1)
- st->discard = AVDISCARD_ALL;
- else {
- demuxer->video->id = i;
- demuxer->video->sh = demuxer->v_streams[i];
- }
- priv->video_streams++;
break;
}
case AVMEDIA_TYPE_SUBTITLE: {
sh_sub_t *sh_sub;
- char type;
- if (codec->codec_id == AV_CODEC_ID_TEXT ||
- codec->codec_id == AV_CODEC_ID_SUBRIP)
- type = 't';
- else if (codec->codec_id == AV_CODEC_ID_MOV_TEXT)
- type = 'm';
- else if (codec->codec_id == AV_CODEC_ID_SSA)
- type = 'a';
- else if (codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
- type = 'v';
- else if (codec->codec_id == AV_CODEC_ID_XSUB)
- type = 'x';
- else if (codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
- type = 'b';
- else if (codec->codec_id == AV_CODEC_ID_DVB_TELETEXT)
- type = 'd';
- else if (codec->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE)
- type = 'p';
- else
- break;
- sh_sub = new_sh_sub_sid(demuxer, i, priv->sub_streams);
- if (!sh_sub)
+ sh = new_sh_stream(demuxer, STREAM_SUB);
+ if (!sh)
break;
- sh = sh_sub->gsh;
- priv->sstreams[priv->sub_streams] = i;
- sh_sub->type = type;
+ sh_sub = sh->sub;
+
if (codec->extradata_size) {
sh_sub->extradata = malloc(codec->extradata_size);
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
sh_sub->extradata_len = codec->extradata_size;
}
- priv->sub_streams++;
+ st->discard = AVDISCARD_DEFAULT;
break;
}
case AVMEDIA_TYPE_ATTACHMENT: {
@@ -449,9 +415,12 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
codec->extradata_size});
break;
}
- default:
- st->discard = AVDISCARD_ALL;
+ default: ;
}
+
+ assert(priv->num_streams == i); // directly mapped
+ MP_TARRAY_APPEND(priv, priv->streams, priv->num_streams, sh);
+
if (sh) {
sh->codec = mp_codec_from_av_codec_id(codec->codec_id);
sh->lav_headers = avcodec_alloc_context3(codec->codec);
@@ -460,7 +429,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
if (st->disposition & AV_DISPOSITION_DEFAULT)
sh->default_track = 1;
- if (matches_avinputformat_name(priv, "mpeg"))
+ if (matches_avinputformat_name(priv, "mpeg") ||
+ matches_avinputformat_name(priv, "mpegts"))
sh->demuxer_id = st->id;
AVDictionaryEntry *title = av_dict_get(st->metadata, "title", NULL, 0);
if (title && title->value)
@@ -471,6 +441,14 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
}
}
+// 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);
+}
+
static demuxer_t *demux_open_lavf(demuxer_t *demuxer)
{
struct MPOpts *opts = demuxer->opts;
@@ -564,9 +542,7 @@ static demuxer_t *demux_open_lavf(demuxer_t *demuxer)
start, end);
}
- for (i = 0; i < avfc->nb_streams; i++)
- handle_stream(demuxer, avfc, i);
- priv->nb_streams_last = avfc->nb_streams;
+ add_new_streams(demuxer);
if (avfc->nb_programs) {
int p;
@@ -579,13 +555,7 @@ static demuxer_t *demux_open_lavf(demuxer_t *demuxer)
}
}
- mp_msg(MSGT_HEADER, MSGL_V, "LAVF: %d audio and %d video streams found\n",
- priv->audio_streams, priv->video_streams);
mp_msg(MSGT_HEADER, MSGL_V, "LAVF: build %d\n", LIBAVFORMAT_BUILD);
- demuxer->audio->id = -2; // wait for higher-level code to select track
- if (!priv->video_streams) {
- demuxer->video->id = -2; // audio-only / sub-only
- }
demuxer->ts_resets_possible = priv->avif->flags & AVFMT_TS_DISCONT;
@@ -623,8 +593,6 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds)
{
lavf_priv_t *priv = demux->priv;
demux_packet_t *dp;
- demux_stream_t *ds;
- int id;
mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_lavf_fill_buffer()\n");
demux->filepos = stream_tell(demux->stream);
@@ -636,32 +604,20 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds)
}
talloc_set_destructor(pkt, destroy_avpacket);
- // handle any new streams that might have been added
- for (id = priv->nb_streams_last; id < priv->avfc->nb_streams; id++)
- handle_stream(demux, priv->avfc, id);
-
- priv->nb_streams_last = priv->avfc->nb_streams;
+ add_new_streams(demux);
- id = pkt->stream_index;
+ assert(pkt->stream_index >= 0 && pkt->stream_index < priv->num_streams);
+ AVStream *st = priv->avfc->streams[pkt->stream_index];
+ struct sh_stream *stream = priv->streams[pkt->stream_index];
- assert(id >= 0 && id < MAX_S_STREAMS);
- if (demux->s_streams[id] && demux->sub->id == -1 &&
- demux->s_streams[id]->gsh->demuxer_id == priv->autoselect_sub)
+ if (stream && stream->type == STREAM_SUB && demux->sub->id < 0 &&
+ stream->demuxer_id == priv->autoselect_sub)
{
priv->autoselect_sub = -1;
- demux->sub->id = id;
- }
-
- if (id == demux->audio->id) {
- // audio
- ds = demux->audio;
- } else if (id == demux->video->id) {
- // video
- ds = demux->video;
- } else if (id == demux->sub->id) {
- // subtitle
- ds = demux->sub;
- } else {
+ demux->sub->id = stream->stream_index;
+ }
+
+ if (!demuxer_stream_is_selected(demux, stream)) {
talloc_free(pkt);
return