Android MediaCodec 框架 基于codec2

news2024/11/29 18:42:10

系列文章的目的是什么?

粗略:

  • 解码需要哪些基础的服务?
  • 标准解码的调用流程?
  • 各个流程的作用是什么?
  • 解码框架的层次?
  • 各个层次的作用?

细化:

  • 解码参数的配置?
  • 解码输入数据包的流转?
  • 解码输出帧内存的申请和管理?

文章目录

      • HIDL上游
      • HIDL 下游
      • HIDL接口
      • 基础的codec2 服务

在这里插入图片描述

首先从MediaCodec 到具体的解码Component 梳理出一条路径,然后在具体理解里面的细节。 本文就从MediaCodec出发 理解Android 解码框架的各个层次, 总的来说可以分为三个部分

  • HIDL 层之上,这一层主要是对外部的应用提供接口 并提供输入和输出buffer的管理,流程的控制等等。
  • HIDL 层之下,提供创建具体的解码组件,解码组件的实现,对数据包解码 并返会解码后的图像。
  • codec service,提供创建解码组件的服务,HIDL层之上通过这个服务调用到HIDL 之下。
    在这里插入图片描述

HIDL上游

如图所示 上游主要包含了以下这些部分。

  • MediaCodec

MediaCodec 首先会创建出ccodec,后续的操作都是通过ccodec 这个codecbase进行调用(这里是为了兼容ACodec 和 Codec2的情况)。同时也通过这个ccodec获取codec创建的CCodecBufferChannel。

  1. 创建codecbase 这里就是CCodec, 在MediaCodec 这一级是调用到CCodec。
  2. 将创建好的ccodec 注册到looper 中。这个looper是应用层设置到mediacodec中的。
  3. 注册CodecCallback到ccodec,注册BufferCallback到CCodecBufferChannel。
  • CCodec
    1. 创建 CCodecBufferChannel 和 CCodecConfig。
    2. 通过codec2的service 获取componentStore, 并通过componentStore来创建解码器的component。这里面主要是通过codec2client 这个类来完成的。
    3. 将创建好的组件设置到CCodecBufferChannel,以便后续调用。
    4. 回调一些错误等信息到MediaCodec。

codec2client:

和下游HIDL进行交互 的客户端, 主要是调用IComponetStore 和IComponet的接口。

  1. 查看codec2client是如何创建出来的?
std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);


std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
    std::string const& name = GetServiceNames()[index];
    LOG(WARNING) << "Creating a Codec2 client to service \"" << name << "\"";
    sp<Base> baseStore = Base::getService(name);
    CHECK(baseStore) << "Codec2 service \"" << name << "\""
                        " inaccessible for unknown reasons.";
    LOG(WARNING) << "Client to Codec2 service \"" << name << "\" created";
    return std::make_shared<Codec2Client>(baseStore, index);
}


  • GetServiceNames()。 通过Manifest来获取hal的名字

Manifest定义了HAL的名字”android.hardware.media.c2”, hidl传输方式”hwbinder”,interface的名字”IComponentStore”,instance的名字”default”。而GetServiceNames也是通过这些信息去定位到具体的HAL。

  • Base::getService(name): 其中Base是IComponentStore类型,也就是service 端。通过名字获取到service端的服务。 然后赋值到baseStore。

  • 接着用这个baseStore初始化创建codec2client(也就是mBase 是baseStore)。

    std::make_shared<Codec2Client>(baseStore, index)

  • 所以说codecclinet 调用的接口会调用到service 端的ComponentStore。

CCodecBufferChannel:管理输入和输出buffer的地方,当时有输入和输出buffer的时候通过回调上报到MediaCodec ,随后MediaCodec上报到应用

HIDL 下游

下游包括两个方面 一个是componentStore 另一个是Componet

  • componetStore

    调用关系以createComponent 为例。调用流程如下

    codec2client----->(HIDL)compometStore(获取真正的store)------>C2PlatformComponentStore(或者vendor自己实现的componetstore) -----> C2SoftAvcDecFactory .

    在HIDL 上层 codec2clinet 获取componetStore服务的时候 会调用下面的函数返回C2PlatformComponentStore。而后调用createCompoent就调用到这个类当中。

    在这个类的创建componet中会根据具体的名字找到componet调用其的createComponent,比如avc的C2SoftAvcDecFactory 的 createComponent

c2store.cpp
std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
    static std::mutex mutex;
    static std::weak_ptr<C2ComponentStore> platformStore;
    std::lock_guard<std::mutex> lock(mutex);
    std::shared_ptr<C2ComponentStore> store = platformStore.lock();
    if (store == nullptr) {
        store = std::make_shared<C2PlatformComponentStore>();
        platformStore = store;
    }
    return store;
}

c2_status_t C2PlatformComponentStore::createComponent(
        C2String name, std::shared_ptr<C2Component> *const component) {
    // This method SHALL return within 100ms.
    component->reset();
    std::shared_ptr<ComponentModule> module;
    c2_status_t res = findComponent(name, &module);
    if (res == C2_OK) {
        // TODO: get a unique node ID
        res = module->createComponent(0, component);
    }
    return res;
}
  • component

    compont的调用 也是通过HIDL的接口调用到 SimpleC2Component ,然后 SimpleC2Component 调用具体的avc、hevc等等的componet。 SimpleC2Component 是每个compont的基类。

    以queue接口为例 HIDL上层的codec2bufferChannel 会调用具体解码组件的queue接口 将待解码的数据包放入的具体的component中 首先调用到Codec2Client 这个调用componet的queue,然后调用到SimpleC2Component的queue_nb, queue_nb发送消息, 在消息处理线程中调用子类的process函数。

    c2_status_t Codec2Client::Component::queue(
            std::list<std::unique_ptr<C2Work>>* const items) {
        Return<Status> transStatus = mBase1_0->queue(workBundle);
    }
    
    // Methods from ::android::hardware::media::c2::V1_1::IComponent
    Return<Status> Component::queue(const WorkBundle& workBundle) {
        return static_cast<Status>(mComponent->queue_nb(&c2works));
    }
    
    c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
        {
        if (queueWasEmpty) {
            (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
        }
    }
    
    bool SimpleC2Component::processQueue() {
        }
        process(work, mOutputBlockPool);
    }
    

HIDL接口

  • IComponentStore

    C2ComponentStore(这定义了各种接口, codec2client/C2PlatformComponentStore都继承他并实现里面的接口。)
    有哪些接口 主要是
    createComponent: 创建各种编解码器组件
    createInterface:创建定义各种组件的配置
    listComponents:列出所有的组件。

  • IComponent

    主要定义了对组件的各种操作 实际可以分为数据流和控制流, 数据流包括配置编码输入surface,解码输出surface,输入解码包,清空编解码数据。控制流:启动组件、退出组件、释放组件等等操作

    connectToInputSurface:使用surface启动组件

    queue: 将work 放到组件中。
    drain: 清空组件,不是堵塞运行的。

    setOutputSurface: 设置输出的surface。

    start: 启动组件。

    stop: stop组件。

基础的codec2 服务

frameworks\av\media\codec2\hidl\services\vendor.cpp
在这里面的rc 中会启动一个android.hardware.media.c2@1.2-default-service
这个main函数中实现的是一个componentStore。

        store = new utils::ComponentStore(
                std::make_shared<StoreImpl>());
            constexpr char const* serviceName = "default";
            if (store->registerAsService(serviceName) != OK) {
                LOG(ERROR) << "Cannot register Codec2's IComponentStore service"
                              " with instance name << \""
                           << serviceName << "\".";
            } else {
                LOG(DEBUG) << "Codec2's IComponentStore service registered. "
                              "Instance name: \"" << serviceName << "\".";
            }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1096012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【iOS】——用单例类封装网络请求

文章目录 一、JSONModel1.JSONModel的简单介绍2.JSONModel的使用 二、单例类和Block传值 一、JSONModel 1.JSONModel的简单介绍 JSONModel一个第三方库&#xff0c;这个库用来将网络请求到的JSON格式的数据转化成Foundation框架下的Model类的属性&#xff0c;这样我们就可以直…

冠军方案!2023第二届广州·琶洲算法大赛

Datawhale干货 作者&#xff1a;唐楚柳&#xff0c;算法工程师&#xff0c;冠军选手 1.简介 大家好我是‍Alex‍&#xff0c;31岁&#xff0c;现为一名图像算法工程师&#xff0c;主要研究方向是计算机视觉图像识别。工作之余的研究兴趣包括ocr&#xff0c;aigc&#xff0c;ll…

[自学记录06|*Animation]四元数、死锁与方位插值

一、前言 还记得在很久以前不知道什么时候&#xff0c;看到过一个TA的面经&#xff0c;里面提到了四元数和万向锁&#xff0c;当时自己也查了一些资料&#xff0c;但是看的也是云里雾里&#xff0c;恰巧这两天学校的动画原理课讲到了这&#xff0c;打算整理一下做个小结。 二、…

【Linux学习笔记】 - 项目自动化工具make/Makefile的使用

一、背景知识 会不会写makefile&#xff0c;从一个侧面说明了一个人是否具备完成大型工程的能力。一个工程中的源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中。makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先编译&#xff0c;哪些文件需…

芯片学习记录SN74AHC1G14DBV

SN74AHC1G14DBV 芯片介绍 SN74AHC1G14器件是单个逆变器门。该器件执行布尔函数Y /A.The器件作为独立的逆变器门发挥作用&#xff0c;但由于施密特作用&#xff0c;门可能对正&#xff08;VT&#xff09;和负&#xff08;VT−&#xff09;信号具有不同的输入阈值电平。 引脚信…

07测试Maven中依赖的范围,依赖的传递原则,依赖排除的配置

依赖的特性 scope标签在dependencies/dependency标签内,可选值有compile(默认值),test,provided,system,runtime,import compile&#xff1a;在项目实际运行时真正要用到的jar包都是以compile的范围进行依赖 ,比如第三方框架SSM所需的jar包test&#xff1a;测试过程中使用的j…

大数据基础技能入门指南

本文介绍了数据工作中数据基础和复杂数据查询两个基础技能。 背景 当下&#xff0c;不管是业务升级迭代项目&#xff0c;还是体验优化项目&#xff0c;对于数据的需求都越来越大。数据需求主要集中在以下几个方面&#xff1a; 项目数据看板搭建&#xff1a;特别是一些AB实验的看…

【算法练习Day20】修剪二叉搜索树将有序数组转换为二叉搜索树把二叉搜索树转换为累加树

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 修剪二叉搜索树将有序数组转…

Grade 5 Math

数形结合 5 2 3 https://download.csdn.net/download/spencer_tseng/88431286

深入理解 Java 中的 synchronized 关键字

引入多线程的重要性和挑战 可以参考另一篇文章 https://blog.csdn.net/qq_41956309/article/details/133717408 JMM&#xff08;Java Memory Model&#xff0c;Java 内存模型&#xff09; 什么是JMM JMM&#xff08;Java Memory Model&#xff0c;Java 内存模型&#xff09…

怎么在抖音上引流?分享五个抖音引流推广必备的几个方法

大家好&#xff0c;我是 小刘今天为大家分享的是抖音引流知识分享&#xff0c;今天咱们聊一些干货知识&#xff0c;绝对会让你们有一个重新的认知。抖音的流量大&#xff0c;是毋庸置疑的&#xff0c;抖音也是最早一批短视频平台。抖音于2017年上线&#xff0c;一开始主要是通过…

Golang学习记录:基础知识篇(一)

Golang学习&#xff1a;基础知识篇&#xff08;一&#xff09; 前言什么是Golang&#xff1f;Go语言的基础语法语言结构基础语法数据类型基础使用 前言 很久之前就想学Go语言了&#xff0c;但是一直有其他东西要学&#xff0c;因为我学的是Java嘛&#xff0c;所以后面学的东西…

配置VScode开发环境-CUDA编程

如果觉得本篇文章对您的学习起到帮助作用&#xff0c;请 点赞 关注 评论 &#xff0c;留下您的足迹&#x1f4aa;&#x1f4aa;&#x1f4aa; 本文主要介绍VScode下的CUDA编程配置&#xff0c;因此记录以备日后查看&#xff0c;同时&#xff0c;如果能够帮助到更多人&#xf…

操作系统导论-第四章作业(待更)

一、进程 进程就是运行中的程序&#xff0c;程序本身是没有生命周期的&#xff0c;它只是存储在磁盘上的一些指令&#xff08;或者一些静态数据&#xff09;&#xff0c;操作系统将这些指令和数据加载到内存中&#xff0c;使其运行起来。 1.1 虚拟化CPU技术 根据我们平时使用…

基于Java的共享充电宝管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

AI时代助力程序员与项目经理的双翼飞翔:从开发到成长的秘诀

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

企业网盘中支持在线编辑的有哪些选项?

企业网盘作为现代企业不可或缺的工具之一&#xff0c;为企业提供了便捷的文件存储和共享功能。而其中支持在线编辑的解决方案更是减少了对额外软件的依赖&#xff0c;使团队成员可以直接在浏览器中进行实时协作。 什么是在线编辑&#xff1f; 在线编辑是指用户无需下载文件&a…

3D 生成重建008-zero123让扩散模型了解空间信息zero-shot 单图生3d

3D 生成重建008-zero123让扩散模型了解空间信息zero-shot 单图生3d 文章目录 00 论文工作1 论文方法1.1 条件生成微调1.2 维护3d表示 2 效果 0 0 论文工作 之前分享的工作主要尝试是从一个pre-trained 文生图的diffusion模型中去蒸馏知识&#xff0c;从而去维护一个3d的表示…

数据结构上机实验——栈和队列的实现、栈和队列的应用、进制转换、约瑟夫环问题

文章目录 栈和队列上机实验1.要求2.栈的实现&#xff08;以顺序栈为例&#xff09;3.队列的实现&#xff08;以顺序队列为例&#xff09;4.利用栈实现进制转换5.利用队列解决约瑟夫环问题6.全部源码Stack.hQueue.htest.cpp 栈和队列上机实验 1.要求 1.利用栈的基本操作实现将任…

docker-compose部署elk(8.9.0)并开启ssl认证

docker部署elk并开启ssl认证 docker-compose部署elk部署所需yml文件 —— docker-compose-elk.yml部署配置elasticsearch和kibana并开启ssl配置基础数据认证配置elasticsearch和kibana开启https访问 配置logstash创建springboot项目进行测试kibana创建视图&#xff0c;查询日志…