Allow edit list atom to appear earlier in the file

While processing the 'elst' atom, MPEG4Extractor was expecting duration
and sample rate to already be known. This implies an ordering of atoms
that is not required by the spec, and indeed some muxers may emit the
'elst' atom before the atoms that define sample rate and duration.
This change caches the values from the 'elst' atom until a track has
been completely processed, allowing the 'elst' atom to appear first.

Bug: 63390273
Test: decoded test files, ran CTS
Change-Id: I30abca70ead7990eb8a7d19a2e4b31212b9bc311
gugelfrei
Marco Nelissen 7 years ago
parent 3718b84a36
commit 96b48f71a9

@ -463,6 +463,66 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(
return NULL;
}
int64_t duration;
int32_t samplerate;
if (track->has_elst && mHeaderTimescale != 0 &&
track->meta->findInt64(kKeyDuration, &duration) &&
track->meta->findInt32(kKeySampleRate, &samplerate)) {
track->has_elst = false;
if (track->elst_segment_duration > INT64_MAX) {
goto editlistoverflow;
}
int64_t segment_duration = track->elst_segment_duration;
int64_t media_time = track->elst_media_time;
int64_t halfscale = mHeaderTimescale / 2;
int64_t delay;
// delay = ((media_time * samplerate) + halfscale) / mHeaderTimescale;
if (__builtin_mul_overflow(media_time, samplerate, &delay) ||
__builtin_add_overflow(delay, halfscale, &delay) ||
(delay /= mHeaderTimescale, false) ||
delay > INT32_MAX ||
delay < INT32_MIN) {
goto editlistoverflow;
}
track->meta->setInt32(kKeyEncoderDelay, delay);
int64_t scaled_duration;
// scaled_duration = ((duration * mHeaderTimescale) + 500000) / 1000000;
if (__builtin_mul_overflow(duration, mHeaderTimescale, &scaled_duration) ||
__builtin_add_overflow(scaled_duration, 500000, &scaled_duration)) {
goto editlistoverflow;
}
scaled_duration /= 1000000;
int64_t segment_end;
int64_t padding;
if (__builtin_add_overflow(segment_duration, media_time, &segment_end) ||
__builtin_sub_overflow(scaled_duration, segment_end, &padding)) {
goto editlistoverflow;
}
if (padding < 0) {
// track duration from media header (which is what kKeyDuration is) might
// be slightly shorter than the segment duration, which would make the
// padding negative. Clamp to zero.
padding = 0;
}
int64_t paddingsamples;
// paddingsamples = ((padding * samplerate) + halfscale) / mHeaderTimescale;
if (__builtin_mul_overflow(padding, samplerate, &paddingsamples) ||
__builtin_add_overflow(paddingsamples, halfscale, &paddingsamples) ||
(paddingsamples /= mHeaderTimescale, false) ||
paddingsamples > INT32_MAX) {
goto editlistoverflow;
}
track->meta->setInt32(kKeyEncoderPadding, paddingsamples);
}
editlistoverflow:
if ((flags & kIncludeExtensiveMetaData)
&& !track->includes_expensive_metadata) {
track->includes_expensive_metadata = true;
@ -989,6 +1049,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
track->skipTrack = false;
track->timescale = 0;
track->meta->setCString(kKeyMIMEType, "application/octet-stream");
track->has_elst = false;
}
off64_t stop_offset = *offset + chunk_size;
@ -1055,6 +1116,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
{
*offset += chunk_size;
if (!mLastTrack) {
return ERROR_MALFORMED;
}
// See 14496-12 8.6.6
uint8_t version;
if (mDataSource->readAt(data_offset, &version, 1) < 1) {
@ -1069,8 +1134,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
if (entry_count != 1) {
// we only support a single entry at the moment, for gapless playback
ALOGW("ignoring edit list with %d entries", entry_count);
} else if (mHeaderTimescale == 0) {
ALOGW("ignoring edit list because timescale is 0");
} else {
off64_t entriesoffset = data_offset + 8;
uint64_t segment_duration;
@ -1094,31 +1157,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
uint64_t halfscale = mHeaderTimescale / 2;
segment_duration = (segment_duration * 1000000 + halfscale)/ mHeaderTimescale;
media_time = (media_time * 1000000 + halfscale) / mHeaderTimescale;
int64_t duration;
int32_t samplerate;
if (!mLastTrack) {
return ERROR_MALFORMED;
}
if (mLastTrack->meta->findInt64(kKeyDuration, &duration) &&
mLastTrack->meta->findInt32(kKeySampleRate, &samplerate)) {
int64_t delay = (media_time * samplerate + 500000) / 1000000;
mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
int64_t paddingus = duration - (int64_t)(segment_duration + media_time);
if (paddingus < 0) {
// track duration from media header (which is what kKeyDuration is) might
// be slightly shorter than the segment duration, which would make the
// padding negative. Clamp to zero.
paddingus = 0;
}
int64_t paddingsamples = (paddingus * samplerate + 500000) / 1000000;
mLastTrack->meta->setInt32(kKeyEncoderPadding, paddingsamples);
}
// save these for later, because the elst atom might precede
// the atoms that actually gives us the duration and sample rate
// needed to calculate the padding and delay values
mLastTrack->has_elst = true;
mLastTrack->elst_media_time = media_time;
mLastTrack->elst_segment_duration = segment_duration;
}
break;
}

@ -82,6 +82,9 @@ private:
sp<SampleTable> sampleTable;
bool includes_expensive_metadata;
bool skipTrack;
bool has_elst;
int64_t elst_media_time;
uint64_t elst_segment_duration;
};
Vector<SidxEntry> mSidxEntries;

Loading…
Cancel
Save