From patchwork Tue Mar 5 16:02:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Charles Liu X-Patchwork-Id: 12199 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 7DF87447DB6 for ; Tue, 5 Mar 2019 18:03:11 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5BD6D68A441; Tue, 5 Mar 2019 18:03:11 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf1-f193.google.com (mail-pf1-f193.google.com [209.85.210.193]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F3C32689E22 for ; Tue, 5 Mar 2019 18:03:04 +0200 (EET) Received: by mail-pf1-f193.google.com with SMTP id i19so6041059pfd.0 for ; Tue, 05 Mar 2019 08:03:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=7cH2KFMv3hX8unHjrFNhrQog6q8O1i4/gB7txr8F4j8=; b=um2xME6PToZeDpTa2qR2zXQovypBspq4lmsbPdureiSNwAdWj2lNpS5Cw7J+bxzET0 hDEE/dXjQ1FfBCsJF3zX5FBnF4uA20D4yRImIgAhguSzmSHtrCtCAuJ/9V4fREV4Ti/t XJETQryqdmjdjArHdcf7HVKRHC0Wg7t0KgMNeRdYIBQVzWzVWN0uJtUyy5vKAdmHJoYn dyIe45e91aeSBHpPRYdlikEysdOeQpYrIJKKbcN2YT2c9zXB6BuvOhNkAyoO1noUtL5w LCzFFMOlM5fpVQ1l8JN/Sqc8aeWUGWfHoMEmvjRlkQiGrIXKYCRO6Vw2hZf62tet21Q4 ui+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=7cH2KFMv3hX8unHjrFNhrQog6q8O1i4/gB7txr8F4j8=; b=IqM5zYOZ9rO+3fBmuVIQBso2GpBT6YG6QRWe1TM9SzmhvLEw22ZEUv9njLI8dxyvVs k9wil5lOJAmbyDaCu01h3w8/0EdwusGCuL31Fdo5HjoCjKpZm2GAszMmn7taNTBTXxtW ZzVa+AILpRytV4ST3JCk/kOrcxp82WdPbg81jDF83qkVXQpy2vMCzEpQ/AKMi0ljY1Ul ssgsMwFWIy6FS06teGRUPa8GzMe81WFuRUvIZxwJaE2ZGHmQY8OHmidkorFkyfhVvI4N 2G9hjhPDVCX8lem6NkAt07uqKKGltZJ3QJPzkZvmnLvXMJbyDMn8AWnqSxodDzhJYTW9 6aCg== X-Gm-Message-State: APjAAAXmVbzNRCFUqaoPGF1CuQBbgoqVtad3QKpxTLcoJbpqkAQIf3kg x2BbgejEbsfH9tsrbsyTKgng8EdueE0= X-Google-Smtp-Source: APXvYqzAdBUDcnSr/RqSdzm/Oz889GIIxUqVV/95nJWeS8VcYymdhxVjpqh452EXDlgkb+tkXHVm1Q== X-Received: by 2002:a63:460a:: with SMTP id t10mr1946032pga.354.1551801782055; Tue, 05 Mar 2019 08:03:02 -0800 (PST) Received: from localhost.localdomain ([138.91.24.251]) by smtp.gmail.com with ESMTPSA id t23sm20732579pfa.111.2019.03.05.08.02.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 05 Mar 2019 08:03:00 -0800 (PST) From: Charles Liu To: ffmpeg-devel@ffmpeg.org Date: Wed, 6 Mar 2019 00:02:43 +0800 Message-Id: <20190305160243.13451-1-liuchh83@gmail.com> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat/mov: fix hang while seek on a kind of fragmented mp4. X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Charles Liu Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 1. organize fragmented information according to the tracks. 2. do NOT skip the last boxes of fragmented info. ticket #7572 Signed-off-by: Charles Liu --- libavformat/isom.h | 10 +- libavformat/mov.c | 378 +++++++++++++++++++++------------------------ 2 files changed, 185 insertions(+), 203 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 69452cae8e..eea8fa4e8f 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -125,7 +125,7 @@ typedef struct MOVEncryptionIndex { } MOVEncryptionIndex; typedef struct MOVFragmentStreamInfo { - int id; + unsigned stsd_id; int64_t sidx_pts; int64_t first_tfra_pts; int64_t tfdt_dts; @@ -136,14 +136,13 @@ typedef struct MOVFragmentStreamInfo { typedef struct MOVFragmentIndexItem { int64_t moof_offset; int headers_read; - int current; - int nb_stream_info; - MOVFragmentStreamInfo * stream_info; + MOVFragmentStreamInfo stream_info; } MOVFragmentIndexItem; typedef struct MOVFragmentIndex { int allocated_size; int complete; + int id; // track id int current; int nb_items; MOVFragmentIndexItem * item; @@ -274,7 +273,8 @@ typedef struct MOVContext { int moov_retry; int use_mfra_for; int has_looked_for_mfra; - MOVFragmentIndex frag_index; + unsigned nb_frag_indices; + MOVFragmentIndex *frag_indices; 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 a7d444b0ee..b150710a40 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -1153,59 +1153,29 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; /* now go for mdat */ } -static MOVFragmentStreamInfo * get_frag_stream_info( - MOVFragmentIndex *frag_index, - int index, - int id) +static MOVFragmentIndex *mov_find_frag_index(MOVFragmentIndex *frag_indices, int nb_frag_indices, int track_id) { - int i; - MOVFragmentIndexItem * item; + unsigned i; + MOVFragmentIndex *frag_index = NULL; - if (index < 0 || index >= frag_index->nb_items) - return NULL; - item = &frag_index->item[index]; - for (i = 0; i < item->nb_stream_info; i++) - if (item->stream_info[i].id == id) - return &item->stream_info[i]; + for (i = 0; i < nb_frag_indices; i++) + if (frag_indices[i].id == track_id) + frag_index = &frag_indices[i]; - // This shouldn't happen - return NULL; + return frag_index; } -static void set_frag_stream(MOVFragmentIndex *frag_index, int id) +static MOVFragmentStreamInfo *get_current_frag_stream_info(MOVContext *c, int id) { - int i; - MOVFragmentIndexItem * item; + MOVFragmentIndex *frag_index = NULL; - if (frag_index->current < 0 || - frag_index->current >= frag_index->nb_items) - return; - - item = &frag_index->item[frag_index->current]; - for (i = 0; i < item->nb_stream_info; i++) - if (item->stream_info[i].id == id) { - item->current = i; - return; - } - - // id not found. This shouldn't happen. - item->current = -1; -} - -static MOVFragmentStreamInfo * get_current_frag_stream_info( - MOVFragmentIndex *frag_index) -{ - MOVFragmentIndexItem *item; - if (frag_index->current < 0 || + frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, id); + if (!frag_index || + frag_index->current < 0 || frag_index->current >= frag_index->nb_items) return NULL; - item = &frag_index->item[frag_index->current]; - if (item->current >= 0 && item->current < item->nb_stream_info) - return &item->stream_info[item->current]; - - // This shouldn't happen - return NULL; + return &frag_index->item[frag_index->current].stream_info; } static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset) @@ -1232,9 +1202,9 @@ static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset) return b; } -static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info) -{ - av_assert0(frag_stream_info); +static int64_t get_frag_time(MOVFragmentIndex *frag_index, + int index, int track_id) { + MOVFragmentStreamInfo *frag_stream_info = &frag_index->item[index].stream_info; if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) return frag_stream_info->sidx_pts; if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) @@ -1242,31 +1212,9 @@ static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info) return frag_stream_info->tfdt_dts; } -static int64_t get_frag_time(MOVFragmentIndex *frag_index, - int index, int track_id) -{ - MOVFragmentStreamInfo * frag_stream_info; - int64_t timestamp; - int i; - - if (track_id >= 0) { - frag_stream_info = get_frag_stream_info(frag_index, index, track_id); - return frag_stream_info->sidx_pts; - } - - for (i = 0; i < frag_index->item[index].nb_stream_info; i++) { - frag_stream_info = &frag_index->item[index].stream_info[i]; - timestamp = get_stream_info_time(frag_stream_info); - if (timestamp != AV_NOPTS_VALUE) - return timestamp; - } - return AV_NOPTS_VALUE; -} - static int search_frag_timestamp(MOVFragmentIndex *frag_index, - AVStream *st, int64_t timestamp) -{ - int a, b, m, m0; + AVStream *st, int64_t timestamp) { + int a, b, m; int64_t frag_time; int id = -1; @@ -1282,89 +1230,102 @@ static int search_frag_timestamp(MOVFragmentIndex *frag_index, b = frag_index->nb_items; while (b - a > 1) { - m0 = m = (a + b) >> 1; - - while (m < b && - (frag_time = get_frag_time(frag_index, m, id)) == AV_NOPTS_VALUE) - m++; + m = (a + b) >> 1; + frag_time = get_frag_time(frag_index, m, id); + if (frag_time == AV_NOPTS_VALUE) + return -1; - if (m < b && frag_time <= timestamp) + if (frag_time >= timestamp) + b = m; + if (frag_time <= timestamp) a = m; - else - b = m0; } return a; } -static int update_frag_index(MOVContext *c, int64_t offset) +static int update_frag_index(MOVContext *c, int track_id, int64_t offset) { int index, i; - MOVFragmentIndexItem * item; - MOVFragmentStreamInfo * frag_stream_info; + MOVFragmentIndex *frag_index = NULL; + MOVFragmentIndexItem *item; + + if (!c->frag_indices) { + if (!c->fc->nb_streams) + return -1; + + c->nb_frag_indices = c->fc->nb_streams; + c->frag_indices = av_mallocz_array(c->nb_frag_indices, sizeof(*c->frag_indices)); + if (!c->frag_indices) + return AVERROR(ENOMEM); + + for (i = 0; i < c->fc->nb_streams; i++) + c->frag_indices[i].id = c->fc->streams[i]->id; + } + + frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, track_id); + if (!frag_index) + return -1; // If moof_offset already exists in frag_index, return index to it - index = search_frag_moof_offset(&c->frag_index, offset); - if (index < c->frag_index.nb_items && - c->frag_index.item[index].moof_offset == offset) + index = search_frag_moof_offset(frag_index, offset); + if (index < frag_index->nb_items && + frag_index->item[index].moof_offset == offset) { + frag_index->current = index; return index; + } // offset is not yet in frag index. // Insert new item at index (sorted by moof offset) - item = av_fast_realloc(c->frag_index.item, - &c->frag_index.allocated_size, - (c->frag_index.nb_items + 1) * - sizeof(*c->frag_index.item)); - if(!item) - return -1; - c->frag_index.item = item; - - frag_stream_info = av_realloc_array(NULL, c->fc->nb_streams, - sizeof(*item->stream_info)); - if (!frag_stream_info) - return -1; + item = av_fast_realloc(frag_index->item, + &frag_index->allocated_size, + (frag_index->nb_items + 1) * + sizeof(*frag_index->item)); + if (!item) + return AVERROR(ENOMEM); + frag_index->item = item; for (i = 0; i < c->fc->nb_streams; i++) { // Avoid building frag index if streams lack track id. if (c->fc->streams[i]->id < 0) return AVERROR_INVALIDDATA; - - frag_stream_info[i].id = c->fc->streams[i]->id; - frag_stream_info[i].sidx_pts = AV_NOPTS_VALUE; - frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE; - frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE; - frag_stream_info[i].index_entry = -1; - frag_stream_info[i].encryption_index = NULL; } - if (index < c->frag_index.nb_items) - memmove(c->frag_index.item + index + 1, c->frag_index.item + index, - (c->frag_index.nb_items - index) * sizeof(*c->frag_index.item)); + if (index < frag_index->nb_items) + memmove(frag_index->item + index + 1, frag_index->item + index, + (frag_index->nb_items - index) * sizeof(*frag_index->item)); - item = &c->frag_index.item[index]; + item = &frag_index->item[index]; item->headers_read = 0; - item->current = 0; - item->nb_stream_info = c->fc->nb_streams; item->moof_offset = offset; - item->stream_info = frag_stream_info; - c->frag_index.nb_items++; + item->stream_info.sidx_pts = AV_NOPTS_VALUE; + item->stream_info.tfdt_dts = AV_NOPTS_VALUE; + item->stream_info.first_tfra_pts = AV_NOPTS_VALUE; + item->stream_info.index_entry = -1; + item->stream_info.encryption_index = NULL; + + frag_index->nb_items++; + frag_index->current = index; return index; } -static void fix_frag_index_entries(MOVFragmentIndex *frag_index, int index, - int id, int entries) +static void fix_frag_index_entries(MOVFragmentIndex *frag_indices, int nb_frag_indices, int track_id, + int index, int entries) { int i; - MOVFragmentStreamInfo * frag_stream_info; + MOVFragmentIndex *frag_index; if (index < 0) return; - for (i = index; i < frag_index->nb_items; i++) { - frag_stream_info = get_frag_stream_info(frag_index, i, id); - if (frag_stream_info && frag_stream_info->index_entry >= 0) - frag_stream_info->index_entry += entries; - } + + frag_index = mov_find_frag_index(frag_indices, nb_frag_indices, track_id); + if (!frag_index) + return; + + for (i = index; i < frag_index->nb_items; i++) + if (frag_index->item[i].stream_info.index_entry >= 0) + frag_index->item[i].stream_info.index_entry += entries; } static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) @@ -1389,7 +1350,6 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) } c->fragment.moof_offset = c->fragment.implicit_offset = avio_tell(pb) - 8; av_log(c->fc, AV_LOG_TRACE, "moof offset %"PRIx64"\n", c->fragment.moof_offset); - c->frag_index.current = update_frag_index(c, c->fragment.moof_offset); return mov_read_default(c, pb, atom); } @@ -4560,7 +4520,8 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVFragment *frag = &c->fragment; MOVTrackExt *trex = NULL; - int flags, track_id, i; + int flags, track_id, i, index; + MOVFragmentIndex *frag_index = NULL; c->fragment.found_tfhd = 1; @@ -4580,7 +4541,6 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } frag->track_id = track_id; - set_frag_stream(&c->frag_index, track_id); frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ? avio_rb64(pb) : flags & MOV_TFHD_DEFAULT_BASE_IS_MOOF ? @@ -4595,6 +4555,14 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb) : trex->flags; av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags); + index = update_frag_index(c, frag->track_id, frag->moof_offset); + if (index < 0) return index; + + frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, track_id); + if (index < frag_index->nb_items) + frag_index->item[index].stream_info.stsd_id = frag->stsd_id; + frag_index->item[index].headers_read = 1; + return 0; } @@ -4673,7 +4641,7 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom) base_media_decode_time = avio_rb32(pb); } - frag_stream_info = get_current_frag_stream_info(&c->frag_index); + frag_stream_info = get_current_frag_stream_info(c, c->fragment.track_id); if (frag_stream_info) frag_stream_info->tfdt_dts = base_media_decode_time; sc->track_end = base_media_decode_time; @@ -4698,6 +4666,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) size_t old_ctts_allocated_size; AVIndexEntry *new_entries; MOVFragmentStreamInfo * frag_stream_info; + MOVFragmentIndex *frag_index = NULL; if (!frag->found_tfhd) { av_log(c->fc, AV_LOG_ERROR, "trun track id unknown, no tfhd was found\n"); @@ -4725,12 +4694,14 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) // and it's samples are in index_entries at the given position. // New index entries will be inserted before the index_entry found. index_entry_pos = st->nb_index_entries; - for (i = c->frag_index.current + 1; i < c->frag_index.nb_items; i++) { - frag_stream_info = get_frag_stream_info(&c->frag_index, i, frag->track_id); - if (frag_stream_info && frag_stream_info->index_entry >= 0) { - next_frag_index = i; - index_entry_pos = frag_stream_info->index_entry; - break; + frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, st->id); + if (frag_index) { + for (i = frag_index->current + 1; i < frag_index->nb_items; i++) { + if (frag_index->item[i].stream_info.index_entry >= 0) { + next_frag_index = i; + index_entry_pos = frag_index->item[i].stream_info.index_entry; + break; + } } } av_assert0(index_entry_pos <= st->nb_index_entries); @@ -4745,7 +4716,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb); if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); - frag_stream_info = get_current_frag_stream_info(&c->frag_index); + frag_stream_info = get_current_frag_stream_info(c, c->fragment.track_id); if (frag_stream_info) { if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && @@ -4939,8 +4910,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) // If a hole was created to insert the new index_entries into, // the index_entry recorded for all subsequent moof must // be incremented by the number of entries inserted. - fix_frag_index_entries(&c->frag_index, next_frag_index, - frag->track_id, entries); + fix_frag_index_entries(c->frag_indices, c->nb_frag_indices, frag->track_id, + next_frag_index, entries); if (pb->eof_reached) { av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted TRUN atom\n"); @@ -4965,6 +4936,8 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *ref_st = NULL; MOVStreamContext *sc, *ref_sc = NULL; AVRational timescale; + MOVFragmentIndex *frag_index; + MOVFragmentStreamInfo *frag_stream_info = NULL; version = avio_r8(pb); if (version > 1) { @@ -5009,7 +4982,6 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) for (i = 0; i < item_count; i++) { int index; - MOVFragmentStreamInfo * frag_stream_info; uint32_t size = avio_rb32(pb); uint32_t duration = avio_rb32(pb); if (size & 0x80000000) { @@ -5019,8 +4991,10 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb); // sap_flags timestamp = av_rescale_q(pts, st->time_base, timescale); - index = update_frag_index(c, offset); - frag_stream_info = get_frag_stream_info(&c->frag_index, index, track_id); + index = update_frag_index(c, track_id, offset); + if (index < 0) return index; + + frag_stream_info = get_current_frag_stream_info(c, track_id); if (frag_stream_info) frag_stream_info->sidx_pts = timestamp; @@ -5035,13 +5009,11 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (offset == avio_size(pb)) { // Find first entry in fragment index that came from an sidx. // This will pretty much always be the first entry. - for (i = 0; i < c->frag_index.nb_items; i++) { - MOVFragmentIndexItem * item = &c->frag_index.item[i]; - for (j = 0; ref_st == NULL && j < item->nb_stream_info; j++) { - MOVFragmentStreamInfo * si; - si = &item->stream_info[j]; - if (si->sidx_pts != AV_NOPTS_VALUE) { - ref_st = c->fc->streams[j]; + for (i = 0; i < c->nb_frag_indices; i++) { + MOVFragmentIndex *frag_index = &c->frag_indices[i]; + for (j = 0; j < frag_index->nb_items; j++) { + if (frag_index->item[j].stream_info.sidx_pts != AV_NOPTS_VALUE) { + ref_st = c->fc->streams[i]; ref_sc = ref_st->priv_data; break; } @@ -5055,7 +5027,9 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } - c->frag_index.complete = 1; + frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, st->id); + if (frag_index) + frag_index->complete = 1; } return 0; @@ -5859,12 +5833,12 @@ static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encry AVStream *st; int i; - frag_stream_info = get_current_frag_stream_info(&c->frag_index); + frag_stream_info = get_current_frag_stream_info(c, c->fragment.track_id); if (frag_stream_info) { for (i = 0; i < c->fc->nb_streams; i++) { - if (c->fc->streams[i]->id == frag_stream_info->id) { - st = c->fc->streams[i]; - break; + if (c->fc->streams[i]->id == c->fragment.track_id) { + st = c->fc->streams[i]; + break; } } if (i == c->fc->nb_streams) @@ -6182,6 +6156,7 @@ static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom) int i, ret; unsigned int version, entry_count, aux_info_type, aux_info_param; unsigned int alloc_size = 0; + MOVFragmentIndex *frag_index; ret = get_current_encryption_info(c, &encryption_index, &sc); if (ret != 1) @@ -6249,9 +6224,10 @@ static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom) } else { encryption_index->auxiliary_offsets[i] = avio_rb64(pb); } - if (c->frag_index.current >= 0) { + + frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, c->fragment.track_id); + if (frag_index && frag_index->current >= 0) encryption_index->auxiliary_offsets[i] += c->fragment.base_data_offset; - } } if (pb->eof_reached) { @@ -6572,22 +6548,23 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s return 0; } -static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index) +static int cenc_filter(MOVContext *mov, AVStream *st, MOVStreamContext *sc, AVPacket *pkt, int current_index) { - MOVFragmentStreamInfo *frag_stream_info; - MOVEncryptionIndex *encryption_index; + MOVEncryptionIndex *encryption_index = NULL; AVEncryptionInfo *encrypted_sample; - int encrypted_index, ret; + int encrypted_index = current_index, ret, index = -1; + MOVFragmentIndex *frag_index; - frag_stream_info = get_frag_stream_info(&mov->frag_index, mov->frag_index.current, st->id); - encrypted_index = current_index; - encryption_index = NULL; - if (frag_stream_info) { + frag_index = mov_find_frag_index(mov->frag_indices, mov->nb_frag_indices, st->id); + if (frag_index) + index = search_frag_timestamp(frag_index, st, pkt->pts); + + if (index != -1) { // Note this only supports encryption info in the first sample descriptor. - if (mov->fragment.stsd_id == 1) { - if (frag_stream_info->encryption_index) { - encrypted_index = current_index - frag_stream_info->index_entry; - encryption_index = frag_stream_info->encryption_index; + if (frag_index->item[index].stream_info.stsd_id == 1) { + if (frag_index->item[index].stream_info.encryption_index) { + encrypted_index = current_index - frag_index->item[index].stream_info.index_entry; + encryption_index = frag_index->item[index].stream_info.encryption_index; } else { encryption_index = sc->cenc.encryption_index; } @@ -6873,9 +6850,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) return err; } if (c->found_moov && c->found_mdat && - ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) || + ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX) || start_pos + a.size == avio_size(pb))) { - if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) + if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX) c->next_root_atom = start_pos + a.size; c->atom_depth --; return 0; @@ -7232,14 +7209,15 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->trex_data); av_freep(&mov->bitrates); - for (i = 0; i < mov->frag_index.nb_items; i++) { - MOVFragmentStreamInfo *frag = mov->frag_index.item[i].stream_info; - for (j = 0; j < mov->frag_index.item[i].nb_stream_info; j++) { - mov_free_encryption_index(&frag[j].encryption_index); - } - av_freep(&mov->frag_index.item[i].stream_info); + for (i = 0; i < mov->nb_frag_indices; i++) { + MOVFragmentIndex *index = &mov->frag_indices[i]; + for (j = 0; j < index->nb_items; j++) + mov_free_encryption_index(&index->item[j].stream_info.encryption_index); + + av_freep(&index->item); } - av_freep(&mov->frag_index.item); + av_freep(&mov->frag_indices); + mov->nb_frag_indices = 0; av_freep(&mov->aes_decrypt); av_freep(&mov->chapter_tracks); @@ -7287,6 +7265,7 @@ static int read_tfra(MOVContext *mov, AVIOContext *f) int64_t pos = avio_tell(f); uint32_t size = avio_rb32(f); unsigned track_id, item_count; + MOVFragmentStreamInfo *frag_stream_info = NULL; if (avio_rb32(f) != MKBETAG('t', 'f', 'r', 'a')) { return 1; @@ -7301,7 +7280,6 @@ static int read_tfra(MOVContext *mov, AVIOContext *f) for (i = 0; i < item_count; i++) { int64_t time, offset; int index; - MOVFragmentStreamInfo * frag_stream_info; if (avio_feof(f)) { return AVERROR_INVALIDDATA; @@ -7318,11 +7296,14 @@ static int read_tfra(MOVContext *mov, AVIOContext *f) // The first sample of each stream in a fragment is always a random // access sample. So it's entry in the tfra can be used as the // initial PTS of the fragment. - index = update_frag_index(mov, offset); - frag_stream_info = get_frag_stream_info(&mov->frag_index, index, track_id); + index = update_frag_index(mov, track_id, offset); + if (index < 0) return index; + + frag_stream_info = get_current_frag_stream_info(mov, track_id); if (frag_stream_info && - frag_stream_info->first_tfra_pts == AV_NOPTS_VALUE) + frag_stream_info->first_tfra_pts == AV_NOPTS_VALUE) { frag_stream_info->first_tfra_pts = time; + } for (j = 0; j < ((fieldlength >> 4) & 3) + 1; j++) avio_r8(f); @@ -7584,10 +7565,6 @@ static int mov_read_header(AVFormatContext *s) } ff_configure_buffers_for_index(s, AV_TIME_BASE); - for (i = 0; i < mov->frag_index.nb_items; i++) - if (mov->frag_index.item[i].moof_offset <= mov->fragment.moof_offset) - mov->frag_index.item[i].headers_read = 1; - return 0; } @@ -7624,27 +7601,26 @@ static int should_retry(AVIOContext *pb, int error_code) { return 1; } -static int mov_switch_root(AVFormatContext *s, int64_t target, int index) +static int mov_switch_root(AVFormatContext *s, int64_t target) { - int ret; + int ret, i, index; + MOVFragmentIndex *frag_index; MOVContext *mov = s->priv_data; - if (index >= 0 && index < mov->frag_index.nb_items) - target = mov->frag_index.item[index].moof_offset; 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; - if (index < 0 || index >= mov->frag_index.nb_items) - index = search_frag_moof_offset(&mov->frag_index, target); - if (index < mov->frag_index.nb_items) { - if (index + 1 < mov->frag_index.nb_items) - mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; - if (mov->frag_index.item[index].headers_read) - return 0; - mov->frag_index.item[index].headers_read = 1; + for (i = 0; i < mov->nb_frag_indices; i++) { + frag_index = mov_find_frag_index(mov->frag_indices, mov->nb_frag_indices, i + 1); + if (frag_index == NULL) + return -1; + + index = search_frag_moof_offset(frag_index, target); + if (index < frag_index->nb_items) + if (frag_index->item[index].moof_offset == target && frag_index->item[index].headers_read) + return 0; } mov->found_mdat = 0; @@ -7696,7 +7672,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) if (!sample || (mov->next_root_atom && sample->pos > mov->next_root_atom)) { if (!mov->next_root_atom) return AVERROR_EOF; - if ((ret = mov_switch_root(s, mov->next_root_atom, -1)) < 0) + if ((ret = mov_switch_root(s, mov->next_root_atom)) < 0) return ret; goto retry; } @@ -7820,17 +7796,23 @@ static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp { MOVContext *mov = s->priv_data; int index; + int64_t target; + MOVFragmentIndex *frag_index; - if (!mov->frag_index.complete) + frag_index = mov_find_frag_index(mov->frag_indices, mov->nb_frag_indices, st->id); + if (frag_index == NULL || !frag_index->complete) return 0; - index = search_frag_timestamp(&mov->frag_index, st, timestamp); + index = search_frag_timestamp(frag_index, st, timestamp); if (index < 0) index = 0; - if (!mov->frag_index.item[index].headers_read) - return mov_switch_root(s, -1, index); - if (index + 1 < mov->frag_index.nb_items) - mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; + + if (index < frag_index->nb_items) { + target = frag_index->item[index].moof_offset; + + if (!frag_index->item[index].headers_read) + return mov_switch_root(s, target); + } return 0; }