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.
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 @@
         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 @@
             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 @@
     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..faad42ba
--- /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 @@
       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 @@
         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 @@
     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 @@
 
     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 @@
     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 @@
             }
 
             if (flags & kSyncSample_Flag) {
-                return findClosestSyncSample(*sample_index, sample_index);
+                return findClosestSyncSample_l(*sample_index, sample_index);
             }
 
             return OK;
@@ -552,7 +352,7 @@
     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::findThumbnailSample(uint32_t *sample_index) {
+    Mutex::Autolock autoLock(mLock);
+
     if (mSyncSampleOffset < 0) {
         // All samples are sync-samples.
         *sample_index = 0;
@@ -620,7 +422,7 @@
 
         // 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 @@
     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 @@
     ////////////////////////////////////////////////////////////////////////////
 
     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 @@
     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 @@
     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 &);
 };