Extract video thumbnails from the largest sync sample among the first 20.

Also fixes OMXCodec seek behaviour on the very first call to OMXCodec::read()
diff --git a/include/media/stagefright/AMRExtractor.h b/include/media/stagefright/AMRExtractor.h
index c8710d3..debf006 100644
--- a/include/media/stagefright/AMRExtractor.h
+++ b/include/media/stagefright/AMRExtractor.h
@@ -30,7 +30,7 @@
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     static sp<MetaData> makeAMRFormat(bool isWide);
 
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
index 11ba01d..074973b 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/include/media/stagefright/MP3Extractor.h
@@ -32,7 +32,7 @@
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
 protected:
     virtual ~MP3Extractor();
diff --git a/include/media/stagefright/MPEG4Extractor.h b/include/media/stagefright/MPEG4Extractor.h
index 932e30f..ce4736d 100644
--- a/include/media/stagefright/MPEG4Extractor.h
+++ b/include/media/stagefright/MPEG4Extractor.h
@@ -33,7 +33,7 @@
 
     size_t countTracks();
     sp<MediaSource> getTrack(size_t index);
-    sp<MetaData> getTrackMetaData(size_t index);
+    sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
 protected:
     virtual ~MPEG4Extractor();
@@ -44,6 +44,7 @@
         sp<MetaData> meta;
         uint32_t timescale;
         sp<SampleTable> sampleTable;
+        bool includes_expensive_metadata;
     };
 
     sp<DataSource> mDataSource;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 67e45bd..4d6b989 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -33,7 +33,12 @@
 
     virtual size_t countTracks() = 0;
     virtual sp<MediaSource> getTrack(size_t index) = 0;
-    virtual sp<MetaData> getTrackMetaData(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags = 0) = 0;
 
 protected:
     MediaExtractor() {}
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index d48ea41..c2d8f98 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -46,6 +46,7 @@
     kKeyDecoderComponent  = 'decC',  // cstring
     kKeyBufferID          = 'bfID',
     kKeyMaxInputSize      = 'inpS',
+    kKeyThumbnailTime     = 'thbT',  // int64_t (usecs)
 };
 
 enum {
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index c069128..5ac59c8 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -108,6 +108,9 @@
         return NULL;
     }
 
+    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
+            i, MediaExtractor::kIncludeExtensiveMetaData);
+
     sp<MediaSource> source = mExtractor->getTrack(i);
 
     if (source.get() == NULL) {
@@ -132,6 +135,12 @@
     // Read one output buffer, ignore format change notifications
     // and spurious empty buffers.
 
+    MediaSource::ReadOptions options;
+    int64_t thumbNailTime;
+    if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
+        options.setSeekTo(thumbNailTime);
+    }
+
     MediaBuffer *buffer = NULL;
     status_t err;
     do {
@@ -139,7 +148,8 @@
             buffer->release();
             buffer = NULL;
         }
-        err = decoder->read(&buffer);
+        err = decoder->read(&buffer, &options);
+        options.clearSeekTo();
     } while (err == INFO_FORMAT_CHANGED
              || (buffer != NULL && buffer->range_length() == 0));
 
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 1660351..74f055e 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -86,7 +86,7 @@
     return new AMRSource(mDataSource, mIsWide);
 }
 
-sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) {
+sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index b7dd9ba..78b8eb2 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -393,7 +393,7 @@
             mMeta, mDataSource, mFirstFramePos, mFixedHeader);
 }
 
-sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
     if (mFirstFramePos < 0 || index != 0) {
         return NULL;
     }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index da714f8..382133c 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -179,7 +179,8 @@
     return n;
 }
 
-sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
+sp<MetaData> MPEG4Extractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -199,6 +200,25 @@
         return NULL;
     }
 
+    if ((flags & kIncludeExtensiveMetaData)
+            && !track->includes_expensive_metadata) {
+        track->includes_expensive_metadata = true;
+
+        const char *mime;
+        CHECK(track->meta->findCString(kKeyMIMEType, &mime));
+        if (!strncasecmp("video/", mime, 6)) {
+            uint32_t sampleIndex;
+            uint32_t sampleTime;
+            if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
+                    && track->sampleTable->getDecodingTime(
+                        sampleIndex, &sampleTime) == OK) {
+                track->meta->setInt64(
+                        kKeyThumbnailTime,
+                        ((int64_t)sampleTime * 1000000) / track->timescale);
+            }
+        }
+    }
+
     return track->meta;
 }
 
@@ -353,6 +373,7 @@
             mLastTrack = track;
 
             track->meta = new MetaData;
+            track->includes_expensive_metadata = false;
             track->timescale = 0;
             track->sampleTable = new SampleTable(mDataSource);
             track->meta->setCString(kKeyMIMEType, "application/octet-stream");
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ff001e8..f8c0bda 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1943,9 +1943,24 @@
         return UNKNOWN_ERROR;
     }
 
+    bool seeking = false;
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        seeking = true;
+    }
+
     if (mInitialBufferSubmit) {
         mInitialBufferSubmit = false;
 
+        if (seeking) {
+            CHECK(seekTimeUs >= 0);
+            mSeekTimeUs = seekTimeUs;
+
+            // There's no reason to trigger the code below, there's
+            // nothing to flush yet.
+            seeking = false;
+        }
+
         drainInputBuffers();
 
         if (mState == EXECUTING) {
@@ -1955,8 +1970,7 @@
         }
     }
 
-    int64_t seekTimeUs;
-    if (options && options->getSeekTo(&seekTimeUs)) {
+    if (seeking) {
         CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
 
         mSignalledEOS = false;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 5c5bb4d..3eed52a 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -575,5 +575,52 @@
     return OK;
 }
 
+status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
+    if (mSyncSampleOffset < 0) {
+        // All samples are sync-samples.
+        *sample_index = 0;
+        return OK;
+    }
+
+    uint32_t bestSampleIndex = 0;
+    size_t maxSampleSize = 0;
+
+    static const size_t kMaxNumSyncSamplesToScan = 20;
+
+    // Consider the first kMaxNumSyncSamplesToScan sync samples and
+    // pick the one with the largest (compressed) size as the thumbnail.
+
+    size_t numSamplesToScan = mNumSyncSamples;
+    if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
+        numSamplesToScan = kMaxNumSyncSamplesToScan;
+    }
+
+    for (size_t i = 0; i < numSamplesToScan; ++i) {
+        uint32_t x;
+        if (mDataSource->read_at(
+                    mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
+            return ERROR_IO;
+        }
+        x = ntohl(x);
+        --x;
+
+        // Now x is a sample index.
+        size_t sampleSize;
+        status_t err = getSampleSize(x, &sampleSize);
+        if (err != OK) {
+            return err;
+        }
+
+        if (i == 0 || sampleSize > maxSampleSize) {
+            bestSampleIndex = x;
+            maxSampleSize = sampleSize;
+        }
+    }
+
+    *sample_index = bestSampleIndex;
+
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 34a0649..ead3431 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -75,6 +75,8 @@
     status_t findClosestSyncSample(
             uint32_t start_sample_index, uint32_t *sample_index);
 
+    status_t findThumbnailSample(uint32_t *sample_index);
+
 protected:
     ~SampleTable();