从codec2play熟悉codec2_listmanifestbyinterface-程序员宅基地

技术标签: android  media  

加载codec component

codec2play是android上codec2的一个demo程序,在frameworks/av/media/codec2/components/cmds目录下可以找到原始代码,这里把hardware component创建和software component创建做一个对比,加深对codec2的理解。


hardware component创建

首先,Codec2Client::CreateFromService中通过hidl ServiceManager获取ServiceManager对象,然后通过listManifestByInterface接口,查询平台的component name,然后返回name合集,根据name创建创建Codec2Client对象client,SetPreferredCodec2ComponentStore将client设置到gPreferredComponentStore,后面创建component就从这个store里面创建。

// create decoder component
std::shared_ptr<Codec2Client> client = Codec2Client::CreateFromService("default");
SetPreferredCodec2ComponentStore(std::make_shared<Codec2ClientInterfaceWrapper>(client));
mComponent = Codec2Client::CreateComponentByName("c2.qti.avc.decoder", mClientListener, &client);

serviceManager中获取service的代码:

transResult = serviceManager->listManifestByInterface(
    IComponentStore::descriptor,
    [&defaultNames, &vendorNames, &otherNames](
        hidl_vec<hidl_string> const& instanceNames) {
    
        for (hidl_string const& instanceName : instanceNames) {
    
            char const* name = instanceName.c_str();
            if (strncmp(name, "default", 7) == 0) {
    
                defaultNames.emplace_back(name);
            } else if (strncmp(name, "vendor", 6) == 0) {
    
                vendorNames.emplace_back(name);
            } else {
    
                otherNames.emplace_back(name);
            }
        }
    });

Base1_0和Base1_1的定义实际上是V1_0和V1_1的IComponent别名:

typedef ::android::hardware::media::c2::V1_0::IComponent Base1_0;
typedef ::android::hardware::media::c2::V1_1::IComponent Base1_1;
typedef Base1_0 Base;

hidl中的接口类的声明:

namespace android::hardware::media::c2::V1_0 {
    
struct IConfigurable;
struct IComponent;
struct IComponentInterface;
struct IComponentStore;
struct IInputSink;
struct IInputSurface;
struct IInputSurfaceConnection;
}  // namespace android::hardware::media::c2::V1_0

namespace android::hardware::media::c2::V1_1 {
    
struct IComponent;
struct IComponentStore;
}  // namespace android::hardware::media::c2::V1_1

通过Base1_0或者Base1_1的createComponent接口,创建component:

c2_status_t status;
sp<Component::HidlListener> hidlListener = new Component::HidlListener{
    };

mBase1_0->createComponent(
    name,
    hidlListener,
    ClientManager::getInstance(),
    [&status, component, hidlListener](
        Status s,
        const sp<hardware::media::c2::V1_0::IComponent>& c) {
    
        status = static_cast<c2_status_t>(s);
        if (status != C2_OK) {
    
            return;
        }
        *component = std::make_shared<Codec2Client::Component>(c);
        hidlListener->component = *component;
    }
);

其中lambda表达式可以理解为一个函数指针对应的函数体,要知道这个在哪调用,进入createComponent_1_1函数就可以看到,最后component创建后以后会作为参数c传递给lambda表达式,status的值作为参数s,在createComponent_1_1中通过_hidl_cb调用,lambda表达式实际上就是_hidl_cb

[&status, component, hidlListener](
        Status s,
        const sp<hardware::media::c2::V1_0::IComponent>& c) {
     
        status = static_cast<c2_status_t>(s);
        if (status != C2_OK) {
     
            return;
        }
        *component = std::make_shared<Codec2Client::Component>(c);
        hidlListener->component = *component;
    }

ComponentStore::createComponent_1_1函数,也就是hidl中的::android::hardware::media::c2::V1_1::utils::ComponentStore::createComponent_1_1,真正创建component就是在这里创建的。

// from ::android::hardware::media::c2::V1_1::utils::ComponentStore
Return<void> ComponentStore::createComponent_1_1(
     const hidl_string& name,
     const sp<IComponentListener>& listener,
     const sp<IClientManager>& pool,
     createComponent_1_1_cb _hidl_cb) {
    

 sp<Component> component;
 std::shared_ptr<C2Component> c2component;
 Status status = static_cast<Status>(
         mStore->createComponent(name, &c2component));

 if (status == Status::OK) {
    
     onInterfaceLoaded(c2component->intf());
     component = new Component(c2component, listener, this, pool);
     if (!component) {
    
         status = Status::CORRUPTED;
     } else {
    
         reportComponentBirth(component.get());
         if (component->status() != C2_OK) {
    
             status = static_cast<Status>(component->status());
         } else {
    
             component->initListener(component);
             if (component->status() != C2_OK) {
    
                 status = static_cast<Status>(component->status());
             }
         }
     }
 }
 // 这个调用就走到lambda表达式里面
 _hidl_cb(status, component);
 return Void();
}

software component创建

codec2play中原始代码是直接获取platform component store,通过store直接创建component的,这个store里面只是注册了软解的codec component。

std::shared_ptr<C2ComponentStore> store = GetCodec2PlatformComponentStore();
std::shared_ptr<C2Component> component;
(void)store->createComponent("c2.android.avc.decoder", &component);

可以看到C2PlatformComponentStore加载的库都在这个列表里面:

C2PlatformComponentStore::C2PlatformComponentStore()
    : mVisited(false),
      mReflector(std::make_shared<C2ReflectorHelper>()),
      mInterface(mReflector) {
    

    auto emplace = [this](const char *libPath) {
    
        mComponents.emplace(libPath, libPath);
    };

    emplace("libcodec2_soft_aacdec.so");
    emplace("libcodec2_soft_aacenc.so");
    emplace("libcodec2_soft_amrnbdec.so");
    emplace("libcodec2_soft_amrnbenc.so");
    emplace("libcodec2_soft_amrwbdec.so");
    emplace("libcodec2_soft_amrwbenc.so");
    emplace("libcodec2_soft_avcdec.so");
    emplace("libcodec2_soft_avcenc.so");
    emplace("libcodec2_soft_flacdec.so");
    emplace("libcodec2_soft_flacenc.so");
    emplace("libcodec2_soft_g711alawdec.so");
    emplace("libcodec2_soft_g711mlawdec.so");
    emplace("libcodec2_soft_gsmdec.so");
    emplace("libcodec2_soft_h263dec.so");
    emplace("libcodec2_soft_h263enc.so");
    emplace("libcodec2_soft_hevcdec.so");
    emplace("libcodec2_soft_hevcenc.so");
    emplace("libcodec2_soft_mp3dec.so");
    emplace("libcodec2_soft_mpeg2dec.so");
    emplace("libcodec2_soft_mpeg4dec.so");
    emplace("libcodec2_soft_mpeg4enc.so");
    emplace("libcodec2_soft_opusdec.so");
    emplace("libcodec2_soft_opusenc.so");
    emplace("libcodec2_soft_rawdec.so");
    emplace("libcodec2_soft_vorbisdec.so");
    emplace("libcodec2_soft_vp8dec.so");
    emplace("libcodec2_soft_vp8enc.so");
    emplace("libcodec2_soft_vp9dec.so");
    emplace("libcodec2_soft_vp9enc.so");
}

hidl相关

hidl的路径结构

hardware/interfaces/media/c2/
├── 1.0
│   ├── Android.bp
│   ├── IComponent.hal
│   ├── IComponentInterface.hal
│   ├── IComponentListener.hal
│   ├── IComponentStore.hal
│   ├── IConfigurable.hal
│   ├── IInputSink.hal
│   ├── IInputSurfaceConnection.hal
│   ├── IInputSurface.hal
│   └── types.hal
└── 1.1
    ├── Android.bp
    ├── IComponent.hal
    └── IComponentStore.hal

hidl client

相关HIDL接口声明
namespace android::hardware::media::c2::V1_0 {
    
struct IConfigurable;
struct IComponent;
struct IComponentInterface;
struct IComponentStore;
struct IInputSink;
struct IInputSurface;
struct IInputSurfaceConnection;
}  // namespace android::hardware::media::c2::V1_0

namespace android::hardware::media::c2::V1_1 {
    
struct IComponent;
struct IComponentStore;
}  // namespace android::hardware::media::c2::V1_1

类似的可以在drm里面看到:

  • drm/libmediadrm/interface/mediadrm/ICrypto.h
namespace android {
     
namespace hardware {
     
class HidlMemory;
namespace drm {
     
namespace V1_0 {
     
struct SharedBuffer;
struct DestinationBuffe
}  // namespace V1_0
}  // namespace drm
}  // namespace hardwar
}  // namespace android
c2::V1_0和c2::V1_1
namespace android
	namespace hardware
		namespace media
			namespace c2
				namespace V1_0
					struct IConfigurable
					struct IComponent
					struct IComponentInterface
					struct IComponentStore
					struct IInputSink
					struct IInputSurface
					struct IInputSurfaceConnection
namespace android
	namespace hardware
		namespace media
			namespace c2
				namespace V1_1
					struct IComponent
					struct IComponentStore
bufferpool & bufferqueue & bufferqueue
namespace android
	namespace hardware
		namespace media
			namespace bufferpool
				namespace V2_0
					struct IClientManager
namespace android
	namespace hardware
		namespace graphics
			namespace bufferqueue
				namespace V1_0
					struct IGraphicBufferProducer
namespace android
	namespace hardware
		namespace graphics
			namespace bufferqueue
				namespace V2_0
					struct IGraphicBufferProducer
IGraphicBufferSource
namespace android
	namespace hardware
		namespace media
			namespace omx
				namespace V1_0
					struct IGraphicBufferSource

Codec2Client是包含以下内部类的主类:

- Listener
- Configurable
- Interface
- Component

Codec2Client中的类、codec2.0接口,和HIDL之间的关系:

- Codec2Client               <==> C2ComponentStore       <==> IComponentStore
- Codec2Client::Listener     <==> C2Component::Listener  <==> IComponentListener
- Codec2Client::Configurable <==> [No equivalent]        <==> IConfigurable
- Codec2Client::Interface    <==> C2ComponentInterface   <==> IComponentInterface
- Codec2Client::Component    <==> C2Component            <==> IComponent

入口点是Codec2Client::CreateFromService(),它创建一个Codec2Client对象,在Codec2Client中,可以通过调用createComponent()和createInterface()来创建接口和组件对象。createComponent()接受一个Listener对象,该对象必须由用户实现。

目前,createBlockPool()是唯一一个生成可配置对象。但是请注意,接口、组件和Codec2Client是可配置的所有子类。

hidl service

Codec2Client::CreateFromService
	getServiceIndex
		Codec2Client::GetServiceNames
			serviceManager = IServiceManager::getService
			serviceManager->listManifestByInterface

Codec2Client::CreateFromService会通过Hidl ServiceManager::listManifestByInterface获取service名字,创建Codec2Client,然后SetPreferredCodec2ComponentStore之后,就可以访问vendor的store。

// set up preferred component store to access vendor store parameters
client = Codec2Client::CreateFromService("default");
if (client) {
    
    ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
    SetPreferredCodec2ComponentStore(
        std::make_shared<Codec2ClientInterfaceWrapper>(client));
}

CCodec中的渲染

这部分是从CCodecBufferChannel::renderOutputBuffer代码中找出来的,用于理解hardwarecodec的渲染流程,首先从output中获得c2Buffer,然后创建android::IGraphicBufferProducer::QueueBufferInput对象qbi,最后是mComponent->queueToOutputSurface把buffer送给surface显示。

这部分的调用栈:

NuPlayer::Decoder::onRenderBuffer
    MediaCodec::renderOutputBufferAndRelease
        MediaCodec::onReleaseOutputBuffer
            CCodecBufferChannel::renderOutputBuffer

CCodecBufferChannel::renderOutputBuffer中的主要代码:

// c2Buffer
std::shared_ptr<C2Buffer> c2Buffer;
bool released = false;
{
    
    Mutexed<Output>::Locked output(mOutput);
    if (output->buffers) {
    
        released = output->buffers->releaseBuffer(buffer, &c2Buffer);
    }
}

// get C2ConstGraphicBlock
std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
if (blocks.size() != 1u) {
    
    ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
    return UNKNOWN_ERROR;
}
const C2ConstGraphicBlock &block = blocks.front();

// TODO: revisit this after C2Fence implementation.
android::IGraphicBufferProducer::QueueBufferInput qbi(
    timestampNs,
    false, // droppable
    dataSpace,
    Rect(blocks.front().crop().left,
         blocks.front().crop().top,
         blocks.front().crop().right(),
         blocks.front().crop().bottom()),
    videoScalingMode,
    transform,
    Fence::NO_FENCE, 0);

// we don't have dirty regions
qbi.setSurfaceDamage(Region::INVALID_REGION);
android::IGraphicBufferProducer::QueueBufferOutput qbo;
status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
if (result != OK) {
    
    ALOGI("[%s] queueBuffer failed: %d", mName, result);
    return result;
}

codec2play中的软解渲染

int slot;
sp<Fence> fence;
std::shared_ptr<C2Buffer> output;
const sp<IGraphicBufferProducer> &igbp = mSurface->getIGraphicBufferProducer();
size_t size = work->worklets.front()->output.buffers.size();
if (size == 1u) {
    
    output = work->worklets.front()->output.buffers[0];
} else {
    
    fprintf(stderr, "got output buffers size: %zu.\n", size);
}

// 从work中拿到C2Buffer类型的output后进行渲染
if (output != nullptr) {
    
    const C2ConstGraphicBlock block = output->data().graphicBlocks().front();
    native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(block.handle());

    sp<GraphicBuffer> buffer(new GraphicBuffer(
        grallocHandle,
        GraphicBuffer::CLONE_HANDLE,
        block.width(),
        block.height(),
        HAL_PIXEL_FORMAT_YV12,
        1,
        (uint64_t)GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
        block.width()));
    native_handle_delete(grallocHandle);

    // 创建QueueBufferInput
    status_t err = igbp->attachBuffer(&slot, buffer);
    IGraphicBufferProducer::QueueBufferInput qbi(
        (work->worklets.front()->output.ordinal.timestamp * 1000ll).peekll(),
        false,
        HAL_DATASPACE_UNKNOWN,
        Rect(block.width(), block.height()),
        NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
        0,
        Fence::NO_FENCE,
        0);
    
    // 调用IGraphicBufferProducer::queueBuffer把inputbuffer给送给surface
    IGraphicBufferProducer::QueueBufferOutput qbo;
    err = igbp->queueBuffer(slot, qbi, &qbo);

    fprintf(stderr, "%d igbp queue buffer.\n", gettid());
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hongszh/article/details/124591363

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签