From fd21270f231724df703891f310a16af1fa13d17f Mon Sep 17 00:00:00 2001 From: Arun Johnson Date: Tue, 16 Apr 2024 23:05:25 +0000 Subject: MultiAccessUnitHelper to handle dynamic config MultiAccessUnitHelper can accept changes to its config on the fly Bug: 335714093 Flag: com.android.media.codec.flags.large_audio_frame Change-Id: I18ad7b238f0689be8a313cdab0021cfe7a18e0db --- media/codec2/hal/common/MultiAccessUnitHelper.cpp | 142 +++++++++++++++++---- .../include/codec2/common/MultiAccessUnitHelper.h | 19 +++ 2 files changed, 136 insertions(+), 25 deletions(-) diff --git a/media/codec2/hal/common/MultiAccessUnitHelper.cpp b/media/codec2/hal/common/MultiAccessUnitHelper.cpp index 8086ef20eb..f70d63ee38 100644 --- a/media/codec2/hal/common/MultiAccessUnitHelper.cpp +++ b/media/codec2/hal/common/MultiAccessUnitHelper.cpp @@ -27,6 +27,7 @@ #include #include +static inline constexpr uint32_t MAX_SUPPORTED_SIZE = ( 10 * 512000 * 8 * 2u); namespace android { static C2R MultiAccessUnitParamsSetter( @@ -39,8 +40,6 @@ static C2R MultiAccessUnitParamsSetter( res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.thresholdSize))); } else if (me.v.maxSize < me.v.thresholdSize) { me.set().maxSize = me.v.thresholdSize; - } else if (me.v.thresholdSize == 0 && me.v.maxSize > 0) { - me.set().thresholdSize = me.v.maxSize; } std::vector> failures; res.retrieveFailures(&failures); @@ -61,9 +60,9 @@ MultiAccessUnitInterface::MultiAccessUnitInterface( .withDefault(new C2LargeFrame::output(0u, 0, 0)) .withFields({ C2F(mLargeFrameParams, maxSize).inRange( - 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u)), + 0, c2_min(UINT_MAX, MAX_SUPPORTED_SIZE)), C2F(mLargeFrameParams, thresholdSize).inRange( - 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u)) + 0, c2_min(UINT_MAX, MAX_SUPPORTED_SIZE)) }) .withSetter(MultiAccessUnitParamsSetter) .build()); @@ -115,6 +114,18 @@ bool MultiAccessUnitInterface::getDecoderSampleRateAndChannelCount( return false; } +bool MultiAccessUnitInterface::getMaxInputSize( + C2StreamMaxBufferSizeInfo::input* const maxInputSize) const { + if (maxInputSize == nullptr || mC2ComponentIntf == nullptr) { + return false; + } + c2_status_t err = mC2ComponentIntf->query_vb({maxInputSize}, {}, C2_MAY_BLOCK, nullptr); + if (err != OK) { + return false; + } + return true; +} + //C2MultiAccessUnitBuffer class C2MultiAccessUnitBuffer : public C2Buffer { public: @@ -128,6 +139,7 @@ class C2MultiAccessUnitBuffer : public C2Buffer { MultiAccessUnitHelper::MultiAccessUnitHelper( const std::shared_ptr& intf, std::shared_ptr& linearPool): + mMultiAccessOnOffAllowed(true), mInit(false), mInterface(intf), mLinearPool(linearPool) { @@ -152,6 +164,63 @@ bool MultiAccessUnitHelper::isEnabledOnPlatform() { return result; } +bool MultiAccessUnitHelper::tryReconfigure(const std::unique_ptr ¶m) { + C2LargeFrame::output *lfp = C2LargeFrame::output::From(param.get()); + if (lfp == nullptr) { + return false; + } + bool isDecoder = (mInterface->kind() == C2Component::KIND_DECODER) ? true : false; + if (!isDecoder) { + C2StreamMaxBufferSizeInfo::input maxInputSize(0); + if (!mInterface->getMaxInputSize(&maxInputSize)) { + LOG(ERROR) << "Error in reconfigure: " + << "Encoder failed to respond with a valid max input size"; + return false; + } + // This is assuming a worst case compression ratio of 1:1 + // In no case the encoder should give an output more than + // what is being provided to the encoder in a single call. + if (lfp->maxSize < maxInputSize.value) { + lfp->maxSize = maxInputSize.value; + } + } + lfp->maxSize = + (lfp->maxSize > MAX_SUPPORTED_SIZE) ? MAX_SUPPORTED_SIZE : + (lfp->maxSize < 0) ? 0 : lfp->maxSize; + lfp->thresholdSize = + (lfp->thresholdSize > MAX_SUPPORTED_SIZE) ? MAX_SUPPORTED_SIZE : + (lfp->thresholdSize < 0) ? 0 : lfp->thresholdSize; + C2LargeFrame::output currentConfig = mInterface->getLargeFrameParam(); + if ((currentConfig.maxSize == lfp->maxSize) + && (currentConfig.thresholdSize == lfp->thresholdSize)) { + // no need to update + return false; + } + if (isDecoder) { + bool isOnOffTransition = + (currentConfig.maxSize == 0 && lfp->maxSize != 0) + || (currentConfig.maxSize != 0 && lfp->maxSize == 0); + if (isOnOffTransition && !mMultiAccessOnOffAllowed) { + LOG(ERROR) << "Setting new configs not allowed" + << " MaxSize: " << lfp->maxSize + << " ThresholdSize: " << lfp->thresholdSize; + return false; + } + } + std::vector config{lfp}; + std::vector> failures; + if (C2_OK != mInterface->config(config, C2_MAY_BLOCK, &failures)) { + LOG(ERROR) << "Dynamic config not applied for" + << " MaxSize: " << lfp->maxSize + << " ThresholdSize: " << lfp->thresholdSize; + return false; + } + LOG(DEBUG) << "Updated from param maxSize " + << lfp->maxSize + << " ThresholdSize " << lfp->thresholdSize; + return true; +} + std::shared_ptr MultiAccessUnitHelper::getInterface() { return mInterface; } @@ -163,6 +232,7 @@ bool MultiAccessUnitHelper::getStatus() { void MultiAccessUnitHelper::reset() { std::lock_guard l(mLock); mFrameHolder.clear(); + mMultiAccessOnOffAllowed = true; } c2_status_t MultiAccessUnitHelper::error( @@ -181,6 +251,7 @@ c2_status_t MultiAccessUnitHelper::error( } } mFrameHolder.clear(); + mMultiAccessOnOffAllowed = true; return C2_OK; } @@ -232,16 +303,23 @@ c2_status_t MultiAccessUnitHelper::scatter( uint64_t newFrameIdx = mFrameIndex++; // TODO: Do not split buffers if component inherantly supports MultipleFrames. // if thats case, only replace frameindex. - auto cloneInputWork = [&newFrameIdx](std::unique_ptr& inWork, uint32_t flags) { + auto cloneInputWork = [&frameInfo, &newFrameIdx, this] + (std::unique_ptr& inWork, uint32_t flags) -> std::unique_ptr { std::unique_ptr newWork(new C2Work); newWork->input.flags = (C2FrameData::flags_t)flags; newWork->input.ordinal = inWork->input.ordinal; newWork->input.ordinal.frameIndex = newFrameIdx; if (!inWork->input.configUpdate.empty()) { for (std::unique_ptr& param : inWork->input.configUpdate) { - newWork->input.configUpdate.push_back( - std::move(C2Param::Copy(*(param.get())))); + if (param->index() == C2LargeFrame::output::PARAM_TYPE) { + if (tryReconfigure(param)) { + frameInfo.mConfigUpdate.push_back(std::move(param)); + } + } else { + newWork->input.configUpdate.push_back(std::move(param)); + } } + inWork->input.configUpdate.clear(); } newWork->input.infoBuffers = (inWork->input.infoBuffers); if (!inWork->worklets.empty() && inWork->worklets.front() != nullptr) { @@ -331,6 +409,7 @@ c2_status_t MultiAccessUnitHelper::scatter( frameInfo.mLargeFrameTuning = multiAccessParams; std::lock_guard l(mLock); mFrameHolder.push_back(std::move(frameInfo)); + mMultiAccessOnOffAllowed = false; } } return C2_OK; @@ -369,8 +448,7 @@ c2_status_t MultiAccessUnitHelper::gather( if (work->result != C2_OK || work->worklets.empty() || !work->worklets.front() - || (frame->mLargeFrameTuning.thresholdSize == 0 - || frame->mLargeFrameTuning.maxSize == 0)) { + || frame->mLargeFrameTuning.maxSize == 0) { if (removeEntry) { frame->mComponentFrameIds.erase(it); removeEntry = false; @@ -683,26 +761,39 @@ c2_status_t MultiAccessUnitHelper::finalizeWork( frame.mWview->setOffset(0); std::shared_ptr c2Buffer = C2Buffer::CreateLinearBuffer( frame.mBlock->share(0, size, ::C2Fence())); - if (frame.mAccessUnitInfos.size() > 0) { - if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) { - frame.mAccessUnitInfos.back().flags |= - C2FrameData::FLAG_END_OF_STREAM; + frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(c2Buffer)); + } + if (frame.mLargeWork->worklets.front()->output.buffers.size() > 0) { + std::shared_ptr& c2Buffer = + frame.mLargeWork->worklets.front()->output.buffers.front(); + if (c2Buffer != nullptr) { + if (frame.mAccessUnitInfos.size() > 0) { + if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) { + frame.mAccessUnitInfos.back().flags |= C2FrameData::FLAG_END_OF_STREAM; + } + std::shared_ptr largeFrame = + C2AccessUnitInfos::output::AllocShared( + frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos); + frame.mInfos.push_back(largeFrame); + frame.mAccessUnitInfos.clear(); + } + for (auto &info : frame.mInfos) { + c2Buffer->setInfo(std::const_pointer_cast(info)); } - std::shared_ptr largeFrame = - C2AccessUnitInfos::output::AllocShared( - frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos); - frame.mInfos.push_back(largeFrame); - frame.mAccessUnitInfos.clear(); - } - for (auto &info : frame.mInfos) { - c2Buffer->setInfo(std::const_pointer_cast(info)); } - frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(c2Buffer)); - frame.mInfos.clear(); - frame.mBlock.reset(); - frame.mWview.reset(); + } + if (frame.mConfigUpdate.size() > 0) { + outFrameData.configUpdate.insert( + outFrameData.configUpdate.end(), + make_move_iterator(frame.mConfigUpdate.begin()), + make_move_iterator(frame.mConfigUpdate.end())); } } + frame.mConfigUpdate.clear(); + frame.mInfos.clear(); + frame.mBlock.reset(); + frame.mWview.reset(); + LOG(DEBUG) << "Multi access-unitflag setting as " << finalFlags; return C2_OK; } @@ -735,6 +826,7 @@ void MultiAccessUnitHelper::MultiAccessUnitInfo::reset() { mBlock.reset(); mWview.reset(); mInfos.clear(); + mConfigUpdate.clear(); mAccessUnitInfos.clear(); mLargeWork.reset(); } diff --git a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h index bb4464c197..070a1f5fc1 100644 --- a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h +++ b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h @@ -46,6 +46,7 @@ struct MultiAccessUnitInterface : public C2InterfaceHelper { protected: bool getDecoderSampleRateAndChannelCount( uint32_t * const sampleRate_, uint32_t * const channelCount_) const; + bool getMaxInputSize(C2StreamMaxBufferSizeInfo::input* const maxInputSize) const; const std::shared_ptr mC2ComponentIntf; std::shared_ptr mLargeFrameParams; C2ComponentKindSetting mKind; @@ -139,6 +140,11 @@ protected: */ std::vector> mInfos; + /* + * Vector for holding config updates from the wrapper + */ + std::vector> mConfigUpdate; + /* * C2AccessUnitInfos for the current buffer */ @@ -169,6 +175,11 @@ protected: void reset(); }; + /* + * Reconfigure helper + */ + bool tryReconfigure(const std::unique_ptr &p); + /* * Creates a linear block to be used with work */ @@ -195,6 +206,14 @@ protected: uint32_t size, int64_t timestamp); + // Flag to allow dynamic on/off settings on this helper. + // Once enabled and buffers in transit, it is not possible + // to turn this module off by setting the max output value + // to 0. This is because the skip cut buffer expects the + // metadata to be always present along with a valid buffer. + // This flag is used to monitor that state of this module. + bool mMultiAccessOnOffAllowed; + bool mInit; // Interface of this module -- cgit v1.2.3 From d5e0f91aa1b9954753c62cb009fdec24e750a6f5 Mon Sep 17 00:00:00 2001 From: Arun Johnson Date: Thu, 18 Apr 2024 20:09:07 +0000 Subject: Returning buffers more than C2LargeFrame.maxSize MultiAccessUnitHelper will now returns the entire access unit from an encoding component even if the its size is more than the configured maxSize with a warning. This is to make sure we gracefully handle the condition when the underlying component doesn't report C2StreamMaxBufferSizeInfo properly Bug: 335711421 Test: atest android.mediav2.cts.CodecEncoderMultiAccessUnitTest Test: atest android.mediav2.cts.CodecEncoderBlockModelMultiAccessUnitTest Flag: com.android.media.codec.flags.large_audio_frame Change-Id: I1b67cc8eb5870751ed393e95da4007d716e9a2e5 --- media/codec2/hal/common/MultiAccessUnitHelper.cpp | 59 ++++++++++++++--------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/media/codec2/hal/common/MultiAccessUnitHelper.cpp b/media/codec2/hal/common/MultiAccessUnitHelper.cpp index f70d63ee38..b1fa82fe5f 100644 --- a/media/codec2/hal/common/MultiAccessUnitHelper.cpp +++ b/media/codec2/hal/common/MultiAccessUnitHelper.cpp @@ -439,6 +439,7 @@ c2_status_t MultiAccessUnitHelper::gather( std::list::iterator frame = mFrameHolder.begin(); while (!foundFrame && frame != mFrameHolder.end()) { + c2_status_t res = C2_OK; auto it = frame->mComponentFrameIds.find(thisFrameIndex); if (it != frame->mComponentFrameIds.end()) { foundFrame = true; @@ -466,10 +467,27 @@ c2_status_t MultiAccessUnitHelper::gather( addOutWork(frame->mLargeWork); frame->reset(); if (workResult != C2_OK) { - frame->mAccessUnitInfos.clear(); + frame->mComponentFrameIds.clear(); + removeEntry = false; + } + } else if (C2_OK != (res = processWorklets(*frame, work, addOutWork))) { + // Upon error in processing worklets, we return the work with + // result set to the error. This should indicate the error to the + // framework and thus doing what is necessary to handle the + // error. + LOG(DEBUG) << "Error while processing worklets"; + if (frame->mLargeWork == nullptr) { + frame->mLargeWork.reset(new C2Work); + frame->mLargeWork->input.ordinal = frame->inOrdinal; + frame->mLargeWork->input.ordinal.frameIndex = + frame->inOrdinal.frameIndex; } - } else if (C2_OK != processWorklets(*frame, work, addOutWork)) { - LOG(DEBUG) << "Error while processing work"; + frame->mLargeWork->result = res; + finalizeWork(*frame); + addOutWork(frame->mLargeWork); + frame->reset(); + frame->mComponentFrameIds.clear(); + removeEntry = false; } if (removeEntry) { LOG(DEBUG) << "Removing entry: " << thisFrameIndex @@ -606,9 +624,6 @@ c2_status_t MultiAccessUnitHelper::processWorklets(MultiAccessUnitInfo &frame, LOG(DEBUG) << "maxOutSize " << frame.mLargeFrameTuning.maxSize << " threshold " << frame.mLargeFrameTuning.thresholdSize; - if ((*worklet)->output.buffers.size() > 0) { - allocateWork(frame, true, true); - } LOG(DEBUG) << "This worklet has " << (*worklet)->output.buffers.size() << " buffers" << " ts: " << (*worklet)->output.ordinal.timestamp.peekull(); int64_t workletTimestamp = (*worklet)->output.ordinal.timestamp.peekull(); @@ -630,43 +645,39 @@ c2_status_t MultiAccessUnitHelper::processWorklets(MultiAccessUnitInfo &frame, inputSize -= (inputSize % frameSize); } while (inputOffset < inputSize) { - if (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize) { + if ((frame.mWview != nullptr) + && (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize)) { frame.mLargeWork->result = C2_OK; finalizeWork(frame, flagsForCopy); addWork(frame.mLargeWork); frame.reset(); - allocateWork(frame, true, true); } if (mInterface->kind() == C2Component::KIND_ENCODER) { if (inputSize > frame.mLargeFrameTuning.maxSize) { - LOG(ERROR) << "Enc: Output buffer too small for AU, configured with " - << frame.mLargeFrameTuning.maxSize - << " block size: " << blocks.front().size() - << "alloc size " << frame.mWview->size(); - if (frame.mLargeWork - && frame.mWview && frame.mWview->offset() > 0) { + LOG(WARNING) << "WARNING Encoder:" + << " Output buffer too small for configuration" + << " configured max size " << frame.mLargeFrameTuning.maxSize + << " access unit size " << inputSize; + if (frame.mLargeWork && (frame.mWview && frame.mWview->offset() > 0)) { + frame.mLargeWork->result = C2_OK; finalizeWork(frame, flagsForCopy); addWork(frame.mLargeWork); frame.reset(); - allocateWork(frame, true, false); } - frame.mLargeWork->result = C2_NO_MEMORY; - finalizeWork(frame, 0, true); - addWork(frame.mLargeWork); - frame.reset(); - return C2_NO_MEMORY; - } else if (inputSize > frame.mWview->size()) { + frame.mLargeFrameTuning.maxSize = inputSize; + } else if ((frame.mWview != nullptr) + && (inputSize > frame.mWview->size())) { LOG(DEBUG) << "Enc: Large frame hitting bufer limit, current size " << frame.mWview->offset(); - if (frame.mLargeWork - && frame.mWview && frame.mWview->offset() > 0) { + if (frame.mWview->offset() > 0) { + frame.mLargeWork->result = C2_OK; finalizeWork(frame, flagsForCopy); addWork(frame.mLargeWork); frame.reset(); - allocateWork(frame, true, true); } } } + allocateWork(frame, true, true); C2ReadView rView = blocks.front().map().get(); if (rView.error()) { LOG(ERROR) << "Buffer read view error"; -- cgit v1.2.3