Snap for 6856668 from 25c3c32f40307e211630744ca03545c5bcaeb5fa to rvc-d2-release

Change-Id: Idae67e54da6f6ea0deaa87ddb98b6fc152f2cd97
diff --git a/components/V4L2Decoder.cpp b/components/V4L2Decoder.cpp
index 26f1365..d52bd6c 100644
--- a/components/V4L2Decoder.cpp
+++ b/components/V4L2Decoder.cpp
@@ -270,8 +270,9 @@
         auto request = std::move(mDecodeRequests.front());
         mDecodeRequests.pop();
 
-        ALOGV("QBUF to input queue, bitstreadId=%d", request.buffer->id);
-        inputBuffer->SetTimeStamp({.tv_sec = request.buffer->id});
+        const int32_t bitstreamId = request.buffer->id;
+        ALOGV("QBUF to input queue, bitstreadId=%d", bitstreamId);
+        inputBuffer->SetTimeStamp({.tv_sec = bitstreamId});
         size_t planeSize = inputBuffer->GetPlaneSize(0);
         if (request.buffer->size > planeSize) {
             ALOGE("The input size (%zu) is not enough, we need %zu", planeSize,
@@ -286,9 +287,13 @@
         inputBuffer->SetPlaneBytesUsed(0, request.buffer->offset + request.buffer->size);
         std::vector<int> fds;
         fds.push_back(std::move(request.buffer->dmabuf_fd));
-        std::move(*inputBuffer).QueueDMABuf(fds);
+        if (!std::move(*inputBuffer).QueueDMABuf(fds)) {
+            ALOGE("%s(): Failed to QBUF to input queue, bitstreamId=%d", __func__, bitstreamId);
+            onError();
+            return;
+        }
 
-        mPendingDecodeCbs.insert(std::make_pair(request.buffer->id, std::move(request.decodeCb)));
+        mPendingDecodeCbs.insert(std::make_pair(bitstreamId, std::move(request.decodeCb)));
     }
 }
 
@@ -314,14 +319,16 @@
         std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kAborted);
     }
 
-    // Streamoff V4L2 queues to drop input and output buffers.
+    // Streamoff both V4L2 queues to drop input and output buffers.
     mDevice->StopPolling();
     mOutputQueue->Streamoff();
     mFrameAtDevice.clear();
     mInputQueue->Streamoff();
 
-    // Streamon input queue again.
+    // Streamon both V4L2 queues.
     mInputQueue->Streamon();
+    mOutputQueue->Streamon();
+
     if (!mDevice->StartPolling(::base::BindRepeating(&V4L2Decoder::serviceDeviceTask, mWeakThis),
                                ::base::BindRepeating(&V4L2Decoder::onError, mWeakThis))) {
         ALOGE("Failed to start polling V4L2 device.");
@@ -385,15 +392,43 @@
 
         outputDequeued = true;
 
+        const size_t bufferId = dequeuedBuffer->BufferId();
+        const int32_t bitstreamId = static_cast<int32_t>(dequeuedBuffer->GetTimeStamp().tv_sec);
+        const size_t bytesUsed = dequeuedBuffer->GetPlaneBytesUsed(0);
+        const bool isLast = dequeuedBuffer->IsLast();
         ALOGV("DQBUF from output queue, bufferId=%zu, corresponding bitstreamId=%d, bytesused=%zu",
-              dequeuedBuffer->BufferId(),
-              static_cast<int32_t>(dequeuedBuffer->GetTimeStamp().tv_sec),
-              dequeuedBuffer->GetPlaneBytesUsed(0));
-        if (dequeuedBuffer->GetPlaneBytesUsed(0) > 0) {
-            sendOutputBuffer(dequeuedBuffer);
+              bufferId, bitstreamId, bytesUsed);
+
+        // Get the corresponding VideoFrame of the dequeued buffer.
+        auto it = mFrameAtDevice.find(bufferId);
+        ALOG_ASSERT(it != mFrameAtDevice.end(), "buffer %zu is not found at mFrameAtDevice",
+                    bufferId);
+        auto frame = std::move(it->second);
+        mFrameAtDevice.erase(it);
+
+        if (bytesUsed > 0) {
+            ALOGV("Send output frame(bitstreamId=%d) to client", bitstreamId);
+            frame->setBitstreamId(bitstreamId);
+            frame->setVisibleRect(mVisibleRect);
+            mOutputCb.Run(std::move(frame));
+        } else {
+            // Workaround(b/168750131): If the buffer is not enqueued before the next drain is done,
+            // then the driver will fail to notify EOS. So we recycle the buffer immediately.
+            ALOGV("Recycle empty buffer %zu back to V4L2 output queue.", bufferId);
+            dequeuedBuffer.reset();
+            auto outputBuffer = mOutputQueue->GetFreeBuffer(bufferId);
+            ALOG_ASSERT(outputBuffer, "V4L2 output queue slot %zu is not freed.", bufferId);
+
+            if (!std::move(*outputBuffer).QueueDMABuf(frame->getFDs())) {
+                ALOGE("%s(): Failed to recycle empty buffer to output queue.", __func__);
+                onError();
+                return;
+            }
+            mFrameAtDevice.insert(std::make_pair(bufferId, std::move(frame)));
         }
-        if (mDrainCb && dequeuedBuffer->IsLast()) {
-            ALOGD("All buffers are drained.");
+
+        if (mDrainCb && isLast) {
+            ALOGV("All buffers are drained.");
             sendV4L2DecoderCmd(true);
             std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kOk);
             setState(State::Idle);
@@ -420,21 +455,6 @@
     }
 }
 
-void V4L2Decoder::sendOutputBuffer(media::V4L2ReadableBufferRef buffer) {
-    ALOGV("%s(bufferId=%zu)", __func__, buffer->BufferId());
-    ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
-
-    size_t bufferId = buffer->BufferId();
-    auto it = mFrameAtDevice.find(bufferId);
-    ALOG_ASSERT(it != mFrameAtDevice.end(), "buffer %zu is not found at mFrameAtDevice", bufferId);
-    auto block = std::move(it->second);
-    mFrameAtDevice.erase(it);
-
-    block->setBitstreamId(buffer->GetTimeStamp().tv_sec);
-    block->setVisibleRect(mVisibleRect);
-    mOutputCb.Run(std::move(block));
-}
-
 bool V4L2Decoder::dequeueResolutionChangeEvent() {
     ALOGV("%s()", __func__);
     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
@@ -500,8 +520,6 @@
     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
     ALOG_ASSERT(mVideoFramePool, "mVideoFramePool is null, haven't get the instance yet?");
 
-    if (mState == State::Idle) return;
-
     if (mOutputQueue->FreeBuffersCount() == 0) {
         ALOGD("No free V4L2 output buffers, ignore.");
         return;
@@ -556,7 +574,12 @@
     uint32_t v4l2Id = outputBuffer->BufferId();
     ALOGV("QBUF to output queue, blockId=%u, V4L2Id=%u", blockId, v4l2Id);
 
-    std::move(*outputBuffer).QueueDMABuf(frame->getFDs());
+    if (!std::move(*outputBuffer).QueueDMABuf(frame->getFDs())) {
+        ALOGE("%s(): Failed to QBUF to output queue, blockId=%u, V4L2Id=%u", __func__, blockId,
+              v4l2Id);
+        onError();
+        return;
+    }
     if (mFrameAtDevice.find(v4l2Id) != mFrameAtDevice.end()) {
         ALOGE("%s(): V4L2 buffer %d already enqueued.", __func__, v4l2Id);
         onError();
diff --git a/components/include/v4l2_codec2/components/V4L2Decoder.h b/components/include/v4l2_codec2/components/V4L2Decoder.h
index 5539042..bdddc7f 100644
--- a/components/include/v4l2_codec2/components/V4L2Decoder.h
+++ b/components/include/v4l2_codec2/components/V4L2Decoder.h
@@ -62,7 +62,6 @@
     void pumpDecodeRequest();
 
     void serviceDeviceTask(bool event);
-    void sendOutputBuffer(media::V4L2ReadableBufferRef buffer);
     bool dequeueResolutionChangeEvent();
     bool changeResolution();
 
diff --git a/tests/c2_e2e_test/src/org/chromium/c2/test/E2eTestActivity.java b/tests/c2_e2e_test/src/org/chromium/c2/test/E2eTestActivity.java
index e423fc2..140ff82 100644
--- a/tests/c2_e2e_test/src/org/chromium/c2/test/E2eTestActivity.java
+++ b/tests/c2_e2e_test/src/org/chromium/c2/test/E2eTestActivity.java
@@ -29,6 +29,8 @@
     private SurfaceView mSurfaceView;
     private Size mSize;
 
+    private boolean mSurfaceCreated = false;
+    private boolean mCanStartTest = false;
     private Size mExpectedSize;
     private CountDownLatch mLatch;
 
@@ -44,6 +46,8 @@
         mSurfaceView = (SurfaceView) findViewById(R.id.surface);
 
         mSurfaceView.getHolder().addCallback(this);
+
+        mCanStartTest = !getIntent().getBooleanExtra("delay-start", false);
     }
 
     @Override
@@ -55,6 +59,14 @@
 
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
+        mSurfaceCreated = true;
+        maybeStartTest();
+    }
+
+    private void maybeStartTest() {
+        if (!mSurfaceCreated || !mCanStartTest) {
+            return;
+        }
         boolean encode = getIntent().getBooleanExtra("do-encode", false);
         String[] testArgs =
                 getIntent().getStringArrayExtra("test-args") != null
@@ -71,7 +83,7 @@
                                         encode,
                                         testArgs,
                                         testArgs.length,
-                                        holder.getSurface(),
+                                        mSurfaceView.getHolder().getSurface(),
                                         logFile);
                         Log.i(TAG, "Test returned result code " + res);
 
@@ -95,6 +107,12 @@
 
     @Override
     public void onNewIntent(Intent intent) {
+        if (intent.getAction().equals("org.chromium.c2.test.START_TEST")) {
+            mCanStartTest = true;
+            maybeStartTest();
+            return;
+        }
+
         synchronized (this) {
             if (mDecoderPtr != 0) {
                 stopDecoderLoop(mDecoderPtr);