diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/codec_tags.c | 2 | ||||
-rw-r--r-- | demux/demux.c | 254 | ||||
-rw-r--r-- | demux/demux.h | 19 | ||||
-rw-r--r-- | demux/demux_avi.c | 3 | ||||
-rw-r--r-- | demux/demux_lavf.c | 264 | ||||
-rw-r--r-- | demux/demux_mkv.c | 1190 | ||||
-rw-r--r-- | demux/demux_mpg.c | 2 | ||||
-rw-r--r-- | demux/demux_packet.h | 2 | ||||
-rw-r--r-- | demux/demux_ts.c | 13 | ||||
-rw-r--r-- | demux/ebml.c | 25 | ||||
-rw-r--r-- | demux/ebml.h | 4 | ||||
-rw-r--r-- | demux/matroska.h | 3 | ||||
-rw-r--r-- | demux/stheader.h | 30 | ||||
-rw-r--r-- | demux/video.c | 4 |
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 |