抱歉,你查看的文章不存在

Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务

前言:上篇文《Android Multimedia框架总结(十)》总结了音视频的输出过程,从今天开始分析Codec部分,今天分析的是AwesomePlayer到OMX服务过程,也就是开启OpenMax准备相关。

先看下今天的Agenda:

  • 一张图看清OMX在stagefright中的位置
  • 一张图看清OpenMax与Stagefright层级的关系
  • OMX初始化流程
  • OMX服务之NodeInstance列表的管理
  • OMX服务之NodeInstance节点的操作
  • 总结AwesomePlayer到OMX服务过程

背景: Android系统中用OpenMAX来做编解码,Android向上抽象了一层OMXCodec,提供给上层播放器AwesomePlayer用。播放器中音视频解码器mVideosource、mAudiosource都是OMXCodec的实例。 OMXCodec::Create是解码器初始化的入口。 OMXCodec通过IOMX 依赖binder机制 获得OMX服务,OMX服务才是OpenMAX在Android中实现

一张图看清OMX在stagefright中的位置:

一张图看清OpenMax与Stagefright层级的关系:

OMX初始化流程

AwesomePlayer是如何获得OMX服务的?

  • 在AwesomePlayer初始化的时候,会调用AwesomePlayer::onPrepareAsyncEvent。
  • 继而调用AwesomePlayer::initVideoDecoder以及AwesomePlayer::initAudioDecoder。
  • 然后开始正式的进入OMX以及硬件解码器的初始化工作。

之前的AwesomePlayer初始化的一些工作都是在小打小闹。当OMX开始初始时,才是开始真正核心的初始化工作。我们知道,android中的组件都是在提供服务,有server,有client,大多是C/S模型,前面文章已介绍。 AwesomePlayer 中有个变量 OMXClient mClient; 先了解OMXClient.cpp,如下:

OMXClient 有个IOMX的变量mOMX ,这个就是和OMX服务进行binder通信的。

在AwesomePlayer的构造函数中会调用: CHECK_EQ(mClient.connect(), (status_t)OK); OMXClient中代码如下:

OMXClient::connect函数是通过binder机制 获得到MediaPlayerService,然后通过MediaPlayerService来创建OMX的实例。这样OMXClient就获得到了OMX的入口,接下来就可以通过binder机制来获得OMX提供的服务。 也就是说OMXClient 是android中 openmax 的入口。

在创建音视频解码mVideoSource、mAudioSource的时候会把OMXClient中的sp mOMX的实例 传给mVideoSource、mAudioSource来共享使用这个OMX的入口。 也就是说一个AwesomePlayer对应着 一个IOMX 变量,AwesomePlayer中的音视频解码器共用这个IOMX变量来获得OMX服务。

以上分为1,2两个步骤,先看下1中OMXCodec::Create函数

每个AwesomePlayer实例只有一个OMX服务的入口,但是AwesomePlayer不一定就只需要1种解码器。音视频都要有,部分场景下还有多路音频,或者多路视频。 这个时候OMX那边需要建立不同的解码器的组件来对应着AwesomePlayer中不同的解码需求。

本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882

OMX中非常重要的2个成员: OMXMaster 和 OMXNodeInstance。

  • OMX通过这俩个成员来创建和维护不同的openmax 解码器组件,为AwesomePlayer中不同解码需求提供服务。 OMXNodeInstance 负责创建并维护不同的实例,这些实例是根据实际的解码需求创建的,以node_id作为唯一标识。
  • 这样解码器组件中每个OMXCodec在OMX服务端都对应有了自己的OMXNodeInstance实例。AwesomePlayer就可以根据这个OMXNodeInstance来操作相应解码器
  • OMXMaster 维护底层软硬件解码库,是对解码器组件的一个大管家,根据OMXNodeInstance中想要的解码器来创建解码实体组件。

所以我们要追踪下OMXMaster和OMXNodeInstance。 OMX构造函数中会进行初始化。 OMX.cpp中

OMXMaster.cpp中

到这里,我们就明白了AwesomePlayer是如何利用具体的硬件平台上的硬件解码器。

那么针对不同的文件格式,如何选择具体的解码器组件呢? 继续顺着前面的OMXCodec::Create介绍。看一下allocateNode 在OMX.cpp中

会调用makeComponentInstance函数

这样就实现了根据文件编码格式,对具体解码器的连接 接下来了解下OMXcodec如何注册和初始化OMX所需要的回调函数。 OMX服务主要完成三个任务: NodeInstance列表的管理,NodeInstance的操作, 事件的处理。

本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882

NodeInstance列表的管理

  • OMX对解码器组件component的使用,是通过OMXNodeInstance来实现的。 OMXNodeInstance自身的动作包括NodeInstance的生成(allocateNode)和删除(freeNode)。 其实就是对mDispatchers和 mNodeIDToInstance进行添加和删除。
  • mNodeIDToInstance就是一个key为node_id,value为 NodeInstance的名值对列表。 而mDispatchers就是一个key为node_id,value为 OMX::CallbackDispatcher的名值对列表。 并且,一个NodeInstance都拥有一个 OMX::CallbackDispatcher。
  • CallbackDispatcher的作用主要是解码器组件component发出回调动作后,将message分发给对应的OMXcodec客户端。

NodeInstance节点的操作

OMXNodeInstance主要成员函数如下:

这些方法执行时,都是先通过findInstance在mNodeIDToInstance列表中找到对应的NodeInstance,然后调用NodeInstance对应的方法。

  • OMXCodec对具体的component方法的操作,是通过OMXNodeInstance来实现的。 如fillBuffer,emptybuffer,sendCommand等,都是通过OMX_Core.h中的宏定义间接调用OMX_Component.h中的
  • OMX_COMPONENTTYPE这个struct中的相应函数指针来完成。OMX_Core.h和 OMX_Component.h都是OpenMAX标准头文件。 在OMXNodeInstance.cpp中的这样一段代码:
  • 它把三个OMXNodeInstance类的静态方法注册给了kCallbacks。
  • kCallbacks实际就是struct OMX_COMPONENTTYPE和struct OMX_CALLBACKTYPE的具体实现。
  • 而这两者就是在OMX_Core.h和 OMX_Component.h中定义的。

kCallbacks在哪里使用呢?看一下OMX.cpp中的allocateNode方法中的代码:

事件处理函数传给了组件ComponentInstance。也就是传给了具体芯片平台相关的OMX IL 层。 当组件有事件发生时,就会调用OMXNodeInstance中这几个注册过的事件处理函数:

而这几个函数又会去调用OMX中对应的函数,也就是下面这三个:

总结以上代码如下:

  • 这几个函数都采用相同的方式:
  • 根据node_id找到CallbackDispatcher,并把事件信息post过去。 也就是:findDispatcher(node)->post(msg)。

进一步,须要了解CallbackDispatcher的实现机制。它内部开启了一个线程,使用了信号量机制(signal)。 findDispatcher(node)->post(msg)是一个异步操作,只把msg给POST过去,不会等待事件处理完毕就返回了。

问题来了,那么CallbackDispatcher是怎么处理接收到的msg呢? 看以下代码:

这样事件最终还是跨Binder又传到了OMXCodec里面去,交给OMXCodecObserver了。也就是交给了调用OMX service的client端了。 将回调的发生,从service端发送到了client端。

最后,总结一下前面:

  • 1、AwesomePlayer初始化过程中,中通过initVideoDecoder / init AudioDecoder来创建video/Audio解码器mVideoSource/mAudioSource
  • 2、mVideoSource 中通过mVideoTrack来demux 媒体文件,从中获得文件编码格式,继而得到需要的解码器类型,通过类型调用omx->allocateNode 创建OMX node实例与编码格式对应。以后都是通过node实例来操作实际的硬件解码器。
  • 3、MediaPlayerService对象初始化的时候会创建OMX对象,OMX对象的构造函数会创建mMaster,mMaster负责获得与管理硬件平台的硬件解码器组件库。
  • 4、在 omx->allocateNode中 通过mMaster->makeComponentInstance 来创建真正对应的解码器组件。这个解码器组件是完成之后实质的解码工作的。
  • 5、在创建mMaster->makeComponentInstance过程中,也是通过上面mVideoTrack 过来的解码器类型名,找到相对应的解码器的库,然后实例化。
  • 6、解码Component通过输入Port和输出Port来进行交互,通过和OMXCodec共享buffer来进行编解码。
  • 7、AwesomePlayer中包含了mVideoSource,初始化时指向OMXCodec的实际对象。OMXCodec使用了Binder机制,实现了对OMX服务的远程调用,其中IOMX作为接口类定义了OMX的大部分接口函数。
  • 8、OMX的具体实现时,OMXMaster类用于管理OMX的插件,OMXNodeInstance类代表OMX的具体实例,完成和Component的调用和交互,
  • 9、CallbackDispatcher用于调度处理回调函数传回的消息。OMXNodeInstance和CallbackDispatcher一一对应,协同工作,完成不同实例的消息处理。
  • 10、OMXNodeInstance是OMX端的概念,是service端的概念。其service端与OMX在一个进程空间中。
  • 11、OMXObserver是OMXCodec端的概念,是client端的概念。其service端与OMXCodec在一个进程空间中。其Bn,Bp 方向和OMX,OMXNodeInstance相反。主要是用来反向通知onMessage消息 到此,我们就介绍完了awesomeplayer是如何对OMX初始化,以及如何关联到对应硬件平台上的HW decoder的。

原文发布于微信公众号 - 何俊林(DriodDeveloper)

原文发表时间:2016-09-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

码农突围

0 篇文章93 人订阅

相关文章

来自专栏JackeyGao的博客

用户Python3解析超大的csv文件

我在日前获得一个任务,为了做分析, 从一个超大的csv文件中解析email地址和对应的日期时间戳然后插入到数据库中. 我知道有其他工具可以方便的完成我的工作(比...

11120
来自专栏FreeBuf

Windows内核漏洞CVE-2016-0143分析

0x00 背景 4月20日,Nils Sommer在exploitdb上爆出了一枚新的Windows内核漏洞PoC。该漏洞影响所有版本的Windows操作系统,...

24060
来自专栏坚毅的PHP

关于java

大整数10进制转16进制问题 google了都没什么好的解决方法,因为要转换的十进制有300多位,long都装不下,没有直接可用的函数可以拿来用 王总的方法分享...

34180
来自专栏FreeBuf

缓冲区溢出攻击初学者手册(更新版)

说明 之前版本翻译质量不佳,本人赵阳在这里对本文的读者表示深深的歉意。由于本人的疏忽和大意导致您不能很好的读完这篇文章,同时也对原文内容进行了破坏,也对IDF和...

30290
来自专栏前端达人

JavaScript基础——回调(callback)是什么

上篇文章《JavaScript基础——你真的了解JavaScript吗?》,我们明白了JavaScript是一个单线程、非阻塞、异步、解释性语言,清楚了什么是单...

25270
来自专栏高爽的专栏

Hession反序列化导致CPU占用飙高

背景 今天发布一个线上服务,暂且称之为O,发布完后,依赖O服务的2个服务C和W大量Time报警,并且这两个服务的CPU占用都飙到了40%左右,平时只有10%的样...

41500
来自专栏鹅厂少年的奇妙之旅

Go内存模型

Go语言中内存分配大致有3种模式:Stack、Heap、Fixed Size Segment。

80250
来自专栏编程

看我是如何把SQLMap里的功能移植到我的程序的

不知道各位有没有听过不要重复造轮子?因为有些开源的工具,它们经过时间和众人的捶打,其实会比我们自己一个人造出来的轮子考虑的更加周到和全面。可是有时候有些开源工具...

216100
来自专栏梧雨北辰的开发录

iOS面试知识总结之基本概念总结

凡经历过iOS面试的我们总会发觉,即使实际开发中做过许多项目,也难免为一个普通的面试题受挫。这也许不是因为我们技术不过关,而是因为在平时我们忽略了怎样将用到的知...

41970
来自专栏老马寒门IT

Node入门教程(13)第十一章:mocha单元测试+should断言库+istanbul覆盖率测试+art-template

声明: 以下为老马的全栈视频教程的笔记,如果需要了解详情,请直接配合视频学习。视频全部免费,视频地址:https://ke.qq.com/course/2945...

16000

扫码关注云+社区

领取腾讯云代金券