diff --git a/libavformat/isom.h b/libavformat/isom.h index b4f0202a77..d233839dab 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -53,6 +53,12 @@ typedef struct MOVStsc { int id; } MOVStsc; +typedef struct MOVElst { + int64_t duration; + int64_t time; + float rate; +} MOVElst; + typedef struct MOVDref { uint32_t type; char *path; @@ -121,6 +127,8 @@ typedef struct MOVStreamContext { MOVStsc *stsc_data; unsigned int stps_count; unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop + MOVElst *elst_data; + unsigned int elst_count; int ctts_index; int ctts_sample; unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom @@ -131,8 +139,6 @@ typedef struct MOVStreamContext { unsigned int keyframe_count; int *keyframes; int time_scale; - int64_t empty_duration; ///< empty duration of the first edit list entry - int64_t start_time; ///< start time of the media int64_t time_offset; ///< time offset of the edit list entries int current_sample; unsigned int bytes_per_frame; diff --git a/libavformat/mov.c b/libavformat/mov.c index 4cfeb36dc6..a509932618 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2268,11 +2268,32 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int i, j; uint64_t stream_size = 0; + if (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 + + for (i = 0; i < sc->elst_count; i++) { + const MOVElst *e = &sc->elst_data[i]; + if (i == 0 && e->time == -1) { + /* if empty, the first entry is the start time of the stream + * relative to the presentation itself */ + empty_duration = e->duration; + edit_start_index = 1; + } else if (i == edit_start_index && e->time >= 0) { + start_time = e->time; + } else + unsupported = 1; + } + if (unsupported) + av_log(mov->fc, AV_LOG_WARNING, "multiple edit list entries, " + "a/v desync might occur, patch welcome\n"); + /* adjust first dts according to edit list */ - if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) { - if (sc->empty_duration) - sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale); - sc->time_offset = sc->start_time - sc->empty_duration; + if ((empty_duration || start_time) && mov->time_scale > 0) { + if (empty_duration) + empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale); + sc->time_offset = start_time - empty_duration; current_dts = -sc->time_offset; if (sc->ctts_count>0 && sc->stts_count>0 && sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) { @@ -2282,6 +2303,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) st->codec->has_b_frames = 1; } } + } /* only use old uncompressed audio chunk demuxing when stts specifies it */ if (!(st->codec->codec_type == AVMEDIA_TYPE_AUDIO && @@ -2626,6 +2648,7 @@ 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; @@ -3190,8 +3213,7 @@ free_and_return: static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; - int i, edit_count, version, edit_start_index = 0; - int unsupported = 0; + int i, edit_count, version; if (c->fc->nb_streams < 1 || c->ignore_editlist) return 0; @@ -3201,37 +3223,32 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb24(pb); /* flags */ edit_count = avio_rb32(pb); /* entries */ - if ((uint64_t)edit_count*12+8 > atom.size) - return AVERROR_INVALIDDATA; + if (!edit_count) + return 0; + if (sc->elst_data) + av_log(c->fc, AV_LOG_WARNING, "Duplicated ELST atom\n"); + av_free(sc->elst_data); + sc->elst_count = 0; + sc->elst_data = av_malloc_array(edit_count, sizeof(*sc->elst_data)); + if (!sc->elst_data) + return AVERROR(ENOMEM); av_dlog(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count); - for (i=0; ieof_reached; i++) { + MOVElst *e = &sc->elst_data[i]; + if (version == 1) { - duration = avio_rb64(pb); - time = avio_rb64(pb); + e->duration = avio_rb64(pb); + e->time = avio_rb64(pb); } else { - duration = avio_rb32(pb); /* segment duration */ - time = (int32_t)avio_rb32(pb); /* media time */ + e->duration = avio_rb32(pb); /* segment duration */ + e->time = (int32_t)avio_rb32(pb); /* media time */ } - rate = avio_rb32(pb); - if (i == 0 && time == -1) { - sc->empty_duration = duration; - edit_start_index = 1; - } else if (i == edit_start_index && time >= 0) - sc->start_time = time; - else - unsupported = 1; - + e->rate = avio_rb32(pb) / 65536.0; av_dlog(c->fc, "duration=%"PRId64" time=%"PRId64" rate=%f\n", - duration, time, rate / 65536.0); + e->duration, e->time, e->rate); } - - if (unsupported) - av_log(c->fc, AV_LOG_WARNING, "multiple edit list entries, " - "a/v desync might occur, patch welcome\n"); + sc->elst_count = i; return 0; } @@ -3746,6 +3763,7 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->keyframes); av_freep(&sc->stts_data); av_freep(&sc->stps_data); + av_freep(&sc->elst_data); av_freep(&sc->rap_group); av_freep(&sc->display_matrix); }