Loading media/codec2/sfplugin/CCodec.cpp +255 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ #include "C2OMXNode.h" #include "CCodecBufferChannel.h" #include "CCodecConfig.h" #include "Codec2Mapper.h" #include "InputSurfaceWrapper.h" extern "C" android::PersistentSurface *CreateInputSurface(); Loading Loading @@ -717,6 +718,11 @@ void CCodec::configure(const sp<AMessage> &msg) { encoder = false; } int32_t flags; if (!msg->findInt32("flags", &flags)) { return BAD_VALUE; } // TODO: read from intf() if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) { return UNKNOWN_ERROR; Loading @@ -743,6 +749,9 @@ void CCodec::configure(const sp<AMessage> &msg) { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; config->mUsingSurface = surface != nullptr; config->mBuffersBoundToCodec = ((flags & CONFIGURE_FLAG_USE_BLOCK_MODEL) == 0); ALOGD("[%s] buffers are %sbound to CCodec for this session", comp->getName().c_str(), config->mBuffersBoundToCodec ? "" : "not "); // Enforce required parameters int32_t i32; Loading Loading @@ -1299,6 +1308,7 @@ void CCodec::start() { sp<AMessage> inputFormat; sp<AMessage> outputFormat; status_t err2 = OK; bool buffersBoundToCodec = false; { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; Loading @@ -1307,12 +1317,13 @@ void CCodec::start() { if (config->mInputSurface) { err2 = config->mInputSurface->start(); } buffersBoundToCodec = config->mBuffersBoundToCodec; } if (err2 != OK) { mCallback->onError(err2, ACTION_CODE_FATAL); return; } err2 = mChannel->start(inputFormat, outputFormat); err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec); if (err2 != OK) { mCallback->onError(err2, ACTION_CODE_FATAL); return; Loading Loading @@ -1556,7 +1567,11 @@ void CCodec::signalResume() { return; } (void)mChannel->start(nullptr, nullptr); (void)mChannel->start(nullptr, nullptr, [&]{ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->mBuffersBoundToCodec; }()); { Mutexed<State>::Locked state(mState); Loading Loading @@ -1911,5 +1926,243 @@ PersistentSurface *CCodec::CreateInputSurface() { inputSurface->getHalInterface())); } static status_t GetCommonAllocatorIds( const std::vector<std::string> &names, C2Allocator::type_t type, std::set<C2Allocator::id_t> *ids) { int poolMask = GetCodec2PoolMask(); C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask); C2Allocator::id_t defaultAllocatorId = (type == C2Allocator::LINEAR) ? preferredLinearId : C2PlatformAllocatorStore::GRALLOC; ids->clear(); if (names.empty()) { return OK; } std::shared_ptr<Codec2Client::Interface> intf{ Codec2Client::CreateInterfaceByName(names[0].c_str())}; std::vector<std::unique_ptr<C2Param>> params; c2_status_t err = intf->query( {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, ¶ms); if (err == C2_OK && params.size() == 1u) { C2PortAllocatorsTuning::input *allocators = C2PortAllocatorsTuning::input::From(params[0].get()); if (allocators && allocators->flexCount() > 0) { ids->insert(allocators->m.values, allocators->m.values + allocators->flexCount()); } } if (ids->empty()) { // The component does not advertise allocators. Use default. ids->insert(defaultAllocatorId); } for (size_t i = 1; i < names.size(); ++i) { intf = Codec2Client::CreateInterfaceByName(names[i].c_str()); err = intf->query( {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, ¶ms); bool filtered = false; if (err == C2_OK && params.size() == 1u) { C2PortAllocatorsTuning::input *allocators = C2PortAllocatorsTuning::input::From(params[0].get()); if (allocators && allocators->flexCount() > 0) { filtered = true; for (auto it = ids->begin(); it != ids->end(); ) { bool found = false; for (size_t j = 0; j < allocators->flexCount(); ++j) { if (allocators->m.values[j] == *it) { found = true; break; } } if (found) { ++it; } else { it = ids->erase(it); } } } } if (!filtered) { // The component does not advertise supported allocators. Use default. bool containsDefault = (ids->count(defaultAllocatorId) > 0u); if (ids->size() != (containsDefault ? 1 : 0)) { ids->clear(); if (containsDefault) { ids->insert(defaultAllocatorId); } } } } // Finally, filter with pool masks for (auto it = ids->begin(); it != ids->end(); ) { if ((poolMask >> *it) & 1) { ++it; } else { it = ids->erase(it); } } return OK; } static status_t CalculateMinMaxUsage( const std::vector<std::string> &names, uint64_t *minUsage, uint64_t *maxUsage) { static C2StreamUsageTuning::input sUsage{0u /* stream id */}; *minUsage = 0; *maxUsage = ~0ull; for (const std::string &name : names) { std::shared_ptr<Codec2Client::Interface> intf{ Codec2Client::CreateInterfaceByName(name.c_str())}; std::vector<C2FieldSupportedValuesQuery> fields; fields.push_back(C2FieldSupportedValuesQuery::Possible( C2ParamField{&sUsage, &sUsage.value})); c2_status_t err = intf->querySupportedValues(fields, C2_MAY_BLOCK); if (err != C2_OK) { continue; } if (fields[0].status != C2_OK) { continue; } const C2FieldSupportedValues &supported = fields[0].values; if (supported.type != C2FieldSupportedValues::FLAGS) { continue; } if (supported.values.empty()) { *maxUsage = 0; continue; } *minUsage |= supported.values[0].u64; int64_t currentMaxUsage = 0; for (const C2Value::Primitive &flags : supported.values) { currentMaxUsage |= flags.u64; } *maxUsage &= currentMaxUsage; } return OK; } // static status_t CCodec::CanFetchLinearBlock( const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible) { uint64_t minUsage = usage.expected; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators); if (allocators.empty()) { *isCompatible = false; return OK; } CalculateMinMaxUsage(names, &minUsage, &maxUsage); *isCompatible = ((maxUsage & minUsage) == minUsage); return OK; } static std::shared_ptr<C2BlockPool> GetPool(C2Allocator::id_t allocId) { static std::mutex sMutex{}; static std::map<C2Allocator::id_t, std::shared_ptr<C2BlockPool>> sPools; std::unique_lock<std::mutex> lock{sMutex}; std::shared_ptr<C2BlockPool> pool; auto it = sPools.find(allocId); if (it == sPools.end()) { c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool); if (err == OK) { sPools.emplace(allocId, pool); } else { pool.reset(); } } else { pool = it->second; } return pool; } // static std::shared_ptr<C2LinearBlock> CCodec::FetchLinearBlock( size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names) { uint64_t minUsage = usage.expected; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators); if (allocators.empty()) { allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR); } CalculateMinMaxUsage(names, &minUsage, &maxUsage); if ((maxUsage & minUsage) != minUsage) { allocators.clear(); allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR); } std::shared_ptr<C2LinearBlock> block; for (C2Allocator::id_t allocId : allocators) { std::shared_ptr<C2BlockPool> pool = GetPool(allocId); if (!pool) { continue; } c2_status_t err = pool->fetchLinearBlock(capacity, C2MemoryUsage{minUsage}, &block); if (err != C2_OK || !block) { block.reset(); continue; } break; } return block; } // static status_t CCodec::CanFetchGraphicBlock( const std::vector<std::string> &names, bool *isCompatible) { uint64_t minUsage = 0; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators); if (allocators.empty()) { *isCompatible = false; return OK; } CalculateMinMaxUsage(names, &minUsage, &maxUsage); *isCompatible = ((maxUsage & minUsage) == minUsage); return OK; } // static std::shared_ptr<C2GraphicBlock> CCodec::FetchGraphicBlock( int32_t width, int32_t height, int32_t format, uint64_t usage, const std::vector<std::string> &names) { uint32_t halPixelFormat = HAL_PIXEL_FORMAT_YCBCR_420_888; if (!C2Mapper::mapPixelFormatFrameworkToCodec(format, &halPixelFormat)) { ALOGD("Unrecognized pixel format: %d", format); return nullptr; } uint64_t minUsage = 0; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators); if (allocators.empty()) { allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC); } CalculateMinMaxUsage(names, &minUsage, &maxUsage); minUsage |= usage; if ((maxUsage & minUsage) != minUsage) { allocators.clear(); allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC); } std::shared_ptr<C2GraphicBlock> block; for (C2Allocator::id_t allocId : allocators) { std::shared_ptr<C2BlockPool> pool; c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool); if (err != C2_OK || !pool) { continue; } err = pool->fetchGraphicBlock( width, height, halPixelFormat, C2MemoryUsage{minUsage}, &block); if (err != C2_OK || !block) { block.reset(); continue; } break; } return block; } } // namespace android media/codec2/sfplugin/CCodecBufferChannel.cpp +186 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/drm/1.0/types.h> #include <android-base/stringprintf.h> #include <binder/MemoryBase.h> #include <binder/MemoryDealer.h> #include <cutils/properties.h> #include <gui/Surface.h> Loading Loading @@ -249,7 +250,7 @@ CCodecBufferChannel::CCodecBufferChannel( } CCodecBufferChannel::~CCodecBufferChannel() { if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) { if (mCrypto != nullptr && mHeapSeqNum >= 0) { mCrypto->unsetHeap(mHeapSeqNum); } } Loading Loading @@ -409,6 +410,173 @@ status_t CCodecBufferChannel::setParameters(std::vector<std::unique_ptr<C2Param> return OK; } status_t CCodecBufferChannel::attachBuffer( const std::shared_ptr<C2Buffer> &c2Buffer, const sp<MediaCodecBuffer> &buffer) { if (!buffer->copy(c2Buffer)) { return -ENOSYS; } return OK; } void CCodecBufferChannel::ensureDecryptDestination(size_t size) { if (!mDecryptDestination || mDecryptDestination->size() < size) { sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)}; if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) { mCrypto->unsetHeap(mHeapSeqNum); } mDecryptDestination = new MemoryBase(heap, 0, size * 2); if (mCrypto) { mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap)); } } } int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) { CHECK(mCrypto); auto it = mHeapSeqNumMap.find(memory); int32_t heapSeqNum = -1; if (it == mHeapSeqNumMap.end()) { heapSeqNum = mCrypto->setHeap(memory); mHeapSeqNumMap.emplace(memory, heapSeqNum); } else { heapSeqNum = it->second; } return heapSeqNum; } status_t CCodecBufferChannel::attachEncryptedBuffer( const sp<hardware::HidlMemory> &memory, bool secure, const uint8_t *key, const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const sp<MediaCodecBuffer> &buffer) { static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0}; static const C2MemoryUsage kDefaultReadWriteUsage{ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}; size_t size = 0; for (size_t i = 0; i < numSubSamples; ++i) { size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData; } std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool; std::shared_ptr<C2LinearBlock> block; c2_status_t err = pool->fetchLinearBlock( size, secure ? kSecureUsage : kDefaultReadWriteUsage, &block); if (err != C2_OK) { return NO_MEMORY; } if (!secure) { ensureDecryptDestination(size); } ssize_t result = -1; ssize_t codecDataOffset = 0; if (mCrypto) { AString errorDetailMsg; int32_t heapSeqNum = getHeapSeqNum(memory); hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size}; hardware::drm::V1_0::DestinationBuffer dst; if (secure) { dst.type = DrmBufferType::NATIVE_HANDLE; dst.secureMemory = hardware::hidl_handle(block->handle()); } else { dst.type = DrmBufferType::SHARED_MEMORY; IMemoryToSharedBuffer( mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory); } result = mCrypto->decrypt( key, iv, mode, pattern, src, 0, subSamples, numSubSamples, dst, &errorDetailMsg); if (result < 0) { return result; } if (dst.type == DrmBufferType::SHARED_MEMORY) { C2WriteView view = block->map().get(); if (view.error() != C2_OK) { return false; } if (view.size() < result) { return false; } memcpy(view.data(), mDecryptDestination->unsecurePointer(), result); } } else { // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample // directly, the structure definitions should match as checked in DescramblerImpl.cpp. hidl_vec<SubSample> hidlSubSamples; hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/); hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size}; hardware::cas::native::V1_0::DestinationBuffer dst; if (secure) { dst.type = BufferType::NATIVE_HANDLE; dst.secureMemory = hardware::hidl_handle(block->handle()); } else { dst.type = BufferType::SHARED_MEMORY; dst.nonsecureMemory = src; } CasStatus status = CasStatus::OK; hidl_string detailedError; ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED; if (key != nullptr) { sctrl = (ScramblingControl)key[0]; // Adjust for the PES offset codecDataOffset = key[2] | (key[3] << 8); } auto returnVoid = mDescrambler->descramble( sctrl, hidlSubSamples, src, 0, dst, 0, [&status, &result, &detailedError] ( CasStatus _status, uint32_t _bytesWritten, const hidl_string& _detailedError) { status = _status; result = (ssize_t)_bytesWritten; detailedError = _detailedError; }); if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) { ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd", mName, returnVoid.description().c_str(), status, result); return UNKNOWN_ERROR; } if (result < codecDataOffset) { ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result); return BAD_VALUE; } } if (!secure) { C2WriteView view = block->map().get(); if (view.error() != C2_OK) { return UNKNOWN_ERROR; } if (view.size() < result) { return UNKNOWN_ERROR; } memcpy(view.data(), mDecryptDestination->unsecurePointer(), result); } std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer( block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))}; if (!buffer->copy(c2Buffer)) { return -ENOSYS; } return OK; } status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) { QueueGuard guard(mSync); if (!guard.isRunning()) { Loading Loading @@ -774,7 +942,9 @@ void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *arr } status_t CCodecBufferChannel::start( const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) { const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat, bool buffersBoundToCodec) { C2StreamBufferTypeSetting::input iStreamFormat(0u); C2StreamBufferTypeSetting::output oStreamFormat(0u); C2PortReorderBufferDepthTuning::output reorderDepth; Loading Loading @@ -897,7 +1067,9 @@ status_t CCodecBufferChannel::start( input->numSlots = numInputSlots; input->extraBuffers.flush(); input->numExtraSlots = 0u; if (graphic) { if (!buffersBoundToCodec) { input->buffers.reset(new SlotInputBuffers(mName)); } else if (graphic) { if (mInputSurface) { input->buffers.reset(new DummyInputBuffers(mName)); } else if (mMetaMode == MODE_ANW) { Loading Loading @@ -1071,7 +1243,7 @@ status_t CCodecBufferChannel::start( output->outputDelay = outputDelayValue; output->numSlots = numOutputSlots; if (graphic) { if (outputSurface) { if (outputSurface || !buffersBoundToCodec) { output->buffers.reset(new GraphicOutputBuffers(mName)); } else { output->buffers.reset(new RawGraphicOutputBuffers(numOutputSlots, mName)); Loading Loading @@ -1669,6 +1841,16 @@ void CCodecBufferChannel::setMetaMode(MetaMode mode) { } void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) { if (mCrypto != nullptr) { for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) { mCrypto->unsetHeap(entry.second); } mHeapSeqNumMap.clear(); if (mHeapSeqNum >= 0) { mCrypto->unsetHeap(mHeapSeqNum); mHeapSeqNum = -1; } } mCrypto = crypto; } Loading media/codec2/sfplugin/CCodecBufferChannel.h +21 −1 Original line number Diff line number Diff line Loading @@ -70,6 +70,20 @@ public: const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, AString *errorDetailMsg) override; virtual status_t attachBuffer( const std::shared_ptr<C2Buffer> &c2Buffer, const sp<MediaCodecBuffer> &buffer) override; virtual status_t attachEncryptedBuffer( const sp<hardware::HidlMemory> &memory, bool secure, const uint8_t *key, const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const sp<MediaCodecBuffer> &buffer) override; virtual status_t renderOutputBuffer( const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override; virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override; Loading Loading @@ -108,7 +122,10 @@ public: * Start queueing buffers to the component. This object should never queue * buffers before this call has completed. */ status_t start(const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat); status_t start( const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat, bool buffersBoundToCodec); /** * Request initial input buffers to be filled by client. Loading Loading @@ -216,11 +233,14 @@ private: std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, const C2StreamInitDataInfo::output *initData); void sendOutputBuffers(); void ensureDecryptDestination(size_t size); int32_t getHeapSeqNum(const sp<hardware::HidlMemory> &memory); QueueSync mSync; sp<MemoryDealer> mDealer; sp<IMemory> mDecryptDestination; int32_t mHeapSeqNum; std::map<wp<hardware::HidlMemory>, int32_t> mHeapSeqNumMap; std::shared_ptr<Codec2Client::Component> mComponent; std::string mComponentName; ///< component name for debugging Loading media/codec2/sfplugin/CCodecBuffers.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -494,6 +494,44 @@ sp<Codec2Buffer> InputBuffersArray::createNewBuffer() { return mAllocate(); } // SlotInputBuffers bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { sp<Codec2Buffer> newBuffer = createNewBuffer(); *index = mImpl.assignSlot(newBuffer); *buffer = newBuffer; return true; } bool SlotInputBuffers::releaseBuffer( const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer, bool release) { return mImpl.releaseSlot(buffer, c2buffer, release); } bool SlotInputBuffers::expireComponentBuffer( const std::shared_ptr<C2Buffer> &c2buffer) { return mImpl.expireComponentBuffer(c2buffer); } void SlotInputBuffers::flush() { mImpl.flush(); } std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) { TRESPASS("Array mode should not be called at non-legacy mode"); return nullptr; } size_t SlotInputBuffers::numClientBuffers() const { return mImpl.numClientBuffers(); } sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() { return new DummyContainerBuffer{mFormat, nullptr}; } // LinearInputBuffers bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { Loading media/codec2/sfplugin/CCodecBuffers.h +30 −0 Original line number Diff line number Diff line Loading @@ -547,6 +547,36 @@ private: std::function<sp<Codec2Buffer>()> mAllocate; }; class SlotInputBuffers : public InputBuffers { public: SlotInputBuffers(const char *componentName, const char *name = "Slot-Input") : InputBuffers(componentName, name), mImpl(mName) { } ~SlotInputBuffers() override = default; bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) final; bool releaseBuffer( const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer, bool release) final; bool expireComponentBuffer( const std::shared_ptr<C2Buffer> &c2buffer) final; void flush() final; std::unique_ptr<InputBuffers> toArrayMode(size_t size) final; size_t numClientBuffers() const final; protected: sp<Codec2Buffer> createNewBuffer() final; private: FlexBuffersImpl mImpl; }; class LinearInputBuffers : public InputBuffers { public: LinearInputBuffers(const char *componentName, const char *name = "1D-Input") Loading Loading
media/codec2/sfplugin/CCodec.cpp +255 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ #include "C2OMXNode.h" #include "CCodecBufferChannel.h" #include "CCodecConfig.h" #include "Codec2Mapper.h" #include "InputSurfaceWrapper.h" extern "C" android::PersistentSurface *CreateInputSurface(); Loading Loading @@ -717,6 +718,11 @@ void CCodec::configure(const sp<AMessage> &msg) { encoder = false; } int32_t flags; if (!msg->findInt32("flags", &flags)) { return BAD_VALUE; } // TODO: read from intf() if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) { return UNKNOWN_ERROR; Loading @@ -743,6 +749,9 @@ void CCodec::configure(const sp<AMessage> &msg) { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; config->mUsingSurface = surface != nullptr; config->mBuffersBoundToCodec = ((flags & CONFIGURE_FLAG_USE_BLOCK_MODEL) == 0); ALOGD("[%s] buffers are %sbound to CCodec for this session", comp->getName().c_str(), config->mBuffersBoundToCodec ? "" : "not "); // Enforce required parameters int32_t i32; Loading Loading @@ -1299,6 +1308,7 @@ void CCodec::start() { sp<AMessage> inputFormat; sp<AMessage> outputFormat; status_t err2 = OK; bool buffersBoundToCodec = false; { Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; Loading @@ -1307,12 +1317,13 @@ void CCodec::start() { if (config->mInputSurface) { err2 = config->mInputSurface->start(); } buffersBoundToCodec = config->mBuffersBoundToCodec; } if (err2 != OK) { mCallback->onError(err2, ACTION_CODE_FATAL); return; } err2 = mChannel->start(inputFormat, outputFormat); err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec); if (err2 != OK) { mCallback->onError(err2, ACTION_CODE_FATAL); return; Loading Loading @@ -1556,7 +1567,11 @@ void CCodec::signalResume() { return; } (void)mChannel->start(nullptr, nullptr); (void)mChannel->start(nullptr, nullptr, [&]{ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); const std::unique_ptr<Config> &config = *configLocked; return config->mBuffersBoundToCodec; }()); { Mutexed<State>::Locked state(mState); Loading Loading @@ -1911,5 +1926,243 @@ PersistentSurface *CCodec::CreateInputSurface() { inputSurface->getHalInterface())); } static status_t GetCommonAllocatorIds( const std::vector<std::string> &names, C2Allocator::type_t type, std::set<C2Allocator::id_t> *ids) { int poolMask = GetCodec2PoolMask(); C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask); C2Allocator::id_t defaultAllocatorId = (type == C2Allocator::LINEAR) ? preferredLinearId : C2PlatformAllocatorStore::GRALLOC; ids->clear(); if (names.empty()) { return OK; } std::shared_ptr<Codec2Client::Interface> intf{ Codec2Client::CreateInterfaceByName(names[0].c_str())}; std::vector<std::unique_ptr<C2Param>> params; c2_status_t err = intf->query( {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, ¶ms); if (err == C2_OK && params.size() == 1u) { C2PortAllocatorsTuning::input *allocators = C2PortAllocatorsTuning::input::From(params[0].get()); if (allocators && allocators->flexCount() > 0) { ids->insert(allocators->m.values, allocators->m.values + allocators->flexCount()); } } if (ids->empty()) { // The component does not advertise allocators. Use default. ids->insert(defaultAllocatorId); } for (size_t i = 1; i < names.size(); ++i) { intf = Codec2Client::CreateInterfaceByName(names[i].c_str()); err = intf->query( {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, ¶ms); bool filtered = false; if (err == C2_OK && params.size() == 1u) { C2PortAllocatorsTuning::input *allocators = C2PortAllocatorsTuning::input::From(params[0].get()); if (allocators && allocators->flexCount() > 0) { filtered = true; for (auto it = ids->begin(); it != ids->end(); ) { bool found = false; for (size_t j = 0; j < allocators->flexCount(); ++j) { if (allocators->m.values[j] == *it) { found = true; break; } } if (found) { ++it; } else { it = ids->erase(it); } } } } if (!filtered) { // The component does not advertise supported allocators. Use default. bool containsDefault = (ids->count(defaultAllocatorId) > 0u); if (ids->size() != (containsDefault ? 1 : 0)) { ids->clear(); if (containsDefault) { ids->insert(defaultAllocatorId); } } } } // Finally, filter with pool masks for (auto it = ids->begin(); it != ids->end(); ) { if ((poolMask >> *it) & 1) { ++it; } else { it = ids->erase(it); } } return OK; } static status_t CalculateMinMaxUsage( const std::vector<std::string> &names, uint64_t *minUsage, uint64_t *maxUsage) { static C2StreamUsageTuning::input sUsage{0u /* stream id */}; *minUsage = 0; *maxUsage = ~0ull; for (const std::string &name : names) { std::shared_ptr<Codec2Client::Interface> intf{ Codec2Client::CreateInterfaceByName(name.c_str())}; std::vector<C2FieldSupportedValuesQuery> fields; fields.push_back(C2FieldSupportedValuesQuery::Possible( C2ParamField{&sUsage, &sUsage.value})); c2_status_t err = intf->querySupportedValues(fields, C2_MAY_BLOCK); if (err != C2_OK) { continue; } if (fields[0].status != C2_OK) { continue; } const C2FieldSupportedValues &supported = fields[0].values; if (supported.type != C2FieldSupportedValues::FLAGS) { continue; } if (supported.values.empty()) { *maxUsage = 0; continue; } *minUsage |= supported.values[0].u64; int64_t currentMaxUsage = 0; for (const C2Value::Primitive &flags : supported.values) { currentMaxUsage |= flags.u64; } *maxUsage &= currentMaxUsage; } return OK; } // static status_t CCodec::CanFetchLinearBlock( const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible) { uint64_t minUsage = usage.expected; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators); if (allocators.empty()) { *isCompatible = false; return OK; } CalculateMinMaxUsage(names, &minUsage, &maxUsage); *isCompatible = ((maxUsage & minUsage) == minUsage); return OK; } static std::shared_ptr<C2BlockPool> GetPool(C2Allocator::id_t allocId) { static std::mutex sMutex{}; static std::map<C2Allocator::id_t, std::shared_ptr<C2BlockPool>> sPools; std::unique_lock<std::mutex> lock{sMutex}; std::shared_ptr<C2BlockPool> pool; auto it = sPools.find(allocId); if (it == sPools.end()) { c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool); if (err == OK) { sPools.emplace(allocId, pool); } else { pool.reset(); } } else { pool = it->second; } return pool; } // static std::shared_ptr<C2LinearBlock> CCodec::FetchLinearBlock( size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names) { uint64_t minUsage = usage.expected; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators); if (allocators.empty()) { allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR); } CalculateMinMaxUsage(names, &minUsage, &maxUsage); if ((maxUsage & minUsage) != minUsage) { allocators.clear(); allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR); } std::shared_ptr<C2LinearBlock> block; for (C2Allocator::id_t allocId : allocators) { std::shared_ptr<C2BlockPool> pool = GetPool(allocId); if (!pool) { continue; } c2_status_t err = pool->fetchLinearBlock(capacity, C2MemoryUsage{minUsage}, &block); if (err != C2_OK || !block) { block.reset(); continue; } break; } return block; } // static status_t CCodec::CanFetchGraphicBlock( const std::vector<std::string> &names, bool *isCompatible) { uint64_t minUsage = 0; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators); if (allocators.empty()) { *isCompatible = false; return OK; } CalculateMinMaxUsage(names, &minUsage, &maxUsage); *isCompatible = ((maxUsage & minUsage) == minUsage); return OK; } // static std::shared_ptr<C2GraphicBlock> CCodec::FetchGraphicBlock( int32_t width, int32_t height, int32_t format, uint64_t usage, const std::vector<std::string> &names) { uint32_t halPixelFormat = HAL_PIXEL_FORMAT_YCBCR_420_888; if (!C2Mapper::mapPixelFormatFrameworkToCodec(format, &halPixelFormat)) { ALOGD("Unrecognized pixel format: %d", format); return nullptr; } uint64_t minUsage = 0; uint64_t maxUsage = ~0ull; std::set<C2Allocator::id_t> allocators; GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators); if (allocators.empty()) { allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC); } CalculateMinMaxUsage(names, &minUsage, &maxUsage); minUsage |= usage; if ((maxUsage & minUsage) != minUsage) { allocators.clear(); allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC); } std::shared_ptr<C2GraphicBlock> block; for (C2Allocator::id_t allocId : allocators) { std::shared_ptr<C2BlockPool> pool; c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool); if (err != C2_OK || !pool) { continue; } err = pool->fetchGraphicBlock( width, height, halPixelFormat, C2MemoryUsage{minUsage}, &block); if (err != C2_OK || !block) { block.reset(); continue; } break; } return block; } } // namespace android
media/codec2/sfplugin/CCodecBufferChannel.cpp +186 −4 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android/hardware/drm/1.0/types.h> #include <android-base/stringprintf.h> #include <binder/MemoryBase.h> #include <binder/MemoryDealer.h> #include <cutils/properties.h> #include <gui/Surface.h> Loading Loading @@ -249,7 +250,7 @@ CCodecBufferChannel::CCodecBufferChannel( } CCodecBufferChannel::~CCodecBufferChannel() { if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) { if (mCrypto != nullptr && mHeapSeqNum >= 0) { mCrypto->unsetHeap(mHeapSeqNum); } } Loading Loading @@ -409,6 +410,173 @@ status_t CCodecBufferChannel::setParameters(std::vector<std::unique_ptr<C2Param> return OK; } status_t CCodecBufferChannel::attachBuffer( const std::shared_ptr<C2Buffer> &c2Buffer, const sp<MediaCodecBuffer> &buffer) { if (!buffer->copy(c2Buffer)) { return -ENOSYS; } return OK; } void CCodecBufferChannel::ensureDecryptDestination(size_t size) { if (!mDecryptDestination || mDecryptDestination->size() < size) { sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)}; if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) { mCrypto->unsetHeap(mHeapSeqNum); } mDecryptDestination = new MemoryBase(heap, 0, size * 2); if (mCrypto) { mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap)); } } } int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) { CHECK(mCrypto); auto it = mHeapSeqNumMap.find(memory); int32_t heapSeqNum = -1; if (it == mHeapSeqNumMap.end()) { heapSeqNum = mCrypto->setHeap(memory); mHeapSeqNumMap.emplace(memory, heapSeqNum); } else { heapSeqNum = it->second; } return heapSeqNum; } status_t CCodecBufferChannel::attachEncryptedBuffer( const sp<hardware::HidlMemory> &memory, bool secure, const uint8_t *key, const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const sp<MediaCodecBuffer> &buffer) { static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0}; static const C2MemoryUsage kDefaultReadWriteUsage{ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}; size_t size = 0; for (size_t i = 0; i < numSubSamples; ++i) { size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData; } std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool; std::shared_ptr<C2LinearBlock> block; c2_status_t err = pool->fetchLinearBlock( size, secure ? kSecureUsage : kDefaultReadWriteUsage, &block); if (err != C2_OK) { return NO_MEMORY; } if (!secure) { ensureDecryptDestination(size); } ssize_t result = -1; ssize_t codecDataOffset = 0; if (mCrypto) { AString errorDetailMsg; int32_t heapSeqNum = getHeapSeqNum(memory); hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size}; hardware::drm::V1_0::DestinationBuffer dst; if (secure) { dst.type = DrmBufferType::NATIVE_HANDLE; dst.secureMemory = hardware::hidl_handle(block->handle()); } else { dst.type = DrmBufferType::SHARED_MEMORY; IMemoryToSharedBuffer( mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory); } result = mCrypto->decrypt( key, iv, mode, pattern, src, 0, subSamples, numSubSamples, dst, &errorDetailMsg); if (result < 0) { return result; } if (dst.type == DrmBufferType::SHARED_MEMORY) { C2WriteView view = block->map().get(); if (view.error() != C2_OK) { return false; } if (view.size() < result) { return false; } memcpy(view.data(), mDecryptDestination->unsecurePointer(), result); } } else { // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample // directly, the structure definitions should match as checked in DescramblerImpl.cpp. hidl_vec<SubSample> hidlSubSamples; hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/); hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size}; hardware::cas::native::V1_0::DestinationBuffer dst; if (secure) { dst.type = BufferType::NATIVE_HANDLE; dst.secureMemory = hardware::hidl_handle(block->handle()); } else { dst.type = BufferType::SHARED_MEMORY; dst.nonsecureMemory = src; } CasStatus status = CasStatus::OK; hidl_string detailedError; ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED; if (key != nullptr) { sctrl = (ScramblingControl)key[0]; // Adjust for the PES offset codecDataOffset = key[2] | (key[3] << 8); } auto returnVoid = mDescrambler->descramble( sctrl, hidlSubSamples, src, 0, dst, 0, [&status, &result, &detailedError] ( CasStatus _status, uint32_t _bytesWritten, const hidl_string& _detailedError) { status = _status; result = (ssize_t)_bytesWritten; detailedError = _detailedError; }); if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) { ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd", mName, returnVoid.description().c_str(), status, result); return UNKNOWN_ERROR; } if (result < codecDataOffset) { ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result); return BAD_VALUE; } } if (!secure) { C2WriteView view = block->map().get(); if (view.error() != C2_OK) { return UNKNOWN_ERROR; } if (view.size() < result) { return UNKNOWN_ERROR; } memcpy(view.data(), mDecryptDestination->unsecurePointer(), result); } std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer( block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))}; if (!buffer->copy(c2Buffer)) { return -ENOSYS; } return OK; } status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) { QueueGuard guard(mSync); if (!guard.isRunning()) { Loading Loading @@ -774,7 +942,9 @@ void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *arr } status_t CCodecBufferChannel::start( const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) { const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat, bool buffersBoundToCodec) { C2StreamBufferTypeSetting::input iStreamFormat(0u); C2StreamBufferTypeSetting::output oStreamFormat(0u); C2PortReorderBufferDepthTuning::output reorderDepth; Loading Loading @@ -897,7 +1067,9 @@ status_t CCodecBufferChannel::start( input->numSlots = numInputSlots; input->extraBuffers.flush(); input->numExtraSlots = 0u; if (graphic) { if (!buffersBoundToCodec) { input->buffers.reset(new SlotInputBuffers(mName)); } else if (graphic) { if (mInputSurface) { input->buffers.reset(new DummyInputBuffers(mName)); } else if (mMetaMode == MODE_ANW) { Loading Loading @@ -1071,7 +1243,7 @@ status_t CCodecBufferChannel::start( output->outputDelay = outputDelayValue; output->numSlots = numOutputSlots; if (graphic) { if (outputSurface) { if (outputSurface || !buffersBoundToCodec) { output->buffers.reset(new GraphicOutputBuffers(mName)); } else { output->buffers.reset(new RawGraphicOutputBuffers(numOutputSlots, mName)); Loading Loading @@ -1669,6 +1841,16 @@ void CCodecBufferChannel::setMetaMode(MetaMode mode) { } void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) { if (mCrypto != nullptr) { for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) { mCrypto->unsetHeap(entry.second); } mHeapSeqNumMap.clear(); if (mHeapSeqNum >= 0) { mCrypto->unsetHeap(mHeapSeqNum); mHeapSeqNum = -1; } } mCrypto = crypto; } Loading
media/codec2/sfplugin/CCodecBufferChannel.h +21 −1 Original line number Diff line number Diff line Loading @@ -70,6 +70,20 @@ public: const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, AString *errorDetailMsg) override; virtual status_t attachBuffer( const std::shared_ptr<C2Buffer> &c2Buffer, const sp<MediaCodecBuffer> &buffer) override; virtual status_t attachEncryptedBuffer( const sp<hardware::HidlMemory> &memory, bool secure, const uint8_t *key, const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const sp<MediaCodecBuffer> &buffer) override; virtual status_t renderOutputBuffer( const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override; virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override; Loading Loading @@ -108,7 +122,10 @@ public: * Start queueing buffers to the component. This object should never queue * buffers before this call has completed. */ status_t start(const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat); status_t start( const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat, bool buffersBoundToCodec); /** * Request initial input buffers to be filled by client. Loading Loading @@ -216,11 +233,14 @@ private: std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat, const C2StreamInitDataInfo::output *initData); void sendOutputBuffers(); void ensureDecryptDestination(size_t size); int32_t getHeapSeqNum(const sp<hardware::HidlMemory> &memory); QueueSync mSync; sp<MemoryDealer> mDealer; sp<IMemory> mDecryptDestination; int32_t mHeapSeqNum; std::map<wp<hardware::HidlMemory>, int32_t> mHeapSeqNumMap; std::shared_ptr<Codec2Client::Component> mComponent; std::string mComponentName; ///< component name for debugging Loading
media/codec2/sfplugin/CCodecBuffers.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -494,6 +494,44 @@ sp<Codec2Buffer> InputBuffersArray::createNewBuffer() { return mAllocate(); } // SlotInputBuffers bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { sp<Codec2Buffer> newBuffer = createNewBuffer(); *index = mImpl.assignSlot(newBuffer); *buffer = newBuffer; return true; } bool SlotInputBuffers::releaseBuffer( const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer, bool release) { return mImpl.releaseSlot(buffer, c2buffer, release); } bool SlotInputBuffers::expireComponentBuffer( const std::shared_ptr<C2Buffer> &c2buffer) { return mImpl.expireComponentBuffer(c2buffer); } void SlotInputBuffers::flush() { mImpl.flush(); } std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) { TRESPASS("Array mode should not be called at non-legacy mode"); return nullptr; } size_t SlotInputBuffers::numClientBuffers() const { return mImpl.numClientBuffers(); } sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() { return new DummyContainerBuffer{mFormat, nullptr}; } // LinearInputBuffers bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) { Loading
media/codec2/sfplugin/CCodecBuffers.h +30 −0 Original line number Diff line number Diff line Loading @@ -547,6 +547,36 @@ private: std::function<sp<Codec2Buffer>()> mAllocate; }; class SlotInputBuffers : public InputBuffers { public: SlotInputBuffers(const char *componentName, const char *name = "Slot-Input") : InputBuffers(componentName, name), mImpl(mName) { } ~SlotInputBuffers() override = default; bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) final; bool releaseBuffer( const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer, bool release) final; bool expireComponentBuffer( const std::shared_ptr<C2Buffer> &c2buffer) final; void flush() final; std::unique_ptr<InputBuffers> toArrayMode(size_t size) final; size_t numClientBuffers() const final; protected: sp<Codec2Buffer> createNewBuffer() final; private: FlexBuffersImpl mImpl; }; class LinearInputBuffers : public InputBuffers { public: LinearInputBuffers(const char *componentName, const char *name = "1D-Input") Loading