这一节我们将了解Android OpenMax框架,该框架了解完成之后,我们会再回过头去了解 ACodec,将 MediaCodec - ACodec - OpenMax 连接起来,了解组件的创建控制以及 buffer 的流转。
本篇属于个人学习笔记,如有错误欢迎指出。
我将Android OpenMax框架分为3个部分来学习:
- media.codec service:vendor下的HIDL服务,用于查询平台编解码能力,创建/管理编解码组件;
- OpenMax IL:OpenMax 框架标准接口,底层编解码组件须实现这些接口;
- OMXNodeInstance:OpenMax AL 完成 OpenMax IL层的封装与调用,提供给上层 ACodec 调用;
这一节我们先来了解下相关的代码路径:
- hardware/interfaces/media/omx/1.0: 目录下定义有 media.codec 提供的 HIDL service 接口,我们接触比较多的是
IOmx.hal
,IOmxStore.hal
,IOmxStore.hal
以及IOmxNode.hal
; - frameworks/av/services/mediacodec:目录下是 media.codec service 实现文件,编译后会生成 android.hardware.media.omx@1.0-service,位于板子 /vendor/bin/hw 目录下;
- frameworks/av/media/libstagefright/omx:目录下放有 media.codec service 的 Bn 端实现,以及一些工具
OMXUtils.cpp
; - frameworks/native/headers/media_plugin/media/openmax:目录下放有 OpenMax 的标准接口,底层 Omx Component 需要实现这些标准接口,上层 ACodec 也需要按照标准接口来调用;
- 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.cpp
和 OmxStore.cpp
,这两个就是 media.codec
的 native 实现,但是我们似乎没看到 IOmxNode
?不要着急我们先接着往下看。
实现了服务相关的文件,那么就要开启进程启动服务了,相关的代码在 frameworks/av/services/mediacodec 下,阅读 main_codecservice.cpp
的代码我们很容易就看出这个进程提供两个服务 IOmx
和 IOmxStore
,具体的代码这里不再展开,所以上面提到的 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 调用的目的。文章来源:https://www.toymoban.com/news/detail-737980.html
这一节我们对 Android OpenMax 相关的文件以及类做了简单介绍,了解这些之后我们再追代码就可以忽略掉一些中间层,后期如果相关的写作疑问也可以参考这里。文章来源地址https://www.toymoban.com/news/detail-737980.html
到了这里,关于Android 13 - Media框架(13)- OpenMax(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!