Merge "Add support for MPEG editlist gapless info"
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index 5f21da9..7d40379 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -146,9 +146,13 @@
     // this consumer
     sp<BufferQueue> mBufferQueue;
 
-    // mBufferSlot caches GraphicBuffers from the buffer queue
-    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+    struct SlotData {
+        sp<GraphicBuffer> mGraphicBuffer;
+        uint64_t mFrameNumber;
+    };
 
+    // mSlots caches GraphicBuffers and frameNumbers from the buffer queue
+    SlotData mSlots[BufferQueue::NUM_BUFFER_SLOTS];
 
     // The permenent width and height of SMS buffers
     int mWidth;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 409038a..71b6569 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -305,8 +305,9 @@
 
             // First time seeing the buffer?  Added it to the SMS slot
             if (item.mGraphicBuffer != NULL) {
-                mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+                mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
             }
+            mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
 
             // check for the timing of this buffer
             if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
@@ -315,7 +316,8 @@
                 if (mStartTimeNs > 0) {
                     if (item.mTimestamp < mStartTimeNs) {
                         // This frame predates start of record, discard
-                        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
+                        mBufferQueue->releaseBuffer(
+                                item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY,
                                 EGL_NO_SYNC_KHR, Fence::NO_FENCE);
                         continue;
                     }
@@ -345,17 +347,18 @@
 
     // First time seeing the buffer?  Added it to the SMS slot
     if (item.mGraphicBuffer != NULL) {
-        mBufferSlot[mCurrentSlot] = item.mGraphicBuffer;
+        mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
     }
+    mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
 
-    mCurrentBuffers.push_back(mBufferSlot[mCurrentSlot]);
+    mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer);
     int64_t prevTimeStamp = mCurrentTimestamp;
     mCurrentTimestamp = item.mTimestamp;
 
     mNumFramesEncoded++;
     // Pass the data to the MediaBuffer. Pass in only the metadata
 
-    passMetadataBuffer(buffer, mBufferSlot[mCurrentSlot]->handle);
+    passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle);
 
     (*buffer)->setObserver(this);
     (*buffer)->add_ref();
@@ -405,15 +408,16 @@
     }
 
     for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) {
-        if (mBufferSlot[id] == NULL) {
+        if (mSlots[id].mGraphicBuffer == NULL) {
             continue;
         }
 
-        if (bufferHandle == mBufferSlot[id]->handle) {
+        if (bufferHandle == mSlots[id].mGraphicBuffer->handle) {
             ALOGV("Slot %d returned, matches handle = %p", id,
-                    mBufferSlot[id]->handle);
+                    mSlots[id].mGraphicBuffer->handle);
 
-            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+            mBufferQueue->releaseBuffer(id, mSlots[id].mFrameNumber,
+                                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
                     Fence::NO_FENCE);
 
             buffer->setObserver(0);
@@ -469,7 +473,7 @@
     mFrameAvailableCondition.signal();
 
     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-       mBufferSlot[i] = 0;
+       mSlots[i].mGraphicBuffer = 0;
     }
 }
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index ef27879..b3a8463 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -206,24 +206,15 @@
     // Find matching entry in our cached copy of the BufferQueue slots.
     // If we find a match, release that slot.  If we don't, the BufferQueue
     // has dropped that GraphicBuffer, and there's nothing for us to release.
-    //
-    // (We could store "id" in CodecBuffer and avoid the slot search.)
-    int id;
-    for (id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) {
-        if (mBufferSlot[id] == NULL) {
-            continue;
-        }
+    int id = codecBuffer.mBuf;
+    if (mBufferSlot[id] != NULL &&
+        mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
+        ALOGV("cbi %d matches bq slot %d, handle=%p",
+                cbi, id, mBufferSlot[id]->handle);
 
-        if (mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
-            ALOGV("cbi %d matches bq slot %d, handle=%p",
-                    cbi, id, mBufferSlot[id]->handle);
-
-            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
-                    Fence::NO_FENCE);
-            break;
-        }
-    }
-    if (id == BufferQueue::NUM_BUFFER_SLOTS) {
+        mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+    } else {
         ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d",
                 cbi);
     }
@@ -287,11 +278,11 @@
         mBufferSlot[item.mBuf] = item.mGraphicBuffer;
     }
 
-    err = submitBuffer_l(mBufferSlot[item.mBuf], item.mTimestamp / 1000, cbi);
+    err = submitBuffer_l(item, cbi);
     if (err != OK) {
         ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
-        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
-                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+        mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
     } else {
         ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
     }
@@ -326,11 +317,13 @@
     return OK;
 }
 
-status_t GraphicBufferSource::submitBuffer_l(sp<GraphicBuffer>& graphicBuffer,
-        int64_t timestampUsec, int cbi) {
+status_t GraphicBufferSource::submitBuffer_l(
+        const BufferQueue::BufferItem &item, int cbi) {
     ALOGV("submitBuffer_l cbi=%d", cbi);
     CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
-    codecBuffer.mGraphicBuffer = graphicBuffer;
+    codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf];
+    codecBuffer.mBuf = item.mBuf;
+    codecBuffer.mFrameNumber = item.mFrameNumber;
 
     OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
     CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t));
@@ -342,7 +335,7 @@
 
     status_t err = mNodeInstance->emptyDirectBuffer(header, 0,
             4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME,
-            timestampUsec);
+            item.mTimestamp / 1000);
     if (err != OK) {
         ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err);
         codecBuffer.mGraphicBuffer = NULL;
@@ -431,8 +424,8 @@
         BufferQueue::BufferItem item;
         status_t err = mBufferQueue->acquireBuffer(&item);
         if (err == OK) {
-            mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
-                EGL_NO_SYNC_KHR, item.mFence);
+            mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
+                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
         }
         return;
     }
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 562d342..8c6b470 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -104,6 +104,13 @@
     // (mGraphicBuffer == NULL) or in use by the codec.
     struct CodecBuffer {
         OMX_BUFFERHEADERTYPE* mHeader;
+
+        // buffer producer's frame-number for buffer
+        uint64_t mFrameNumber;
+
+        // buffer producer's buffer slot for buffer
+        int mBuf;
+
         sp<GraphicBuffer> mGraphicBuffer;
     };
 
@@ -130,8 +137,7 @@
 
     // Marks the mCodecBuffers entry as in-use, copies the GraphicBuffer
     // reference into the codec buffer, and submits the data to the codec.
-    status_t submitBuffer_l(sp<GraphicBuffer>& graphicBuffer,
-            int64_t timestampUsec, int cbi);
+    status_t submitBuffer_l(const BufferQueue::BufferItem &item, int cbi);
 
     // Submits an empty buffer, with the EOS flag set.   Returns without
     // doing anything if we don't have a codec buffer available.
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 6f4f4c8..1d38993 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -1329,6 +1329,10 @@
 
     // Finally, dispatch any 3A change events to listeners if we got metadata
 
+    if (result->result != NULL) {
+        mResultSignal.signal();
+    }
+
     if (result->result != NULL && listener != NULL) {
         if (new3aState.aeState != cur3aState.aeState) {
             ALOGVV("%s: AE state changed from 0x%x to 0x%x",
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
index 257a45f..4012fc5 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
@@ -93,6 +93,9 @@
     status_t res;
     ATRACE_CALL();
     CameraMetadata frame;
+
+    ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId());
+
     while ( (res = device->getNextFrame(&frame)) == OK) {
 
         camera_metadata_entry_t entry;
@@ -124,6 +127,8 @@
 
 bool ProFrameProcessor::processSingleFrame(CameraMetadata &frame,
                                            const sp<CameraDeviceBase> &device) {
+    ALOGV("%s: Camera %d: Process single frame (is empty? %d)",
+          __FUNCTION__, device->getId(), frame.isEmpty());
     return processListeners(frame, device) == OK;
 }
 
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
index e2c120c..2e06691 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
@@ -373,9 +373,15 @@
 
     size_t idx = 0;
     nsecs_t minTimestamp = -1;
+
+    size_t emptyCount = mFrameList.size();
+
     for (size_t j = 0; j < mFrameList.size(); j++) {
         const CameraMetadata &frame = mFrameList[j];
         if (!frame.isEmpty()) {
+
+            emptyCount--;
+
             camera_metadata_ro_entry_t entry;
             entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
             if (entry.count == 0) {
@@ -387,7 +393,12 @@
             if (minTimestamp > frameTimestamp || minTimestamp == -1) {
 
                 entry = frame.find(ANDROID_CONTROL_AE_STATE);
+
                 if (entry.count == 0) {
+                    /**
+                     * This is most likely a HAL bug. The aeState field is
+                     * mandatory, so it should always be in a metadata packet.
+                     */
                     ALOGW("%s: ZSL queue frame has no AE state field!",
                             __FUNCTION__);
                     continue;
@@ -402,9 +413,30 @@
                 minTimestamp = frameTimestamp;
                 idx = j;
             }
+
+            ALOGVV("%s: Saw timestamp %lld", __FUNCTION__, frameTimestamp);
         }
     }
 
+    if (emptyCount == mFrameList.size()) {
+        /**
+         * This could be mildly bad and means our ZSL was triggered before
+         * there were any frames yet received by the camera framework.
+         *
+         * This is a fairly corner case which can happen under:
+         * + a user presses the shutter button real fast when the camera starts
+         *     (startPreview followed immediately by takePicture).
+         * + burst capture case (hitting shutter button as fast possible)
+         *
+         * If this happens in steady case (preview running for a while, call
+         *     a single takePicture) then this might be a fwk bug.
+         */
+        ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
+    }
+
+    ALOGV("%s: Candidate timestamp %lld (idx %d), empty frames: %d",
+          __FUNCTION__, minTimestamp, idx, emptyCount);
+
     if (metadataIdx) {
         *metadataIdx = idx;
     }
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 2fa78a4..dfa1066 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -101,12 +101,6 @@
 
     } // end scope of mMutex autolock
 
-    if (pinnedBuffer != 0) {
-        BI_LOGV("Pinned buffer frame %lld, timestamp %lld",
-                pinnedBuffer->getBufferItem().mFrameNumber,
-                pinnedBuffer->getBufferItem().mTimestamp);
-    }
-
     if (waitForFence) {
         status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
                 "RingBufferConsumer::pinSelectedBuffer");
@@ -172,6 +166,9 @@
     if (it == end) {
         BI_LOGE("Failed to pin buffer (timestamp %lld, framenumber %lld)",
                  item.mTimestamp, item.mFrameNumber);
+    } else {
+        BI_LOGV("Pinned buffer (frame %lld, timestamp %lld)",
+                item.mFrameNumber, item.mTimestamp);
     }
 }
 
@@ -182,7 +179,7 @@
 
     it = mBufferItemList.begin();
     end = mBufferItemList.end();
-    accIt = it;
+    accIt = end;
 
     if (it == end) {
         /**
@@ -197,12 +194,17 @@
 
     for (; it != end; ++it) {
         RingBufferItem& find = *it;
-        if (find.mTimestamp < accIt->mTimestamp && find.mPinCount <= 0) {
-            accIt = it;
+
+        if (find.mPinCount > 0) {
+            if (pinnedFrames != NULL) {
+                ++(*pinnedFrames);
+            }
+            // Filter out pinned frame when searching for buffer to release
+            continue;
         }
 
-        if (find.mPinCount > 0 && pinnedFrames != NULL) {
-            ++(*pinnedFrames);
+        if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
+            accIt = it;
         }
     }
 
@@ -212,7 +214,11 @@
         // In case the object was never pinned, pass the acquire fence
         // back to the release fence. If the fence was already waited on,
         // it'll just be a no-op to wait on it again.
-        err = addReleaseFenceLocked(item.mBuf, item.mFence);
+
+        // item.mGraphicBuffer was populated with the proper graphic-buffer
+        // at acquire even if it was previously acquired
+        err = addReleaseFenceLocked(item.mBuf,
+                item.mGraphicBuffer, item.mFence);
 
         if (err != OK) {
             BI_LOGE("Failed to add release fence to buffer "
@@ -224,7 +230,9 @@
         BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld",
                 item.mTimestamp, item.mFrameNumber);
 
-        err = releaseBufferLocked(item.mBuf,
+        // item.mGraphicBuffer was populated with the proper graphic-buffer
+        // at acquire even if it was previously acquired
+        err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
                                   EGL_NO_DISPLAY,
                                   EGL_NO_SYNC_KHR);
         if (err != OK) {
@@ -308,7 +316,8 @@
 
         RingBufferItem& find = *it;
         if (item.mGraphicBuffer == find.mGraphicBuffer) {
-            status_t res = addReleaseFenceLocked(item.mBuf, item.mFence);
+            status_t res = addReleaseFenceLocked(item.mBuf,
+                    item.mGraphicBuffer, item.mFence);
 
             if (res != OK) {
                 BI_LOGE("Failed to add release fence to buffer "
@@ -323,7 +332,11 @@
     }
 
     if (it == end) {
-        BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld",
+        // This should never happen. If it happens, we have a bug.
+        BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld)",
+                 item.mTimestamp, item.mFrameNumber);
+    } else {
+        BI_LOGV("Unpinned buffer (timestamp %lld, framenumber %lld)",
                  item.mTimestamp, item.mFrameNumber);
     }
 }