diff options
author | Andreas Huber <andih@google.com> | 2010-01-19 10:39:21 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-01-19 10:39:21 -0800 |
commit | c57b67905c2128ddadfeca96785ee1f593b6605a (patch) | |
tree | 7c7fb1b4cc87520eae2ede9229e7fc78d6e88c3e /media/libstagefright | |
parent | 97419ed670a12f48a7609673da8ee5dc0376f075 (diff) | |
download | frameworks_av-c57b67905c2128ddadfeca96785ee1f593b6605a.zip frameworks_av-c57b67905c2128ddadfeca96785ee1f593b6605a.tar.gz frameworks_av-c57b67905c2128ddadfeca96785ee1f593b6605a.tar.bz2 |
Squashed commit of the following:
commit 6689350d7e4dad6d873c1ed95f0a356e3bfd79d1
Author: Andreas Huber <andih@google.com>
Date: Tue Jan 19 09:23:02 2010 -0800
Some tweaks to the SampleIterator.
commit 5638bff6d31442a219806445c3106d47b081fcab
Author: Andreas Huber <andih@google.com>
Date: Fri Jan 15 14:46:29 2010 -0800
A much improved implementation of MPEG4 sample table operations through an iterator.
Diffstat (limited to 'media/libstagefright')
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 17 | ||||
-rw-r--r-- | media/libstagefright/SampleIterator.cpp | 310 | ||||
-rw-r--r-- | media/libstagefright/SampleTable.cpp | 323 | ||||
-rw-r--r-- | media/libstagefright/include/SampleIterator.h | 75 | ||||
-rw-r--r-- | media/libstagefright/include/SampleTable.h | 40 |
6 files changed, 499 insertions, 267 deletions
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index e36e78c..26b9357 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -29,6 +29,7 @@ LOCAL_SRC_FILES += \ MPEG4Extractor.cpp \ MPEG4Writer.cpp \ MediaExtractor.cpp \ + SampleIterator.cpp \ SampleTable.cpp \ ShoutcastSource.cpp \ StagefrightMediaScanner.cpp \ diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 07a5a82..0e9900b 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -232,8 +232,9 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData( uint32_t sampleIndex; uint32_t sampleTime; if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK - && track->sampleTable->getDecodingTime( - sampleIndex, &sampleTime) == OK) { + && track->sampleTable->getMetaDataForSample( + sampleIndex, NULL /* offset */, NULL /* size */, + &sampleTime) == OK) { track->meta->setInt64( kKeyThumbnailTime, ((int64_t)sampleTime * 1000000) / track->timescale); @@ -929,20 +930,16 @@ status_t MPEG4Source::read( if (mBuffer == NULL) { newBuffer = true; - status_t err = mSampleTable->getSampleOffsetAndSize( - mCurrentSampleIndex, &offset, &size); - - if (err != OK) { - return err; - } - - err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts); + status_t err = + mSampleTable->getMetaDataForSample( + mCurrentSampleIndex, &offset, &size, &dts); if (err != OK) { return err; } err = mGroup->acquire_buffer(&mBuffer); + if (err != OK) { CHECK_EQ(mBuffer, NULL); return err; diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp new file mode 100644 index 0000000..faad42b --- /dev/null +++ b/media/libstagefright/SampleIterator.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SampleIterator" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + +#include "include/SampleIterator.h" + +#include <arpa/inet.h> + +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/Utils.h> + +#include "include/SampleTable.h" + +namespace android { + +SampleIterator::SampleIterator(SampleTable *table) + : mTable(table), + mInitialized(false), + mTimeToSampleIndex(0), + mTTSSampleIndex(0), + mTTSSampleTime(0), + mTTSCount(0), + mTTSDuration(0) { + reset(); +} + +void SampleIterator::reset() { + mSampleToChunkIndex = 0; + mFirstChunk = 0; + mFirstChunkSampleIndex = 0; + mStopChunk = 0; + mStopChunkSampleIndex = 0; + mSamplesPerChunk = 0; + mChunkDesc = 0; +} + +status_t SampleIterator::seekTo(uint32_t sampleIndex) { + LOGV("seekTo(%d)", sampleIndex); + + if (mTable->mSampleToChunkOffset < 0 + || mTable->mChunkOffsetOffset < 0 + || mTable->mSampleSizeOffset < 0 + || mTable->mTimeToSampleCount == 0) { + + return ERROR_MALFORMED; + } + + if (mInitialized && mCurrentSampleIndex == sampleIndex) { + return OK; + } + + if (!mInitialized || sampleIndex < mFirstChunkSampleIndex) { + reset(); + } + + if (sampleIndex >= mStopChunkSampleIndex) { + status_t err; + if ((err = findChunkRange(sampleIndex)) != OK) { + LOGE("findChunkRange failed"); + return err; + } + } + + CHECK(sampleIndex < mStopChunkSampleIndex); + + uint32_t chunk = + (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk + + mFirstChunk; + + if (!mInitialized || chunk != mCurrentChunkIndex) { + mCurrentChunkIndex = chunk; + + status_t err; + if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) { + LOGE("getChunkOffset return error"); + return err; + } + + mCurrentChunkSampleSizes.clear(); + + uint32_t firstChunkSampleIndex = + mFirstChunkSampleIndex + + mSamplesPerChunk * (mCurrentChunkIndex - mFirstChunk); + + for (uint32_t i = 0; i < mSamplesPerChunk; ++i) { + size_t sampleSize; + if ((err = getSampleSizeDirect( + firstChunkSampleIndex + i, &sampleSize)) != OK) { + LOGE("getSampleSizeDirect return error"); + return err; + } + + mCurrentChunkSampleSizes.push(sampleSize); + } + } + + uint32_t chunkRelativeSampleIndex = + (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk; + + mCurrentSampleOffset = mCurrentChunkOffset; + for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) { + mCurrentSampleOffset += mCurrentChunkSampleSizes[i]; + } + + mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex]; + if (sampleIndex < mTTSSampleIndex) { + mTimeToSampleIndex = 0; + mTTSSampleIndex = 0; + mTTSSampleTime = 0; + mTTSCount = 0; + mTTSDuration = 0; + } + + status_t err; + if ((err = findSampleTime(sampleIndex, &mCurrentSampleTime)) != OK) { + LOGE("findSampleTime return error"); + return err; + } + + mCurrentSampleIndex = sampleIndex; + + mInitialized = true; + + return OK; +} + +status_t SampleIterator::findChunkRange(uint32_t sampleIndex) { + CHECK(sampleIndex >= mFirstChunkSampleIndex); + + while (sampleIndex >= mStopChunkSampleIndex) { + if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) { + return ERROR_OUT_OF_RANGE; + } + + mFirstChunkSampleIndex = mStopChunkSampleIndex; + + const SampleTable::SampleToChunkEntry *entry = + &mTable->mSampleToChunkEntries[mSampleToChunkIndex]; + + mFirstChunk = entry->startChunk; + mSamplesPerChunk = entry->samplesPerChunk; + mChunkDesc = entry->chunkDesc; + + if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) { + mStopChunk = entry[1].startChunk; + + mStopChunkSampleIndex = + mFirstChunkSampleIndex + + (mStopChunk - mFirstChunk) * mSamplesPerChunk; + } else { + mStopChunk = 0xffffffff; + mStopChunkSampleIndex = 0xffffffff; + } + + ++mSampleToChunkIndex; + } + + return OK; +} + +status_t SampleIterator::getChunkOffset(uint32_t chunk, off_t *offset) { + *offset = 0; + + if (chunk >= mTable->mNumChunkOffsets) { + return ERROR_OUT_OF_RANGE; + } + + if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) { + uint32_t offset32; + + if (mTable->mDataSource->readAt( + mTable->mChunkOffsetOffset + 8 + 4 * chunk, + &offset32, + sizeof(offset32)) < (ssize_t)sizeof(offset32)) { + return ERROR_IO; + } + + *offset = ntohl(offset32); + } else { + CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64); + + uint64_t offset64; + if (mTable->mDataSource->readAt( + mTable->mChunkOffsetOffset + 8 + 8 * chunk, + &offset64, + sizeof(offset64)) < (ssize_t)sizeof(offset64)) { + return ERROR_IO; + } + + *offset = ntoh64(offset64); + } + + return OK; +} + +status_t SampleIterator::getSampleSizeDirect( + uint32_t sampleIndex, size_t *size) { + *size = 0; + + if (sampleIndex >= mTable->mNumSampleSizes) { + return ERROR_OUT_OF_RANGE; + } + + if (mTable->mDefaultSampleSize > 0) { + *size = mTable->mDefaultSampleSize; + return OK; + } + + switch (mTable->mSampleSizeFieldSize) { + case 32: + { + if (mTable->mDataSource->readAt( + mTable->mSampleSizeOffset + 12 + 4 * sampleIndex, + size, sizeof(*size)) < (ssize_t)sizeof(*size)) { + return ERROR_IO; + } + + *size = ntohl(*size); + break; + } + + case 16: + { + uint16_t x; + if (mTable->mDataSource->readAt( + mTable->mSampleSizeOffset + 12 + 2 * sampleIndex, + &x, sizeof(x)) < (ssize_t)sizeof(x)) { + return ERROR_IO; + } + + *size = ntohs(x); + break; + } + + case 8: + { + uint8_t x; + if (mTable->mDataSource->readAt( + mTable->mSampleSizeOffset + 12 + sampleIndex, + &x, sizeof(x)) < (ssize_t)sizeof(x)) { + return ERROR_IO; + } + + *size = x; + break; + } + + default: + { + CHECK_EQ(mTable->mSampleSizeFieldSize, 4); + + uint8_t x; + if (mTable->mDataSource->readAt( + mTable->mSampleSizeOffset + 12 + sampleIndex / 2, + &x, sizeof(x)) < (ssize_t)sizeof(x)) { + return ERROR_IO; + } + + *size = (sampleIndex & 1) ? x & 0x0f : x >> 4; + break; + } + } + + return OK; +} + +status_t SampleIterator::findSampleTime( + uint32_t sampleIndex, uint32_t *time) { + if (sampleIndex >= mTable->mNumSampleSizes) { + return ERROR_OUT_OF_RANGE; + } + + while (sampleIndex >= mTTSSampleIndex + mTTSCount) { + if (mTimeToSampleIndex == mTable->mTimeToSampleCount) { + return ERROR_OUT_OF_RANGE; + } + + mTTSSampleIndex += mTTSCount; + mTTSSampleTime += mTTSCount * mTTSDuration; + + mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex]; + mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1]; + + ++mTimeToSampleIndex; + } + + *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex); + + return OK; +} + +} // namespace android + diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 2de96d4..89a522e 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -15,9 +15,11 @@ */ #define LOG_TAG "SampleTable" +//#define LOG_NDEBUG 0 #include <utils/Log.h> #include "include/SampleTable.h" +#include "include/SampleIterator.h" #include <arpa/inet.h> @@ -27,10 +29,16 @@ namespace android { -static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); -static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); -static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); -static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); +// static +const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); +// static +const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); +// static +const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); +// static +const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); + +//////////////////////////////////////////////////////////////////////////////// SampleTable::SampleTable(const sp<DataSource> &source) : mDataSource(source), @@ -46,12 +54,20 @@ SampleTable::SampleTable(const sp<DataSource> &source) mTimeToSampleCount(0), mTimeToSample(NULL), mSyncSampleOffset(-1), - mNumSyncSamples(0) { + mNumSyncSamples(0), + mSampleToChunkEntries(NULL) { + mSampleIterator = new SampleIterator(this); } SampleTable::~SampleTable() { + delete[] mSampleToChunkEntries; + mSampleToChunkEntries = NULL; + delete[] mTimeToSample; mTimeToSample = NULL; + + delete mSampleIterator; + mSampleIterator = NULL; } status_t SampleTable::setChunkOffsetParams( @@ -124,6 +140,25 @@ status_t SampleTable::setSampleToChunkParams( return ERROR_MALFORMED; } + mSampleToChunkEntries = + new SampleToChunkEntry[mNumSampleToChunkOffsets]; + + for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { + uint8_t buffer[12]; + if (mDataSource->readAt( + mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) + != (ssize_t)sizeof(buffer)) { + return ERROR_IO; + } + + CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. + + // We want the chunk index to be 0-based. + mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; + mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); + mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); + } + return OK; } @@ -250,217 +285,10 @@ uint32_t SampleTable::countChunkOffsets() const { return mNumChunkOffsets; } -status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) { - *offset = 0; - - if (mChunkOffsetOffset < 0) { - return ERROR_MALFORMED; - } - - if (chunk_index >= mNumChunkOffsets) { - return ERROR_OUT_OF_RANGE; - } - - if (mChunkOffsetType == kChunkOffsetType32) { - uint32_t offset32; - - if (mDataSource->readAt( - mChunkOffsetOffset + 8 + 4 * chunk_index, - &offset32, - sizeof(offset32)) < (ssize_t)sizeof(offset32)) { - return ERROR_IO; - } - - *offset = ntohl(offset32); - } else { - CHECK_EQ(mChunkOffsetType, kChunkOffsetType64); - - uint64_t offset64; - if (mDataSource->readAt( - mChunkOffsetOffset + 8 + 8 * chunk_index, - &offset64, - sizeof(offset64)) < (ssize_t)sizeof(offset64)) { - return ERROR_IO; - } - - *offset = ntoh64(offset64); - } - - return OK; -} - -status_t SampleTable::getChunkForSample( - uint32_t sample_index, - uint32_t *chunk_index, - uint32_t *chunk_relative_sample_index, - uint32_t *desc_index) { - *chunk_index = 0; - *chunk_relative_sample_index = 0; - *desc_index = 0; - - if (mSampleToChunkOffset < 0) { - return ERROR_MALFORMED; - } - - if (sample_index >= countSamples()) { - return ERROR_END_OF_STREAM; - } - - uint32_t first_chunk = 0; - uint32_t samples_per_chunk = 0; - uint32_t chunk_desc_index = 0; - - uint32_t index = 0; - while (index < mNumSampleToChunkOffsets) { - uint8_t buffer[12]; - if (mDataSource->readAt(mSampleToChunkOffset + 8 + index * 12, - buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) { - return ERROR_IO; - } - - uint32_t stop_chunk = U32_AT(buffer); - if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) { - break; - } - - sample_index -= (stop_chunk - first_chunk) * samples_per_chunk; - first_chunk = stop_chunk; - samples_per_chunk = U32_AT(&buffer[4]); - chunk_desc_index = U32_AT(&buffer[8]); - - ++index; - } - - *chunk_index = sample_index / samples_per_chunk + first_chunk - 1; - *chunk_relative_sample_index = sample_index % samples_per_chunk; - *desc_index = chunk_desc_index; - - return OK; -} - uint32_t SampleTable::countSamples() const { return mNumSampleSizes; } -status_t SampleTable::getSampleSize( - uint32_t sample_index, size_t *sample_size) { - *sample_size = 0; - - if (mSampleSizeOffset < 0) { - return ERROR_MALFORMED; - } - - if (sample_index >= mNumSampleSizes) { - return ERROR_OUT_OF_RANGE; - } - - if (mDefaultSampleSize > 0) { - *sample_size = mDefaultSampleSize; - return OK; - } - - switch (mSampleSizeFieldSize) { - case 32: - { - if (mDataSource->readAt( - mSampleSizeOffset + 12 + 4 * sample_index, - sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) { - return ERROR_IO; - } - - *sample_size = ntohl(*sample_size); - break; - } - - case 16: - { - uint16_t x; - if (mDataSource->readAt( - mSampleSizeOffset + 12 + 2 * sample_index, - &x, sizeof(x)) < (ssize_t)sizeof(x)) { - return ERROR_IO; - } - - *sample_size = ntohs(x); - break; - } - - case 8: - { - uint8_t x; - if (mDataSource->readAt( - mSampleSizeOffset + 12 + sample_index, - &x, sizeof(x)) < (ssize_t)sizeof(x)) { - return ERROR_IO; - } - - *sample_size = x; - break; - } - - default: - { - CHECK_EQ(mSampleSizeFieldSize, 4); - - uint8_t x; - if (mDataSource->readAt( - mSampleSizeOffset + 12 + sample_index / 2, - &x, sizeof(x)) < (ssize_t)sizeof(x)) { - return ERROR_IO; - } - - *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4; - break; - } - } - - return OK; -} - -status_t SampleTable::getSampleOffsetAndSize( - uint32_t sample_index, off_t *offset, size_t *size) { - Mutex::Autolock autoLock(mLock); - - *offset = 0; - *size = 0; - - uint32_t chunk_index; - uint32_t chunk_relative_sample_index; - uint32_t desc_index; - status_t err = getChunkForSample( - sample_index, &chunk_index, &chunk_relative_sample_index, - &desc_index); - - if (err != OK) { - return err; - } - - err = getChunkOffset(chunk_index, offset); - - if (err != OK) { - return err; - } - - for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) { - size_t sample_size; - err = getSampleSize(sample_index - j - 1, &sample_size); - - if (err != OK) { - return err; - } - - *offset += sample_size; - } - - err = getSampleSize(sample_index, size); - - if (err != OK) { - return err; - } - - return OK; -} - status_t SampleTable::getMaxSampleSize(size_t *max_size) { Mutex::Autolock autoLock(mLock); @@ -468,7 +296,7 @@ status_t SampleTable::getMaxSampleSize(size_t *max_size) { for (uint32_t i = 0; i < mNumSampleSizes; ++i) { size_t sample_size; - status_t err = getSampleSize(i, &sample_size); + status_t err = getSampleSize_l(i, &sample_size); if (err != OK) { return err; @@ -482,34 +310,6 @@ status_t SampleTable::getMaxSampleSize(size_t *max_size) { return OK; } -status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) { - // XXX FIXME idiotic (for the common use-case) O(n) algorithm below... - - Mutex::Autolock autoLock(mLock); - - if (sample_index >= mNumSampleSizes) { - return ERROR_OUT_OF_RANGE; - } - - uint32_t cur_sample = 0; - *time = 0; - for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { - uint32_t n = mTimeToSample[2 * i]; - uint32_t delta = mTimeToSample[2 * i + 1]; - - if (sample_index < cur_sample + n) { - *time += delta * (sample_index - cur_sample); - - return OK; - } - - *time += delta * n; - cur_sample += n; - } - - return ERROR_OUT_OF_RANGE; -} - uint32_t abs_difference(uint32_t time1, uint32_t time2) { return time1 > time2 ? time1 - time2 : time2 - time1; } @@ -539,7 +339,7 @@ status_t SampleTable::findClosestSample( } if (flags & kSyncSample_Flag) { - return findClosestSyncSample(*sample_index, sample_index); + return findClosestSyncSample_l(*sample_index, sample_index); } return OK; @@ -552,7 +352,7 @@ status_t SampleTable::findClosestSample( return ERROR_OUT_OF_RANGE; } -status_t SampleTable::findClosestSyncSample( +status_t SampleTable::findClosestSyncSample_l( uint32_t start_sample_index, uint32_t *sample_index) { *sample_index = 0; @@ -590,6 +390,8 @@ status_t SampleTable::findClosestSyncSample( } status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { + Mutex::Autolock autoLock(mLock); + if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = 0; @@ -620,7 +422,7 @@ status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { // Now x is a sample index. size_t sampleSize; - status_t err = getSampleSize(x, &sampleSize); + status_t err = getSampleSize_l(x, &sampleSize); if (err != OK) { return err; } @@ -636,5 +438,38 @@ status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { return OK; } +status_t SampleTable::getSampleSize_l( + uint32_t sampleIndex, size_t *sampleSize) { + return mSampleIterator->getSampleSizeDirect( + sampleIndex, sampleSize); +} + +status_t SampleTable::getMetaDataForSample( + uint32_t sampleIndex, + off_t *offset, + size_t *size, + uint32_t *decodingTime) { + Mutex::Autolock autoLock(mLock); + + status_t err; + if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { + return err; + } + + if (offset) { + *offset = mSampleIterator->getSampleOffset(); + } + + if (size) { + *size = mSampleIterator->getSampleSize(); + } + + if (decodingTime) { + *decodingTime = mSampleIterator->getSampleTime(); + } + + return OK; +} + } // namespace android diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h new file mode 100644 index 0000000..a5eaed9 --- /dev/null +++ b/media/libstagefright/include/SampleIterator.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <utils/Vector.h> + +namespace android { + +struct SampleTable; + +struct SampleIterator { + SampleIterator(SampleTable *table); + + status_t seekTo(uint32_t sampleIndex); + + uint32_t getChunkIndex() const { return mCurrentChunkIndex; } + uint32_t getDescIndex() const { return mChunkDesc; } + off_t getSampleOffset() const { return mCurrentSampleOffset; } + size_t getSampleSize() const { return mCurrentSampleSize; } + uint32_t getSampleTime() const { return mCurrentSampleTime; } + + status_t getSampleSizeDirect( + uint32_t sampleIndex, size_t *size); + +private: + SampleTable *mTable; + + bool mInitialized; + + uint32_t mSampleToChunkIndex; + uint32_t mFirstChunk; + uint32_t mFirstChunkSampleIndex; + uint32_t mStopChunk; + uint32_t mStopChunkSampleIndex; + uint32_t mSamplesPerChunk; + uint32_t mChunkDesc; + + uint32_t mCurrentChunkIndex; + off_t mCurrentChunkOffset; + Vector<size_t> mCurrentChunkSampleSizes; + + uint32_t mTimeToSampleIndex; + uint32_t mTTSSampleIndex; + uint32_t mTTSSampleTime; + uint32_t mTTSCount; + uint32_t mTTSDuration; + + uint32_t mCurrentSampleIndex; + off_t mCurrentSampleOffset; + size_t mCurrentSampleSize; + uint32_t mCurrentSampleTime; + + void reset(); + status_t findChunkRange(uint32_t sampleIndex); + status_t getChunkOffset(uint32_t chunk, off_t *offset); + status_t findSampleTime(uint32_t sampleIndex, uint32_t *time); + + SampleIterator(const SampleIterator &); + SampleIterator &operator=(const SampleIterator &); +}; + +} // namespace android + diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h index ead3431..533ce84 100644 --- a/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/include/SampleTable.h @@ -28,6 +28,7 @@ namespace android { class DataSource; +struct SampleIterator; class SampleTable : public RefBase { public: @@ -50,21 +51,16 @@ public: //////////////////////////////////////////////////////////////////////////// uint32_t countChunkOffsets() const; - status_t getChunkOffset(uint32_t chunk_index, off_t *offset); - - status_t getChunkForSample( - uint32_t sample_index, uint32_t *chunk_index, - uint32_t *chunk_relative_sample_index, uint32_t *desc_index); uint32_t countSamples() const; - status_t getSampleSize(uint32_t sample_index, size_t *sample_size); - - status_t getSampleOffsetAndSize( - uint32_t sample_index, off_t *offset, size_t *size); status_t getMaxSampleSize(size_t *size); - status_t getDecodingTime(uint32_t sample_index, uint32_t *time); + status_t getMetaDataForSample( + uint32_t sampleIndex, + off_t *offset, + size_t *size, + uint32_t *decodingTime); enum { kSyncSample_Flag = 1 @@ -72,15 +68,17 @@ public: status_t findClosestSample( uint32_t req_time, uint32_t *sample_index, uint32_t flags); - status_t findClosestSyncSample( - uint32_t start_sample_index, uint32_t *sample_index); - status_t findThumbnailSample(uint32_t *sample_index); protected: ~SampleTable(); private: + static const uint32_t kChunkOffsetType32; + static const uint32_t kChunkOffsetType64; + static const uint32_t kSampleSizeType32; + static const uint32_t kSampleSizeTypeCompact; + sp<DataSource> mDataSource; Mutex mLock; @@ -102,6 +100,22 @@ private: off_t mSyncSampleOffset; uint32_t mNumSyncSamples; + SampleIterator *mSampleIterator; + + struct SampleToChunkEntry { + uint32_t startChunk; + uint32_t samplesPerChunk; + uint32_t chunkDesc; + }; + SampleToChunkEntry *mSampleToChunkEntries; + + friend struct SampleIterator; + + status_t findClosestSyncSample_l( + uint32_t start_sample_index, uint32_t *sample_index); + + status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size); + SampleTable(const SampleTable &); SampleTable &operator=(const SampleTable &); }; |