summaryrefslogtreecommitdiffstats
path: root/media/libstagefright
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-01-19 10:39:21 -0800
committerAndreas Huber <andih@google.com>2010-01-19 10:39:21 -0800
commitc57b67905c2128ddadfeca96785ee1f593b6605a (patch)
tree7c7fb1b4cc87520eae2ede9229e7fc78d6e88c3e /media/libstagefright
parent97419ed670a12f48a7609673da8ee5dc0376f075 (diff)
downloadframeworks_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.mk1
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp17
-rw-r--r--media/libstagefright/SampleIterator.cpp310
-rw-r--r--media/libstagefright/SampleTable.cpp323
-rw-r--r--media/libstagefright/include/SampleIterator.h75
-rw-r--r--media/libstagefright/include/SampleTable.h40
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 &);
};