Android 13 - Media框架(26)- OMXNodeInstance(三)

上一节我们了解了OMXNodeInstance中的端口定义,这一节我们一起来学习ACodec、OMXNode、OMX 组件使用的 buffer 到底是怎么分配出来的,以及如何关联起来的。(我们只会去了解 graphic buffer的创建、input bytebuffer的创建、secure buffer的创建)

1、ACodec::allocateOutputMetadataBuffers

我们先一起来回忆一下,ACodec在使用surface的情况下给ouput port分配buffer使用的是allocateOutputMetadataBuffers方法,这时候真正的graphic buffer还未分配出来,BufferInfo的状态还是OWNED_BY_NATIVE_WINDOW(意为 buffer 还在 native 中)。

    for (OMX_U32 i = 0; i < bufferCount; i++) {BufferInfo info;info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;info.mFenceFd = -1;info.mRenderInfo = NULL;info.mGraphicBuffer = NULL;info.mNewGraphicBuffer = false;info.mDequeuedAt = mDequeueCounter;// 创建 meta datainfo.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));// Initialize fence fd to -1 to avoid warning in freeBuffer().((VideoNativeMetadata *)info.mData->base())->nFenceFd = -1;info.mCodecData = info.mData;err = mOMXNode->useBuffer(kPortIndexOutput, OMXBuffer::sPreset, &info.mBufferID);mBuffers[kPortIndexOutput].push(info);ALOGV("[%s] allocated meta buffer with ID %u",mComponentName.c_str(), info.mBufferID);}

这里BufferInfo是作为分配出来的buffer的索引,分配的 mCodecData (Meta data) 没有任何作用,仅仅是起着占位的作用。

ACodec 需要给这个 BufferInfo 打上索引,调用useBuffer时,传入的OMXBuffer类型是kBufferTypePreset,这个内容可以到 OMXBuffer.cpp 中查询。

1.1、useBuffer

进入到 OMXNodeInstance 中,首先就会检查 port mode,我们可以看到,如果port mode不是dynamic的类型,会直接报错。

status_t OMXNodeInstance::useBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuffer, IOMX::buffer_id *buffer) {switch (omxBuffer.mBufferType) {case OMXBuffer::kBufferTypePreset: {if (mPortMode[portIndex] != IOMX::kPortModeDynamicANWBuffer&& mPortMode[portIndex] != IOMX::kPortModeDynamicNativeHandle) {break;}return useBuffer_l(portIndex, NULL, NULL, buffer);}}

kBufferTypePreset 在这里应该表示的是占位的意思。

我们不要被 useBuffer 的参数 buffer 迷惑了,它其实是一个 int 类型。判断完成后就会进入到 useBuffer_l 中。

1.2、useBuffer_l

进入下面的内容之前我们首先要了解的是,之所以方法名为 use buffer,指的是 OMX 组件端口使用的 buffer 是在其他地方分配的,OMX 组件仅仅只是使用。

useBuffer_l 的设计思路其实和之前的一篇文章中的 enableNativeBuffers_l 类似,它是把几个不同的设定写到一个函数体当中,用入参来判断当前走的是什么设定。useBuffer_l 有两个参数,但是它其实有三种可能的设定,一种是IMemory,另一种是 IHidlMemory,最后一个是两个参数都为 NULL,表示是一个占位

status_t OMXNodeInstance::useBuffer_l(OMX_U32 portIndex, const sp<IMemory> &params,const sp<IHidlMemory> &hParams, IOMX::buffer_id *buffer) {BufferMeta *buffer_meta;OMX_BUFFERHEADERTYPE *header;OMX_ERRORTYPE err = OMX_ErrorNone;// 判断是否使用 meta databool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;// 如果使用graphic buffer但是不用meta data则直接报错if (!isMetadata && mGraphicBufferEnabled[portIndex]) {ALOGE("b/62948670");android_errorWriteLog(0x534e4554, "62948670");return INVALID_OPERATION;}// 检查参数,不能同时设定两个参数size_t paramsSize;void* paramsPointer;if (params != NULL && hParams != NULL) {return BAD_VALUE;}// 解析传递的buffer的指针以及buffer的大小,如果什么都没有传,那么指针为NULLif (params != NULL) {// TODO: Using unsecurePointer() has some associated security pitfalls//       (see declaration for details).//       Either document why it is safe in this case or address the//       issue (e.g. by copying).paramsPointer = params->unsecurePointer();paramsSize = params->size();} else if (hParams != NULL) {paramsPointer = hParams->getPointer();paramsSize = hParams->getSize();} else {paramsPointer = nullptr;}// 使用的buffer的大小OMX_U32 allottedSize;// metadata mode下,设定的是占位符,OMXNode 与 OMX 组件之间通过 metadata交流,metadata buffer由 OMXNode分配// 这里需要根据不同的类型分配不同类型的meta data,确定metadata sizeif (isMetadata) {if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource) {allottedSize = sizeof(VideoGrallocMetadata);} else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer) {// allottedSize = sizeof(VideoNativeMetadata);} else if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource) {allottedSize = sizeof(VideoNativeHandleMetadata);} else {return BAD_VALUE;}} else {// NULL 只允许出现在 meta mode 当中// 如果不使用meta data 并且 没有传 buffer下来,那么直接报错// NULL params is allowed only in metadata mode.if (paramsPointer == nullptr) {ALOGE("b/25884056");return BAD_VALUE;}allottedSize = paramsSize;}// 是否是与graphic搭配使用的metadatabool isOutputGraphicMetadata = (portIndex == kPortIndexOutput) &&(mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource ||mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer);// 是否需要分配bufferuint32_t requiresAllocateBufferBit =(portIndex == kPortIndexInput)? kRequiresAllocateBufferOnInputPorts: kRequiresAllocateBufferOnOutputPorts;// quirks 模式下,如果不是使用的 meta data mode,则需要让 OMX 组件分配buffer// we use useBuffer for output metadata regardless of quirksif (!isOutputGraphicMetadata && (mQuirks & requiresAllocateBufferBit)) {// metadata buffers are not connected cross process; only copy if not meta.// quirks 模式下,将 OMX 组件分配的buffer 和 上层 buffer相关绑定,进行数据拷贝// 这应该是很没有效率的一种行为buffer_meta = new BufferMeta(params, hParams, portIndex, !isMetadata /* copy */, NULL /* data */);err = OMX_AllocateBuffer(mHandle, &header, portIndex, buffer_meta, allottedSize);if (err != OMX_ErrorNone) {CLOG_ERROR(allocateBuffer, err,SIMPLE_BUFFER(portIndex, (size_t)allottedSize,paramsPointer));}} else {OMX_U8 *data = NULL;// metadata buffers are not connected cross process// use a backup buffer instead of the actual bufferif (isMetadata) {// 为 meta data buffer 分配空间data = new (std::nothrow) OMX_U8[allottedSize];if (data == NULL) {return NO_MEMORY;}memset(data, 0, allottedSize);// 将 meta data buffer 封装到 BufferMeta 当中buffer_meta = new BufferMeta(params, hParams, portIndex, false /* copy */, data);} else {// 如果不是 meta data mode,直接使用buffer指针data = static_cast<OMX_U8 *>(paramsPointer);// 将 buffer 封装到 BufferMeta 当中buffer_meta = new BufferMeta(params, hParams, portIndex, false /* copy */, NULL);}// 直接把创建的 BufferMeta 传递给 OMX 组件使用,不需要进行buffer拷贝err = OMX_UseBuffer(mHandle, &header, portIndex, buffer_meta,allottedSize, data);if (err != OMX_ErrorNone) {CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));}}if (err != OMX_ErrorNone) {delete buffer_meta;buffer_meta = NULL;*buffer = 0;return StatusFromOMXError(err);}// 检查创建的buffer header中的上层数据是否和 创建的 buffer meta 相同CHECK_EQ(header->pAppPrivate, buffer_meta);// 为 buffer header 创建 index*buffer = makeBufferID(header);addActiveBuffer(portIndex, *buffer);sp<IOMXBufferSource> bufferSource(getBufferSource());if (bufferSource != NULL && portIndex == kPortIndexInput) {bufferSource->onInputBufferAdded(*buffer);}CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%u(%zu)@%p", allottedSize, paramsSize, paramsPointer));return OK;
}

useBuffer 的内容很长,里面有很多判断,很多同学可能读不太明白里面到底想干什么,这里我们就来解析一下:

  1. 首先,它会判断configure阶段配置的一些内容, 比如说metadata mode需要和graphic buffer共同使用;IMemory 参数和 IHidlMemory 参数不能同时设定;

  2. 接下来会分为两种情况,

    • metadata mode,也就是我们上面讨论的传下来的buffer类型是kBufferTypePreset的情况(占位),这种情况上层没有真正传buffer下来,OMX组件和上层通过metadata进行数据传递,所以usebuffer中会根据configure的配置获取需要传递的metadata类型,计算metadata所需的size;
    • preset byte buffer,这种就是普通的non secure buffer,可以通过指针读写buffer中的数据,use buffer需要获取buffer的地址以及大小;
  3. 判断是否用quirks,这个东西我们在创建OMXNodeInstance时有看见过,它是在xml中配置的,一旦有了这个配置,那么只要端口不是metadata mode,则需要让OMX组件分配buffer,上层传下来的buffer会与OMX分配的buffer做绑定,创建一个BufferMeta,上层传的数据会在这里做拷贝,写入到OMX组件分配的buffer当中。(这里是调用OMX_AllocateBuffer的地方之一)
    请添加图片描述

  4. 如果不使用quirks,那么数据就不需要在OMXNodeInstance层做中转了。

    • metadata mode,分配meta data大小的buffer,创建出BufferMeta;
    • preset byte buffer,直接用上层传的buffer创建BufferMeta;
    • 调用OMX_UseBuffer,将 BufferMeta 和 metadata/buffer 注册到 OMX 组件当中,并且创建出 OMX_BUFFERHEADERTYPE
  5. 为创建出的 OMX_BUFFERHEADERTYPE 分配 id;

到这里,useBuffer_l 的分析就完成了,之所以要在 OMXNodeInstance 这一层创建 BufferMeta,可能就是为了记录上层传下来的所有buffer,或者是做数据中转用的。

quirks模式会在 OMXNodeInstance 层多做一次数据拷贝,现在已经被弃用了。

再放上两张示意图:

一张是 preset byte buffer:
请添加图片描述

另一张是meta data,可以看到 meta data 模式下,output buffer 不会有任何东西回传给上层。
请添加图片描述

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

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

相关文章

免费更新UltraNews v2.8.0 已注册 – Laravel报纸,博客多语言系统,支持AI作家,内容生成器脚本

UltraNews v2.8.0 已注册 – Laravel报纸&#xff0c;博客多语言系统&#xff0c;支持AI作家&#xff0c;内容生成器脚本 一、概述 在网络内容创作与管理领域&#xff0c;UltraNews v2.8.0以其高度现代化和多功能性而独树一帜。这是一个基于Laravel框架构建的报纸、博客多语言…

实习课知识整理4:点击某个商品如何跳转到并展示出商品详情页

项目情景&#xff1a;当我们点击某个商品时&#xff0c;我们需要查看商品的具体的信息并进行购买的操作 简单理解以下就是&#xff0c;当我们点击一个url链接时&#xff0c;该链接需要携带一个参数到后端&#xff0c;一般设为商品的Id&#xff0c;然后后端通过Id从数据库中查找…

怎么卸载macOS上的爱思助手如何卸载macOS上的logitech g hub,如何卸载顽固macOS应用

1.在App Store里下载Cleaner One Pro &#xff08;注意&#xff0c;不需要订阅付费&#xff01;&#xff01;&#xff01;白嫖基础功能就完全够了&#xff01;&#xff01;&#xff01;&#xff09; 2.运行软件&#xff0c;在左侧目录中选择“应用程序管理”&#xff0c;然后点…

C++初阶——类和对象

呀哈喽&#xff0c;我是结衣 C入门之后&#xff0c;我们就进入了C的初阶的学习了&#xff0c;在了解类和对象之前&#xff0c;我们还是先了解&#xff0c;面向过程和面向对象的初步认识。 在本篇博客中&#xff0c;我们要讲的内容有 1.面向过程和面向对象初步认识 2.类的引入 3…

RasaGPT对话系统的工作原理

RasaGPT 结合了 Rasa 和 Langchain 这 2 个开源项目&#xff0c;当超出 Rasa 现有意图(out_of_scope)的时候&#xff0c;就会执行 ActionGPTFallback&#xff0c;本质上就是利用 Langchain 做了一个 RAG&#xff0c;调用 LLM API。RasaGPT 涉及的技术栈比较多而复杂&#xff0c…

面试官:看你简历了解过并发,我们简单聊一聊

前言&#xff1a; 今天和大家探讨最近的面试题&#xff0c;好久没有面试了&#xff0c;所以在此记录一下。本篇文章主要讲解CyclicBarrier和CountDownLatch的知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出&#xf…

羊了个羊抓包速通,让第二关变成和第一关一样难度

目录 一.前言 二.前期准备 2.1抓包环境 2.2安装电脑版微信环境 2.3配置bp与浏览器VPN 2.4配置proxifier 三.开始抓包 3.1前期准备 3.2抓包ing 一.前言 羊了个羊是一款经典微信小程序游戏&#xff0c;号称“第一关谁都能过&#xff0c;第二关谁能过&#xff1f;“。那…

Python使用多线程解析超大日志文件

目录 一、引言 二、多线程基本概念 三、Python中的多线程实现 四、使用多线程解析超大日志文件 五、性能优化和注意事项 总结 一、引言 在处理大量数据时&#xff0c;单线程处理方式往往效率低下&#xff0c;而多线程技术可以有效地提高处理速度。Python提供了多种多线程…

详解Vue3中的内置组件(transition)

本文主要介绍Vue3中的内置组件&#xff08;transition&#xff09;的普通写法和setup写法。 目录 一、在普通写法中使用内置组件&#xff08;transition&#xff09;二、在setup写法中使用内置组件&#xff08;transition&#xff09;三、使用注意项 在Vue3中&#xff0c;内置了…

3 个适用于 Mac 电脑操作的 Android 数据恢复最佳工具 [附步骤]

在当今的数字时代&#xff0c;无论是由于意外删除、系统故障还是其他原因&#xff0c;从 Android 设备中丢失数据不仅会带来不便&#xff0c;而且会造成非常严重的后果。特别是对于Mac用户来说&#xff0c;从Android手机恢复数据是一个很大的麻烦。幸运的是&#xff0c;随着许多…

九:爬虫-MongoDB基础

MongoDB介绍 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。它支持的数据结构非常松散&#xff0c;因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大&#xff0c;其…

【MySQL】数据库的SQL语句详解

目录 一、操作系统了解 二、关系型数据库与非关系型数据库的区别 三、关系型数据库的四种语言 四、DDL语言&#xff08;数据库定义语言&#xff0c;管理创建对象如库、表、字段、索引等&#xff09; 1、库的增删改查&#xff1b; 2、表的增删改查&#xff1b; 3、字段的增…

机场数据治理系列介绍(2):六图法开展数据治理的步骤与要点

目录 一、机场数据治理的六图法 1、何为六图法 二、应用数据治理六图法的相关工作步骤 1、制定战略目标 2、梳理业务情况 3、收集需求 4、构建数智应用地图 5、选择合适的算法 6、建立数据地图 7、持续改进和优化 三、相关要点 1、明确数据治理三张清单 2、持续构…

Chainlink 开发者故事:Krypton 从构思到产品的 Chainlink BUILD之旅

识别问题&#xff0c;构思解决方案&#xff0c;建立它&#xff0c;推出它&#xff0c;然后扩展它。这就是科技初创企业的操作手册。 现在&#xff0c;前Chainlink黑客马拉松获奖者&#xff0c;当前的Chainlink BUILD成员Krypton已经进行到了第四步&#xff1a;推出。Krypton团…

敏捷开发 - 知识普及

敏捷开发- Scrum 前言 知乎有一篇文章描写Scrum,我觉得比较好:https://zhuanlan.zhihu.com/p/631459977 简单科普下PM和PMO 原文来源:https://zhuanlan.zhihu.com/p/546820914 PM - 项目经理(Project Manager) ​ 需要具备以下能力 ​ 1.号召力 2.影响力 3.交流能力 4.应…

IDEA的facets和artifacts

在软件开发领域&#xff0c;IDEA 是指 JetBrains 公司的 IntelliJ IDEA&#xff0c;是一款流行的集成开发环境&#xff08;Integrated Development Environment&#xff09;。在 IntelliJ IDEA 中&#xff0c;"facets" 和 "artifacts" 是两个概念&#xff…

智能优化算法应用:基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.材料生成算法4.实验参数设定5.算法结果6.…

实习课知识整理3:首页商品列表的展示

对于一个购物商城的项目&#xff0c;主体还得是商品&#xff0c;这篇博客主要介绍如何将数据库中的信息渲染到页面上&#xff0c;这边后端是SpringBoot,前端是html配合thymeleaf模板 1. 编写查询数据库的方法 在这边我在页面上需要两部分的信息&#xff0c;一个是所有的商品&am…

Alnet网络分析与demo实例

参考自 up主的b站链接&#xff1a;霹雳吧啦Wz的个人空间-霹雳吧啦Wz个人主页-哔哩哔哩视频这位大佬的博客 Fun_机器学习,pytorch图像分类,工具箱-CSDN博客 数据集下载 http://download.tensorflow.org/example_images/flower_photos.tgz 包含 5 中类型的花&#xff0c;每种…

论文降重方法同义词替换的效果对比与评价 快码论文

大家好&#xff0c;今天来聊聊论文降重方法同义词替换的效果对比与评价&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 标题&#xff1a;论文降重方法同义词替换的效果对比…