从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

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法