Support for communicating if a buffer read from the _extractor_ is a sync sample or not.

Change-Id: Ie71506224d937cfff1fa1273bfac31c47db8845f
related-to-bug: 2900534
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 9fc1d27..70af2da 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -263,6 +263,7 @@
 
     buffer->set_range(0, frameSize);
     buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 
     mOffset += frameSize;
     mCurrentTimeUs += 20000;  // Each frame is 20ms
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 2248e23..4058fbc 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -683,6 +683,7 @@
     buffer->set_range(0, frame_size);
 
     buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 
     mCurrentPos += frame_size;
     mCurrentTimeUs += frame_size * 8000ll / bitrate;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index d937838..6af3a7f 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1551,13 +1551,14 @@
     off_t offset;
     size_t size;
     uint32_t dts;
+    bool isSyncSample;
     bool newBuffer = false;
     if (mBuffer == NULL) {
         newBuffer = true;
 
         status_t err =
             mSampleTable->getMetaDataForSample(
-                    mCurrentSampleIndex, &offset, &size, &dts);
+                    mCurrentSampleIndex, &offset, &size, &dts, &isSyncSample);
 
         if (err != OK) {
             return err;
@@ -1594,6 +1595,10 @@
                         kKeyTargetTime, targetSampleTimeUs);
             }
 
+            if (isSyncSample) {
+                mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+            }
+
             ++mCurrentSampleIndex;
         }
 
@@ -1696,6 +1701,10 @@
                     kKeyTargetTime, targetSampleTimeUs);
         }
 
+        if (isSyncSample) {
+            mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+        }
+
         ++mCurrentSampleIndex;
 
         *out = mBuffer;
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 641a876..b699d8f 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -181,6 +181,8 @@
     }
 #endif
 
+    packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+
     *out = packet;
 
     return OK;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 2e62f9f..27faf4f 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -55,6 +55,8 @@
       mTimeToSample(NULL),
       mSyncSampleOffset(-1),
       mNumSyncSamples(0),
+      mSyncSamples(NULL),
+      mLastSyncSampleIndex(0),
       mSampleToChunkEntries(NULL) {
     mSampleIterator = new SampleIterator(this);
 }
@@ -63,6 +65,9 @@
     delete[] mSampleToChunkEntries;
     mSampleToChunkEntries = NULL;
 
+    delete[] mSyncSamples;
+    mSyncSamples = NULL;
+
     delete[] mTimeToSample;
     mTimeToSample = NULL;
 
@@ -278,6 +283,18 @@
     if (mNumSyncSamples < 2) {
         LOGW("Table of sync samples is empty or has only a single entry!");
     }
+
+    mSyncSamples = new uint32_t[mNumSyncSamples];
+    size_t size = mNumSyncSamples * sizeof(uint32_t);
+    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
+            != (ssize_t)size) {
+        return ERROR_IO;
+    }
+
+    for (size_t i = 0; i < mNumSyncSamples; ++i) {
+        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
+    }
+
     return OK;
 }
 
@@ -394,14 +411,7 @@
 
     uint32_t left = 0;
     while (left < mNumSyncSamples) {
-        uint32_t x;
-        if (mDataSource->readAt(
-                    mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
-            return ERROR_IO;
-        }
-
-        x = ntohl(x);
-        --x;
+        uint32_t x = mSyncSamples[left];
 
         if (x >= start_sample_index) {
             break;
@@ -421,14 +431,7 @@
     --x;
 
     if (left + 1 < mNumSyncSamples) {
-        uint32_t y;
-        if (mDataSource->readAt(
-                    mSyncSampleOffset + 8 + (left + 1) * 4, &y, 4) != 4) {
-            return ERROR_IO;
-        }
-
-        y = ntohl(y);
-        --y;
+        uint32_t y = mSyncSamples[left + 1];
 
         // our sample lies between sync samples x and y.
 
@@ -486,13 +489,7 @@
                     return ERROR_OUT_OF_RANGE;
                 }
 
-                if (mDataSource->readAt(
-                            mSyncSampleOffset + 8 + (left + 1) * 4, &x, 4) != 4) {
-                    return ERROR_IO;
-                }
-
-                x = ntohl(x);
-                --x;
+                x = mSyncSamples[left + 1];
 
                 CHECK(x >= start_sample_index);
             }
@@ -532,13 +529,7 @@
     }
 
     for (size_t i = 0; i < numSamplesToScan; ++i) {
-        uint32_t x;
-        if (mDataSource->readAt(
-                    mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
-            return ERROR_IO;
-        }
-        x = ntohl(x);
-        --x;
+        uint32_t x = mSyncSamples[i];
 
         // Now x is a sample index.
         size_t sampleSize;
@@ -568,7 +559,8 @@
         uint32_t sampleIndex,
         off_t *offset,
         size_t *size,
-        uint32_t *decodingTime) {
+        uint32_t *decodingTime,
+        bool *isSyncSample) {
     Mutex::Autolock autoLock(mLock);
 
     status_t err;
@@ -588,6 +580,28 @@
         *decodingTime = mSampleIterator->getSampleTime();
     }
 
+    if (isSyncSample) {
+        *isSyncSample = false;
+        if (mSyncSampleOffset < 0) {
+            // Every sample is a sync sample.
+            *isSyncSample = true;
+        } else {
+            size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
+                    && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
+                ? mLastSyncSampleIndex : 0;
+
+            while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
+                ++i;
+            }
+
+            if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
+                *isSyncSample = true;
+            }
+
+            mLastSyncSampleIndex = i;
+        }
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 7c2b07e..39b1b96 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -358,6 +358,7 @@
             1000000LL * (mCurrentPos - mOffset)
                 / (mNumChannels * bytesPerSample) / mSampleRate);
 
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 
     *out = buffer;
 
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index a2b2c99..f830690 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -60,7 +60,8 @@
             uint32_t sampleIndex,
             off_t *offset,
             size_t *size,
-            uint32_t *decodingTime);
+            uint32_t *decodingTime,
+            bool *isSyncSample = NULL);
 
     enum {
         kFlagBefore,
@@ -105,6 +106,8 @@
 
     off_t mSyncSampleOffset;
     uint32_t mNumSyncSamples;
+    uint32_t *mSyncSamples;
+    size_t mLastSyncSampleIndex;
 
     SampleIterator *mSampleIterator;
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 3739be1..71f6587 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -296,6 +296,7 @@
 
     MediaBuffer *buffer = new MediaBuffer(size + 2);
     buffer->meta_data()->setInt64(kKeyTime, timeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
     long res = block->Read(
             mExtractor->mReader, (unsigned char *)buffer->data() + 2);