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修饰的成员函数表示该函数保证…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门  是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
