Merge cherrypicks of [5093442] into pi-qpr1-release

Change-Id: I41829b5b9ed7e18d8c248d9bb0081047ef081203
diff --git a/codec2/hidl/client/client.cpp b/codec2/hidl/client/client.cpp
index 6ad6a15..ff67681 100644
--- a/codec2/hidl/client/client.cpp
+++ b/codec2/hidl/client/client.cpp
@@ -342,12 +342,13 @@
             return Void();
         }
         // release input buffers potentially held by the component from queue
+        size_t numDiscardedInputBuffers = 0;
         std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
         if (strongComponent) {
-            strongComponent->handleOnWorkDone(workItems);
+            numDiscardedInputBuffers = strongComponent->handleOnWorkDone(workItems);
         }
         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
-            listener->onWorkDone(component, workItems);
+            listener->onWorkDone(component, workItems, numDiscardedInputBuffers);
         } else {
             ALOGD("onWorkDone -- listener died.");
         }
@@ -841,7 +842,7 @@
     return static_cast<c2_status_t>(static_cast<Status>(transResult));
 }
 
-void Codec2Client::Component::handleOnWorkDone(
+size_t Codec2Client::Component::handleOnWorkDone(
         const std::list<std::unique_ptr<C2Work>> &workItems) {
     // Input buffers' lifetime management
     std::vector<uint64_t> inputDone;
@@ -856,6 +857,7 @@
         }
     }
 
+    size_t numDiscardedInputBuffers = 0;
     {
         std::lock_guard<std::mutex> lock(mInputBuffersMutex);
         for (uint64_t inputIndex : inputDone) {
@@ -870,6 +872,7 @@
                         (long long)inputIndex, it->second.size());
                 mInputBuffers.erase(it);
                 mInputBufferCount.erase(inputIndex);
+                ++numDiscardedInputBuffers;
             }
         }
     }
@@ -884,6 +887,7 @@
     if (igbp) {
         holdBufferQueueBlocks(workItems, igbp, bqId, generation);
     }
+    return numDiscardedInputBuffers;
 }
 
 std::shared_ptr<C2Buffer> Codec2Client::Component::freeInputBuffer(
diff --git a/codec2/hidl/client/include/codec2/hidl/client.h b/codec2/hidl/client/include/codec2/hidl/client.h
index 01da733..fb59ad6 100644
--- a/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/codec2/hidl/client/include/codec2/hidl/client.h
@@ -243,19 +243,31 @@
 
 struct Codec2Client::Listener {
 
+    // This is called when the component produces some output.
+    //
+    // numDiscardedInputBuffers is the number of input buffers contained in
+    // workItems that have just become unused. Note that workItems may contain
+    // more input buffers than numDiscardedInputBuffers because buffers that
+    // have been previously reported by onInputBufferDone() are not counted
+    // towards numDiscardedInputBuffers, but may still show up in workItems.
     virtual void onWorkDone(
             const std::weak_ptr<Component>& comp,
-            std::list<std::unique_ptr<C2Work>>& workItems) = 0;
+            std::list<std::unique_ptr<C2Work>>& workItems,
+            size_t numDiscardedInputBuffers) = 0;
 
+    // This is called when the component goes into a tripped state.
     virtual void onTripped(
             const std::weak_ptr<Component>& comp,
             const std::vector<std::shared_ptr<C2SettingResult>>& settingResults
             ) = 0;
 
+    // This is called when the component encounters an error.
     virtual void onError(
             const std::weak_ptr<Component>& comp,
             uint32_t errorCode) = 0;
 
+    // This is called when the process that hosts the component shuts down
+    // unexpectedly.
     virtual void onDeath(
             const std::weak_ptr<Component>& comp) = 0;
 
@@ -284,6 +296,7 @@
         RenderedFrame(const RenderedFrame&) = default;
     };
 
+    // This is called when the component becomes aware of frames being rendered.
     virtual void onFramesRendered(
             const std::vector<RenderedFrame>& renderedFrames) = 0;
 
@@ -408,7 +421,8 @@
     friend struct Codec2Client;
 
     struct HidlListener;
-    void handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> &workItems);
+    // Return the number of input buffers that should be discarded.
+    size_t handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> &workItems);
     // Remove an input buffer from mInputBuffers and return it.
     std::shared_ptr<C2Buffer> freeInputBuffer(uint64_t frameIndex, size_t bufferIndex);
 
diff --git a/media/sfplugin/CCodec.cpp b/media/sfplugin/CCodec.cpp
index 7609642..baf9cb6 100644
--- a/media/sfplugin/CCodec.cpp
+++ b/media/sfplugin/CCodec.cpp
@@ -449,13 +449,14 @@
 
     virtual void onWorkDone(
             const std::weak_ptr<Codec2Client::Component>& component,
-            std::list<std::unique_ptr<C2Work>>& workItems) override {
+            std::list<std::unique_ptr<C2Work>>& workItems,
+            size_t numDiscardedInputBuffers) override {
         (void)component;
         sp<CCodec> codec(mCodec.promote());
         if (!codec) {
             return;
         }
-        codec->onWorkDone(workItems);
+        codec->onWorkDone(workItems, numDiscardedInputBuffers);
     }
 
     virtual void onTripped(
@@ -1423,10 +1424,22 @@
     config->setParameters(comp, params, C2_MAY_BLOCK);
 }
 
-void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
-    {
-        Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
-        queue->splice(queue->end(), workItems);
+void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems,
+                        size_t numDiscardedInputBuffers) {
+    if (!workItems.empty()) {
+        {
+            Mutexed<std::list<size_t>>::Locked numDiscardedInputBuffersQueue(
+                    mNumDiscardedInputBuffersQueue);
+            numDiscardedInputBuffersQueue->insert(
+                    numDiscardedInputBuffersQueue->end(),
+                    workItems.size() - 1, 0);
+            numDiscardedInputBuffersQueue->emplace_back(
+                    numDiscardedInputBuffers);
+        }
+        {
+            Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
+            queue->splice(queue->end(), workItems);
+        }
     }
     (new AMessage(kWhatWorkDone, this))->post();
 }
@@ -1502,6 +1515,7 @@
         }
         case kWhatWorkDone: {
             std::unique_ptr<C2Work> work;
+            size_t numDiscardedInputBuffers;
             bool shouldPost = false;
             {
                 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
@@ -1512,6 +1526,16 @@
                 queue->pop_front();
                 shouldPost = !queue->empty();
             }
+            {
+                Mutexed<std::list<size_t>>::Locked numDiscardedInputBuffersQueue(
+                        mNumDiscardedInputBuffersQueue);
+                if (numDiscardedInputBuffersQueue->empty()) {
+                    numDiscardedInputBuffers = 0;
+                } else {
+                    numDiscardedInputBuffers = numDiscardedInputBuffersQueue->front();
+                    numDiscardedInputBuffersQueue->pop_front();
+                }
+            }
             if (shouldPost) {
                 (new AMessage(kWhatWorkDone, this))->post();
             }
@@ -1579,7 +1603,8 @@
             }
             mChannel->onWorkDone(
                     std::move(work), changed ? config->mOutputFormat : nullptr,
-                    initData.hasChanged() ? initData.update().get() : nullptr);
+                    initData.hasChanged() ? initData.update().get() : nullptr,
+                    numDiscardedInputBuffers);
             break;
         }
         case kWhatWatch: {
diff --git a/media/sfplugin/CCodec.h b/media/sfplugin/CCodec.h
index a02963c..78b009e 100644
--- a/media/sfplugin/CCodec.h
+++ b/media/sfplugin/CCodec.h
@@ -66,7 +66,8 @@
     virtual void signalRequestIDRFrame() override;
 
     void initiateReleaseIfStuck();
-    void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
+    void onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems,
+                    size_t numDiscardedInputBuffers);
     void onInputBufferDone(const std::shared_ptr<C2Buffer>& buffer);
 
 protected:
@@ -172,6 +173,7 @@
     typedef CCodecConfig Config;
     Mutexed<Config> mConfig;
     Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
+    Mutexed<std::list<size_t>> mNumDiscardedInputBuffersQueue;
 
     friend class CCodecCallbackImpl;
 
diff --git a/media/sfplugin/CCodecBufferChannel.cpp b/media/sfplugin/CCodecBufferChannel.cpp
index 90b33de..bf14e09 100644
--- a/media/sfplugin/CCodecBufferChannel.cpp
+++ b/media/sfplugin/CCodecBufferChannel.cpp
@@ -1330,7 +1330,7 @@
 // CCodecBufferChannel::PipelineCapacity
 
 CCodecBufferChannel::PipelineCapacity::PipelineCapacity()
-      : input(0), lentInput(0), component(0), output(0),
+      : input(0), component(0), output(0),
         mName("<UNKNOWN COMPONENT>") {
 }
 
@@ -1341,15 +1341,14 @@
         const char* newName,
         const char* callerTag) {
     input.store(newInput, std::memory_order_relaxed);
-    lentInput.store(0, std::memory_order_relaxed);
     component.store(newComponent, std::memory_order_relaxed);
     output.store(newOutput, std::memory_order_relaxed);
     mName = newName;
     ALOGV("[%s] %s -- PipelineCapacity::initialize(): "
           "pipeline availability initialized ==> "
-          "input = %d (-%d), component = %d, output = %d",
+          "input = %d, component = %d, output = %d",
             mName, callerTag ? callerTag : "*",
-            newInput, 0, newComponent, newOutput);
+            newInput, newComponent, newOutput);
 }
 
 bool CCodecBufferChannel::PipelineCapacity::allocate(const char* callerTag) {
@@ -1359,10 +1358,9 @@
     if (prevInput > 0 && prevComponent > 0 && prevOutput > 0) {
         ALOGV("[%s] %s -- PipelineCapacity::allocate() returns true: "
               "pipeline availability -1 all ==> "
-              "input = %d (-%d), component = %d, output = %d",
+              "input = %d, component = %d, output = %d",
                 mName, callerTag ? callerTag : "*",
                 prevInput - 1,
-                lentInput.load(std::memory_order_relaxed),
                 prevComponent - 1,
                 prevOutput - 1);
         return true;
@@ -1372,10 +1370,9 @@
     output.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::allocate() returns false: "
           "pipeline availability unchanged ==> "
-          "input = %d (-%d), component = %d, output = %d",
+          "input = %d, component = %d, output = %d",
             mName, callerTag ? callerTag : "*",
             prevInput,
-            lentInput.load(std::memory_order_relaxed),
             prevComponent,
             prevOutput);
     return false;
@@ -1387,54 +1384,28 @@
     int prevOutput = output.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::free(): "
           "pipeline availability +1 all ==> "
-          "input = %d (-%d), component = %d, output = %d",
+          "input = %d, component = %d, output = %d",
             mName, callerTag ? callerTag : "*",
             prevInput + 1,
-            lentInput.load(std::memory_order_relaxed),
             prevComponent + 1,
             prevOutput + 1);
 }
 
-int CCodecBufferChannel::PipelineCapacity::lendInputSlot(
+int CCodecBufferChannel::PipelineCapacity::freeInputSlots(
+        size_t numDiscardedInputBuffers,
         const char* callerTag) {
-    int prevInput = input.fetch_add(1, std::memory_order_relaxed);
-    int prevLentInput = lentInput.fetch_add(1, std::memory_order_relaxed);
-    ALOGV("[%s] %s -- PipelineCapacity::lendInputSlot(): "
-          "pipeline availability +1 (-1) input ==> "
-          "input = %d (-%d), component = %d, output = %d",
+    int prevInput = input.fetch_add(numDiscardedInputBuffers,
+                                    std::memory_order_relaxed);
+    ALOGV("[%s] %s -- PipelineCapacity::freeInputSlots(%zu): "
+          "pipeline availability +%zu input ==> "
+          "input = %d, component = %d, output = %d",
             mName, callerTag ? callerTag : "*",
-            prevInput + 1,
-            prevLentInput + 1,
+            numDiscardedInputBuffers,
+            numDiscardedInputBuffers,
+            prevInput + static_cast<int>(numDiscardedInputBuffers),
             component.load(std::memory_order_relaxed),
             output.load(std::memory_order_relaxed));
-    return prevInput + 1;
-}
-
-int CCodecBufferChannel::PipelineCapacity::freeInputSlot(
-        const char* callerTag) {
-    int prevLentInput = lentInput.fetch_sub(1, std::memory_order_relaxed);
-    if (prevLentInput > 0) {
-        ALOGV("[%s] %s -- PipelineCapacity::freeInputSlot(): "
-              "pipeline availability +0 (+1) input ==> "
-              "input = %d (-%d), component = %d, output = %d",
-                mName, callerTag ? callerTag : "*",
-                input.load(std::memory_order_relaxed),
-                prevLentInput - 1,
-                component.load(std::memory_order_relaxed),
-                output.load(std::memory_order_relaxed));
-        return input.load(std::memory_order_relaxed);
-    }
-    lentInput.fetch_add(1, std::memory_order_relaxed);
-    int prevInput = input.fetch_add(1, std::memory_order_relaxed);
-    ALOGV("[%s] %s -- PipelineCapacity::freeInputSlot(): "
-          "pipeline availability +1 (+0) input ==> "
-          "input = %d (-%d), component = %d, output = %d",
-            mName, callerTag ? callerTag : "*",
-            prevInput + 1,
-            prevLentInput,
-            component.load(std::memory_order_relaxed),
-            output.load(std::memory_order_relaxed));
-    return prevInput + 1;
+    return prevInput + numDiscardedInputBuffers;
 }
 
 int CCodecBufferChannel::PipelineCapacity::freeComponentSlot(
@@ -1442,10 +1413,9 @@
     int prevComponent = component.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::freeComponentSlot(): "
           "pipeline availability +1 component ==> "
-          "input = %d (-%d), component = %d, output = %d",
+          "input = %d, component = %d, output = %d",
             mName, callerTag ? callerTag : "*",
             input.load(std::memory_order_relaxed),
-            lentInput.load(std::memory_order_relaxed),
             prevComponent + 1,
             output.load(std::memory_order_relaxed));
     return prevComponent + 1;
@@ -1456,10 +1426,9 @@
     int prevOutput = output.fetch_add(1, std::memory_order_relaxed);
     ALOGV("[%s] %s -- PipelineCapacity::freeOutputSlot(): "
           "pipeline availability +1 output ==> "
-          "input = %d (-%d), component = %d, output = %d",
+          "input = %d, component = %d, output = %d",
             mName, callerTag ? callerTag : "*",
             input.load(std::memory_order_relaxed),
-            lentInput.load(std::memory_order_relaxed),
             component.load(std::memory_order_relaxed),
             prevOutput + 1);
     return prevOutput + 1;
@@ -1859,8 +1828,10 @@
     bool released = false;
     {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
-        if (*buffers) {
-            released = (*buffers)->releaseBuffer(buffer, nullptr);
+        if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) {
+            buffers.unlock();
+            released = true;
+            mAvailablePipelineCapacity.freeInputSlots(1, "discardBuffer");
         }
     }
     {
@@ -2233,7 +2204,8 @@
     }
     for (const sp<MediaCodecBuffer> &buffer : toBeQueued) {
         if (queueInputBufferInternal(buffer) != OK) {
-            mAvailablePipelineCapacity.free("requestInitialInputBuffers");
+            mAvailablePipelineCapacity.freeComponentSlot("requestInitialInputBuffers");
+            mAvailablePipelineCapacity.freeOutputSlot("requestInitialInputBuffers");
         }
     }
     return OK;
@@ -2283,8 +2255,10 @@
 
 void CCodecBufferChannel::onWorkDone(
         std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
-        const C2StreamInitDataInfo::output *initData) {
-    mAvailablePipelineCapacity.freeInputSlot("onWorkDone");
+        const C2StreamInitDataInfo::output *initData,
+        size_t numDiscardedInputBuffers) {
+    mAvailablePipelineCapacity.freeInputSlots(numDiscardedInputBuffers,
+                                              "onWorkDone");
     mAvailablePipelineCapacity.freeComponentSlot("onWorkDone");
     if (handleWork(std::move(work), outputFormat, initData)) {
         mAvailablePipelineCapacity.freeOutputSlot("onWorkDone");
@@ -2300,7 +2274,7 @@
         newInputSlotAvailable = (*buffers)->expireComponentBuffer(buffer);
     }
     if (newInputSlotAvailable) {
-        mAvailablePipelineCapacity.lendInputSlot("onInputBufferDone");
+        mAvailablePipelineCapacity.freeInputSlots(1, "onInputBufferDone");
         feedInputBufferIfAvailable();
     }
 }
diff --git a/media/sfplugin/CCodecBufferChannel.h b/media/sfplugin/CCodecBufferChannel.h
index f9e086f..8631235 100644
--- a/media/sfplugin/CCodecBufferChannel.h
+++ b/media/sfplugin/CCodecBufferChannel.h
@@ -125,10 +125,14 @@
      * @param workItems   finished work item.
      * @param outputFormat new output format if it has changed, otherwise nullptr
      * @param initData    new init data (CSD) if it has changed, otherwise nullptr
+     * @param numDiscardedInputBuffers the number of input buffers that are
+     *                    returned for the first time (not previously returned by
+     *                    onInputBufferDone()).
      */
     void onWorkDone(
             std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
-            const C2StreamInitDataInfo::output *initData);
+            const C2StreamInitDataInfo::output *initData,
+            size_t numDiscardedInputBuffers);
 
     /**
      * Make an input buffer available for the client as it is no longer needed
@@ -283,11 +287,6 @@
     struct PipelineCapacity {
         // The number of available input capacity.
         std::atomic_int input;
-        // The number of input buffers that have been released by
-        // onInputBufferDone() but not onWorkDone(). Once onWorkDone() is
-        // called, this number will decrease unless it is already zero; in
-        // which case #input will increase instead.
-        std::atomic_int lentInput;
         // The number of available component capacity.
         std::atomic_int component;
         // The number of available output capacity.
@@ -318,41 +317,31 @@
         // essentially undoes an allocate() call.
         void free(const char* callerTag = nullptr);
 
-        // Increase #input and #lentInput by 1.
+        // Increase #input by @p numDiscardedInputBuffers.
         //
         // callerTag is used for logging only.
         //
-        // lendInputSlot() is called by CCodecBufferChannel when
-        // onInputBufferDone() is called. This means an input buffer has been
-        // freed, but a subsequent call to onWorkDone() will not free an input
-        // buffer.
-        int lendInputSlot(const char* callerTag = nullptr);
-
-        // Increase #input by one if #lentInput is 0; otherwise, decrease
-        // #lentInput by 1.
-        //
-        // callerTag is used for logging only.
-        //
-        // freeInputSlot() is called by CCodecBufferChannel when onWorkDone() is
-        // called. If #lentInput is not zero, that means the input buffer for
-        // the returned work has already been freed, so #input will not
-        // increase.
-        int freeInputSlot(const char* callerTag = nullptr);
+        // freeInputSlots() is called by CCodecBufferChannel when onWorkDone()
+        // or onInputBufferDone() is called. @p numDiscardedInputBuffers is
+        // provided in onWorkDone(), and is 1 in onInputBufferDone().
+        int freeInputSlots(size_t numDiscardedInputBuffers,
+                           const char* callerTag = nullptr);
 
         // Increase #component by one and return the updated value.
         //
         // callerTag is used for logging only.
         //
-        // freeComponentSlot() is called by CCodecBufferChannel when onWorkDone() is
-        // called.
+        // freeComponentSlot() is called by CCodecBufferChannel when
+        // onWorkDone() is called.
         int freeComponentSlot(const char* callerTag = nullptr);
 
         // Increase #output by one and return the updated value.
         //
         // callerTag is used for logging only.
         //
-        // freeOutputSlot() is called by CCodecBufferChannel when discardBuffer() is
-        // called on an output buffer or when renderOutputBuffer() is called.
+        // freeOutputSlot() is called by CCodecBufferChannel when
+        // discardBuffer() is called on an output buffer or when
+        // renderOutputBuffer() is called.
         int freeOutputSlot(const char* callerTag = nullptr);
 
     private: