Loading media/libstagefright/MPEG4Extractor.cpp +5 −86 Original line number Diff line number Diff line Loading @@ -377,7 +377,7 @@ status_t MPEG4Extractor::readMetaData() { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } mInitCheck = verifyIfStreamable(); mInitCheck = OK; } else { mInitCheck = err; } Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -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( Loading Loading @@ -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<SampleTable> audioSamples = audio->sampleTable; sp<SampleTable> 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<DataSource> &source, String8 *mimeType, float *confidence) { uint8_t header[8]; Loading media/libstagefright/SampleTable.cpp +112 −47 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ SampleTable::SampleTable(const sp<DataSource> &source) mNumSampleSizes(0), mTimeToSampleCount(0), mTimeToSample(NULL), mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), mSyncSampleOffset(-1), Loading @@ -73,6 +74,9 @@ SampleTable::~SampleTable() { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; delete[] mSampleTimeEntries; mSampleTimeEntries = NULL; delete[] mTimeToSample; mTimeToSample = NULL; Loading Loading @@ -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; for (uint32_t j = 0; j < n; ++j) { CHECK(sampleIndex < mNumSampleSizes); mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; mSampleTimeEntries[sampleIndex].mCompositionTime = sampleTime + getCompositionTimeOffset(sampleIndex); ++sampleIndex; sampleTime += delta; } } uint32_t time1 = time + j * delta; uint32_t time2 = time1 + delta; qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), CompareIncreasingTime); } uint32_t sampleTime; if (i+1 == mTimeToSampleCount || (abs_difference(req_time, time1) < abs_difference(req_time, time2))) { *sample_index = cur_sample + j; sampleTime = time1; 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 { *sample_index = cur_sample + j + 1; sampleTime = time2; left = center; break; } } if (left == mNumSampleSizes) { --left; } uint32_t closestIndex = left; switch (flags) { case kFlagBefore: { if (sampleTime > req_time && *sample_index > 0) { --*sample_index; while (closestIndex > 0 && mSampleTimeEntries[closestIndex].mCompositionTime > req_time) { --closestIndex; } break; } case kFlagAfter: { if (sampleTime < req_time && *sample_index + 1 < mNumSampleSizes) { ++*sample_index; while (closestIndex + 1 < mNumSampleSizes && mSampleTimeEntries[closestIndex].mCompositionTime < req_time) { ++closestIndex; } break; } default: break; } { CHECK(flags == kFlagClosest); return OK; 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; } } time += delta * n; cur_sample += n; break; } } return ERROR_OUT_OF_RANGE; *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; return OK; } status_t SampleTable::findSyncSampleNear( Loading Loading @@ -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); Loading @@ -630,8 +695,8 @@ status_t SampleTable::getMetaDataForSample( *size = mSampleIterator->getSampleSize(); } if (decodingTime) { *decodingTime = mSampleIterator->getSampleTime(); if (compositionTime) { *compositionTime = mSampleIterator->getSampleTime(); } if (isSyncSample) { Loading media/libstagefright/include/MPEG4Extractor.h +0 −2 Original line number Diff line number Diff line Loading @@ -92,8 +92,6 @@ private: Track *findTrackByMimePrefix(const char *mimePrefix); status_t verifyIfStreamable(); MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; Loading media/libstagefright/include/SampleTable.h +11 −1 Original line number Diff line number Diff line Loading @@ -63,7 +63,7 @@ public: uint32_t sampleIndex, off64_t *offset, size_t *size, uint32_t *decodingTime, uint32_t *compositionTime, bool *isSyncSample = NULL); enum { Loading Loading @@ -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; Loading @@ -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 &); }; Loading Loading
media/libstagefright/MPEG4Extractor.cpp +5 −86 Original line number Diff line number Diff line Loading @@ -377,7 +377,7 @@ status_t MPEG4Extractor::readMetaData() { mFileMetaData->setCString(kKeyMIMEType, "audio/mp4"); } mInitCheck = verifyIfStreamable(); mInitCheck = OK; } else { mInitCheck = err; } Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -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( Loading Loading @@ -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<SampleTable> audioSamples = audio->sampleTable; sp<SampleTable> 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<DataSource> &source, String8 *mimeType, float *confidence) { uint8_t header[8]; Loading
media/libstagefright/SampleTable.cpp +112 −47 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ SampleTable::SampleTable(const sp<DataSource> &source) mNumSampleSizes(0), mTimeToSampleCount(0), mTimeToSample(NULL), mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), mSyncSampleOffset(-1), Loading @@ -73,6 +74,9 @@ SampleTable::~SampleTable() { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; delete[] mSampleTimeEntries; mSampleTimeEntries = NULL; delete[] mTimeToSample; mTimeToSample = NULL; Loading Loading @@ -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; for (uint32_t j = 0; j < n; ++j) { CHECK(sampleIndex < mNumSampleSizes); mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; mSampleTimeEntries[sampleIndex].mCompositionTime = sampleTime + getCompositionTimeOffset(sampleIndex); ++sampleIndex; sampleTime += delta; } } uint32_t time1 = time + j * delta; uint32_t time2 = time1 + delta; qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), CompareIncreasingTime); } uint32_t sampleTime; if (i+1 == mTimeToSampleCount || (abs_difference(req_time, time1) < abs_difference(req_time, time2))) { *sample_index = cur_sample + j; sampleTime = time1; 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 { *sample_index = cur_sample + j + 1; sampleTime = time2; left = center; break; } } if (left == mNumSampleSizes) { --left; } uint32_t closestIndex = left; switch (flags) { case kFlagBefore: { if (sampleTime > req_time && *sample_index > 0) { --*sample_index; while (closestIndex > 0 && mSampleTimeEntries[closestIndex].mCompositionTime > req_time) { --closestIndex; } break; } case kFlagAfter: { if (sampleTime < req_time && *sample_index + 1 < mNumSampleSizes) { ++*sample_index; while (closestIndex + 1 < mNumSampleSizes && mSampleTimeEntries[closestIndex].mCompositionTime < req_time) { ++closestIndex; } break; } default: break; } { CHECK(flags == kFlagClosest); return OK; 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; } } time += delta * n; cur_sample += n; break; } } return ERROR_OUT_OF_RANGE; *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; return OK; } status_t SampleTable::findSyncSampleNear( Loading Loading @@ -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); Loading @@ -630,8 +695,8 @@ status_t SampleTable::getMetaDataForSample( *size = mSampleIterator->getSampleSize(); } if (decodingTime) { *decodingTime = mSampleIterator->getSampleTime(); if (compositionTime) { *compositionTime = mSampleIterator->getSampleTime(); } if (isSyncSample) { Loading
media/libstagefright/include/MPEG4Extractor.h +0 −2 Original line number Diff line number Diff line Loading @@ -92,8 +92,6 @@ private: Track *findTrackByMimePrefix(const char *mimePrefix); status_t verifyIfStreamable(); MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; Loading
media/libstagefright/include/SampleTable.h +11 −1 Original line number Diff line number Diff line Loading @@ -63,7 +63,7 @@ public: uint32_t sampleIndex, off64_t *offset, size_t *size, uint32_t *decodingTime, uint32_t *compositionTime, bool *isSyncSample = NULL); enum { Loading Loading @@ -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; Loading @@ -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 &); }; Loading