|
|
|
@ -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;
|
|
|
|
|
}
|
|
|
|
|