Add default active developers into OWNERS am: 6d3563e6de
am: 8097524b1b

Change-Id: If8f274d094edbca82cab5c33905cbae812870ad7
diff --git a/C2VDAComponent.cpp b/C2VDAComponent.cpp
index 1f30f7d..fd7b313 100644
--- a/C2VDAComponent.cpp
+++ b/C2VDAComponent.cpp
@@ -63,6 +63,7 @@
 
 const uint32_t kDpbOutputBufferExtraCount = 3;  // Use the same number as ACodec.
 const int kDequeueRetryDelayUs = 10000;  // Wait time of dequeue buffer retry in microseconds.
+const int32_t kAllocateBufferMaxRetries = 10;  // Max retry time for fetchGraphicBlock timeout.
 }  // namespace
 
 C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper)
@@ -207,7 +208,6 @@
         mVDAInitResult(VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE),
         mComponentState(ComponentState::UNINITIALIZED),
         mPendingOutputEOS(false),
-        mLastOutputTimestamp(-1),
         mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN),
         mState(State::UNLOADED),
         mWeakThisFactory(this) {
@@ -306,9 +306,12 @@
 
     CHECK_LE(work->input.buffers.size(), 1u);
     if (work->input.buffers.empty()) {
-        // Client may queue an EOS work with no input buffer, otherwise every work must have one
-        // input buffer.
-        CHECK(drainMode != NO_DRAIN);
+        // Client may queue a work with no input buffer for either it's EOS or empty CSD, otherwise
+        // every work must have one input buffer.
+        CHECK(drainMode != NO_DRAIN || work->input.flags & C2FrameData::FLAG_CODEC_CONFIG);
+        // Emplace a nullptr to unify the check for work done.
+        ALOGV("Got a work with no input buffer! Emplace a nullptr inside.");
+        work->input.buffers.emplace_back(nullptr);
     } else {
         // If input.buffers is not empty, the buffer should have meaningful content inside.
         C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front();
@@ -366,8 +369,14 @@
         return;
     }
 
-    // TODO(johnylin): when buffer is returned, we should confirm that output format is not changed
-    //                 yet. If changed, just let the buffer be released.
+    if (block->width() != static_cast<uint32_t>(mOutputFormat.mCodedSize.width()) ||
+        block->height() != static_cast<uint32_t>(mOutputFormat.mCodedSize.height())) {
+        // Output buffer is returned after we changed output resolution. Just let the buffer be
+        // released.
+        ALOGV("Discard obsolete graphic block: pool id=%u", poolId);
+        return;
+    }
+
     GraphicBlockInfo* info = getGraphicBlockByPoolId(poolId);
     if (!info) {
         reportError(C2_CORRUPTED);
@@ -405,18 +414,14 @@
     mBuffersInClient++;
 
     // Attach output buffer to the work corresponded to bitstreamId.
-    auto block = info->mGraphicBlock;
-    work->worklets.front()->output.buffers.emplace_back(C2Buffer::CreateGraphicBuffer(
-            block->share(C2Rect(mOutputFormat.mVisibleRect.width(),
-                                mOutputFormat.mVisibleRect.height()),
-                         C2Fence())));
+    C2ConstGraphicBlock constBlock = info->mGraphicBlock->share(
+            C2Rect(mOutputFormat.mVisibleRect.width(), mOutputFormat.mVisibleRect.height()),
+            C2Fence());
+    MarkBlockPoolDataAsShared(constBlock);
+    work->worklets.front()->output.buffers.emplace_back(
+            C2Buffer::CreateGraphicBuffer(std::move(constBlock)));
     info->mGraphicBlock.reset();
 
-    // TODO: this does not work for timestamps as they can wrap around
-    int64_t currentTimestamp = ::base::checked_cast<int64_t>(work->input.ordinal.timestamp.peek());
-    CHECK_GE(currentTimestamp, mLastOutputTimestamp);
-    mLastOutputTimestamp = currentTimestamp;
-
     reportFinishedWorkIfAny();
 }
 
@@ -470,9 +475,6 @@
     // mPendingWorks must be empty after draining is finished.
     CHECK(mPendingWorks.empty());
 
-    // Last stream is finished. Reset the timestamp record.
-    mLastOutputTimestamp = -1;
-
     // Work dequeueing was stopped while component draining. Restart it.
     mTaskRunner->PostTask(FROM_HERE,
                           ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this)));
@@ -534,8 +536,6 @@
 void C2VDAComponent::onFlushDone() {
     ALOGV("onFlushDone");
     reportAbandonedWorks();
-    // Reset the timestamp record.
-    mLastOutputTimestamp = -1;
     mComponentState = ComponentState::STARTED;
 
     // Work dequeueing was stopped while component flushing. Restart it.
@@ -551,7 +551,6 @@
     // do something for them?
     reportAbandonedWorks();
     mPendingOutputFormat.reset();
-    mLastOutputTimestamp = -1;
     if (mVDAAdaptor.get()) {
         mVDAAdaptor->destroy();
         mVDAAdaptor.reset(nullptr);
@@ -652,14 +651,15 @@
     ALOGV("tryChangeOutputFormat");
     CHECK(mPendingOutputFormat);
 
-    // Change the output format only after all output buffers are returned
-    // from clients.
-    // TODO(johnylin): don't need to wait for new proposed buffer flow.
+    // At this point, all output buffers should not be owned by accelerator. The component is not
+    // able to know when a client will release all owned output buffers by now. But it is ok to
+    // leave them to client since componenet won't own those buffers anymore.
+    // TODO(johnylin): we may also set a parameter for component to keep dequeueing buffers and
+    //                 change format only after the component owns most buffers. This may prevent
+    //                 too many buffers are still on client's hand while component starts to
+    //                 allocate more buffers. However, it leads latency on output format change.
     for (const auto& info : mGraphicBlocks) {
-        if (info.mState == GraphicBlockInfo::State::OWNED_BY_CLIENT) {
-            ALOGV("wait buffer: %d for output format change", info.mBlockId);
-            return;
-        }
+        CHECK(info.mState != GraphicBlockInfo::State::OWNED_BY_ACCELERATOR);
     }
 
     CHECK_EQ(mPendingOutputFormat->mPixelFormat, HalPixelFormat::YCbCr_420_888);
@@ -749,13 +749,23 @@
         std::shared_ptr<C2GraphicBlock> block;
         C2MemoryUsage usage = {
                 mSecureMode ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ, 0};
-        err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, &block);
-        if (err != C2_OK) {
-            mGraphicBlocks.clear();
-            ALOGE("failed to allocate buffer: %d", err);
-            reportError(err);
-            return err;
+
+        int32_t retries_left = kAllocateBufferMaxRetries;
+        err = C2_NO_INIT;
+        while (err != C2_OK) {
+            err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage,
+                                               &block);
+            if (err == C2_TIMED_OUT && retries_left > 0) {
+                ALOGD("allocate buffer timeout, %d retry time(s) left...", retries_left);
+                retries_left--;
+            } else if (err != C2_OK) {
+                mGraphicBlocks.clear();
+                ALOGE("failed to allocate buffer: %d", err);
+                reportError(err);
+                return err;
+            }
         }
+
         uint32_t poolId;
         if (useBufferQueue) {
             err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId);
@@ -1098,11 +1108,6 @@
     std::list<std::unique_ptr<C2Work>> finishedWorks;
 
     // Work should be reported as done if both input and output buffer are returned by VDA.
-
-    // Note that not every input buffer has matched output (ex. CSD header for H.264).
-    // However, the timestamp is guaranteed to be monotonic increasing for buffers in display order.
-    // That is, since VDA output is in display order, if we get a returned output with timestamp T,
-    // it implies all works with timestamp <= T are done.
     // EOS work will not be reported here. reportEOSWork() does it.
     auto iter = mPendingWorks.begin();
     while (iter != mPendingWorks.end()) {
@@ -1122,8 +1127,8 @@
 }
 
 bool C2VDAComponent::isWorkDone(const C2Work* work) const {
-    if (work->input.buffers.empty()) {
-        // This is EOS work with no input buffer and should be processed by reportEOSWork().
+    if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+        // This is EOS work and should be processed by reportEOSWork().
         return false;
     }
     if (work->input.buffers.front()) {
@@ -1135,13 +1140,12 @@
         // returned by reportEOSWork() instead.
         return false;
     }
-    if (mLastOutputTimestamp < 0) {
-        return false;  // No output buffer is returned yet.
+    if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) &&
+        work->worklets.front()->output.buffers.empty()) {
+        // Output buffer is not returned from VDA yet.
+        return false;
     }
-    if (work->input.ordinal.timestamp > static_cast<uint64_t>(mLastOutputTimestamp)) {
-        return false;  // Output buffer is not returned by VDA yet.
-    }
-    return true;  // Output buffer is returned, or it has no related output buffer.
+    return true;  // Output buffer is returned, or it has no related output buffer (CSD work).
 }
 
 void C2VDAComponent::reportEOSWork() {
diff --git a/include/C2VDAComponent.h b/include/C2VDAComponent.h
index 254b9b0..477bc1c 100644
--- a/include/C2VDAComponent.h
+++ b/include/C2VDAComponent.h
@@ -293,9 +293,6 @@
     // The pending output format. We need to wait until all buffers are returned back to apply the
     // format change.
     std::unique_ptr<VideoFormat> mPendingOutputFormat;
-    // Record the timestamp of the last output buffer. This is used to determine if the work is
-    // finished.
-    int64_t mLastOutputTimestamp;
 
     // The indicator of whether component is in secure mode.
     bool mSecureMode;