Android 13 - Media框架(31)- ACodec(七)
之前的章节中我们解了 input buffer 是如何传递给 OMX 的,以及Output buffer 是如何分配并且注册给 OMX 的。这一节我们就来看ACodec是如何处理OMX的Callback的。
1、OMXNodeInstance Callback
这一节我们只大致记录Callback是如何传递给ACodec的。在之前的学习中我们了解到OMXNodeInstance中会有一个专门的线程来处理OMX的callback,这个线程的作用是把Callback按照时间顺序回传给ACodec。
CallbackDispatcher中维护了一个list,将消息回传给ACodec时并不是将list中的消息一条一条回传的,而是将list中所有的消息一次性回传,这也就是为什么ACodec处理OMXNodeInstance的消息时会有循环遍历。
在调用CodecObserver做消息上抛之前,会调用OMXNodeInstance::handleMessage 对消息做预处理,这里的预处里包括是否要将buffer做拷贝等等。
2、onOMXEmptyBufferDone
OMX使用完input buffer后,消息上抛到ACodec层,ACodec 会调用onOMXEmptyBufferDone再处理input buffer。
bool ACodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID, int fenceFd) {ALOGV("[%s] onOMXEmptyBufferDone %u",mCodec->mComponentName.c_str(), bufferID);BufferInfo *info = mCodec->findBufferByID(kPortIndexInput, bufferID);BufferInfo::Status status = BufferInfo::getSafeStatus(info);// 检查 Buffer 状态if (status != BufferInfo::OWNED_BY_COMPONENT) {ALOGE("Wrong ownership in EBD: %s(%d) buffer #%u", _asString(status), status, bufferID);mCodec->dumpBuffers(kPortIndexInput);if (fenceFd >= 0) {::close(fenceFd);}return false;}// input buffer 回到 ACodecinfo->mStatus = BufferInfo::OWNED_BY_US;// input buffers cannot take fences, so wait for any fence now(void)mCodec->waitForFence(fenceFd, "onOMXEmptyBufferDone");fenceFd = -1;// still save fence for completenessinfo->setWriteFence(fenceFd, "onOMXEmptyBufferDone");// We're in "store-metadata-in-buffers" mode, the underlying// OMX component had access to data that's implicitly refcounted// by this "MediaBuffer" object. Now that the OMX component has// told us that it's done with the input buffer, we can decrement// the mediaBuffer's reference count.info->mData->meta()->setObject("mediaBufferHolder", sp<MediaBufferHolder>(nullptr));// 获取当前的 PortModePortMode mode = getPortMode(kPortIndexInput);switch (mode) {case KEEP_BUFFERS:break;case RESUBMIT_BUFFERS:postFillThisBuffer(info);break;case FREE_BUFFERS:default:ALOGE("SHOULD NOT REACH HERE: cannot free empty output buffers");return false;}return true;
}
对input buffer的处理很简单,检查当前ACodec处在的状态并作出反应,如果处在 ExecutingState 则调用 postFillThisBuffer 将 Buffer 提交给 MediaCodec,同时清除 ACodec 存储的 mData。其他状态下则持有 input buffer 不会将其回传给 MediaCodec。
2、onOMXFillBufferDone
ACodec 处理 output buffer 的代码比较长,但是也不难,接下来就做分解学习:
首先有个 debug log,我们可以打开宏TRACK_BUFFER_TIMING来使用这部分内容,把input buffer写给 OMX 时会将pts以及调用时间做记录,在output buffer回传回来时,检查pts,打印出解码该帧消耗的时间。
#if TRACK_BUFFER_TIMINGindex = mCodec->mBufferStats.indexOfKey(timeUs);if (index >= 0) {ACodec::BufferStats *stats = &mCodec->mBufferStats.editValueAt(index);stats->mFillBufferDoneTimeUs = ALooper::GetNowUs();ALOGI("frame PTS %lld: %lld",timeUs,stats->mFillBufferDoneTimeUs - stats->mEmptyBufferTimeUs);mCodec->mBufferStats.removeItemsAt(index);stats = NULL;}
#endif
记录output BufferInfo是在第几帧被使用,mDequeueCounter可以看作是当前解码的帧数。
info->mDequeuedAt = ++mCodec->mDequeueCounter;info->mStatus = BufferInfo::OWNED_BY_US;
2.1 Executing
在 Executing 状态下,会检查output buffer flag 和 size:
- output buffer size为0,flag 不是 OMX_BUFFERFLAG_EOS,说明没有解出有效数据,重新回传给 OMX 使用;
- output buffer size为0,flag 是 OMX_BUFFERFLAG_EOS,ACodec 已经收到 EOS,重新把 buffer 交给 OMX;
- 其他情况说明数据有效,或者是flag是 OMX_BUFFERFLAG_EOS,需要把output buffer回传给上层。
case RESUBMIT_BUFFERS:{// 如果output buffer长度为0,flag 不是 OMX_BUFFERFLAG_EOS// 如果output buffer长度为0,已将收到 EOS// 重新把 output buffer 提交给 OMXif (rangeLength == 0 && (!(flags & OMX_BUFFERFLAG_EOS)|| mCodec->mPortEOS[kPortIndexOutput])) {ALOGV("[%s] calling fillBuffer %u",mCodec->mComponentName.c_str(), info->mBufferID);err = mCodec->fillBuffer(info);if (err != OK) {mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));return true;}break;}sp<MediaCodecBuffer> buffer = info->mData;// ......// 设定 ptsbuffer->meta()->setInt64("timeUs", timeUs);// 解除 ACodec 引用info->mData.clear();// 调用 drainThisBuffermCodec->mBufferChannel->drainThisBuffer(info->mBufferID, flags);info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;// 如果 flag 为 OMX_BUFFERFLAG_EOS,将PortEOS置为trueif (flags & OMX_BUFFERFLAG_EOS) {ALOGV("[%s] saw output EOS", mCodec->mComponentName.c_str());mCodec->mCallback->onEos(mCodec->mInputEOSResult);mCodec->mPortEOS[kPortIndexOutput] = true;}break;}
2.2 OutputPortSettingsChangedState
ACodec::BaseState::PortMode ACodec::OutputPortSettingsChangedState::getPortMode(OMX_U32 portIndex) {if (portIndex == kPortIndexOutput) {return FREE_BUFFERS;}CHECK_EQ(portIndex, (OMX_U32)kPortIndexInput);return RESUBMIT_BUFFERS;
}
相关文章:
Android 13 - Media框架(31)- ACodec(七)
之前的章节中我们解了 input buffer 是如何传递给 OMX 的,以及Output buffer 是如何分配并且注册给 OMX 的。这一节我们就来看ACodec是如何处理OMX的Callback的。 1、OMXNodeInstance Callback 这一节我们只大致记录Callback是如何传递给ACodec的。在之前的学习中我…...

快速了解VR全景拍摄技术运用在旅游景区的优势
豆腐脑加了糖、烤红薯加了勺,就连索菲亚大教堂前都有了“人造月亮”,在这个冬季,“尔滨”把各地游客宠上了天。面对更多的游客无法实地游玩,哈尔滨冰雪世界再添新玩法,借助VR全景拍摄技术对冬季经典冰雪体验项目进行全…...

分布形态的度量_峰度系数的探讨
集中趋势和离散程度是数据分布的两个重要特征,但要全面了解数据分布的特点,还应掌握数据分布的形态。 描述数据分布形态的度量有偏度系数和峰度系数, 其中偏度系数描述数据的对称性,峰度系数描述与正态分布的偏离程度。 峰度系数反映分布峰的尖峭程度的重要指标. 当…...

HCIP 重发布
拓扑图&IP划分如下: 第一步,配置接口IP&环回地址 以R1为例,R2~R4同理 interface GigabitEthernet 0/0/0 ip address 12.1.1.1 24 interface GigabitEthernet 0/0/1 ip address 13.1.1.1 24 interface LoopBack 0 ip address 1.1.1.…...
FX图中的节点代表什么操作
在 FX 图中,每个节点代表一个操作。这些操作可以是函数调用、方法调用、模块实例调用,也可以是 torch.nn.Module 实例的调用。每个节点都对应一个调用站点,如运算符、方法和模块。 一.节点操作 下面是一些节点可能代表的操作: 1…...

【Java 设计模式】创建型之单例模式
文章目录 1. 定义2. 应用场景3. 代码实现1)懒汉式2)饿汉式 4. 应用示例结语 在软件开发中,单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。单例模式在需要控制某些资源,如数…...

FlinkAPI开发之窗口(Window)
案例用到的测试数据请参考文章: Flink自定义Source模拟数据流 原文链接:https://blog.csdn.net/m0_52606060/article/details/135436048 窗口的概念 Flink是一种流式计算引擎,主要是来处理无界数据流的,数据源源不断、无穷无尽。…...

【Unity】Joystick Pack摇杆插件实现锁四向操作
Joystick Pack 简介:一款Unity摇杆插件,非常轻量化 摇杆移动类型:圆形、横向、竖向 摇杆类型: Joystick描述Fixed固定位置Floating浮动操纵杆从用户触碰的地方开始,一直固定到触碰被释放。Dynamic动态操纵…...

29 旋转工具箱
效果演示 实现了一个菜单按钮的动画效果,当鼠标悬停在菜单按钮上时,菜单按钮会旋转315度,菜单按钮旋转的同时,菜单按钮旋转的8个小圆圈也会依次旋转360度,并且每个小圆圈的旋转方向和菜单按钮的旋转方向相反࿰…...

WeNet2.0:提高端到端ASR的生产力
摘要 最近,我们提供了 WeNet [1],这是一个面向生产(工业生产环境需求)的端到端语音识别工具包,在单个模型中,它引入了统一的两次two-pass (U2) 框架和内置运行时(built-in runtime)…...
第九部分 使用函数 (四)
目录 一、foreach 函数 二、if 函数 三、call 函数 一、foreach 函数 foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile 中的 foreach 函数几乎是仿照于 Unix 标准 Shell(/bin/sh)中的 for 语句,或…...

一文读懂「Prompt Engineering」提示词工程
在了解提示过程之前,先了解一下什么是提示prompt,见最后附录部分 一、什么是Prompt Engingering? 提示工程(Prompt Engingering),也被称为上下文提示(In-Context Prompting)&#x…...

微信小程序(一)简单的结构及样式演示
注释很详细,直接上代码 涉及内容: view和text标签的使用类的使用flex布局水平方向上均匀分布子元素垂直居中对齐子元素字体大小文字颜色底部边框的宽和颜色 源码: index.wxml <view class"navs"><text class"active…...
【设计模式】外观模式
前言 1. 单例模式(Singleton Pattern):保证一个类只有一个实例,并提供一个全局的访问点。 2. 工厂模式(Factory Pattern):定义一个创建对象的接口,但由子类决定要实例化的类是哪一…...

优先级队列(Priority Queue)
文章目录 优先级队列(Priority Queue)实现方式基于数组实现基于堆实现方法实现offer(E value)poll()peek()isEmpty()isFull() 优先级队列的实现细节 优先级队列(Priority Queue) 优先级队列是一种特殊的队列,其中的元素…...

12-桥接模式(Bridge)
意图 将抽象部分与它的实现部分分离,使他们可以独立地变化 个人理解 一句话概括就是只要是在抽象类中聚合了某个接口或者抽象类,就是使用了桥接模式。 抽象类A中聚合了抽象类B(或者接口B),A的子类的方法中在相同的场…...
Zookeeper+Kafka概述
一 Zookeeper 1.1 Zookeeper定义 Zookeeper是一个开源的、分布式的,为分布式框架提供协调服务的Apache项目。 1.2 Zookeeper特点 Zookeeper:一个领导者(leader),多个跟随者(Follower)组成的…...

架构师 - 架构师是做什么的 - 学习总结
架构师核心定义 架构师是什么 架构师是业务和技术之间的桥梁 架构师的核心职责是消除不确定性、和降低复杂性 架构设计环 架构师的三个核心能力 架构师的三个关键思维 架构师主要职责 架构设计 Vs 方案设计 架构设计前期 主要任务 澄清不确定性 明确利益干系人的诉求消除冲…...

全链路压测方案(一)—方案调研
一、概述 在业务系统中,保证系统稳定至关重要,直接影响线上业务稳定和性能。测试工作作为保证生产质量的最后一关,扮演者重要的角色。全链路压测是一种重要的测试工具和手段。可以解决系统中多环节多节点无法全流程打满流量的痛点问题&a…...
c++关键字const
C中的const是一种常量修饰符。在变量、函数参数和成员函数中使用const可以限制其对数据的修改。 const修饰的数据在定义时必须进行初始化,且不能被修改,因此使用const可以提高代码的安全性和可读性。在C中,const修饰的成员函数表示该函数保证…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...