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

这一节我们将了解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. GAN的一些问题

    GAN为什么难以训练? 大多深度模型的训练都使用优化算法寻找损失函数比较低的值.优化算法通常是个可靠的"下山"过程.生成对抗神经网络要求双方在博弈的过程中达到势均力敌(均衡).每个 ...

  2. sql 语句系列(多表之链二)[八百章之第四章]

    从多个表中返回缺失值 比如说查询每个员工的部门,且查看部门的所有员工. 这里考虑一种情况就是可能有部门没有员工,同样有些员工还没有分配部门. 解析使用 full outer join. select ...

  3. 力扣13(java)-罗马数字转整数(简单)

    题目: 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值I 1V 5X 10L 50C 100D 500M 1000例如, 罗马数字 2 写做 II ,即为两个并列的 1 ...

  4. FileStream 的 FlushAsync 方法在 .NET Framework 与 .NET Core 行为的不同

    本文记录 FileStream 的 FlushAsync 方法在 .NET Framework 与 .NET Core 行为的不同 在使用 HID 设备进行 IO 通讯时,可以采用 FileStrea ...

  5. Vue3 和 Vue2 的异同及开发中具体区别

    目录 总体来说 性能提升 树摇(Tree shaking) 碎片化节点(Fragment) 传送门 (Teleport) Suspense 更好的TypeScript支持 Composition AP ...

  6. AtCoder Beginner Contest 333

    总结 人生第一次掉rating 各种降智操作 A 水题 B 逆天操作 WA了3发 第三次交的时候以为过了,等到切完E发现怎么B还没过( #include<bits/stdc++.h> us ...

  7. 【OpenVINO™】使用OpenVINO™ C# API 部署 YOLO-World实现实时开放词汇对象检测

    YOLO-World是一个融合了实时目标检测与增强现实(AR)技术的创新平台,旨在将现实世界与数字世界无缝对接.该平台以YOLO(You Only Look Once)算法为核心,实现了对视频中物体的 ...

  8. 安装pyenv-win(windows 环境)支持多个python环境管理

    安装pyenv-win(windows 环境)支持多个python环境管理 https://blog.csdn.net/dair6/article/details/129128240

  9. go http请求如果参数中带有"等特殊字符,参数传输可能会出现问题

    编码完整的URL url.QueryEscape(urlStr) 编码完整的URL 如果我们要对完整的 URL 进行编码呢? 就是PHP中 urlencode() 函数的功能. 在 GO 语言下可以直 ...

  10. 一篇文章让你掌握99%的Python运算符。干货很多,建议收藏!!!

    Python 中的运算符是编程中的基础概念,用于执行各种操作和数据计算.以下是一些 Python 中的主要运算符的概述: 运算符 1. 算术运算符 算术运算符语法规则 +:加法 -:减法 *:乘法 / ...