From 1c67cfd91cc3d18a2e4e1402bb439fe4db0f76b2 Mon Sep 17 00:00:00 2001
From: Ulrik <ulrikm@spotify.com>
Date: Mon, 13 Dec 2021 22:30:42 +0100
Subject: [PATCH 08/15] avformat/mov:Do not set `next_root_atom` for
unfragmented files
"Root boxes" in the mp4 demuxer denotes groups of boxes in a fragmented
file that works self-contained. Example of such "root boxes"
`ftyp,moov,sidx', `ftyp,moov,mdat`, `moof,mdat`...
Therefore, if `next_root_atom` is 0, that can be seen as a sign that the
file is fragmented, and we should avoid setting it when assuming the file
is not fragmented.
---
libavformat/mov.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
@@ -90,6 +90,9 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st);
static int64_t add_ctts_entry(MOVCtts** ctts_data, unsigned int* ctts_count, unsigned int* allocated_size,
int count, int duration);
+// Number of mdats we see without moof, before we assume non-fragmented file with lots of mdats
+#define FRAG_HEURISTIC_THRESHOLD_MDAT_WITHOUT_MOOx 5
+
static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
unsigned len, const char *key)
{
@@ -1363,7 +1366,7 @@ static int mov_read_mdat(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (atom.size == 0) /* wrong one (MP4) */
return 0;
c->found_mdat+=1;
- if (c->found_mdat == 5 && !c->found_moov) {
+ if (c->found_mdat == FRAG_HEURISTIC_THRESHOLD_MDAT_WITHOUT_MOOx && !c->found_moov) {
/* Some mp4:s consist of 100s or even 1000s of mdats, with a moov at the end. To avoid a
ton of seeking, we heuristically look for a moov at the end of the file instead */
mov_heuristic_scan_moov(c, pb);
@@ -1647,7 +1650,7 @@ static int mov_try_read_moov(MOVContext *c, AVIOContext *pb, int64_t offset, int
break;
}
if (child.size - ret + avio_tell(pb) > filesize) {
- av_log(c->fc, AV_LOG_TRACE, "Remaining boxes does not align with EOF", offset);
+ av_log(c->fc, AV_LOG_TRACE, "Remaining boxes does not align with EOF");
return -1;
}
avio_seek(pb, child.size - ret, SEEK_CUR);
@@ -9496,20 +9499,20 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
} else {
int64_t start_pos = avio_tell(pb);
int64_t left;
- uint8_t index_satisfied, at_end;
+ uint8_t might_be_fragmented, index_satisfied, at_end;
int err = parse(c, pb, a);
if (err < 0) {
c->atom_depth --;
return err;
}
+ /* If we've seen 5 mdats, with no fragments seen, we assume file is not fragmented */
+ might_be_fragmented = (c->found_mdat < FRAG_HEURISTIC_THRESHOLD_MDAT_WITHOUT_MOOx) || (c->frag_index.nb_items > 0);
index_satisfied = (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
|| (c->fc->flags & AVFMT_FLAG_IGNIDX)
- || c->frag_index.complete
- || (c->found_mdat > 2 && (c->frag_index.nb_items == 0)); /* If we've read past 2
- mdats, with no fragments in fragment-index, we assume file is not fragmented */
+ || c->frag_index.complete;
at_end = (start_pos + a.size) == avio_size(pb);
- if (c->found_moov && c->found_mdat && (a.size <= INT64_MAX - start_pos) && (index_satisfied || at_end)) {
- if (!at_end)
+ if (c->found_moov && c->found_mdat && (a.size <= INT64_MAX - start_pos) && (index_satisfied || at_end || !might_be_fragmented)) {
+ if (!at_end && might_be_fragmented)
c->next_root_atom = start_pos + a.size;
c->atom_depth --;
return 0;
--
2.39.2