Merge "Remove streamability verification, it's taking too long. Also..."
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1ca2d6d..f9db1a1 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -377,7 +377,7 @@
             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
         }
 
-        mInitCheck = verifyIfStreamable();
+        mInitCheck = OK;
     } else {
         mInitCheck = err;
     }
@@ -1904,7 +1904,7 @@
 
     off64_t offset;
     size_t size;
-    uint32_t dts;
+    uint32_t cts;
     bool isSyncSample;
     bool newBuffer = false;
     if (mBuffer == NULL) {
@@ -1912,7 +1912,7 @@
 
         status_t err =
             mSampleTable->getMetaDataForSample(
-                    mCurrentSampleIndex, &offset, &size, &dts, &isSyncSample);
+                    mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);
 
         if (err != OK) {
             return err;
@@ -1942,7 +1942,7 @@
             mBuffer->set_range(0, size);
             mBuffer->meta_data()->clear();
             mBuffer->meta_data()->setInt64(
-                    kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
+                    kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
 
             if (targetSampleTimeUs >= 0) {
                 mBuffer->meta_data()->setInt64(
@@ -2060,7 +2060,7 @@
 
         mBuffer->meta_data()->clear();
         mBuffer->meta_data()->setInt64(
-                kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
+                kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             mBuffer->meta_data()->setInt64(
@@ -2094,87 +2094,6 @@
     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];
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 423df70..08db902 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -53,6 +53,7 @@
       mNumSampleSizes(0),
       mTimeToSampleCount(0),
       mTimeToSample(NULL),
+      mSampleTimeEntries(NULL),
       mCompositionTimeDeltaEntries(NULL),
       mNumCompositionTimeDeltaEntries(0),
       mSyncSampleOffset(-1),
@@ -73,6 +74,9 @@
     delete[] mCompositionTimeDeltaEntries;
     mCompositionTimeDeltaEntries = NULL;
 
+    delete[] mSampleTimeEntries;
+    mSampleTimeEntries = NULL;
+
     delete[] mTimeToSample;
     mTimeToSample = NULL;
 
@@ -381,67 +385,128 @@
     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);
 
-            uint32_t time1 = time + j * delta;
-            uint32_t time2 = time1 + delta;
+            mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
 
-            uint32_t sampleTime;
-            if (i+1 == mTimeToSampleCount
-                    || (abs_difference(req_time, time1)
-                        < abs_difference(req_time, time2))) {
-                *sample_index = cur_sample + j;
-                sampleTime = time1;
-            } else {
-                *sample_index = cur_sample + j + 1;
-                sampleTime = time2;
-            }
+            mSampleTimeEntries[sampleIndex].mCompositionTime =
+                sampleTime + getCompositionTimeOffset(sampleIndex);
 
-            switch (flags) {
-                case kFlagBefore:
-                {
-                    if (sampleTime > req_time && *sample_index > 0) {
-                        --*sample_index;
-                    }
-                    break;
-                }
-
-                case kFlagAfter:
-                {
-                    if (sampleTime < req_time
-                            && *sample_index + 1 < mNumSampleSizes) {
-                        ++*sample_index;
-                    }
-                    break;
-                }
-
-                default:
-                    break;
-            }
-
-            return OK;
+            ++sampleIndex;
+            sampleTime += delta;
         }
-
-        time += delta * n;
-        cur_sample += n;
     }
 
-    return ERROR_OUT_OF_RANGE;
+    qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
+          CompareIncreasingTime);
+}
+
+status_t SampleTable::findSampleAtTime(
+        uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+    buildSampleEntriesTable();
+
+    uint32_t left = 0;
+    uint32_t right = mNumSampleSizes;
+    while (left < right) {
+        uint32_t center = (left + right) / 2;
+        uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
+
+        if (req_time < centerTime) {
+            right = center;
+        } else if (req_time > centerTime) {
+            left = center + 1;
+        } else {
+            left = center;
+            break;
+        }
+    }
+
+    if (left == mNumSampleSizes) {
+        --left;
+    }
+
+    uint32_t closestIndex = left;
+
+    switch (flags) {
+        case kFlagBefore:
+        {
+            while (closestIndex > 0
+                    && mSampleTimeEntries[closestIndex].mCompositionTime
+                            > req_time) {
+                --closestIndex;
+            }
+            break;
+        }
+
+        case kFlagAfter:
+        {
+            while (closestIndex + 1 < mNumSampleSizes
+                    && mSampleTimeEntries[closestIndex].mCompositionTime
+                            < req_time) {
+                ++closestIndex;
+            }
+            break;
+        }
+
+        default:
+        {
+            CHECK(flags == kFlagClosest);
+
+            if (closestIndex > 0) {
+                // Check left neighbour and pick closest.
+                uint32_t absdiff1 =
+                    abs_difference(
+                            mSampleTimeEntries[closestIndex].mCompositionTime,
+                            req_time);
+
+                uint32_t absdiff2 =
+                    abs_difference(
+                            mSampleTimeEntries[closestIndex - 1].mCompositionTime,
+                            req_time);
+
+                if (absdiff1 > absdiff2) {
+                    closestIndex = closestIndex - 1;
+                }
+            }
+
+            break;
+        }
+    }
+
+    *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
+
+    return OK;
 }
 
 status_t SampleTable::findSyncSampleNear(
@@ -613,7 +678,7 @@
         uint32_t sampleIndex,
         off64_t *offset,
         size_t *size,
-        uint32_t *decodingTime,
+        uint32_t *compositionTime,
         bool *isSyncSample) {
     Mutex::Autolock autoLock(mLock);
 
@@ -630,8 +695,8 @@
         *size = mSampleIterator->getSampleSize();
     }
 
-    if (decodingTime) {
-        *decodingTime = mSampleIterator->getSampleTime();
+    if (compositionTime) {
+        *compositionTime = mSampleIterator->getSampleTime();
     }
 
     if (isSyncSample) {
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index d9ef208..3bd4c7e 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -92,8 +92,6 @@
 
     Track *findTrackByMimePrefix(const char *mimePrefix);
 
-    status_t verifyIfStreamable();
-
     MPEG4Extractor(const MPEG4Extractor &);
     MPEG4Extractor &operator=(const MPEG4Extractor &);
 };
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 2f95de9..f44e0a2 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -63,7 +63,7 @@
             uint32_t sampleIndex,
             off64_t *offset,
             size_t *size,
-            uint32_t *decodingTime,
+            uint32_t *compositionTime,
             bool *isSyncSample = NULL);
 
     enum {
@@ -107,6 +107,12 @@
     uint32_t mTimeToSampleCount;
     uint32_t *mTimeToSample;
 
+    struct SampleTimeEntry {
+        uint32_t mSampleIndex;
+        uint32_t mCompositionTime;
+    };
+    SampleTimeEntry *mSampleTimeEntries;
+
     uint32_t *mCompositionTimeDeltaEntries;
     size_t mNumCompositionTimeDeltaEntries;
 
@@ -130,6 +136,10 @@
 
     uint32_t getCompositionTimeOffset(uint32_t sampleIndex) const;
 
+    static int CompareIncreasingTime(const void *, const void *);
+
+    void buildSampleEntriesTable();
+
     SampleTable(const SampleTable &);
     SampleTable &operator=(const SampleTable &);
 };