summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/codec_tags.c5
-rw-r--r--demux/demux.c217
-rw-r--r--demux/demux.h15
-rw-r--r--demux/demux_avi.c3
-rw-r--r--demux/demux_lavf.c257
-rw-r--r--demux/demux_mf.c9
-rw-r--r--demux/demux_mkv.c1246
-rw-r--r--demux/demux_mpg.c2
-rw-r--r--demux/demux_packet.h2
-rw-r--r--demux/demux_ts.c8
-rw-r--r--demux/ebml.c81
-rw-r--r--demux/ebml.h6
-rw-r--r--demux/matroska.h6
-rw-r--r--demux/mf.c8
-rw-r--r--demux/stheader.h30
-rw-r--r--demux/video.c4
16 files changed, 925 insertions, 974 deletions
diff --git a/demux/codec_tags.c b/demux/codec_tags.c
index 429da5582c..2af450ad07 100644
--- a/demux/codec_tags.c
+++ b/demux/codec_tags.c
@@ -103,6 +103,8 @@ static const struct mp_codec_tag mp_audio_codec_tags[] = {
{0x3 , "pcm"}, // lavf: pcm_f32le
{0xfffe , "pcm"},
// ------- internal mplayer FourCCs ------
+ {MKTAG('O', 'p', 'u', 's'), "opus"}, // demux_mkv.c
+ {MKTAG('a', 'L', 'a', 'C'), "alac"}, // demux_mkv.c
{MKTAG('S', 'a', 'd', 'x'), "adpcm_adx"},
{MKTAG('A', 'M', 'V', 'A'), "adpcm_ima_amv"},
{MKTAG('R', 'o', 'Q', 'A'), "roq_dpcm"},
@@ -308,6 +310,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},
};
@@ -349,7 +352,7 @@ static const char *lookup_tag(const struct mp_codec_tag *mp_table,
}
const struct AVCodecTag *av_tags[] = {av_table, NULL};
int id = av_codec_get_id(av_tags, tag);
- return id == CODEC_ID_NONE ? NULL : mp_codec_from_av_codec_id(id);
+ return id == AV_CODEC_ID_NONE ? NULL : mp_codec_from_av_codec_id(id);
}
void mp_set_video_codec_from_tag(struct sh_video *sh)
diff --git a/demux/demux.c b/demux/demux.c
index a99a050ee2..e1bb960e78 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;
@@ -116,8 +116,6 @@ static struct demux_packet *create_packet(size_t len)
dp->stream_pts = MP_NOPTS_VALUE;
dp->pos = 0;
dp->keyframe = false;
- dp->refcount = 1;
- dp->master = NULL;
dp->buffer = NULL;
dp->avpacket = NULL;
return dp;
@@ -131,11 +129,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 +141,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,38 +160,16 @@ 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);
+ if (dp->avpacket)
+ talloc_free(dp->avpacket);
+ else
+ free(dp->buffer);
free(dp);
}
@@ -209,20 +192,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 +241,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 +263,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 +325,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 +346,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 +361,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 +374,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 +390,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 +400,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 +428,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)
{
@@ -496,18 +470,18 @@ void ds_add_packet(demux_stream_t *ds, demux_packet_t *dp)
static void allocate_parser(AVCodecContext **avctx, AVCodecParserContext **parser, const char *format)
{
- enum CodecID codec_id = mp_codec_to_av_codec_id(format);
+ enum AVCodecID codec_id = mp_codec_to_av_codec_id(format);
switch (codec_id) {
- case CODEC_ID_AAC_LATM:
- case CODEC_ID_AC3:
- case CODEC_ID_EAC3:
- case CODEC_ID_DTS:
- case CODEC_ID_FLAC:
- case CODEC_ID_MLP:
- case CODEC_ID_MP3:
- case CODEC_ID_MP2:
- case CODEC_ID_TRUEHD:
+ case AV_CODEC_ID_AAC_LATM:
+ case AV_CODEC_ID_AC3:
+ case AV_CODEC_ID_EAC3:
+ case AV_CODEC_ID_DTS:
+ case AV_CODEC_ID_FLAC:
+ case AV_CODEC_ID_MLP:
+ case AV_CODEC_ID_MP3:
+ case AV_CODEC_ID_MP2:
+ case AV_CODEC_ID_TRUEHD:
*avctx = avcodec_alloc_context3(NULL);
if (!*avctx)
return;
@@ -519,7 +493,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 +521,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;
@@ -678,9 +652,9 @@ int ds_fill_buffer(demux_stream_t *ds)
break; // EOF
}
- if (demux->type == DEMUXER_TYPE_LAVF ||
- demux->type == DEMUXER_TYPE_MATROSKA)
- {
+ struct sh_video *sh_video = demux->video->sh;
+
+ if (sh_video && sh_video->gsh->attached_picture) {
if (demux->audio)
ds->fill_count += demux->audio->packs - apacks;
if (demux->video && demux->video->packs > vpacks)
@@ -948,6 +922,7 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
opts->correct_pts =
demux_control(demuxer, DEMUXER_CTRL_CORRECT_PTS,
NULL) == DEMUXER_CTRL_OK;
+ demuxer_sort_chapters(demuxer);
return demuxer;
} else {
// demux_mov can return playlist instead of mov
@@ -1223,7 +1198,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)
@@ -1233,11 +1212,11 @@ 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();
}
+
int new_id = demuxer->ds[type]->id;
void *new = NULL;
if (new_id >= 0) {
@@ -1248,6 +1227,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,
@@ -1278,10 +1267,10 @@ static int chapter_compare(const void *p1, const void *p2)
return 1;
else if (c1->start < c2->start)
return -1;
- return 0;
+ return c1->original_index > c2->original_index ? 1 :-1; // never equal
}
-static void demuxer_sort_chapters(demuxer_t *demuxer)
+void demuxer_sort_chapters(demuxer_t *demuxer)
{
qsort(demuxer->chapters, demuxer->num_chapters,
sizeof(struct demux_chapter), chapter_compare);
@@ -1290,24 +1279,14 @@ static void demuxer_sort_chapters(demuxer_t *demuxer)
int demuxer_add_chapter(demuxer_t *demuxer, struct bstr name,
uint64_t start, uint64_t end)
{
- if (!(demuxer->num_chapters % 32))
- demuxer->chapters = talloc_realloc(demuxer, demuxer->chapters,
- struct demux_chapter,
- demuxer->num_chapters + 32);
-
- demuxer->chapters[demuxer->num_chapters].start = start;
- demuxer->chapters[demuxer->num_chapters].end = end;
- demuxer->chapters[demuxer->num_chapters].name = name.len ?
- talloc_strndup(demuxer->chapters, name.start, name.len) :
- talloc_strdup(demuxer->chapters, mp_gtext("unknown"));
-
- demuxer->num_chapters++;
-
- if (demuxer->num_chapters > 1
- && demuxer->chapters[demuxer->num_chapters - 2].start
- < demuxer->chapters[demuxer->num_chapters - 1].start)
- demuxer_sort_chapters(demuxer);
-
+ struct demux_chapter new = {
+ .original_index = demuxer->num_chapters,
+ .start = start,
+ .end = end,
+ .name = name.len ? bstrdup0(demuxer, name)
+ : talloc_strdup(demuxer, mp_gtext("unknown")),
+ };
+ MP_TARRAY_APPEND(demuxer, demuxer->chapters, demuxer->num_chapters, new);
return 0;
}
diff --git a/demux/demux.h b/demux/demux.h
index 41551975cc..3d66139d69 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
@@ -103,6 +105,7 @@ enum timestamp_type {
#define SEEK_FACTOR (1 << 1)
#define SEEK_FORWARD (1 << 2)
#define SEEK_BACKWARD (1 << 3)
+#define SEEK_SUBPREROLL (1 << 4)
// demux_lavf can pass lavf buffers using FF_INPUT_BUFFER_PADDING_SIZE instead
#define MP_INPUT_BUFFER_PADDING_SIZE 16
@@ -182,6 +185,7 @@ typedef struct demuxer_desc {
typedef struct demux_chapter
{
+ int original_index;
uint64_t start, end;
char *name;
} demux_chapter_t;
@@ -209,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 {
@@ -281,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
@@ -303,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);
@@ -393,6 +399,7 @@ int demuxer_add_chapter(struct demuxer *demuxer, struct bstr name,
uint64_t start, uint64_t end);
int demuxer_seek_chapter(struct demuxer *demuxer, int chapter,
double *seek_pts);
+void demuxer_sort_chapters(demuxer_t *demuxer);
/// Get current chapter index if available.
int demuxer_get_current_chapter(struct demuxer *demuxer, double time_now);
@@ -412,4 +419,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 50f9f1e8f0..8a8b003680 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;
@@ -323,21 +318,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
@@ -345,16 +342,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;
@@ -369,8 +364,8 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
* heuristic makes up works with subtitles in practice.
*/
double fps;
- if (st->r_frame_rate.num)
- fps = av_q2d(st->r_frame_rate);
+ if (st->avg_frame_rate.num)
+ fps = av_q2d(st->avg_frame_rate);
else
fps = 1.0 / FFMAX(av_q2d(st->time_base),
av_q2d(st->codec->time_base) *
@@ -388,68 +383,40 @@ 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 == CODEC_ID_TEXT ||
- codec->codec_id == AV_CODEC_ID_SUBRIP)
- type = 't';
- else if (codec->codec_id == CODEC_ID_MOV_TEXT)
- type = 'm';
- else if (codec->codec_id == CODEC_ID_SSA)
- type = 'a';
- else if (codec->codec_id == CODEC_ID_DVD_SUBTITLE)
- type = 'v';
- else if (codec->codec_id == CODEC_ID_XSUB)
- type = 'x';
- else if (codec->codec_id == CODEC_ID_DVB_SUBTITLE)
- type = 'b';
- else if (codec->codec_id == CODEC_ID_DVB_TELETEXT)
- type = 'd';
- else if (codec->codec_id == 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: {
AVDictionaryEntry *ftag = av_dict_get(st->metadata, "filename",
NULL, 0);
char *filename = ftag ? ftag->value : NULL;
- if (st->codec->codec_id == CODEC_ID_TTF)
+ if (st->codec->codec_id == AV_CODEC_ID_TTF)
demuxer_add_attachment(demuxer, bstr0(filename),
bstr0("application/x-truetype-font"),
(struct bstr){codec->extradata,
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);
@@ -469,6 +436,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;
@@ -562,9 +537,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;
@@ -577,13 +550,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;
@@ -621,8 +588,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);
@@ -634,32 +599,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 1;
}
@@ -672,26 +625,22 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds)
dp = new_demux_packet_fromdata(pkt->data, pkt->size);
dp->avpacket = pkt;
- AVStream *st = priv->avfc->streams[id];
-
int64_t ts = priv->use_dts ? pkt->dts : pkt->pts;
if (ts == AV_NOPTS_VALUE && (st->disposition & AV_DISPOSITION_ATTACHED_PIC))
ts = 0;
if (ts != AV_NOPTS_VALUE) {
- dp->pts = ts * av_q2d(priv->avfc->streams[id]->time_base);
+ dp->pts = ts * av_q2d(st->time_base);
priv->last_pts = dp->pts * AV_TIME_BASE;
// always set duration for subtitles, even if AV_PKT_FLAG_KEY isn't set,
// otherwise they will stay on screen to long if e.g. ASS is demuxed
// from mkv
- if ((ds == demux->sub || (pkt->flags & AV_PKT_FLAG_KEY)) &&
+ if ((stream->type == STREAM_SUB || (pkt->flags & AV_PKT_FLAG_KEY)) &&
pkt->convergence_duration > 0)
- dp->duration = pkt->convergence_duration *
- av_q2d(priv->avfc->streams[id]->time_base);
+ dp->duration = pkt->convergence_duration * av_q2d(st->time_base);
}
dp->pos = demux->filepos;
dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY;