Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1951d936 authored by Wonsik Kim's avatar Wonsik Kim
Browse files

CCodec: fix input surface throttling

There were no throttling in place for video encoders set up with
input surfaces. Throttle based on the number of output buffers
notified to the client.

Bug: 310807188
Test: atest android.hardware.camera2.cts.RecordingTest
Test: atest android.mediav2.cts.CodecEncoderSurfaceTest
Change-Id: Ifec1d16ed25f8100ae1f1eb06a490c955c0c4961
parent 30fe7300
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -43,6 +43,16 @@ flag {
  bug: "325520135"
}

flag {
  name: "input_surface_throttle"
  namespace: "codec_fwk"
  description: "Bugfix flag for input surface throttle"
  bug: "342269852"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "large_audio_frame_finish"
  namespace: "codec_fwk"
+4 −0
Original line number Diff line number Diff line
@@ -105,6 +105,10 @@ void C2AidlNode::onInputBufferDone(c2_cntr64_t index) {
    return mImpl->onInputBufferDone(index);
}

void C2AidlNode::onInputBufferEmptied() {
    return mImpl->onInputBufferEmptied();
}

android_dataspace C2AidlNode::getDataspace() {
    return mImpl->getDataspace();
}
+7 −1
Original line number Diff line number Diff line
@@ -68,12 +68,18 @@ public:
    void setFrameSize(uint32_t width, uint32_t height);

    /**
     * Clean up work item reference.
     * Notify that the input buffer reference is no longer needed by the component.
     * Clean up if necessary.
     *
     * \param index input work index
     */
    void onInputBufferDone(c2_cntr64_t index);

    /**
     * Notify input buffer is emptied.
     */
    void onInputBufferEmptied();

    /**
     * Returns dataspace information from GraphicBufferSource.
     */
+61 −12
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <C2Debug.h>
#include <C2PlatformSupport.h>

#include <android_media_codec.h>
#include <android/fdsan.h>
#include <media/stagefright/foundation/ColorUtils.h>
#include <ui/Fence.h>
@@ -373,7 +374,10 @@ status_t C2NodeImpl::submitBuffer(
    }
    work->worklets.clear();
    work->worklets.emplace_back(new C2Worklet);
    mBufferIdsInUse.lock()->emplace(work->input.ordinal.frameIndex.peeku(), buffer);
    {
        Mutexed<BuffersTracker>::Locked buffers(mBuffersTracker);
        buffers->mIdsInUse.emplace(work->input.ordinal.frameIndex.peeku(), buffer);
    }
    mQueueThread->queue(comp, fenceFd, std::move(work), std::move(fd0), std::move(fd1));

    return OK;
@@ -405,29 +409,74 @@ void C2NodeImpl::setFrameSize(uint32_t width, uint32_t height) {
}

void C2NodeImpl::onInputBufferDone(c2_cntr64_t index) {
    if (mAidlHal) {
        if (!mAidlBufferSource) {
            ALOGD("Buffer source not set (index=%llu)", index.peekull());
    if (android::media::codec::provider_->input_surface_throttle()) {
        Mutexed<BuffersTracker>::Locked buffers(mBuffersTracker);
        auto it = buffers->mIdsInUse.find(index.peeku());
        if (it == buffers->mIdsInUse.end()) {
            ALOGV("Untracked input index %llu (maybe already removed)", index.peekull());
            return;
        }
        int32_t bufferId = it->second;
        (void)buffers->mIdsInUse.erase(it);
        buffers->mAvailableIds.push_back(bufferId);
    } else {
        if (!mBufferSource) {
            ALOGD("Buffer source not set (index=%llu)", index.peekull());
        if (!hasBufferSource()) {
            return;
        }
    }

        int32_t bufferId = 0;
        {
        decltype(mBufferIdsInUse)::Locked bufferIds(mBufferIdsInUse);
        auto it = bufferIds->find(index.peeku());
        if (it == bufferIds->end()) {
            Mutexed<BuffersTracker>::Locked buffers(mBuffersTracker);
            auto it = buffers->mIdsInUse.find(index.peeku());
            if (it == buffers->mIdsInUse.end()) {
                ALOGV("Untracked input index %llu (maybe already removed)", index.peekull());
                return;
            }
            bufferId = it->second;
        (void)bufferIds->erase(it);
            (void)buffers->mIdsInUse.erase(it);
        }
        notifyInputBufferEmptied(bufferId);
    }
}

void C2NodeImpl::onInputBufferEmptied() {
    if (!android::media::codec::provider_->input_surface_throttle()) {
        ALOGE("onInputBufferEmptied should not be called "
              "when input_surface_throttle is false");
        return;
    }
    if (!hasBufferSource()) {
        return;
    }
    int32_t bufferId = 0;
    {
        Mutexed<BuffersTracker>::Locked buffers(mBuffersTracker);
        if (buffers->mAvailableIds.empty()) {
            ALOGV("The codec is ready to take more input buffers "
                    "but no input buffers are ready yet.");
            return;
        }
        bufferId = buffers->mAvailableIds.front();
        buffers->mAvailableIds.pop_front();
    }
    notifyInputBufferEmptied(bufferId);
}

bool C2NodeImpl::hasBufferSource() {
    if (mAidlHal) {
        if (!mAidlBufferSource) {
            ALOGD("Buffer source not set");
            return false;
        }
    } else {
        if (!mBufferSource) {
            ALOGD("Buffer source not set");
            return false;
        }
    }
    return true;
}

void C2NodeImpl::notifyInputBufferEmptied(int32_t bufferId) {
    if (mAidlHal) {
        ::ndk::ScopedFileDescriptor nullFence;
        (void)mAidlBufferSource->onInputBufferEmptied(bufferId, nullFence);
+20 −2
Original line number Diff line number Diff line
@@ -73,12 +73,18 @@ struct C2NodeImpl {
    void setFrameSize(uint32_t width, uint32_t height);

    /**
     * Clean up work item reference.
     * Notify that the input buffer reference is no longer needed by the component.
     * Clean up if necessary.
     *
     * \param index input work index
     */
    void onInputBufferDone(c2_cntr64_t index);

    /**
     * Notify input buffer is emptied.
     */
    void onInputBufferEmptied();

    /**
     * Returns dataspace information from GraphicBufferSource.
     */
@@ -118,12 +124,24 @@ private:
    c2_cntr64_t mPrevInputTimestamp; // input timestamp for previous frame
    c2_cntr64_t mPrevCodecTimestamp; // adjusted (codec) timestamp for previous frame

    Mutexed<std::map<uint64_t, uint32_t>> mBufferIdsInUse;
    // Tracks the status of buffers
    struct BuffersTracker {
        BuffersTracker() = default;

        // Keeps track of buffers that are used by the component. Maps timestamp -> ID
        std::map<uint64_t, uint32_t> mIdsInUse;
        // Keeps track of the buffer IDs that are available after being released from the component.
        std::list<uint32_t> mAvailableIds;
    };
    Mutexed<BuffersTracker> mBuffersTracker;

    class QueueThread;
    sp<QueueThread> mQueueThread;

    bool mAidlHal;

    bool hasBufferSource();
    void notifyInputBufferEmptied(int32_t bufferId);
};

}  // namespace android
Loading