当前位置: 首页 > news >正文

Android MediaCodec 框架 基于codec2

系列文章的目的是什么?

粗略:

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

细化:

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

文章目录

      • 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 IDres = 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 << "\".";}

相关文章:

Android MediaCodec 框架 基于codec2

系列文章的目的是什么&#xff1f; 粗略&#xff1a; 解码需要哪些基础的服务&#xff1f;标准解码的调用流程&#xff1f;各个流程的作用是什么&#xff1f;解码框架的层次&#xff1f;各个层次的作用&#xff1f; 细化&#xff1a; 解码参数的配置&#xff1f;解码输入数…...

【RocketMQ 系列三】RocketMQ集群搭建(2m-2s-sync)

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…...

Go TLS服务端绑定证书的几种方式

随着互联网的发展&#xff0c;网站提供的服务类型和规模不断扩大&#xff0c;同时也对Web服务的安全性提出了更高的要求。TLS(Transport Layer Security)[1]已然成为Web服务最重要的安全基础设施之一。默认情况下&#xff0c;一个TLS服务器通常只绑定一个证书[2]&#xff0c;但…...

【算法与数据结构】--高级算法和数据结构--排序和搜索

一、常见排序算法 以下是一些常见的排序算法&#xff0c;包括冒泡排序、选择排序、插入排序、快速排序和归并排序。每种排序算法的讲解以及附带C#和Java示例&#xff1a; 1.1 冒泡排序 (Bubble Sort) 讲解&#xff1a; 冒泡排序是一种简单的比较排序算法。它多次遍历待排序的…...

【Java】jvm 元空间、常量池(了解)

JDK1.8 以前的 HotSpot JVM 有方法区&#xff0c;也叫永久代&#xff08;permanent generation&#xff09;方法区用于存放已被虚拟机加载的类信息&#xff0c;常量、静态遍历&#xff0c;即编译器编译后的代码JDK1.7 开始了方法区的部分移除&#xff1a;符号引用&#xff08;S…...

Spring Boot自动加载

问&#xff1a;自动装配如何实现的&#xff1f; 答&#xff1a;简单来说就是自动去把第三方组件的Bean装载到IOC容器中&#xff0c;不需要开发人员再去写Bean相关的配置&#xff0c;在springboot应用里面只需要在启动类上去加上SpringBootApplication注解&#xff0c;就可以去实…...

MPNN 模型:GNN 传递规则的实现

首先&#xff0c;假如我们定义一个极简的传递规则 A是邻接矩阵&#xff0c;X是特征矩阵&#xff0c; 其物理意义就是 通过矩阵乘法操作&#xff0c;批量把图中的相邻节点汇聚到当前节点。 但是由于A的对角线都是 0.因此自身的节点特征会被过滤掉。 图神经网络的核心是 吸周围…...

Flink kafka 数据汇不指定分区器导致的问题

背景 在flink中&#xff0c;我们经常使用kafka作为flink的数据汇&#xff0c;也就是目标数据的存储地&#xff0c;然而当我们使用FlinkKafkaProducer作为数据汇连接器时&#xff0c;我们需要注意一些注意事项&#xff0c;本文就来记录一下 使用kafka数据汇连接器 首先我们看…...

【软考】14.1 面向对象基本概念/分析设计测试

《面向对象开发》 对象 现实生活中实际存在的一个实体&#xff1b;构成系统的一个基本单位由对象名、属性和方法组成 类 实体的形式化描述&#xff1b;对象是类的实例&#xff0c;类是对象的模板可分为&#xff1a;实体类&#xff1a;现实世界中真实的实体接口类&#xff08;边…...

MFC-对话框

目录 1、模态和非模态对话框&#xff1a; &#xff08;1&#xff09;、对话框的创建 &#xff08;2&#xff09;、更改默认的对话框名称 &#xff08;3&#xff09;、创建模态对话框 1&#xff09;、创建按钮跳转的界面 2&#xff09;、在跳转的窗口添加类 3&#xff0…...

Essential Steps in Natural Language Processing (NLP)

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…...

Flink中KeyBy、分区、分组的正确理解

1.Flink中的KeyBy 在Flink中&#xff0c;KeyBy作为我们常用的一个聚合类型算子&#xff0c;它可以按照相同的Key对数据进行重新分区&#xff0c;分区之后分配到对应的子任务当中去。 源码解析 keyBy 得到的结果将不再是 DataStream&#xff0c;而是会将 DataStream 转换为 Key…...

QT6集成CEF3--01 准备工作

QT6集成CEF3--01 准备工作 一、所有使用到的工具软件清单:二、准备工作三、cefclient示例程序四、特别注意 一、所有使用到的工具软件清单: CEF 二进制发行包 cef_binary_117.2.5gda4c36achromium-117.0.5938.152_windows64.tar.bz2 CMake 编译工具 cmake-3.22.6-windows-x86_…...

随机误差理论与测量

文章目录 第1节 随机误差的性质和特点第2节 随机误差的数字特性标准差的估计 第3节 单次测量结果的精度指标第4节 多次测量结果的精度指标算数平均值的分布特性与标准差算数平均值的置信度算数平均值的精度指标&#xff08;常用的有4个) 第5节 非等精度测量 第1节 随机误差的性…...

树莓派4b配置通过smbus2使用LCD灯

出现报错&#xff1a; FileNotFoundError: [Errno 2] No such file or directory: ‘/dev/i2c-1’ 则说明没有打开I2C&#xff0c;可通过如下步骤进行设置 1、打开树莓派配置 sudo raspi-config2、进入Interface Options&#xff0c;配置I2C允许 目前很多python3版本已经不…...

UPS 原理和故障案例分享

摘要:不间断电源UPS (Uninterruptible Power System)&#xff0c;主要是由整流器、 逆变器、静态旁路和储能装置等组成;具备高可靠性、高可用性和高质量的独立 电源。通过对收集的 UPS 故障案例进行分析&#xff0c;从施工&#xff0c;调试和运行三个方面筛选 出四个故障案例与…...

Stream流中的 max()和 sorted()方法

需求&#xff1a;某个公司的开发部门&#xff0c;分为开发 一部 和 二部 &#xff0c;现在需要进行年中数据结算。分析&#xff1a; 员工信息至少包含了&#xff08;名称、性别、工资、奖金、处罚记录&#xff09;开发一部有 4 个员工、开发二部有 5 名员工分别筛选出 2 个部门…...

云上攻防-云原生篇Docker安全权限环境检测容器逃逸特权模式危险挂载

文章目录 前言1、Docker是干嘛的&#xff1f;2、Docker对于渗透测试影响&#xff1f;3、Docker渗透测试点有那些&#xff1f;4、前渗透-判断在Docker中方式一&#xff1a;查询cgroup信息方式二&#xff1a;检查/.dockerenv文件方式三&#xff1a;检查mount信息方式四&#xff1…...

PDE数值解中,为什么要引入弱解(weak solution)的概念?

See https://www.zhihu.com/question/24243246?utm_sourceqq&utm_mediumsocial&utm_oi1315073218793488384...

使用pdfjs实现在线预览pdf

在工作中可能会遇到前端展示pdf文件进行预览并提供下载的需求场景,例如操作指引,这个时候需要寻找一款实现该功能的插件,以pdjjs举例子 1. 安装pdf.js npm install pdfjs-dist2. 引入pdf.js import pdfjsLib from pdfjs-dist3.加载pdf文件流 这个地方区分是请求后端接口还是…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式&#xff0c;给定一个隐函数关系&#xff1a; F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 &#x1f9e0; 目标&#xff1a; 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...

表单设计器拖拽对象时添加属性

背景&#xff1a;因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...