diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 941c759fca..65e172a019 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -463,6 +463,66 @@ sp 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; } diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index f84711971d..1efe6b984b 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -82,6 +82,9 @@ private: sp sampleTable; bool includes_expensive_metadata; bool skipTrack; + bool has_elst; + int64_t elst_media_time; + uint64_t elst_segment_duration; }; Vector mSidxEntries;