From 4678a6dc5f09008481524949a9667af5a6190374 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 15 Apr 2011 11:52:29 -0700 Subject: Remove streamability verification, it's taking too long. Also... make sure that findSampleAtTime uses composition time instead of decoding time, at the expense of extra memory. Change-Id: I67d09389b3df7ed265f614bdd0b142ca7f19f86a related-to-bug: 4294536 --- media/libstagefright/MPEG4Extractor.cpp | 91 +-------------- media/libstagefright/SampleTable.cpp | 159 ++++++++++++++++++-------- media/libstagefright/include/MPEG4Extractor.h | 2 - media/libstagefright/include/SampleTable.h | 12 +- 4 files changed, 128 insertions(+), 136 deletions(-) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 1ca2d6d..f9db1a1 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -377,7 +377,7 @@ status_t MPEG4Extractor::readMetaData() { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } - mInitCheck = verifyIfStreamable(); + mInitCheck = OK; } else { mInitCheck = err; } @@ -1904,7 +1904,7 @@ status_t MPEG4Source::read( off64_t offset; size_t size; - uint32_t dts; + uint32_t cts; bool isSyncSample; bool newBuffer = false; if (mBuffer == NULL) { @@ -1912,7 +1912,7 @@ status_t MPEG4Source::read( status_t err = mSampleTable->getMetaDataForSample( - mCurrentSampleIndex, &offset, &size, &dts, &isSyncSample); + mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample); if (err != OK) { return err; @@ -1942,7 +1942,7 @@ status_t MPEG4Source::read( mBuffer->set_range(0, size); mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( - kKeyTime, ((int64_t)dts * 1000000) / mTimescale); + kKeyTime, ((int64_t)cts * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -2060,7 +2060,7 @@ status_t MPEG4Source::read( mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( - kKeyTime, ((int64_t)dts * 1000000) / mTimescale); + kKeyTime, ((int64_t)cts * 1000000) / mTimescale); if (targetSampleTimeUs >= 0) { mBuffer->meta_data()->setInt64( @@ -2094,87 +2094,6 @@ MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix( return NULL; } -status_t MPEG4Extractor::verifyIfStreamable() { - if (!(mDataSource->flags() & DataSource::kIsCachingDataSource)) { - return OK; - } - - Track *audio = findTrackByMimePrefix("audio/"); - Track *video = findTrackByMimePrefix("video/"); - - if (audio == NULL || video == NULL) { - return OK; - } - - sp audioSamples = audio->sampleTable; - sp videoSamples = video->sampleTable; - - off64_t maxOffsetDiff = 0; - int64_t maxOffsetTimeUs = -1; - - for (uint32_t i = 0; i < videoSamples->countSamples(); ++i) { - off64_t videoOffset; - uint32_t videoTime; - bool isSync; - CHECK_EQ((status_t)OK, videoSamples->getMetaDataForSample( - i, &videoOffset, NULL, &videoTime, &isSync)); - - int64_t videoTimeUs = (int64_t)(videoTime * 1E6 / video->timescale); - - uint32_t reqAudioTime = (videoTimeUs * audio->timescale) / 1000000; - uint32_t j; - if (audioSamples->findSampleAtTime( - reqAudioTime, &j, SampleTable::kFlagClosest) != OK) { - continue; - } - - off64_t audioOffset; - uint32_t audioTime; - CHECK_EQ((status_t)OK, audioSamples->getMetaDataForSample( - j, &audioOffset, NULL, &audioTime)); - - int64_t audioTimeUs = (int64_t)(audioTime * 1E6 / audio->timescale); - - off64_t offsetDiff = videoOffset - audioOffset; - if (offsetDiff < 0) { - offsetDiff = -offsetDiff; - } - -#if 0 - printf("%s%d/%d videoTime %.2f secs audioTime %.2f secs " - "videoOffset %lld audioOffset %lld offsetDiff %lld\n", - isSync ? "*" : " ", - i, - j, - videoTimeUs / 1E6, - audioTimeUs / 1E6, - videoOffset, - audioOffset, - offsetDiff); -#endif - - if (offsetDiff > maxOffsetDiff) { - maxOffsetDiff = offsetDiff; - maxOffsetTimeUs = videoTimeUs; - } - } - -#if 0 - printf("max offset diff: %lld at video time: %.2f secs\n", - maxOffsetDiff, maxOffsetTimeUs / 1E6); -#endif - - if (maxOffsetDiff < 1024 * 1024) { - return OK; - } - - LOGE("This content is not streamable, " - "max offset diff: %lld at video time: %.2f secs", - maxOffsetDiff, maxOffsetTimeUs / 1E6); - - return ERROR_UNSUPPORTED; -} - static bool LegacySniffMPEG4( const sp &source, String8 *mimeType, float *confidence) { uint8_t header[8]; diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 423df70..08db902 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -53,6 +53,7 @@ SampleTable::SampleTable(const sp &source) mNumSampleSizes(0), mTimeToSampleCount(0), mTimeToSample(NULL), + mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), mSyncSampleOffset(-1), @@ -73,6 +74,9 @@ SampleTable::~SampleTable() { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; + delete[] mSampleTimeEntries; + mSampleTimeEntries = NULL; + delete[] mTimeToSample; mTimeToSample = NULL; @@ -381,67 +385,128 @@ uint32_t abs_difference(uint32_t time1, uint32_t time2) { return time1 > time2 ? time1 - time2 : time2 - time1; } -status_t SampleTable::findSampleAtTime( - uint32_t req_time, uint32_t *sample_index, uint32_t flags) { - // XXX this currently uses decoding time, instead of composition time. +// static +int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) { + const SampleTimeEntry *a = (const SampleTimeEntry *)_a; + const SampleTimeEntry *b = (const SampleTimeEntry *)_b; - *sample_index = 0; + if (a->mCompositionTime < b->mCompositionTime) { + return -1; + } else if (a->mCompositionTime > b->mCompositionTime) { + return 1; + } + + return 0; +} +void SampleTable::buildSampleEntriesTable() { Mutex::Autolock autoLock(mLock); - uint32_t cur_sample = 0; - uint32_t time = 0; + if (mSampleTimeEntries != NULL) { + return; + } + + mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes]; + + uint32_t sampleIndex = 0; + uint32_t sampleTime = 0; + for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { uint32_t n = mTimeToSample[2 * i]; uint32_t delta = mTimeToSample[2 * i + 1]; - if (req_time < time + n * delta) { - int j = (req_time - time) / delta; - - uint32_t time1 = time + j * delta; - uint32_t time2 = time1 + delta; - - uint32_t sampleTime; - if (i+1 == mTimeToSampleCount - || (abs_difference(req_time, time1) - < abs_difference(req_time, time2))) { - *sample_index = cur_sample + j; - sampleTime = time1; - } else { - *sample_index = cur_sample + j + 1; - sampleTime = time2; - } + for (uint32_t j = 0; j < n; ++j) { + CHECK(sampleIndex < mNumSampleSizes); - switch (flags) { - case kFlagBefore: - { - if (sampleTime > req_time && *sample_index > 0) { - --*sample_index; - } - break; - } + mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; - case kFlagAfter: - { - if (sampleTime < req_time - && *sample_index + 1 < mNumSampleSizes) { - ++*sample_index; - } - break; - } + mSampleTimeEntries[sampleIndex].mCompositionTime = + sampleTime + getCompositionTimeOffset(sampleIndex); + + ++sampleIndex; + sampleTime += delta; + } + } + + qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), + CompareIncreasingTime); +} - default: - break; +status_t SampleTable::findSampleAtTime( + uint32_t req_time, uint32_t *sample_index, uint32_t flags) { + buildSampleEntriesTable(); + + uint32_t left = 0; + uint32_t right = mNumSampleSizes; + while (left < right) { + uint32_t center = (left + right) / 2; + uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime; + + if (req_time < centerTime) { + right = center; + } else if (req_time > centerTime) { + left = center + 1; + } else { + left = center; + break; + } + } + + if (left == mNumSampleSizes) { + --left; + } + + uint32_t closestIndex = left; + + switch (flags) { + case kFlagBefore: + { + while (closestIndex > 0 + && mSampleTimeEntries[closestIndex].mCompositionTime + > req_time) { + --closestIndex; } + break; + } - return OK; + case kFlagAfter: + { + while (closestIndex + 1 < mNumSampleSizes + && mSampleTimeEntries[closestIndex].mCompositionTime + < req_time) { + ++closestIndex; + } + break; } - time += delta * n; - cur_sample += n; + default: + { + CHECK(flags == kFlagClosest); + + if (closestIndex > 0) { + // Check left neighbour and pick closest. + uint32_t absdiff1 = + abs_difference( + mSampleTimeEntries[closestIndex].mCompositionTime, + req_time); + + uint32_t absdiff2 = + abs_difference( + mSampleTimeEntries[closestIndex - 1].mCompositionTime, + req_time); + + if (absdiff1 > absdiff2) { + closestIndex = closestIndex - 1; + } + } + + break; + } } - return ERROR_OUT_OF_RANGE; + *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; + + return OK; } status_t SampleTable::findSyncSampleNear( @@ -613,7 +678,7 @@ status_t SampleTable::getMetaDataForSample( uint32_t sampleIndex, off64_t *offset, size_t *size, - uint32_t *decodingTime, + uint32_t *compositionTime, bool *isSyncSample) { Mutex::Autolock autoLock(mLock); @@ -630,8 +695,8 @@ status_t SampleTable::getMetaDataForSample( *size = mSampleIterator->getSampleSize(); } - if (decodingTime) { - *decodingTime = mSampleIterator->getSampleTime(); + if (compositionTime) { + *compositionTime = mSampleIterator->getSampleTime(); } if (isSyncSample) { diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index d9ef208..3bd4c7e 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -92,8 +92,6 @@ private: Track *findTrackByMimePrefix(const char *mimePrefix); - status_t verifyIfStreamable(); - MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h index 2f95de9..f44e0a2 100644 --- a/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/include/SampleTable.h @@ -63,7 +63,7 @@ public: uint32_t sampleIndex, off64_t *offset, size_t *size, - uint32_t *decodingTime, + uint32_t *compositionTime, bool *isSyncSample = NULL); enum { @@ -107,6 +107,12 @@ private: uint32_t mTimeToSampleCount; uint32_t *mTimeToSample; + struct SampleTimeEntry { + uint32_t mSampleIndex; + uint32_t mCompositionTime; + }; + SampleTimeEntry *mSampleTimeEntries; + uint32_t *mCompositionTimeDeltaEntries; size_t mNumCompositionTimeDeltaEntries; @@ -130,6 +136,10 @@ private: uint32_t getCompositionTimeOffset(uint32_t sampleIndex) const; + static int CompareIncreasingTime(const void *, const void *); + + void buildSampleEntriesTable(); + SampleTable(const SampleTable &); SampleTable &operator=(const SampleTable &); }; -- cgit v1.1