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

Commit 0826325e authored by Wonsik Kim's avatar Wonsik Kim Committed by Gerrit Code Review
Browse files

Merge changes I482c2a73,Id81f03fa,I55264110 into android15-tests-dev

* changes:
  CCodecBufferChannel: decrease balance for discarded work as well
  CCodecBufferChannel: throttle by # of frames in pipeline
  CCodec: lock input surface for concurrent access
parents 63728a5c 4aa3f70e
Loading
Loading
Loading
Loading
+82 −36
Original line number Diff line number Diff line
@@ -222,19 +222,20 @@ public:
    ~HGraphicBufferSourceWrapper() override = default;

    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
        mNode = new C2OMXNode(comp);
        mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(mNode);
        mNode->setFrameSize(mWidth, mHeight);
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        *node = new C2OMXNode(comp);
        mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(*node);
        (*node)->setFrameSize(mWidth, mHeight);
        // Usage is queried during configure(), so setting it beforehand.
        // 64 bit set parameter is existing only in C2OMXNode.
        OMX_U64 usage64 = mConfig.mUsage;
        status_t res = mNode->setParameter(
        status_t res = (*node)->setParameter(
                (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits64,
                &usage64, sizeof(usage64));

        if (res != OK) {
            OMX_U32 usage = mConfig.mUsage & 0xFFFFFFFF;
            (void)mNode->setParameter(
            (void)(*node)->setParameter(
                    (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
                    &usage, sizeof(usage));
        }
@@ -244,17 +245,18 @@ public:
    }

    void disconnect() override {
        if (mNode == nullptr) {
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return;
        }
        sp<IOMXBufferSource> source = mNode->getSource();
        sp<IOMXBufferSource> source = (*node)->getSource();
        if (source == nullptr) {
            ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
            return;
        }
        source->onOmxIdle();
        source->onOmxLoaded();
        mNode.clear();
        node->clear();
        mOmxNode.clear();
    }

@@ -268,7 +270,11 @@ public:
    }

    status_t start() override {
        sp<IOMXBufferSource> source = mNode->getSource();
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return NO_INIT;
        }
        sp<IOMXBufferSource> source = (*node)->getSource();
        if (source == nullptr) {
            return NO_INIT;
        }
@@ -278,7 +284,7 @@ public:

        OMX_PARAM_PORTDEFINITIONTYPE param;
        param.nPortIndex = kPortIndexInput;
        status_t err = mNode->getParameter(OMX_IndexParamPortDefinition,
        status_t err = (*node)->getParameter(OMX_IndexParamPortDefinition,
                                           &param, sizeof(param));
        if (err == OK) {
            numSlots = param.nBufferCountActual;
@@ -297,6 +303,7 @@ public:
    }

    status_t configure(Config &config) {
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        std::stringstream status;
        status_t err = OK;

@@ -317,7 +324,7 @@ public:

        // pts gap
        if (config.mMinAdjustedFps > 0 || config.mFixedAdjustedFps > 0) {
            if (mNode != nullptr) {
            if ((*node) != nullptr) {
                OMX_PARAM_U32TYPE ptrGapParam = {};
                ptrGapParam.nSize = sizeof(OMX_PARAM_U32TYPE);
                float gap = (config.mMinAdjustedFps > 0)
@@ -326,7 +333,7 @@ public:
                // float -> uint32_t is undefined if the value is negative.
                // First convert to int32_t to ensure the expected behavior.
                ptrGapParam.nU32 = int32_t(gap);
                (void)mNode->setParameter(
                (void)(*node)->setParameter(
                        (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
                        &ptrGapParam, sizeof(ptrGapParam));
            }
@@ -426,8 +433,8 @@ public:

        // priority
        if (mConfig.mPriority != config.mPriority) {
            if (config.mPriority != INT_MAX) {
                mNode->setPriority(config.mPriority);
            if (config.mPriority != INT_MAX && (*node) != nullptr) {
                (*node)->setPriority(config.mPriority);
            }
            mConfig.mPriority = config.mPriority;
        }
@@ -441,24 +448,40 @@ public:
    }

    void onInputBufferDone(c2_cntr64_t index) override {
        mNode->onInputBufferDone(index);
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return;
        }
        (*node)->onInputBufferDone(index);
    }

    void onInputBufferEmptied() override {
        mNode->onInputBufferEmptied();
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return;
        }
        (*node)->onInputBufferEmptied();
    }

    android_dataspace getDataspace() override {
        return mNode->getDataspace();
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return HAL_DATASPACE_UNKNOWN;
        }
        return (*node)->getDataspace();
    }

    uint32_t getPixelFormat() override {
        return mNode->getPixelFormat();
        Mutexed<sp<C2OMXNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return PIXEL_FORMAT_UNKNOWN;
        }
        return (*node)->getPixelFormat();
    }

private:
    sp<HGraphicBufferSource> mSource;
    sp<C2OMXNode> mNode;
    Mutexed<sp<C2OMXNode>> mNode;
    sp<hardware::media::omx::V1_0::IOmxNode> mOmxNode;
    uint32_t mWidth;
    uint32_t mHeight;
@@ -479,33 +502,39 @@ public:
    ~AGraphicBufferSourceWrapper() override = default;

    status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
        mNode = ::ndk::SharedRefBase::make<C2AidlNode>(comp);
        mNode->setFrameSize(mWidth, mHeight);
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        *node = ::ndk::SharedRefBase::make<C2AidlNode>(comp);
        (*node)->setFrameSize(mWidth, mHeight);
        // Usage is queried during configure(), so setting it beforehand.
        uint64_t usage = mConfig.mUsage;
        (void)mNode->setConsumerUsage((int64_t)usage);
        (void)(*node)->setConsumerUsage((int64_t)usage);

        return fromAidlStatus(mSource->configure(
                mNode, static_cast<::aidl::android::hardware::graphics::common::Dataspace>(
                (*node), static_cast<::aidl::android::hardware::graphics::common::Dataspace>(
                        mDataSpace)));
    }

    void disconnect() override {
        if (mNode == nullptr) {
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return;
        }
        std::shared_ptr<IAidlBufferSource> source = mNode->getSource();
        std::shared_ptr<IAidlBufferSource> source = (*node)->getSource();
        if (source == nullptr) {
            ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
            return;
        }
        (void)source->onStop();
        (void)source->onRelease();
        mNode.reset();
        node->reset();
    }

    status_t start() override {
        std::shared_ptr<IAidlBufferSource> source = mNode->getSource();
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return NO_INIT;
        }
        std::shared_ptr<IAidlBufferSource> source = (*node)->getSource();
        if (source == nullptr) {
            return NO_INIT;
        }
@@ -513,7 +542,7 @@ public:
        size_t numSlots = 16;

        IAidlNode::InputBufferParams param;
        status_t err = fromAidlStatus(mNode->getInputBufferParams(&param));
        status_t err = fromAidlStatus((*node)->getInputBufferParams(&param));
        if (err == OK) {
            numSlots = param.bufferCountActual;
        }
@@ -531,6 +560,7 @@ public:
    }

    status_t configure(Config &config) {
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        std::stringstream status;
        status_t err = OK;

@@ -551,14 +581,14 @@ public:

        // pts gap
        if (config.mMinAdjustedFps > 0 || config.mFixedAdjustedFps > 0) {
            if (mNode != nullptr) {
            if ((*node) != nullptr) {
                float gap = (config.mMinAdjustedFps > 0)
                        ? c2_min(INT32_MAX + 0., 1e6 / config.mMinAdjustedFps + 0.5)
                        : c2_max(0. - INT32_MAX, -1e6 / config.mFixedAdjustedFps - 0.5);
                // float -> uint32_t is undefined if the value is negative.
                // First convert to int32_t to ensure the expected behavior.
                int32_t gapUs = int32_t(gap);
                (void)mNode->setAdjustTimestampGapUs(gapUs);
                (void)(*node)->setAdjustTimestampGapUs(gapUs);
            }
        }

@@ -650,7 +680,7 @@ public:
        // priority
        if (mConfig.mPriority != config.mPriority) {
            if (config.mPriority != INT_MAX) {
                mNode->setPriority(config.mPriority);
                (*node)->setPriority(config.mPriority);
            }
            mConfig.mPriority = config.mPriority;
        }
@@ -664,24 +694,40 @@ public:
    }

    void onInputBufferDone(c2_cntr64_t index) override {
        mNode->onInputBufferDone(index);
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return;
        }
        (*node)->onInputBufferDone(index);
    }

    void onInputBufferEmptied() override {
        mNode->onInputBufferEmptied();
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return;
        }
        (*node)->onInputBufferEmptied();
    }

    android_dataspace getDataspace() override {
        return mNode->getDataspace();
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return HAL_DATASPACE_UNKNOWN;
        }
        return (*node)->getDataspace();
    }

    uint32_t getPixelFormat() override {
        return mNode->getPixelFormat();
        Mutexed<std::shared_ptr<C2AidlNode>>::Locked node(mNode);
        if ((*node) == nullptr) {
            return PIXEL_FORMAT_UNKNOWN;
        }
        return (*node)->getPixelFormat();
    }

private:
    std::shared_ptr<AGraphicBufferSource> mSource;
    std::shared_ptr<C2AidlNode> mNode;
    Mutexed<std::shared_ptr<C2AidlNode>> mNode;
    uint32_t mWidth;
    uint32_t mHeight;
    Config mConfig;
+57 −24
Original line number Diff line number Diff line
@@ -228,15 +228,23 @@ void CCodecBufferChannel::setComponent(
status_t CCodecBufferChannel::setInputSurface(
        const std::shared_ptr<InputSurfaceWrapper> &surface) {
    ALOGV("[%s] setInputSurface", mName);
    mInputSurface = surface;
    return mInputSurface->connect(mComponent);
    if (!surface) {
        ALOGE("[%s] setInputSurface: surface must not be null", mName);
        return BAD_VALUE;
    }
    Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
    inputSurface->numProcessingBuffersBalance = 0;
    inputSurface->surface = surface;
    mHasInputSurface = true;
    return inputSurface->surface->connect(mComponent);
}

status_t CCodecBufferChannel::signalEndOfInputStream() {
    if (mInputSurface == nullptr) {
    Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
    if (inputSurface->surface == nullptr) {
        return INVALID_OPERATION;
    }
    return mInputSurface->signalEndOfInputStream();
    return inputSurface->surface->signalEndOfInputStream();
}

status_t CCodecBufferChannel::queueInputBufferInternal(
@@ -1061,17 +1069,36 @@ void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
    if (mInputMetEos) {
        return;
    }
    {
    int64_t numOutputSlots = 0;
    bool outputFull = [this, &numOutputSlots]() {
        Mutexed<Output>::Locked output(mOutput);
        if (!output->buffers ||
                output->buffers->hasPending() ||
        if (!output->buffers) {
            ALOGV("[%s] feedInputBufferIfAvailableInternal: "
                  "return because output buffers are null", mName);
            return true;
        }
        numOutputSlots = int64_t(output->numSlots);
        if (output->buffers->hasPending() ||
                (!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
            return;
            ALOGV("[%s] feedInputBufferIfAvailableInternal: "
                  "return because there are no room for more output buffers", mName);
            return true;
        }
        return false;
    }();
    if (android::media::codec::provider_->input_surface_throttle()) {
        Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
        if (inputSurface->surface) {
            if (inputSurface->numProcessingBuffersBalance <= numOutputSlots) {
                ++inputSurface->numProcessingBuffersBalance;
                ALOGV("[%s] feedInputBufferIfAvailableInternal: numProcessingBuffersBalance = %lld",
                      mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
                inputSurface->surface->onInputBufferEmptied();
            }
        }
    if (android::media::codec::provider_->input_surface_throttle()
            && mInputSurface != nullptr) {
        mInputSurface->onInputBufferEmptied();
    }
    if (outputFull) {
        return;
    }
    size_t numActiveSlots = 0;
    while (!mPipelineWatcher.lock()->pipelineFull()) {
@@ -1700,7 +1727,7 @@ status_t CCodecBufferChannel::start(
                && (hasCryptoOrDescrambler() || conforming)) {
            input->buffers.reset(new SlotInputBuffers(mName));
        } else if (graphic) {
            if (mInputSurface) {
            if (mHasInputSurface) {
                input->buffers.reset(new DummyInputBuffers(mName));
            } else if (mMetaMode == MODE_ANW) {
                input->buffers.reset(new GraphicMetadataInputBuffers(mName));
@@ -1983,7 +2010,7 @@ status_t CCodecBufferChannel::start(

status_t CCodecBufferChannel::prepareInitialInputBuffers(
        std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
    if (mInputSurface) {
    if (mHasInputSurface) {
        return OK;
    }

@@ -2109,10 +2136,12 @@ void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {

void CCodecBufferChannel::reset() {
    stop();
    if (mInputSurface != nullptr) {
        mInputSurface.reset();
    }
    mPipelineWatcher.lock()->flush();
    {
        mHasInputSurface = false;
        Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
        inputSurface->surface.reset();
    }
    {
        Mutexed<Input>::Locked input(mInput);
        input->buffers.reset(new DummyInputBuffers(""));
@@ -2206,9 +2235,6 @@ void CCodecBufferChannel::onWorkDone(

void CCodecBufferChannel::onInputBufferDone(
        uint64_t frameIndex, size_t arrayIndex) {
    if (mInputSurface) {
        return;
    }
    std::shared_ptr<C2Buffer> buffer =
            mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
    bool newInputSlotAvailable = false;
@@ -2263,7 +2289,7 @@ bool CCodecBufferChannel::handleWork(
        notifyClient = false;
    }

    if (mInputSurface == nullptr && (work->worklets.size() != 1u
    if (!mHasInputSurface && (work->worklets.size() != 1u
            || !work->worklets.front()
            || !(work->worklets.front()->output.flags &
                 C2FrameData::FLAG_INCOMPLETE))) {
@@ -2472,7 +2498,7 @@ bool CCodecBufferChannel::handleWork(
    c2_cntr64_t timestamp =
        worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
                - work->input.ordinal.timestamp;
    if (mInputSurface != nullptr) {
    if (mHasInputSurface) {
        // When using input surface we need to restore the original input timestamp.
        timestamp = work->input.ordinal.customOrdinal;
    }
@@ -2602,8 +2628,6 @@ void CCodecBufferChannel::sendOutputBuffers() {
        switch (action) {
        case OutputBuffers::SKIP:
            return;
        case OutputBuffers::DISCARD:
            break;
        case OutputBuffers::NOTIFY_CLIENT:
        {
            // TRICKY: we want popped buffers reported in order, so sending
@@ -2631,6 +2655,15 @@ void CCodecBufferChannel::sendOutputBuffers() {
                }
            }
            mCallback->onOutputBufferAvailable(index, outBuffer);
            [[fallthrough]];
        }
        case OutputBuffers::DISCARD: {
            if (mHasInputSurface && android::media::codec::provider_->input_surface_throttle()) {
                Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
                --inputSurface->numProcessingBuffersBalance;
                ALOGV("[%s] onWorkDone: numProcessingBuffersBalance = %lld",
                        mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
            }
            break;
        }
        case OutputBuffers::REALLOCATE:
@@ -2799,7 +2832,7 @@ void CCodecBufferChannel::resetBuffersPixelFormat(bool isEncoder) {
}

void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
    if (mInputSurface == nullptr) {
    if (!mHasInputSurface) {
        mInfoBuffers.push_back(buffer);
    } else {
        std::list<std::unique_ptr<C2Work>> items;
+15 −1
Original line number Diff line number Diff line
@@ -391,7 +391,21 @@ private:
    };
    Mutexed<BlockPools> mBlockPools;

    std::shared_ptr<InputSurfaceWrapper> mInputSurface;
    std::atomic_bool mHasInputSurface;
    struct InputSurface {
        std::shared_ptr<InputSurfaceWrapper> surface;
        // This variable tracks the number of buffers processing
        // in the input surface and codec by counting the # of buffers to
        // be filled in and queued from the input surface and the # of
        // buffers generated from the codec.
        //
        // Note that this variable can go below 0, because it does not take
        // account the number of buffers initially in the buffer queue at
        // start. This is okay, as we only track how many more we allow
        // from the initial state.
        int64_t numProcessingBuffersBalance;
    };
    Mutexed<InputSurface> mInputSurface;

    MetaMode mMetaMode;