From d8bde114fd9685111274713c03985c72de3377b1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 9 Mar 2013 08:49:56 +0100 Subject: Prefix CODEC_ID_ with AV_ The old names have been deprecated a while ago, but were needed for supporting older ffmpeg/libav versions. The deprecated identifiers have been removed from recent Libav and FFmpeg git. This change breaks compatibility with Libav 0.8.x and equivalent FFmpeg releases. --- demux/demux_lavf.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'demux/demux_lavf.c') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 50f9f1e8f0..843bd171e4 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -403,22 +403,22 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) case AVMEDIA_TYPE_SUBTITLE: { sh_sub_t *sh_sub; char type; - if (codec->codec_id == CODEC_ID_TEXT || + if (codec->codec_id == AV_CODEC_ID_TEXT || codec->codec_id == AV_CODEC_ID_SUBRIP) type = 't'; - else if (codec->codec_id == CODEC_ID_MOV_TEXT) + else if (codec->codec_id == AV_CODEC_ID_MOV_TEXT) type = 'm'; - else if (codec->codec_id == CODEC_ID_SSA) + else if (codec->codec_id == AV_CODEC_ID_SSA) type = 'a'; - else if (codec->codec_id == CODEC_ID_DVD_SUBTITLE) + else if (codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE) type = 'v'; - else if (codec->codec_id == CODEC_ID_XSUB) + else if (codec->codec_id == AV_CODEC_ID_XSUB) type = 'x'; - else if (codec->codec_id == CODEC_ID_DVB_SUBTITLE) + else if (codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) type = 'b'; - else if (codec->codec_id == CODEC_ID_DVB_TELETEXT) + else if (codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) type = 'd'; - else if (codec->codec_id == CODEC_ID_HDMV_PGS_SUBTITLE) + else if (codec->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE) type = 'p'; else break; @@ -440,7 +440,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) 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, -- cgit v1.2.3 From dfe7b3898da2e6f9036de0c5c13dccf4a8ca45f7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 9 Mar 2013 08:52:53 +0100 Subject: demux_lavf: use avg_frame_rate instead of r_frame_rate r_frame_rate was deprecated and was finally removed from Libav and FFmpeg git. Not sure what's the correct replacement. avg_frame_rate may or may not be worse than the fallback of using the time_base as guess. The framerate is mostly unused, but needed for frame-based subtitles and for encoding. (It appears encoding guesses a timebase based on the FPS, and I'm not sure why we don't just use the source timebase.) --- demux/demux_lavf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'demux/demux_lavf.c') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 843bd171e4..ba34e7acfa 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -369,8 +369,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) * -- cgit v1.2.3 From 1e53b78b32ba342a201159afb24d43decf78ba08 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 14 Apr 2013 20:53:03 +0200 Subject: demux_lavf: simplify This removes the stream handling mess by using a single list for all stream types. One consequence is that new streams are always set to AVDISCARD_ALL, which could be an issue if packets are read before initializing other streams. However, this doesn't seem to an issue for various reasons, so we don't do anything about it. The new code strictly assumes that libavformat never removes or reorders streams once added to AVFormatContext->streams. Undefined behavior will result if it does. --- demux/demux_lavf.c | 221 ++++++++++++++++++----------------------------------- 1 file changed, 74 insertions(+), 147 deletions(-) (limited to 'demux/demux_lavf.c') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index ba34e7acfa..498f99e014 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; @@ -388,16 +383,6 @@ 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: { @@ -422,18 +407,18 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) 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 = sh->sub; + sh_sub->type = type; 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: { @@ -447,9 +432,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); @@ -469,6 +457,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 +558,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 +571,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 +609,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 +620,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 +646,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; - // append packet to DS stream: - ds_add_packet(ds, dp); + demuxer_add_packet(demux, stream, dp); return 1; } @@ -785,54 +755,17 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) 0 : (double)priv->avfc->start_time / AV_TIME_BASE; return DEMUXER_CTRL_OK; - case DEMUXER_CTRL_SWITCH_AUDIO: - case DEMUXER_CTRL_SWITCH_VIDEO: + case DEMUXER_CTRL_SWITCHED_TRACKS: { - int id = *((int *)arg); - int newid = -2; - int i, curridx = -1; - int nstreams, *pstreams; - demux_stream_t *ds; - - if (cmd == DEMUXER_CTRL_SWITCH_VIDEO) { - ds = demuxer->video; - nstreams = priv->video_streams; - pstreams = priv->vstreams; - } else { - ds = demuxer->audio; - nstreams = priv->audio_streams; - pstreams = priv->astreams; - } - for (i = 0; i < nstreams; i++) { - if (pstreams[i] == ds->id) { //current stream id - curridx = i; - break; + for (int n = 0; n < priv->num_streams; n++) { + struct sh_stream *stream = priv->streams[n]; + AVStream *st = priv->avfc->streams[n]; + if (stream && stream->type != STREAM_SUB) { + bool selected = demuxer_stream_is_selected(demuxer, stream); + st->discard = selected ? AVDISCARD_NONE : AVDISCARD_ALL; } } - - if (id == -1) { // next track - i = (curridx + 2) % (nstreams + 1) - 1; - if (i >= 0) - newid = pstreams[i]; - } else if (id >= 0 && id < nstreams) { // select track by id - i = id; - newid = pstreams[i]; - } else // no sound - i = -1; - - if (i == curridx) { - *(int *) arg = curridx < 0 ? -2 : curridx; - return DEMUXER_CTRL_OK; - } else { - ds_free_packs(ds); - if (ds->id >= 0) - priv->avfc->streams[ds->id]->discard = AVDISCARD_ALL; - ds->id = newid; - *(int *) arg = i < 0 ? -2 : i; - if (newid >= 0) - priv->avfc->streams[newid]->discard = AVDISCARD_NONE; - return DEMUXER_CTRL_OK; - } + return DEMUXER_CTRL_OK; } case DEMUXER_CTRL_AUTOSELECT_SUBTITLE: { @@ -847,6 +780,8 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) int p, i; int start; + add_new_streams(demuxer); + prog->vid = prog->aid = prog->sid = -2; if (priv->avfc->nb_programs < 1) return DEMUXER_CTRL_DONTKNOW; @@ -866,35 +801,27 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) } start = p; redo: + prog->vid = prog->aid = prog->sid = -2; program = priv->avfc->programs[p]; for (i = 0; i < program->nb_stream_indexes; i++) { - switch (priv->avfc->streams[program->stream_index[i]]->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (prog->vid == -2) - prog->vid = program->stream_index[i]; - break; - case AVMEDIA_TYPE_AUDIO: - if (prog->aid == -2) - prog->aid = program->stream_index[i]; - break; - case AVMEDIA_TYPE_SUBTITLE: - if (prog->sid == -2) - prog->sid = program->stream_index[i]; - break; + 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; + } } } - if (prog->aid >= 0 && prog->aid < MAX_A_STREAMS && - demuxer->a_streams[prog->aid]) { - sh_audio_t *sh = demuxer->a_streams[prog->aid]; - prog->aid = sh->aid; - } else - prog->aid = -2; - if (prog->vid >= 0 && prog->vid < MAX_V_STREAMS && - demuxer->v_streams[prog->vid]) { - sh_video_t *sh = demuxer->v_streams[prog->vid]; - prog->vid = sh->vid; - } else - prog->vid = -2; if (prog->progid == -1 && prog->vid == -2 && prog->aid == -2) { p = (p + 1) % priv->avfc->nb_programs; if (p == start) -- cgit v1.2.3 From 331982b99ce3b50b95ac340eb17c6116913480f3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 15 Apr 2013 21:25:21 +0200 Subject: sub, demux: identify subtitle types with the codec name Get rid of the 1-char subtitle type field. Use sh_stream->codec instead just like audio and video do. Use codec names as defined by libavcodec for simplicity, even if they're somewhat verbose and annoying. Note that ffmpeg might switch to "ass" as codec name for ASS, so we don't bother with the current silly "ssa" name. --- demux/demux_lavf.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'demux/demux_lavf.c') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 498f99e014..968e9e60c8 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -387,32 +387,11 @@ static void handle_stream(demuxer_t *demuxer, int i) } 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 = new_sh_stream(demuxer, STREAM_SUB); if (!sh) break; sh_sub = sh->sub; - sh_sub->type = type; if (codec->extradata_size) { sh_sub->extradata = malloc(codec->extradata_size); memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size); -- cgit v1.2.3 From 1bae5641ab21c0f15572dc016a8deef2a32d15b5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 21 Apr 2013 00:21:23 +0200 Subject: 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.) --- demux/demux_lavf.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'demux/demux_lavf.c') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 968e9e60c8..8a8b003680 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -701,8 +701,13 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, // 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. - avformat_seek_file(priv->avfc, -1, INT64_MIN, - priv->last_pts, priv->last_pts, avsflags); + int r = avformat_seek_file(priv->avfc, -1, INT64_MIN, + priv->last_pts, priv->last_pts, avsflags); + // Similar issue as in the normal seeking codepath. + if (r < 0) { + avformat_seek_file(priv->avfc, -1, INT64_MIN, + priv->last_pts, INT64_MAX, avsflags); + } } } -- cgit v1.2.3