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

这一节我们将了解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. leetcode-数组中两元素的最大乘积

    题目描述 给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值. 请你计算并返回该式的最大值. 示例 1: 输入:nums ...

  2. 直播预告丨Hello HarmonyOS进阶课程第四课——ArkUI动画开发

    为了帮助初识HarmonyOS的开发者快速入门,我们曾推出Hello HarmonyOS系列课程,从最基础的配置IDE和创建Hello World开始,详细介绍HarmonyOS基础.开发环境搭建.I ...

  3. Java多线程之Callable和Future

    Java多线程之Callable和Future 本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果. Callable接口类似于Runnable,从名字就可以看出来 ...

  4. ImageJ软件使用教程(二):图像测量

    目录 图像比例尺 加载图像 设置比例尺 标注比例尺 测量长度面积 测量长度 测量面积 参考资料 图像比例尺 使用ImageJ软件测量图像中的长度.面积等信息时,需要先设置图像的比例尺,比例尺用于将图像 ...

  5. 纯CSS实现带小三角提示框

    要实现在页面上点击指定元素时,弹出一个信息提示框.在前面的文章中,我们已经简单介绍了如何使用纯 CSS 创建一个三角形.本文在此基础上,记录如何使用 CSS 创建带三角形的提示框. 实现的原理是创建一 ...

  6. requests模块发送post请求,flask开启服务接收请求,python

    request模块部分 import requests import json if __name__ == '__main__': url = 'http://127.0.0.1:5000' dat ...

  7. pypinyin 获取拼音,作为智能设备的唤醒比对结果

    from pypinyin import lazy_pinyin,TONE,TONE2,TONE3,NORMAL a = "小七同学" b = "小琦同学" c ...

  8. drf视图类的继承关系

  9. ARMS企业级场景被集成场景介绍

    简介: ARMS企业级场景被集成场景介绍 通过本次最佳实践内容,您可以看到ARMS OpenAPI可以灵活的被集成到客户链路监控场景,并对其进行可视化图形展示监控信息. 1. 背景信息 应用实时监控服 ...

  10. 如何用 Nacos 构建服务网格生态

    ​简介: Nacos 在阿里巴巴起源于 2008 年五彩石项目(该项目完成微服务拆分和业务中台建设),成长于十年的阿里双十一峰值考验,这一阶段主要帮助业务解决微服务的扩展性和高可用问题,解决了百万实例 ...