在CCodecBufferChannel的start方法中有这样一段代码,我们再回头看一遍:
status_t CCodecBufferChannel::start(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat,
bool buffersBoundToCodec) {
// ...
if (outputFormat != nullptr) {
// 1.
pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
: preferredLinearId;
// ...
if (outputSurface) {
params.clear();
// 2.
err = mComponent->query({ },
{ C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
C2_DONT_BLOCK,
¶ms);
if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
} else if (err == C2_OK && params.size() == 1) {
C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
C2PortSurfaceAllocatorTuning::output::From(params[0].get());
if (surfaceAllocator) {
std::shared_ptr<C2Allocator> allocator;
// 3.
allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
if (allocator) {
pools->outputAllocatorId = allocator->getId();
} else {
err = C2_BAD_VALUE;
}
}
}
// 4.
if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
&& err != C2_OK
&& ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
}
}
}
}
以上代码不难理解,稍微有点难理解的是代码标注第四段中的三个条件什么时候同时满足(或者说是什么时候outputAllocatorId为BUFFERQUEUE)?先来看单个条件成立的情形:
把各个条件进行拼接后得到,在video decoder且有surface的情况下:
简单来说,在video decoder且有surface的情况下,组件如果没有定义参数C2PortSurfaceAllocatorTuning::output,则使用BUFFERQUEUE;如果组件定义了参数则使用定义值。对于video decoder没有surface的情况,使用Gralloc。
接下来的文章只讨论outputAllocatorId为BUFFERQUEUE的情况!
C2BufferQueueBlockPool专门用于管理通过BufferQueue分配的内存块,这些内存块用于组件的输出端口,被填充的内存块会被送到NativeWindow做渲染。
在Codec2框架中,Input C2BlockPool是在上层(CCodecBufferChannel)创建的,而Output C2BlockPool是在HAL层(Component)创建的。如果outputAllocatorId为BUFFERQUEUE,创建过程除了实例化C2BlockPool外,还有一系列的配置和初始化工作。接下来我们将以C2BufferQueueBlockPool的创建流程作为切入点对它进行了解。
调用Codec2Client::Component的createBlockPool方法,传入outputAllocatorId,然后一路往下到达HIDL层的createBlockPool,在这里会调用C2Store.cpp中的CreateCodec2BlockPool方法。
// CCodecBufferChannel
if ((poolMask >> pools->outputAllocatorId) & 1) {
err = mComponent->createBlockPool(
pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
}
// Component HIDL
Return<void> Component::createBlockPool(
uint32_t allocatorId,
createBlockPool_cb _hidl_cb) {
std::shared_ptr<C2BlockPool> blockPool;
c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
mComponent,
&blockPool);
_hidl_cb(static_cast<Status>(status),
blockPool ? blockPool->getLocalId() : 0,
new CachedConfigurable(
std::make_unique<BlockPoolIntf>(blockPool)));
return Void();
}
// C2Store
switch(allocatorId) {
case C2PlatformAllocatorStore::BUFFERQUEUE:
res = allocatorStore->fetchAllocator(
C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
if (res == C2_OK) {
std::shared_ptr<C2BlockPool> ptr(
new C2BufferQueueBlockPool(allocator, poolId), deleter);
*pool = ptr;
mBlockPools[poolId] = ptr;
mComponents[poolId].insert(
mComponents[poolId].end(),
components.begin(), components.end());
}
break;
}
c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
id_t id, std::shared_ptr<C2Allocator> *const allocator) {
switch (id) {
case C2PlatformAllocatorStore::BUFFERQUEUE:
*allocator = fetchBufferQueueAllocator();
break;
}
}
最后先创建了一个C2AllocatorGralloc,然后将它作为参数创建了一个C2BufferQueueBlockPool。C2BlockPool创建完成后会回传一个outputPoolId给上层,后续的调用会用到此id。
接下来开始对C2BufferQueueBlockPool进行配置,所谓配置就是将它和Surface绑定:
原文阅读:
扫描下方二维码,关注公众号《青山渺渺》阅读音视频开发内容。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- hzar.cn 版权所有 赣ICP备2024042791号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务