关注公众号免费阅读全文,进入音视频开发技术分享群!

这一节我们将了解Android OpenMax框架,该框架了解完成之后,我们会再回过头去了解 ACodec,将 MediaCodec - ACodec - OpenMax 连接起来,了解组件的创建控制以及 buffer 的流转。
本篇属于个人学习笔记,如有错误欢迎指出。

我将Android OpenMax框架分为3个部分来学习:

  1. media.codec service:vendor下的HIDL服务,用于查询平台编解码能力,创建/管理编解码组件;
  2. OpenMax IL:OpenMax 框架标准接口,底层编解码组件须实现这些接口;
  3. OMXNodeInstance:OpenMax AL 完成 OpenMax IL层的封装与调用,提供给上层 ACodec 调用;

这一节我们先来了解下相关的代码路径:

  1. hardware/interfaces/media/omx/1.0: 目录下定义有 media.codec 提供的 HIDL service 接口,我们接触比较多的是IOmx.halIOmxStore.halIOmxStore.hal以及IOmxNode.hal
  2. frameworks/av/services/mediacodec:目录下是 media.codec service 实现文件,编译后会生成 android.hardware.media.omx@1.0-service,位于板子 /vendor/bin/hw 目录下;
  3. frameworks/av/media/libstagefright/omx:目录下放有 media.codec service 的 Bn 端实现,以及一些工具OMXUtils.cpp
  4. frameworks/native/headers/media_plugin/media/openmax:目录下放有 OpenMax 的标准接口,底层 Omx Component 需要实现这些标准接口,上层 ACodec 也需要按照标准接口来调用;
  5. frameworks/av/media/libmedia/omx
    frameworks/av/media/libmedia/omx/1.0:
    以上两个目录下放有对 HIDL 调用的封装,封装有两种类型,一种是 LW (Legacy Wrapper)开头的类,另一种是 TW(Treble Wrapper)开头的。

接下来我们来看这些文件是如何使用的?

media.codec 作为一个 HIDL service 首先要有接口定义,我们查看 hardware/interfaces/media/omx/1.0 目录,可以发现 OpenMax 相关的类定义都是以大写的 I 开头,后面接上 Omx(这里的 O 是大写, mx 是小写)。

接着看 frameworks/av/media/libstagefright/omx/1 目录,路径下看到有 Omx.cppOmxStore.cpp,这两个就是 media.codec 的 native 实现,但是我们似乎没看到 IOmxNode ?不要着急我们先接着往下看。

实现了服务相关的文件,那么就要开启进程启动服务了,相关的代码在 frameworks/av/services/mediacodec 下,阅读 main_codecservice.cpp 的代码我们很容易就看出这个进程提供两个服务 IOmxIOmxStore,具体的代码这里不再展开,所以上面提到的 IOmxNode 并不是一个服务,而是服务提供的内容,接下来的问题就是内容实现在哪里呢?

服务启动后我们要获取并调用服务,这里就要看 ACodec 的代码了:

    sp<CodecObserver> observer = new CodecObserver(notify);
sp<IOMX> omx;
sp<IOMXNode> omxNode;
status_t err = NAME_NOT_FOUND;
OMXClient client;
if (client.connect(owner.c_str()) != OK) {
return false;
}
omx = client.interface();
int prevPriority = androidGetThreadPriority(tid);
err = omx->allocateNode(componentName.c_str(), observer, &omxNode);

这里看到 ACodec 并没有获取 IOmx 服务,而是使用 OMXClient 封装了服务获取过程,接着再调用其 interface 接口返回获取的服务代理,不过这里有点要注意,返回代理的类型是 IOMX(三个字母都是大写),并不是之前提到的 IOmx,里面发生了什么?

status_t OMXClient::connect(const char* name) {
using namespace ::android::hardware::media::omx::V1_0;
if (name == nullptr) {
name = "default";
}
sp<IOmx> tOmx = IOmx::getService(name);
if (tOmx.get() == nullptr) {
ALOGE("Cannot obtain IOmx service.");
return NO_INIT;
}
if (!tOmx->isRemote()) {
ALOGE("IOmx service running in passthrough mode.");
return NO_INIT;
}
mOMX = new utils::LWOmx(tOmx);
ALOGI("IOmx service obtained");
return OK;
}

从 OMXClient::connect 我们可以看到,内部获取的服务代理类型仍为 IOmx,但是又对该代理做了一层封装。IOmx 是一个 Treble 类型的对象,LWOmx 是一个 Legacy 类型的对象。

我们都知道调用 Treble 对象方法时会比较麻烦,要回传函数调用返回值时需要构造一个Lambda函数;Legacy 对象的使用是符合我们常规使用习惯的对象。所以,将 IOmx 封装成为 LWOmx 是为了封装 HIDL 调用,简化使用。

WOmx.h 位于 frameworks/av/media/libmedia/include/media/omx/1.0,可以看到它是继承于 IOMX的,再看 IOMX.h 可以发现其方法名和 IOmx 提供的服务是一致的,那这里就验证了我们的猜想:IOMX 是对 IOmx 代理调用的封装。

与之类似的,调用 IOmx 服务获取 IOmxNode 对象后也要将其封装成为 LW 类型,以便后续的使用:

status_t LWOmx::allocateNode(
char const* name,
sp<IOMXObserver> const& observer,
sp<IOMXNode>* omxNode) {
status_t fnStatus;
status_t transStatus = toStatusT(mBase->allocateNode(
name, new TWOmxObserver(observer),
[&fnStatus, omxNode](Status status, sp<IOmxNode> const& node) {
fnStatus = toStatusT(status);
*omxNode = new LWOmxNode(node);
}));
return transStatus == NO_ERROR ? fnStatus : transStatus;
}

上面都是讲 mediaserver 进程使用 media.codec 进程的服务代理,那有没有反过来调用的情况?当然是有的。

还是看 LWOmx::allocateNode,我们会传入一个 CodecObserver 对象用于接收Omx Callback,但是CodecObserver 是继承于 BnOMXObserver 的,这里会有个问题,CodecObserver 将无法通过 HIDL 调用传递给 media.codec 进程,所以调用之前 LWOmx::allocateNode 将 CodecObserver 封装到了 TWOmxObserver 以便该对象可以通过 HIDL 传输。

struct TWOmxObserver : public IOmxObserver {
sp<IOMXObserver> mBase;
TWOmxObserver(sp<IOMXObserver> const& base);
Return<void> onMessages(const hidl_vec<Message>& tMessages) override;
};

TWOmxObserver 继承于IOmxObserver 接口,因此可以在 HIDL 中进行传输,这也是 TW (Treble Wrapper)的作用。

再看 frameworks/av/media/libmedia/include/media/omx/1.0/WOmxObserver.h 里面还有个 LWOmxObserver ,它的作用上面我们已经讲过了,是将 mediaserver 进程传过来的 TWOmxObserver 对象进行封装,达到简化 HIDL 调用的目的。


这一节我们对 Android OpenMax 相关的文件以及类做了简单介绍,了解这些之后我们再追代码就可以忽略掉一些中间层,后期如果相关的写作疑问也可以参考这里。

Android 13 - Media框架(13)- OpenMax(一)的更多相关文章

  1. 简析Android 兼容性测试框架CTS使用

    一.什么是兼容性测试? 1)为用户提供最好的用户体验,让更多高质量的APP可以顺利的运行在此平台上 2)让程序员能为此平台写更多的高质量的应用程序 3)可以更好的利用Android应用市场 二.CTS ...

  2. 15 个 Android 通用流行框架大全(转)

    1. 缓存 DiskLruCache    Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picas ...

  3. Android 通用流行框架

    原文出处: http://android.jobbole.com/83028/ 1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Andro ...

  4. 经受时间沉淀的15 个 Android 通用流行框架大全

    1. 缓存 名称描述 DiskLruCache: Java实现基于LRU的磁盘缓存 2.图片加载 名称描述 Android    Universal Image Loader 一个强大的加载,缓存,展 ...

  5. Android通用流行框架大全

    1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图 ...

  6. 60.Android通用流行框架大全

    转载:https://segmentfault.com/a/1190000005073746 Android通用流行框架大全 1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的 ...

  7. 15 个 Android 通用流行框架大全

      1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展 ...

  8. Android 通用流行框架大全

    1. 缓存 DiskLruCache    Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picas ...

  9. 玩转Android之数据库框架greenDAO3.0使用指南

    用过ActiveAndroid.玩过ORMLite,穿过千山万水,最终还是发现greenDAO好用,ActiveAndroid我之前有一篇文章介绍过 玩转Android之数据库框架ActiveAndr ...

  10. Android的MVC框架

    http://www.cnblogs.com/wanghafan/archive/2012/07/20/2600786.html MVC是当前比较流行的框架,随便Google下,就可以发现几乎所有的应 ...

随机推荐

  1. Rancher 系列文章-K3S 集群升级

    概述 书接上回:<Rancher 系列文章-Rancher 升级>, 我们提到:将 Rancher 用 Helm 从 v2.6.3 升级到 v2.6.4. 接下来开始进行 K3S 集群的升 ...

  2. 分享一款嵌入式开源按键框架代码工程MultiButton

    一.工程简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块. Github地址:https://github.com/0x1abin/MultiButton 这个项目非常精简,只 ...

  3. 一些奇奇怪怪的js知识

    0.关于前端为什么typeof null 得到的结果是 object 对于 null 来说,很多人会认为他是个对象类型,其实这是错误的. 虽然 `typeof null` 会输出 `object`,但 ...

  4. JavaServlet类

    "感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" 介绍Ser ...

  5. Borůvka MST算法

    当我认为最MST(最小生成树)已经没有什么学的了,才发现世界上还有个这个kruskal和prim结合的玩意 Borůvka 运用并查集的思想,先将每一个初始点集初始化为有且只有自己的点集,然后每一次合 ...

  6. 力扣610(MySQL)-判断三角形(简单)

    题目: 表: Triangle 写一个SQL查询,每三个线段报告它们是否可以形成一个三角形. 以 任意顺序 返回结果表. 查询结果格式如下所示. 示例1:  解题思路: 判断是否形成三角形的准则是:两 ...

  7. 力扣121(java&python)-买卖股票的最佳时机(简单)

    题目: 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格. 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票.设计一 ...

  8. 力扣2(java&python)-两数相加(中等)

    题目: 给你两个 非空 的链表,表示两个非负的整数.它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字. 请你将两个数相加,并以相同形式返回一个表示和的链表. 你可以假设除了数 ...

  9. 一文详解 Serverless 架构模式

    什么是 Serverless 架构?按照 CNCF 对 Serverless 计算的定义,Serverless 架构应该是采用 FaaS(函数即服务)和 BaaS(后端服务)服务来解决问题的一种设计. ...

  10. 10亿+文件数压测,阿里云JindoFS轻松应对

    简介: Apache Hadoop FileSystem (HDFS) 是被广为使用的大数据存储方案,其核心元数据服务 NameNode 将全部元数据存放在内存中,因此所能承载的元数据规模受限于内存, ...