2015-10-04 1:57 GMT+09:00 Rodger Combs <rodger.co...@gmail.com>: > Fixes trac #3842 > --- > libavformat/isom.h | 2 + > libavformat/mov.c | 250 > ++++++++++++++++++++++++++++++++++++++++++++--------- > 2 files changed, 213 insertions(+), 39 deletions(-) > > diff --git a/libavformat/isom.h b/libavformat/isom.h > index aee9d6e..6e921c0 100644 > --- a/libavformat/isom.h > +++ b/libavformat/isom.h > @@ -103,6 +103,7 @@ typedef struct MOVSbgp { > typedef struct MOVFragmentIndexItem { > int64_t moof_offset; > int64_t time; > + int headers_read; > } MOVFragmentIndexItem; > > typedef struct MOVFragmentIndex { > @@ -197,6 +198,7 @@ typedef struct MOVContext { > int has_looked_for_mfra; > MOVFragmentIndex** fragment_index_data; > unsigned fragment_index_count; > + int fragment_index_complete; > int atom_depth; > unsigned int aax_mode; ///< 'aax' file has been detected > uint8_t file_key[20]; > diff --git a/libavformat/mov.c b/libavformat/mov.c > index da170a6..5aa7491 100644 > --- a/libavformat/mov.c > +++ b/libavformat/mov.c > @@ -3349,7 +3349,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext > *pb, MOVAtom atom) > MOVFragment *frag = &c->fragment; > MOVTrackExt *trex = NULL; > MOVFragmentIndex* index = NULL; > - int flags, track_id, i; > + int flags, track_id, i, found = 0; > > avio_r8(pb); /* version */ > flags = avio_rb24(pb); > @@ -3367,15 +3367,6 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext > *pb, MOVAtom atom) > av_log(c->fc, AV_LOG_ERROR, "could not find corresponding > trex\n"); > return AVERROR_INVALIDDATA; > } > - for (i = 0; i < c->fragment_index_count; i++) { > - MOVFragmentIndex* candidate = c->fragment_index_data[i]; > - if (candidate->track_id == frag->track_id) { > - av_log(c->fc, AV_LOG_DEBUG, > - "found fragment index for track %u\n", frag->track_id); > - index = candidate; > - break; > - } > - } > > frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ? > avio_rb64(pb) : flags & > MOV_TFHD_DEFAULT_BASE_IS_MOOF ? > @@ -3389,23 +3380,32 @@ static int mov_read_tfhd(MOVContext *c, > AVIOContext *pb, MOVAtom atom) > frag->flags = flags & MOV_TFHD_DEFAULT_FLAGS ? > avio_rb32(pb) : trex->flags; > frag->time = AV_NOPTS_VALUE; > - if (index) { > - int i, found = 0; > - for (i = index->current_item; i < index->item_count; i++) { > - if (frag->implicit_offset == index->items[i].moof_offset) { > - av_log(c->fc, AV_LOG_DEBUG, "found fragment index entry " > - "for track %u and moof_offset %"PRId64"\n", > - frag->track_id, index->items[i].moof_offset); > - frag->time = index->items[i].time; > - index->current_item = i + 1; > - found = 1; > + for (i = 0; i < c->fragment_index_count; i++) { > + int j; > + MOVFragmentIndex* candidate = c->fragment_index_data[i]; > + if (candidate->track_id == frag->track_id) { > + av_log(c->fc, AV_LOG_DEBUG, > + "found fragment index for track %u\n", frag->track_id); > + index = candidate; > + for (j = index->current_item; j < index->item_count; j++) { > + if (frag->implicit_offset == index->items[j].moof_offset) > { > + av_log(c->fc, AV_LOG_DEBUG, "found fragment index > entry " > + "for track %u and moof_offset %"PRId64"\n", > + frag->track_id, index->items[j].moof_offset); > + frag->time = index->items[j].time; > + index->current_item = j + 1; > + found = 1; > + break; > + } > } > + if (found) > + break; > } > - if (!found) { > - av_log(c->fc, AV_LOG_WARNING, "track %u has a fragment index " > - "but it doesn't have an (in-order) entry for > moof_offset " > - "%"PRId64"\n", frag->track_id, frag->implicit_offset); > - } > + } > + if (index && !found) { > + av_log(c->fc, AV_LOG_DEBUG, "track %u has a fragment index but " > + "it doesn't have an (in-order) entry for moof_offset " > + "%"PRId64"\n", frag->track_id, frag->implicit_offset); > } > av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags); > return 0; > @@ -3596,7 +3596,99 @@ static int mov_read_trun(MOVContext *c, AVIOContext > *pb, MOVAtom atom) > return AVERROR_EOF; > > frag->implicit_offset = offset; > - st->duration = sc->track_end = dts + sc->time_offset; > + > + sc->track_end = dts + sc->time_offset; > + if (st->duration < sc->track_end) > + st->duration = sc->track_end; > + > + return 0; > +} > + > +static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) > +{ > + int64_t offset = avio_tell(pb) + atom.size, pts; > + uint8_t version; > + unsigned i, track_id; > + AVStream *st = NULL; > + MOVStreamContext *sc; > + MOVFragmentIndex *index; > + MOVFragmentIndex **tmp; > + AVRational timescale; > + > + version = avio_r8(pb); > + if (version > 1) > + return AVERROR_PATCHWELCOME; > + > + avio_rb24(pb); // flags > + > + track_id = avio_rb32(pb); // Reference ID > + for (i = 0; i < c->fc->nb_streams; i++) { > + if (c->fc->streams[i]->id == track_id) { > + st = c->fc->streams[i]; > + break; > + } > + } > + if (!st) { > + av_log(c->fc, AV_LOG_ERROR, "could not find corresponding track > id %d\n", track_id); > + return AVERROR_INVALIDDATA; > + } > + > + sc = st->priv_data; > + > + timescale = av_make_q(1, avio_rb32(pb)); > + > + if (version == 0) { > + pts = avio_rb32(pb); > + offset += avio_rb32(pb); > + } else { > + pts = avio_rb64(pb); > + offset += avio_rb64(pb); > + } > + > + avio_rb16(pb); // reserved > + > + index = av_mallocz(sizeof(MOVFragmentIndex)); > + if (!index) { > + return AVERROR(ENOMEM); > + } > + > + index->track_id = track_id; > + > + index->item_count = avio_rb16(pb); > + index->items = av_mallocz_array( > + index->item_count, sizeof(MOVFragmentIndexItem)); > + > + if (!index->items) { > + av_freep(&index); > + return AVERROR(ENOMEM); > + } > + > + tmp = av_realloc_array(c->fragment_index_data, > + c->fragment_index_count + 1, > + sizeof(MOVFragmentIndex*)); > + if (!tmp) { > + av_freep(&index->items); > + av_freep(&index); > + return AVERROR(ENOMEM); > + } > + c->fragment_index_data = tmp; > + c->fragment_index_data[c->fragment_index_count++] = index; > + > + for (i = 0; i < index->item_count; i++) { > + uint32_t size = avio_rb32(pb) & 0x7FFFFFFF; >
I'd prefer you write log to tell sidx atom reference is not implemented yet and patches welcome if you are going to implement it currently. > + uint32_t duration = avio_rb32(pb); > + avio_rb32(pb); // sap_flags > + index->items[i].moof_offset = offset; > + index->items[i].time = av_rescale_q(pts, st->time_base, > timescale); > + offset += size; > + pts += duration; > + } > + > + st->duration = sc->track_end = pts; > + > + if (offset == avio_size(pb)) > + c->fragment_index_complete = 1; > + > return 0; > } > > @@ -3854,6 +3946,7 @@ static const MOVParseTableEntry > mov_default_parse_table[] = { > { MKTAG('a','l','a','c'), mov_read_alac }, /* alac specific atom */ > { MKTAG('a','v','c','C'), mov_read_glbl }, > { MKTAG('p','a','s','p'), mov_read_pasp }, > +{ MKTAG('s','i','d','x'), mov_read_sidx }, > { MKTAG('s','t','b','l'), mov_read_default }, > { MKTAG('s','t','c','o'), mov_read_stco }, > { MKTAG('s','t','p','s'), mov_read_stps }, > @@ -3978,9 +4071,9 @@ static int mov_read_default(MOVContext *c, > AVIOContext *pb, MOVAtom atom) > return err; > } > if (c->found_moov && c->found_mdat && > - ((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX) || > + ((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX || > c->fragment_index_complete) || > start_pos + a.size == avio_size(pb))) { > - if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX) > + if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX || > c->fragment_index_complete) > c->next_root_atom = start_pos + a.size; > c->atom_depth --; > return 0; > @@ -4585,6 +4678,52 @@ static int should_retry(AVIOContext *pb, int > error_code) { > return 1; > } > > +static int mov_switch_root(AVFormatContext *s, int64_t target) > +{ > + MOVContext *mov = s->priv_data; > + int i, j; > + int already_read = 0; > + > + if (avio_seek(s->pb, target, SEEK_SET) != target) { > + av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": > partial file\n", target); > + return AVERROR_INVALIDDATA; > + } > + > + mov->next_root_atom = 0; > + > + for (i = 0; i < mov->fragment_index_count; i++) { > + MOVFragmentIndex *index = mov->fragment_index_data[i]; > + int found = 0; > + for (j = 0; j < index->item_count; j++) { > + MOVFragmentIndexItem *item = &index->items[j]; > + if (found) { > + mov->next_root_atom = item->moof_offset; > + break; // Advance to next index in outer loop > + } else if (item->moof_offset == target) { > + index->current_item = FFMIN(j, index->current_item); > + if (item->headers_read) > + already_read = 1; > + item->headers_read = 1; > + found = 1; > + } > + } > + if (!found) > + index->current_item = 0; > + } > + > + if (already_read) > + return 0; > + > + mov->found_mdat = 0; > + > + if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), > INT64_MAX }) < 0 || > + avio_feof(s->pb)) > + return AVERROR_EOF; > + av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n", > avio_tell(s->pb)); > + > + return 1; > +} > + > static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) > { > MOVContext *mov = s->priv_data; > @@ -4595,19 +4734,11 @@ static int mov_read_packet(AVFormatContext *s, > AVPacket *pkt) > mov->fc = s; > retry: > sample = mov_find_next_sample(s, &st); > - if (!sample) { > - mov->found_mdat = 0; > + if (!sample || (mov->next_root_atom && sample->pos > > mov->next_root_atom)) { > if (!mov->next_root_atom) > return AVERROR_EOF; > - if (avio_seek(s->pb, mov->next_root_atom, SEEK_SET) != > mov->next_root_atom) { > - av_log(mov->fc, AV_LOG_ERROR, "next root atom offset > 0x%"PRIx64": partial file\n", mov->next_root_atom); > - return AVERROR_INVALIDDATA; > - } > - mov->next_root_atom = 0; > - if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), > INT64_MAX }) < 0 || > - avio_feof(s->pb)) > - return AVERROR_EOF; > - av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n", > avio_tell(s->pb)); > + if ((ret = mov_switch_root(s, mov->next_root_atom)) < 0) > + return ret; > goto retry; > } > sc = st->priv_data; > @@ -4685,12 +4816,53 @@ static int mov_read_packet(AVFormatContext *s, > AVPacket *pkt) > return 0; > } > > +static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t > timestamp) > +{ > + MOVContext *mov = s->priv_data; > + int64_t offset = -1; > + MOVFragmentIndex *index = NULL; > + int i; > + > + if (!mov->fragment_index_count) > + return 0; > + > + for (i = 0; i < mov->fragment_index_count; i++) { > + if (mov->fragment_index_data[i]->track_id == st->id) { > + index = mov->fragment_index_data[i]; > + break; > + } > + } > + if (!index) > + return 0; > + > + if (mov->fragment_index_complete) { > + for (i = index->item_count - 1; i >= 0; i--) { > + if (index->items[i].time <= timestamp) { > + if (index->items[i].headers_read) > + return 0; > + > + offset = index->items[i].moof_offset; > + break; > + } > + } > + } > + > + if (offset == -1) > + return 0; > + > + return mov_switch_root(s, offset); > +} > + > static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t > timestamp, int flags) > { > MOVStreamContext *sc = st->priv_data; > int sample, time_sample; > int i; > > + int ret = mov_seek_fragment(s, st, timestamp); > + if (ret < 0) > + return ret; > + > sample = av_index_search_timestamp(st, timestamp, flags); > av_log(s, AV_LOG_TRACE, "stream %d, timestamp %"PRId64", sample > %d\n", st->index, timestamp, sample); > if (sample < 0 && st->nb_index_entries && timestamp < > st->index_entries[0].timestamp) > -- > 2.6.0 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel