C2SoftFlacEnc: Send single frame per output by using cloneAndSend

Bug: 169310292
Test: atest CtsMediaV2TestCases:AudioEncoderTest
   CtsMediaV2TestCases:CodecEncoderTest
   CtsMediaEncoderTestCases:EncoderTest
   CtsMediaCodecTestCases:MediaCodecTest
   VtsHalMediaC2V1_0TargetAudioEncTest

Change-Id: Iecb2f4b18594a50d5e64ef271713e6676a319b93
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index 182edfb..591d56d 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -188,12 +188,6 @@
     return onStop();
 }
 
-static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
-    work->worklets.front()->output.flags = work->input.flags;
-    work->worklets.front()->output.buffers.clear();
-    work->worklets.front()->output.ordinal = work->input.ordinal;
-}
-
 void C2SoftFlacEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
@@ -245,12 +239,10 @@
         mWroteHeader = true;
     }
 
-    const uint32_t sampleRate = mIntf->getSampleRate();
     const uint32_t channelCount = mIntf->getChannelCount();
     const bool inputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
     const unsigned sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
     const unsigned frameSize = channelCount * sampleSize;
-    const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
 
     size_t outCapacity = inSize;
     outCapacity += mBlockSize * frameSize;
@@ -270,6 +262,33 @@
         return;
     }
 
+    class FillWork {
+    public:
+        FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
+                 const std::shared_ptr<C2Buffer> &buffer)
+            : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
+        ~FillWork() = default;
+
+        void operator()(const std::unique_ptr<C2Work> &work) {
+            work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
+            work->worklets.front()->output.buffers.clear();
+            work->worklets.front()->output.ordinal = mOrdinal;
+            work->workletsProcessed = 1u;
+            work->result = C2_OK;
+            if (mBuffer) {
+                work->worklets.front()->output.buffers.push_back(mBuffer);
+            }
+            ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
+                  mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
+                  mBuffer ? "" : "o");
+        }
+
+    private:
+        const uint32_t mFlags;
+        const C2WorkOrdinalStruct mOrdinal;
+        const std::shared_ptr<C2Buffer> mBuffer;
+    };
+
     mEncoderWriteData = true;
     mEncoderReturnedNbBytes = 0;
     size_t inPos = 0;
@@ -308,14 +327,33 @@
         mOutputBlock.reset();
         return;
     }
-    fillEmptyWork(work);
-    if (mEncoderReturnedNbBytes != 0) {
-        std::shared_ptr<C2Buffer> buffer = createLinearBuffer(std::move(mOutputBlock), 0, mEncoderReturnedNbBytes);
-        work->worklets.front()->output.buffers.push_back(buffer);
-        work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
-    } else {
-        ALOGV("encoder process_interleaved returned without data to write");
+
+    // cloneAndSend will create clone of work when more than one encoded frame is produced
+    while (mOutputBuffers.size() > 1) {
+        const OutputBuffer& front = mOutputBuffers.front();
+        C2WorkOrdinalStruct ordinal = work->input.ordinal;
+        ordinal.frameIndex = front.frameIndex;
+        ordinal.timestamp = front.timestampUs;
+        cloneAndSend(work->input.ordinal.frameIndex.peeku(), work,
+                     FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer));
+        mOutputBuffers.pop_front();
     }
+
+    std::shared_ptr<C2Buffer> buffer;
+    C2WorkOrdinalStruct ordinal = work->input.ordinal;
+    if (mOutputBuffers.size() == 1) {
+        const OutputBuffer& front = mOutputBuffers.front();
+        ordinal.frameIndex = front.frameIndex;
+        ordinal.timestamp = front.timestampUs;
+        buffer = front.buffer;
+        mOutputBuffers.pop_front();
+    }
+    // finish the response for the overall transaction.
+    // this includes any final frame that the encoder produced during this request
+    // this response is required even if no data was encoded.
+    FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0),
+             ordinal, buffer)(work);
+
     mOutputBlock = nullptr;
     if (eos) {
         mSignalledOutputEos = true;
@@ -349,6 +387,8 @@
     // write encoded data
     C2WriteView wView = mOutputBlock->map().get();
     uint8_t* outData = wView.data();
+    const uint32_t sampleRate = mIntf->getSampleRate();
+    const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
     ALOGV("writing %zu bytes of encoded data on output", bytes);
     // increment mProcessedSamples to maintain audio synchronization during
     // play back
@@ -359,7 +399,12 @@
         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
     }
     memcpy(outData + mEncoderReturnedNbBytes, buffer, bytes);
+
+    std::shared_ptr<C2Buffer> c2Buffer =
+        createLinearBuffer(mOutputBlock, mEncoderReturnedNbBytes, bytes);
+    mOutputBuffers.push_back({c2Buffer, mAnchorTimeStamp + outTimeStamp, current_frame});
     mEncoderReturnedNbBytes += bytes;
+
     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
 }