Loading media/codec2/core/include/C2Buffer.h +98 −7 Original line number Diff line number Diff line Loading @@ -642,7 +642,8 @@ public: * \retval C2_REFUSED no permission to complete the allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this allocator does not support 1D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation * (unexpected) */ virtual c2_status_t newLinearAllocation( uint32_t capacity __unused, C2MemoryUsage usage __unused, Loading @@ -666,7 +667,8 @@ public: * \retval C2_REFUSED no permission to recreate the allocation * \retval C2_BAD_VALUE invalid handle (caller error) * \retval C2_OMITTED this allocator does not support 1D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation * (unexpected) */ virtual c2_status_t priorLinearAllocation( const C2Handle *handle __unused, Loading Loading @@ -699,7 +701,8 @@ public: * \retval C2_REFUSED no permission to complete the allocation * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this allocator does not support 2D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation * (unexpected) */ virtual c2_status_t newGraphicAllocation( uint32_t width __unused, uint32_t height __unused, uint32_t format __unused, Loading @@ -724,7 +727,8 @@ public: * \retval C2_REFUSED no permission to recreate the allocation * \retval C2_BAD_VALUE invalid handle (caller error) * \retval C2_OMITTED this allocator does not support 2D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during recreation * (unexpected) */ virtual c2_status_t priorGraphicAllocation( const C2Handle *handle __unused, Loading Loading @@ -908,7 +912,8 @@ public: * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this pool does not support linear blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchLinearBlock( uint32_t capacity __unused, C2MemoryUsage usage __unused, Loading Loading @@ -937,7 +942,8 @@ public: * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this pool does not support circular blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchCircularBlock( uint32_t capacity __unused, C2MemoryUsage usage __unused, Loading Loading @@ -969,7 +975,8 @@ public: * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller * error) * \retval C2_OMITTED this pool does not support 2D blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchGraphicBlock( uint32_t width __unused, uint32_t height __unused, uint32_t format __unused, Loading @@ -980,6 +987,90 @@ public: } virtual ~C2BlockPool() = default; /** * Blocking fetch for linear block. Obtains a linear writable block of given |capacity| * and |usage|. If a block can be successfully obtained, the block is stored in |block|, * |fence| is set to a null-fence and C2_OK is returned. * * If a block cannot be temporarily obtained, |block| is set to nullptr, a waitable fence * is stored into |fence| and C2_BLOCKING is returned. * * Otherwise, |block| is set to nullptr and |fence| is set to a null-fence. The waitable * fence is signalled when the temporary restriction on fetch is lifted. * e.g. more memory is available to fetch because some meomory or prior blocks were released. * * \param capacity the size of requested block. * \param usage the memory usage info for the requested block. Returned blocks will be * optimized for this usage, but may be used with any usage. One exception: * protected blocks/buffers can only be used in a protected scenario. * \param block pointer to where the obtained block shall be stored on success. nullptr will * be stored here on failure * \param fence pointer to where the fence shall be stored on C2_BLOCKING error. * * \retval C2_OK the operation was successful * \retval C2_NO_MEMORY not enough memory to complete any required allocation * \retval C2_TIMED_OUT the operation timed out * \retval C2_BLOCKING the operation is blocked * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this pool does not support linear blocks nor fence. * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchLinearBlock( uint32_t capacity __unused, C2MemoryUsage usage __unused, std::shared_ptr<C2LinearBlock> *block /* nonnull */, C2Fence *fence /* nonnull */) { *block = nullptr; (void) fence; return C2_OMITTED; } /** * Blocking fetch for 2D graphic block. Obtains a 2D graphic writable block of given |capacity| * and |usage|. If a block can be successfully obtained, the block is stored in |block|, * |fence| is set to a null-fence and C2_OK is returned. * * If a block cannot be temporarily obtained, |block| is set to nullptr, a waitable fence * is stored into |fence| and C2_BLOCKING is returned. * * Otherwise, |block| is set to nullptr and |fence| is set to a null-fence. The waitable * fence is signalled when the temporary restriction on fetch is lifted. * e.g. more memory is available to fetch because some meomory or prior blocks were released. * * \param width the width of requested block (the obtained block could be slightly larger, e.g. * to accommodate any system-required alignment) * \param height the height of requested block (the obtained block could be slightly larger, * e.g. to accommodate any system-required alignment) * \param format the pixel format of requested block. This could be a vendor specific format. * \param usage the memory usage info for the requested block. Returned blocks will be * optimized for this usage, but may be used with any usage. One exception: * protected blocks/buffers can only be used in a protected scenario. * \param block pointer to where the obtained block shall be stored on success. nullptr * will be stored here on failure * \param fence pointer to where the fence shall be stored on C2_BLOCKING error. * * \retval C2_OK the operation was successful * \retval C2_NO_MEMORY not enough memory to complete any required allocation * \retval C2_TIMED_OUT the operation timed out * \retval C2_BLOCKING the operation is blocked * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller * error) * \retval C2_OMITTED this pool does not support 2D blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchGraphicBlock( uint32_t width __unused, uint32_t height __unused, uint32_t format __unused, C2MemoryUsage usage __unused, std::shared_ptr<C2GraphicBlock> *block /* nonnull */, C2Fence *fence /* nonnull */) { *block = nullptr; (void) fence; return C2_OMITTED; } protected: C2BlockPool() = default; }; Loading media/codec2/sfplugin/C2OMXNode.cpp +35 −1 Original line number Diff line number Diff line Loading @@ -33,12 +33,14 @@ #include <OMX_IndexExt.h> #include <android/fdsan.h> #include <media/stagefright/foundation/ColorUtils.h> #include <media/stagefright/omx/OMXUtils.h> #include <media/stagefright/MediaErrors.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <utils/Thread.h> #include "utils/Codec2Mapper.h" #include "C2OMXNode.h" namespace android { Loading Loading @@ -71,6 +73,23 @@ public: jobs->cond.broadcast(); } void setDataspace(android_dataspace dataspace) { Mutexed<Jobs>::Locked jobs(mJobs); ColorUtils::convertDataSpaceToV0(dataspace); jobs->configUpdate.emplace_back(new C2StreamDataSpaceInfo::input(0u, dataspace)); int32_t standard; int32_t transfer; int32_t range; ColorUtils::getColorConfigFromDataSpace(dataspace, &range, &standard, &transfer); std::unique_ptr<C2StreamColorAspectsInfo::input> colorAspects = std::make_unique<C2StreamColorAspectsInfo::input>(0u); if (C2Mapper::map(standard, &colorAspects->primaries, &colorAspects->matrix) && C2Mapper::map(transfer, &colorAspects->transfer) && C2Mapper::map(range, &colorAspects->range)) { jobs->configUpdate.push_back(std::move(colorAspects)); } } protected: bool threadLoop() override { constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000; // 10ms Loading Loading @@ -102,6 +121,9 @@ protected: uniqueFds.push_back(std::move(queue.workList.front().fd1)); queue.workList.pop_front(); } for (const std::unique_ptr<C2Param> ¶m : jobs->configUpdate) { items.front()->input.configUpdate.emplace_back(C2Param::Copy(*param)); } jobs.unlock(); for (int fenceFd : fenceFds) { Loading @@ -119,6 +141,7 @@ protected: queued = true; } if (queued) { jobs->configUpdate.clear(); return true; } if (i == 0) { Loading Loading @@ -161,6 +184,7 @@ private: std::map<std::weak_ptr<Codec2Client::Component>, Queue, std::owner_less<std::weak_ptr<Codec2Client::Component>>> queues; std::vector<std::unique_ptr<C2Param>> configUpdate; Condition cond; }; Mutexed<Jobs> mJobs; Loading @@ -172,6 +196,9 @@ C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp) mQueueThread(new QueueThread) { android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); mQueueThread->run("C2OMXNode", PRIORITY_AUDIO); Mutexed<android_dataspace>::Locked ds(mDataspace); *ds = HAL_DATASPACE_UNKNOWN; } status_t C2OMXNode::freeNode() { Loading Loading @@ -461,8 +488,11 @@ status_t C2OMXNode::dispatchMessage(const omx_message& msg) { android_dataspace dataSpace = (android_dataspace)msg.u.event_data.data1; uint32_t pixelFormat = msg.u.event_data.data3; // TODO: set dataspace on component to see if it impacts color aspects ALOGD("dataspace changed to %#x pixel format: %#x", dataSpace, pixelFormat); mQueueThread->setDataspace(dataSpace); Mutexed<android_dataspace>::Locked ds(mDataspace); *ds = dataSpace; return OK; } Loading Loading @@ -495,4 +525,8 @@ void C2OMXNode::onInputBufferDone(c2_cntr64_t index) { (void)mBufferSource->onInputBufferEmptied(bufferId, -1); } android_dataspace C2OMXNode::getDataspace() { return *mDataspace.lock(); } } // namespace android media/codec2/sfplugin/C2OMXNode.h +6 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,11 @@ struct C2OMXNode : public BnOMXNode { */ void onInputBufferDone(c2_cntr64_t index); /** * Returns dataspace information from GraphicBufferSource. */ android_dataspace getDataspace(); private: std::weak_ptr<Codec2Client::Component> mComp; sp<IOMXBufferSource> mBufferSource; Loading @@ -101,6 +106,7 @@ private: uint32_t mWidth; uint32_t mHeight; uint64_t mUsage; Mutexed<android_dataspace> mDataspace; // WORKAROUND: timestamp adjustment Loading media/codec2/sfplugin/CCodec.cpp +40 −2 Original line number Diff line number Diff line Loading @@ -211,8 +211,6 @@ public: (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usage, sizeof(usage)); // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we // communicate that directly to the component. mSource->configure( mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace)); return OK; Loading Loading @@ -411,6 +409,10 @@ public: mNode->onInputBufferDone(index); } android_dataspace getDataspace() override { return mNode->getDataspace(); } private: sp<HGraphicBufferSource> mSource; sp<C2OMXNode> mNode; Loading Loading @@ -1612,6 +1614,7 @@ void CCodec::start() { outputFormat = config->mOutputFormat = config->mOutputFormat->dup(); if (config->mInputSurface) { err2 = config->mInputSurface->start(); config->mInputSurfaceDataspace = config->mInputSurface->getDataspace(); } buffersBoundToCodec = config->mBuffersBoundToCodec; } Loading Loading @@ -1699,6 +1702,7 @@ void CCodec::stop() { if (config->mInputSurface) { config->mInputSurface->disconnect(); config->mInputSurface = nullptr; config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN; } } { Loading Loading @@ -1748,6 +1752,7 @@ void CCodec::initiateRelease(bool sendCallback /* = true */) { if (config->mInputSurface) { config->mInputSurface->disconnect(); config->mInputSurface = nullptr; config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN; } } Loading Loading @@ -2001,6 +2006,39 @@ void CCodec::signalRequestIDRFrame() { config->setParameters(comp, params, C2_MAY_BLOCK); } status_t CCodec::querySupportedParameters(std::vector<std::string> *names) { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->querySupportedParameters(names); } status_t CCodec::describeParameter( const std::string &name, CodecParameterDescriptor *desc) { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->describe(name, desc); } status_t CCodec::subscribeToParameters(const std::vector<std::string> &names) { std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp; if (!comp) { return INVALID_OPERATION; } Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->subscribeToVendorConfigUpdate(comp, names); } status_t CCodec::unsubscribeFromParameters(const std::vector<std::string> &names) { std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp; if (!comp) { return INVALID_OPERATION; } Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->unsubscribeFromVendorConfigUpdate(comp, names); } void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) { if (!workItems.empty()) { Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); Loading media/codec2/sfplugin/CCodecConfig.cpp +114 −18 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <C2Param.h> #include <util/C2InterfaceHelper.h> #include <media/stagefright/CodecBase.h> #include <media/stagefright/MediaCodecConstants.h> #include "CCodecConfig.h" Loading Loading @@ -290,8 +291,8 @@ struct StandardParams { std::vector<std::string> getPathsForDomain( Domain any, Domain all = Domain::ALL) const { std::vector<std::string> res; for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mConfigMappers) { for (const ConfigMapper &cm : el.second) { for (const auto &[key, mappers] : mConfigMappers) { for (const ConfigMapper &cm : mappers) { ALOGV("filtering %s %x %x %x %x", cm.path().c_str(), cm.domain(), any, (cm.domain() & any), (cm.domain() & any & all)); if ((cm.domain() & any) && ((cm.domain() & any & all) == (any & all))) { Loading Loading @@ -1061,7 +1062,7 @@ status_t CCodecConfig::initialize( std::vector<std::string> keys; mParamUpdater->getKeysForParamIndex(desc->index(), &keys); for (const std::string &key : keys) { mVendorParamIndices.insert_or_assign(key, desc->index()); mVendorParams.insert_or_assign(key, desc); } } } Loading Loading @@ -1128,6 +1129,12 @@ bool CCodecConfig::updateConfiguration( insertion.first->second = std::move(p); } } if (mInputSurface && (domain & mOutputDomain) && mInputSurfaceDataspace != mInputSurface->getDataspace()) { changed = true; mInputSurfaceDataspace = mInputSurface->getDataspace(); } ALOGV("updated configuration has %zu params (%s)", mCurrentConfig.size(), changed ? "CHANGED" : "no change"); Loading Loading @@ -1193,8 +1200,8 @@ sp<AMessage> CCodecConfig::getFormatForDomain( const ReflectedParamUpdater::Dict &reflected, Domain portDomain) const { sp<AMessage> msg = new AMessage; for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mStandardParams->getKeys()) { for (const ConfigMapper &cm : el.second) { for (const auto &[key, mappers] : mStandardParams->getKeys()) { for (const ConfigMapper &cm : mappers) { if ((cm.domain() & portDomain) == 0 // input-output-coded-raw || (cm.domain() & mDomain) != mDomain // component domain + kind (these must match) || (cm.domain() & IS_READ) == 0) { Loading @@ -1218,26 +1225,26 @@ sp<AMessage> CCodecConfig::getFormatForDomain( ALOGD("unexpected untyped query value for key: %s", cm.path().c_str()); continue; } msg->setItem(el.first.c_str(), item); msg->setItem(key.c_str(), item); } } bool input = (portDomain & Domain::IS_INPUT); std::vector<std::string> vendorKeys; for (const std::pair<std::string, ReflectedParamUpdater::Value> &entry : reflected) { auto it = mVendorParamIndices.find(entry.first); if (it == mVendorParamIndices.end()) { for (const auto &[key, value] : reflected) { auto it = mVendorParams.find(key); if (it == mVendorParams.end()) { continue; } if (mSubscribedIndices.count(it->second) == 0) { C2Param::Index index = it->second->index(); if (mSubscribedIndices.count(index) == 0) { continue; } // For vendor parameters, we only care about direction if ((input && !it->second.forInput()) || (!input && !it->second.forOutput())) { if ((input && !index.forInput()) || (!input && !index.forOutput())) { continue; } const ReflectedParamUpdater::Value &value = entry.second; C2Value c2Value; sp<ABuffer> bufValue; AString strValue; Loading @@ -1249,10 +1256,10 @@ sp<AMessage> CCodecConfig::getFormatForDomain( } else if (value.find(&strValue)) { item.set(strValue); } else { ALOGD("unexpected untyped query value for key: %s", entry.first.c_str()); ALOGD("unexpected untyped query value for key: %s", key.c_str()); continue; } msg->setItem(entry.first.c_str(), item); msg->setItem(key.c_str(), item); } { // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present Loading Loading @@ -1356,7 +1363,6 @@ sp<AMessage> CCodecConfig::getFormatForDomain( msg->removeEntryAt(msg->findEntryByName("color-matrix")); } // calculate dataspace for raw graphic buffers if not specified by component, or if // using surface with unspecified aspects (as those must be defaulted which may change // the dataspace) Loading Loading @@ -1394,6 +1400,23 @@ sp<AMessage> CCodecConfig::getFormatForDomain( } } if (mInputSurface) { android_dataspace dataspace = mInputSurface->getDataspace(); ColorUtils::convertDataSpaceToV0(dataspace); int32_t standard; ColorUtils::getColorConfigFromDataSpace(dataspace, &range, &standard, &transfer); if (range != 0) { msg->setInt32(KEY_COLOR_RANGE, range); } if (standard != 0) { msg->setInt32(KEY_COLOR_STANDARD, standard); } if (transfer != 0) { msg->setInt32(KEY_COLOR_TRANSFER, transfer); } msg->setInt32("android._dataspace", dataspace); } // HDR static info C2HdrStaticMetadataStruct hdr; Loading Loading @@ -1811,8 +1834,81 @@ const C2Param *CCodecConfig::getConfigParameterValue(C2Param::Index index) const status_t CCodecConfig::subscribeToAllVendorParams( const std::shared_ptr<Codec2Client::Configurable> &configurable, c2_blocking_t blocking) { for (const std::pair<std::string, C2Param::Index> &entry : mVendorParamIndices) { mSubscribedIndices.insert(entry.second); for (const auto &[path, desc] : mVendorParams) { mSubscribedIndices.insert(desc->index()); } return subscribeToConfigUpdate(configurable, {}, blocking); } status_t CCodecConfig::querySupportedParameters(std::vector<std::string> *names) { if (!names) { return BAD_VALUE; } names->clear(); // TODO: expand to standard params for (const auto &[key, desc] : mVendorParams) { names->push_back(key); } return OK; } status_t CCodecConfig::describe(const std::string &name, CodecParameterDescriptor *desc) { if (!desc) { return BAD_VALUE; } // TODO: expand to standard params desc->name = name; switch (mParamUpdater->getTypeForKey(name)) { case C2FieldDescriptor::INT32: case C2FieldDescriptor::UINT32: case C2FieldDescriptor::CNTR32: desc->type = AMessage::kTypeInt32; return OK; case C2FieldDescriptor::INT64: case C2FieldDescriptor::UINT64: case C2FieldDescriptor::CNTR64: desc->type = AMessage::kTypeInt64; return OK; case C2FieldDescriptor::FLOAT: desc->type = AMessage::kTypeFloat; return OK; case C2FieldDescriptor::STRING: desc->type = AMessage::kTypeString; return OK; case C2FieldDescriptor::BLOB: desc->type = AMessage::kTypeBuffer; return OK; default: return NAME_NOT_FOUND; } } status_t CCodecConfig::subscribeToVendorConfigUpdate( const std::shared_ptr<Codec2Client::Configurable> &configurable, const std::vector<std::string> &names, c2_blocking_t blocking) { for (const std::string &name : names) { auto it = mVendorParams.find(name); if (it == mVendorParams.end()) { ALOGD("%s is not a recognized vendor parameter; ignored.", name.c_str()); continue; } mSubscribedIndices.insert(it->second->index()); } return subscribeToConfigUpdate(configurable, {}, blocking); } status_t CCodecConfig::unsubscribeFromVendorConfigUpdate( const std::shared_ptr<Codec2Client::Configurable> &configurable, const std::vector<std::string> &names, c2_blocking_t blocking) { for (const std::string &name : names) { auto it = mVendorParams.find(name); if (it == mVendorParams.end()) { ALOGD("%s is not a recognized vendor parameter; ignored.", name.c_str()); continue; } mSubscribedIndices.erase(it->second->index()); } return subscribeToConfigUpdate(configurable, {}, blocking); } Loading Loading
media/codec2/core/include/C2Buffer.h +98 −7 Original line number Diff line number Diff line Loading @@ -642,7 +642,8 @@ public: * \retval C2_REFUSED no permission to complete the allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this allocator does not support 1D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation * (unexpected) */ virtual c2_status_t newLinearAllocation( uint32_t capacity __unused, C2MemoryUsage usage __unused, Loading @@ -666,7 +667,8 @@ public: * \retval C2_REFUSED no permission to recreate the allocation * \retval C2_BAD_VALUE invalid handle (caller error) * \retval C2_OMITTED this allocator does not support 1D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation * (unexpected) */ virtual c2_status_t priorLinearAllocation( const C2Handle *handle __unused, Loading Loading @@ -699,7 +701,8 @@ public: * \retval C2_REFUSED no permission to complete the allocation * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this allocator does not support 2D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during allocation * (unexpected) */ virtual c2_status_t newGraphicAllocation( uint32_t width __unused, uint32_t height __unused, uint32_t format __unused, Loading @@ -724,7 +727,8 @@ public: * \retval C2_REFUSED no permission to recreate the allocation * \retval C2_BAD_VALUE invalid handle (caller error) * \retval C2_OMITTED this allocator does not support 2D allocations * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during recreation * (unexpected) */ virtual c2_status_t priorGraphicAllocation( const C2Handle *handle __unused, Loading Loading @@ -908,7 +912,8 @@ public: * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this pool does not support linear blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchLinearBlock( uint32_t capacity __unused, C2MemoryUsage usage __unused, Loading Loading @@ -937,7 +942,8 @@ public: * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this pool does not support circular blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchCircularBlock( uint32_t capacity __unused, C2MemoryUsage usage __unused, Loading Loading @@ -969,7 +975,8 @@ public: * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller * error) * \retval C2_OMITTED this pool does not support 2D blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected) * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchGraphicBlock( uint32_t width __unused, uint32_t height __unused, uint32_t format __unused, Loading @@ -980,6 +987,90 @@ public: } virtual ~C2BlockPool() = default; /** * Blocking fetch for linear block. Obtains a linear writable block of given |capacity| * and |usage|. If a block can be successfully obtained, the block is stored in |block|, * |fence| is set to a null-fence and C2_OK is returned. * * If a block cannot be temporarily obtained, |block| is set to nullptr, a waitable fence * is stored into |fence| and C2_BLOCKING is returned. * * Otherwise, |block| is set to nullptr and |fence| is set to a null-fence. The waitable * fence is signalled when the temporary restriction on fetch is lifted. * e.g. more memory is available to fetch because some meomory or prior blocks were released. * * \param capacity the size of requested block. * \param usage the memory usage info for the requested block. Returned blocks will be * optimized for this usage, but may be used with any usage. One exception: * protected blocks/buffers can only be used in a protected scenario. * \param block pointer to where the obtained block shall be stored on success. nullptr will * be stored here on failure * \param fence pointer to where the fence shall be stored on C2_BLOCKING error. * * \retval C2_OK the operation was successful * \retval C2_NO_MEMORY not enough memory to complete any required allocation * \retval C2_TIMED_OUT the operation timed out * \retval C2_BLOCKING the operation is blocked * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error) * \retval C2_OMITTED this pool does not support linear blocks nor fence. * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchLinearBlock( uint32_t capacity __unused, C2MemoryUsage usage __unused, std::shared_ptr<C2LinearBlock> *block /* nonnull */, C2Fence *fence /* nonnull */) { *block = nullptr; (void) fence; return C2_OMITTED; } /** * Blocking fetch for 2D graphic block. Obtains a 2D graphic writable block of given |capacity| * and |usage|. If a block can be successfully obtained, the block is stored in |block|, * |fence| is set to a null-fence and C2_OK is returned. * * If a block cannot be temporarily obtained, |block| is set to nullptr, a waitable fence * is stored into |fence| and C2_BLOCKING is returned. * * Otherwise, |block| is set to nullptr and |fence| is set to a null-fence. The waitable * fence is signalled when the temporary restriction on fetch is lifted. * e.g. more memory is available to fetch because some meomory or prior blocks were released. * * \param width the width of requested block (the obtained block could be slightly larger, e.g. * to accommodate any system-required alignment) * \param height the height of requested block (the obtained block could be slightly larger, * e.g. to accommodate any system-required alignment) * \param format the pixel format of requested block. This could be a vendor specific format. * \param usage the memory usage info for the requested block. Returned blocks will be * optimized for this usage, but may be used with any usage. One exception: * protected blocks/buffers can only be used in a protected scenario. * \param block pointer to where the obtained block shall be stored on success. nullptr * will be stored here on failure * \param fence pointer to where the fence shall be stored on C2_BLOCKING error. * * \retval C2_OK the operation was successful * \retval C2_NO_MEMORY not enough memory to complete any required allocation * \retval C2_TIMED_OUT the operation timed out * \retval C2_BLOCKING the operation is blocked * \retval C2_REFUSED no permission to complete any required allocation * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller * error) * \retval C2_OMITTED this pool does not support 2D blocks * \retval C2_CORRUPTED some unknown, unrecoverable error occurred during operation * (unexpected) */ virtual c2_status_t fetchGraphicBlock( uint32_t width __unused, uint32_t height __unused, uint32_t format __unused, C2MemoryUsage usage __unused, std::shared_ptr<C2GraphicBlock> *block /* nonnull */, C2Fence *fence /* nonnull */) { *block = nullptr; (void) fence; return C2_OMITTED; } protected: C2BlockPool() = default; }; Loading
media/codec2/sfplugin/C2OMXNode.cpp +35 −1 Original line number Diff line number Diff line Loading @@ -33,12 +33,14 @@ #include <OMX_IndexExt.h> #include <android/fdsan.h> #include <media/stagefright/foundation/ColorUtils.h> #include <media/stagefright/omx/OMXUtils.h> #include <media/stagefright/MediaErrors.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <utils/Thread.h> #include "utils/Codec2Mapper.h" #include "C2OMXNode.h" namespace android { Loading Loading @@ -71,6 +73,23 @@ public: jobs->cond.broadcast(); } void setDataspace(android_dataspace dataspace) { Mutexed<Jobs>::Locked jobs(mJobs); ColorUtils::convertDataSpaceToV0(dataspace); jobs->configUpdate.emplace_back(new C2StreamDataSpaceInfo::input(0u, dataspace)); int32_t standard; int32_t transfer; int32_t range; ColorUtils::getColorConfigFromDataSpace(dataspace, &range, &standard, &transfer); std::unique_ptr<C2StreamColorAspectsInfo::input> colorAspects = std::make_unique<C2StreamColorAspectsInfo::input>(0u); if (C2Mapper::map(standard, &colorAspects->primaries, &colorAspects->matrix) && C2Mapper::map(transfer, &colorAspects->transfer) && C2Mapper::map(range, &colorAspects->range)) { jobs->configUpdate.push_back(std::move(colorAspects)); } } protected: bool threadLoop() override { constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000; // 10ms Loading Loading @@ -102,6 +121,9 @@ protected: uniqueFds.push_back(std::move(queue.workList.front().fd1)); queue.workList.pop_front(); } for (const std::unique_ptr<C2Param> ¶m : jobs->configUpdate) { items.front()->input.configUpdate.emplace_back(C2Param::Copy(*param)); } jobs.unlock(); for (int fenceFd : fenceFds) { Loading @@ -119,6 +141,7 @@ protected: queued = true; } if (queued) { jobs->configUpdate.clear(); return true; } if (i == 0) { Loading Loading @@ -161,6 +184,7 @@ private: std::map<std::weak_ptr<Codec2Client::Component>, Queue, std::owner_less<std::weak_ptr<Codec2Client::Component>>> queues; std::vector<std::unique_ptr<C2Param>> configUpdate; Condition cond; }; Mutexed<Jobs> mJobs; Loading @@ -172,6 +196,9 @@ C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp) mQueueThread(new QueueThread) { android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); mQueueThread->run("C2OMXNode", PRIORITY_AUDIO); Mutexed<android_dataspace>::Locked ds(mDataspace); *ds = HAL_DATASPACE_UNKNOWN; } status_t C2OMXNode::freeNode() { Loading Loading @@ -461,8 +488,11 @@ status_t C2OMXNode::dispatchMessage(const omx_message& msg) { android_dataspace dataSpace = (android_dataspace)msg.u.event_data.data1; uint32_t pixelFormat = msg.u.event_data.data3; // TODO: set dataspace on component to see if it impacts color aspects ALOGD("dataspace changed to %#x pixel format: %#x", dataSpace, pixelFormat); mQueueThread->setDataspace(dataSpace); Mutexed<android_dataspace>::Locked ds(mDataspace); *ds = dataSpace; return OK; } Loading Loading @@ -495,4 +525,8 @@ void C2OMXNode::onInputBufferDone(c2_cntr64_t index) { (void)mBufferSource->onInputBufferEmptied(bufferId, -1); } android_dataspace C2OMXNode::getDataspace() { return *mDataspace.lock(); } } // namespace android
media/codec2/sfplugin/C2OMXNode.h +6 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,11 @@ struct C2OMXNode : public BnOMXNode { */ void onInputBufferDone(c2_cntr64_t index); /** * Returns dataspace information from GraphicBufferSource. */ android_dataspace getDataspace(); private: std::weak_ptr<Codec2Client::Component> mComp; sp<IOMXBufferSource> mBufferSource; Loading @@ -101,6 +106,7 @@ private: uint32_t mWidth; uint32_t mHeight; uint64_t mUsage; Mutexed<android_dataspace> mDataspace; // WORKAROUND: timestamp adjustment Loading
media/codec2/sfplugin/CCodec.cpp +40 −2 Original line number Diff line number Diff line Loading @@ -211,8 +211,6 @@ public: (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usage, sizeof(usage)); // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we // communicate that directly to the component. mSource->configure( mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace)); return OK; Loading Loading @@ -411,6 +409,10 @@ public: mNode->onInputBufferDone(index); } android_dataspace getDataspace() override { return mNode->getDataspace(); } private: sp<HGraphicBufferSource> mSource; sp<C2OMXNode> mNode; Loading Loading @@ -1612,6 +1614,7 @@ void CCodec::start() { outputFormat = config->mOutputFormat = config->mOutputFormat->dup(); if (config->mInputSurface) { err2 = config->mInputSurface->start(); config->mInputSurfaceDataspace = config->mInputSurface->getDataspace(); } buffersBoundToCodec = config->mBuffersBoundToCodec; } Loading Loading @@ -1699,6 +1702,7 @@ void CCodec::stop() { if (config->mInputSurface) { config->mInputSurface->disconnect(); config->mInputSurface = nullptr; config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN; } } { Loading Loading @@ -1748,6 +1752,7 @@ void CCodec::initiateRelease(bool sendCallback /* = true */) { if (config->mInputSurface) { config->mInputSurface->disconnect(); config->mInputSurface = nullptr; config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN; } } Loading Loading @@ -2001,6 +2006,39 @@ void CCodec::signalRequestIDRFrame() { config->setParameters(comp, params, C2_MAY_BLOCK); } status_t CCodec::querySupportedParameters(std::vector<std::string> *names) { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->querySupportedParameters(names); } status_t CCodec::describeParameter( const std::string &name, CodecParameterDescriptor *desc) { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->describe(name, desc); } status_t CCodec::subscribeToParameters(const std::vector<std::string> &names) { std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp; if (!comp) { return INVALID_OPERATION; } Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->subscribeToVendorConfigUpdate(comp, names); } status_t CCodec::unsubscribeFromParameters(const std::vector<std::string> &names) { std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp; if (!comp) { return INVALID_OPERATION; } Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->unsubscribeFromVendorConfigUpdate(comp, names); } void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) { if (!workItems.empty()) { Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); Loading
media/codec2/sfplugin/CCodecConfig.cpp +114 −18 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <C2Param.h> #include <util/C2InterfaceHelper.h> #include <media/stagefright/CodecBase.h> #include <media/stagefright/MediaCodecConstants.h> #include "CCodecConfig.h" Loading Loading @@ -290,8 +291,8 @@ struct StandardParams { std::vector<std::string> getPathsForDomain( Domain any, Domain all = Domain::ALL) const { std::vector<std::string> res; for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mConfigMappers) { for (const ConfigMapper &cm : el.second) { for (const auto &[key, mappers] : mConfigMappers) { for (const ConfigMapper &cm : mappers) { ALOGV("filtering %s %x %x %x %x", cm.path().c_str(), cm.domain(), any, (cm.domain() & any), (cm.domain() & any & all)); if ((cm.domain() & any) && ((cm.domain() & any & all) == (any & all))) { Loading Loading @@ -1061,7 +1062,7 @@ status_t CCodecConfig::initialize( std::vector<std::string> keys; mParamUpdater->getKeysForParamIndex(desc->index(), &keys); for (const std::string &key : keys) { mVendorParamIndices.insert_or_assign(key, desc->index()); mVendorParams.insert_or_assign(key, desc); } } } Loading Loading @@ -1128,6 +1129,12 @@ bool CCodecConfig::updateConfiguration( insertion.first->second = std::move(p); } } if (mInputSurface && (domain & mOutputDomain) && mInputSurfaceDataspace != mInputSurface->getDataspace()) { changed = true; mInputSurfaceDataspace = mInputSurface->getDataspace(); } ALOGV("updated configuration has %zu params (%s)", mCurrentConfig.size(), changed ? "CHANGED" : "no change"); Loading Loading @@ -1193,8 +1200,8 @@ sp<AMessage> CCodecConfig::getFormatForDomain( const ReflectedParamUpdater::Dict &reflected, Domain portDomain) const { sp<AMessage> msg = new AMessage; for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mStandardParams->getKeys()) { for (const ConfigMapper &cm : el.second) { for (const auto &[key, mappers] : mStandardParams->getKeys()) { for (const ConfigMapper &cm : mappers) { if ((cm.domain() & portDomain) == 0 // input-output-coded-raw || (cm.domain() & mDomain) != mDomain // component domain + kind (these must match) || (cm.domain() & IS_READ) == 0) { Loading @@ -1218,26 +1225,26 @@ sp<AMessage> CCodecConfig::getFormatForDomain( ALOGD("unexpected untyped query value for key: %s", cm.path().c_str()); continue; } msg->setItem(el.first.c_str(), item); msg->setItem(key.c_str(), item); } } bool input = (portDomain & Domain::IS_INPUT); std::vector<std::string> vendorKeys; for (const std::pair<std::string, ReflectedParamUpdater::Value> &entry : reflected) { auto it = mVendorParamIndices.find(entry.first); if (it == mVendorParamIndices.end()) { for (const auto &[key, value] : reflected) { auto it = mVendorParams.find(key); if (it == mVendorParams.end()) { continue; } if (mSubscribedIndices.count(it->second) == 0) { C2Param::Index index = it->second->index(); if (mSubscribedIndices.count(index) == 0) { continue; } // For vendor parameters, we only care about direction if ((input && !it->second.forInput()) || (!input && !it->second.forOutput())) { if ((input && !index.forInput()) || (!input && !index.forOutput())) { continue; } const ReflectedParamUpdater::Value &value = entry.second; C2Value c2Value; sp<ABuffer> bufValue; AString strValue; Loading @@ -1249,10 +1256,10 @@ sp<AMessage> CCodecConfig::getFormatForDomain( } else if (value.find(&strValue)) { item.set(strValue); } else { ALOGD("unexpected untyped query value for key: %s", entry.first.c_str()); ALOGD("unexpected untyped query value for key: %s", key.c_str()); continue; } msg->setItem(entry.first.c_str(), item); msg->setItem(key.c_str(), item); } { // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present Loading Loading @@ -1356,7 +1363,6 @@ sp<AMessage> CCodecConfig::getFormatForDomain( msg->removeEntryAt(msg->findEntryByName("color-matrix")); } // calculate dataspace for raw graphic buffers if not specified by component, or if // using surface with unspecified aspects (as those must be defaulted which may change // the dataspace) Loading Loading @@ -1394,6 +1400,23 @@ sp<AMessage> CCodecConfig::getFormatForDomain( } } if (mInputSurface) { android_dataspace dataspace = mInputSurface->getDataspace(); ColorUtils::convertDataSpaceToV0(dataspace); int32_t standard; ColorUtils::getColorConfigFromDataSpace(dataspace, &range, &standard, &transfer); if (range != 0) { msg->setInt32(KEY_COLOR_RANGE, range); } if (standard != 0) { msg->setInt32(KEY_COLOR_STANDARD, standard); } if (transfer != 0) { msg->setInt32(KEY_COLOR_TRANSFER, transfer); } msg->setInt32("android._dataspace", dataspace); } // HDR static info C2HdrStaticMetadataStruct hdr; Loading Loading @@ -1811,8 +1834,81 @@ const C2Param *CCodecConfig::getConfigParameterValue(C2Param::Index index) const status_t CCodecConfig::subscribeToAllVendorParams( const std::shared_ptr<Codec2Client::Configurable> &configurable, c2_blocking_t blocking) { for (const std::pair<std::string, C2Param::Index> &entry : mVendorParamIndices) { mSubscribedIndices.insert(entry.second); for (const auto &[path, desc] : mVendorParams) { mSubscribedIndices.insert(desc->index()); } return subscribeToConfigUpdate(configurable, {}, blocking); } status_t CCodecConfig::querySupportedParameters(std::vector<std::string> *names) { if (!names) { return BAD_VALUE; } names->clear(); // TODO: expand to standard params for (const auto &[key, desc] : mVendorParams) { names->push_back(key); } return OK; } status_t CCodecConfig::describe(const std::string &name, CodecParameterDescriptor *desc) { if (!desc) { return BAD_VALUE; } // TODO: expand to standard params desc->name = name; switch (mParamUpdater->getTypeForKey(name)) { case C2FieldDescriptor::INT32: case C2FieldDescriptor::UINT32: case C2FieldDescriptor::CNTR32: desc->type = AMessage::kTypeInt32; return OK; case C2FieldDescriptor::INT64: case C2FieldDescriptor::UINT64: case C2FieldDescriptor::CNTR64: desc->type = AMessage::kTypeInt64; return OK; case C2FieldDescriptor::FLOAT: desc->type = AMessage::kTypeFloat; return OK; case C2FieldDescriptor::STRING: desc->type = AMessage::kTypeString; return OK; case C2FieldDescriptor::BLOB: desc->type = AMessage::kTypeBuffer; return OK; default: return NAME_NOT_FOUND; } } status_t CCodecConfig::subscribeToVendorConfigUpdate( const std::shared_ptr<Codec2Client::Configurable> &configurable, const std::vector<std::string> &names, c2_blocking_t blocking) { for (const std::string &name : names) { auto it = mVendorParams.find(name); if (it == mVendorParams.end()) { ALOGD("%s is not a recognized vendor parameter; ignored.", name.c_str()); continue; } mSubscribedIndices.insert(it->second->index()); } return subscribeToConfigUpdate(configurable, {}, blocking); } status_t CCodecConfig::unsubscribeFromVendorConfigUpdate( const std::shared_ptr<Codec2Client::Configurable> &configurable, const std::vector<std::string> &names, c2_blocking_t blocking) { for (const std::string &name : names) { auto it = mVendorParams.find(name); if (it == mVendorParams.end()) { ALOGD("%s is not a recognized vendor parameter; ignored.", name.c_str()); continue; } mSubscribedIndices.erase(it->second->index()); } return subscribeToConfigUpdate(configurable, {}, blocking); } Loading