From ef784dee016c6e47eb58bb8697f19fa1157b5e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Mon, 1 Dec 2014 17:25:09 +0100 Subject: [PATCH] avformat/RFC/WIP: add basic timeline support --- ffmpeg.c | 3 +++ ffplay.c | 3 +++ libavcodec/avcodec.h | 1 + libavformat/mov.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index eef774b..a3ec228 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2206,6 +2206,9 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt) if (ret < 0) return ret; + if (got_output && ist->decoded_frame && (avpkt.flags & AV_PKT_FLAG_NOPRESENTATION)) + got_output = 0; + avpkt.dts= avpkt.pts= AV_NOPTS_VALUE; diff --git a/ffplay.c b/ffplay.c index 1914a66..c28a004 100644 --- a/ffplay.c +++ b/ffplay.c @@ -610,6 +610,9 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) { break; } + if (got_frame && frame && (d->pkt_temp.flags & AV_PKT_FLAG_NOPRESENTATION)) + got_frame = 0; + if (ret < 0) { d->packet_pending = 0; } else { diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index dabae1b..b723deb 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1195,6 +1195,7 @@ typedef struct AVPacket { } AVPacket; #define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted +#define AV_PKT_FLAG_NOPRESENTATION 0x0010 ///< The packet should be decoded but ignored for presentation enum AVSideDataParamChangeFlags { AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, diff --git a/libavformat/mov.c b/libavformat/mov.c index 33c491a..27954fb 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2241,8 +2241,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int stps_index = 0; unsigned int i, j; uint64_t stream_size = 0; - - if (sc->elst_count) { + if (0 && sc->elst_count) { int i, edit_start_index = 0, unsupported = 0; int64_t empty_duration = 0; // empty duration of the first edit list entry int64_t start_time = 0; // start time of the media @@ -2622,7 +2621,6 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_freep(&sc->keyframes); av_freep(&sc->stts_data); av_freep(&sc->stps_data); - av_freep(&sc->elst_data); av_freep(&sc->rap_group); return 0; @@ -4057,6 +4055,67 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) return sample; } +static void packet_honor_timeline(const MOVElst *elst, int elst_count, AVPacket *pkt) +{ + int i; + int64_t total_drop_time = 0; + + //av_log(0,0,"honor timeline elst=%p elst_count=%d pts=%"PRId64"\n", elst, elst_count, pkt->pts); + + if (!elst || !elst_count || pkt->pts == AV_NOPTS_VALUE) + return; + + /* If the first segment is an empty entry, the duration is the start time + * of the stream relative to the presentation itself */ + if (elst[0].time == -1) { + const int64_t empty_initial_duration = elst[0].duration; + pkt->pts += empty_initial_duration; + //if (pkt->dts != AV_NOPTS_VALUE) + // pkt->dts += empty_initial_duration; + + av_log(0,0,"initial empty duration: %"PRId64"\n", empty_initial_duration); + + /* If there is only this special entry, we can consider that the rest + * should be displayed */ + if (elst_count == 1) + return; + } + + for (i = 0; i < elst_count; i++) { + int64_t gap; + const MOVElst *segment = &elst[i]; + const MOVElst *next = i < elst_count - 1 ? &elst[i + 1] : NULL; + const MOVElst *prev = i > 0 ? &elst[i - 1] : NULL; + int64_t end = segment->duration ? segment->time + segment->duration : -1; + + if (!segment->duration && next) + end = next->time; + + if (prev) gap = segment->time - prev->time - prev->duration; + else gap = segment->time; + + total_drop_time += gap * segment->rate; + + if (pkt->pts >= segment->time && (end == -1 || pkt->pts <= end)) + break; + } + + if (i == elst_count) { + pkt->flags |= AV_PKT_FLAG_NOPRESENTATION; + av_log(0,0,"pts=%"PRId64" -> not part of the presentation\n", pkt->pts); + } else { + if (total_drop_time) + av_log(0,0,"[%"PRId64"] pts:%"PRId64"->%"PRId64" dts:%"PRId64"->%"PRId64"\n", + -total_drop_time, + pkt->pts, pkt->pts - total_drop_time, + pkt->dts, pkt->dts - total_drop_time); + pkt->pts -= total_drop_time; + //if (pkt->dts != AV_NOPTS_VALUE) + // pkt->dts -= total_drop_time; + // TODO: if audio, add a side data to truncate + } +} + static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) { MOVContext *mov = s->priv_data; @@ -4143,6 +4202,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) goto retry; pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0; pkt->pos = sample->pos; + packet_honor_timeline(sc->elst_data, sc->elst_count, pkt); av_dlog(s, "stream %d, pts %"PRId64", dts %"PRId64", pos 0x%"PRIx64", duration %d\n", pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration); return 0; -- 2.1.3