Android OMX
AwesomePlayer 中 媒体流buffer 中的传递
一 OMXClient
AwesomePlayer 在创建OMXCodec 的时候调用了mClient.interface()。 mClient 类型为: OMXClient.OMXClient 负责OMX的客户端调用。
status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false, // createEncoder
mVideoTrack,
NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
}
status_t AwesomePlayer::initAudioDecoder() {
mAudioSource = OMXCodec::Create(
mClient.interface(), mAudioTrack->getFormat(),
false, // createEncoder
mAudioTrack);
}
}
看下OMXClient的头文件:interface函数返回一个 sp 类型的 mOMX。
class OMXClient {
public:
OMXClient();
status_t connect();
void disconnect();
sp<IOMX> interface() {
return mOMX;
}
private:
sp<IOMX> mOMX;
OMXClient(const OMXClient &);
OMXClient &operator=(const OMXClient &);
};
在OMXClient.cpp 文件中是OMXClient 的实现,三个函数,构造函数为空;connect 函数中获取binder系统服务,然后获取到 MediaPlayerService 的binder服务,从MediaPlayerService获取了一个IOMX mOMX = service->getOMX();
看来OMX 也是binder架构的,OMX 为MediaPlayerService 上的一个匿名binder。
那就看看OMX Binder 架构。OMX继承BnOMX,为服务端。
OMXClient::OMXClient() {
}
status_t OMXClient::connect() {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
mOMX = service->getOMX();
if (!mOMX->livesLocally(NULL /* node */, getpid())) {
ALOGI("Using client-side OMX mux.");
mOMX = new MuxOMX(mOMX);
}
return OK;
}
void OMXClient::disconnect() {
if (mOMX.get() != NULL) {
mOMX.clear();
mOMX = NULL;
}
}
AwesomePlayer 持有一个OMXClient类型的mClient。interface()返回一个OMX的代理。
看到这里好像完了,等等,下面几行代码好像有些不大一样,通常我们获取到service 以后就拿到了Binder的Bp 代理端,可以直接返回了。有两点值得注意:
1. 为什么下面还要判断livesLocally 呢;
2. 又new 了一个MuxOMX ,MuxOMX 是什么鬼?
二 MuxOMX
看看livesLocally 函数定义. livesLocally 生活在本地,生活服务O2O,美团糯米大战吗,扯远了。判断pid是不是在一个进程,
StagefrightPlayer 和MediaPlayerService 是一个进程,return true, 果然是本地服务。那 mOMX = new MuxOMX(mOMX); 这句代码就没有执行,Android4.0 以后的版本中是可以在java 层中调用codec 的,就不在一个进程了,看来要执行这句代码了。在不在一个进程执行很关键,如果在一个进程中 mOMX = service->getOMX(); 的mOMX 对象为BnOMX 就是OMX类。如果不是在一个进程中mOMX 对象为BpOMX 就要走mOMX = new MuxOMX(mOMX)。
OMX.cpp
bool OMX::livesLocally(node_id node, pid_t pid) {
return pid == getpid();
}
看第二个问题 MuxOMX 是什么。MuxOMX 构造中赋值为mRemoteOMX。通常我们在binder 的代理端会持有一个Bpbinder 对象,上边已经获取了BpOMX 然后赋值mRemoteOMX,那mLocalOMX 干嘛呢? 晕 mLocalOMX 也是OMX。
MuOMX 函数调用的时候都会通过getOMX 来决定获取的是 mLocalOMX 还是mRemoteOMX. getOMX根据什么判断呢,node 是否在mIsLocalNode 中。在分配node 的时候可以看到,如果是软解码,node 就会加入到mIsLocalNode 容器中。
因此这个问题可以总结下:
1. 如果是软件码,OMX 和程序运行在一个进程
2. 如果是硬解码在StagefrightPlayer 也是运行在一个进程,在APP 通过binder 跨进程调用。
struct MuxOMX : public IOMX {
......
private:
sp<IOMX> mRemoteOMX;
sp<IOMX> mLocalOMX;
}
MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
: mRemoteOMX(remoteOMX) {
}
bool MuxOMX::isLocalNode(node_id node) const {
Mutex::Autolock autoLock(mLock);
return isLocalNode_l(node);
}
bool MuxOMX::isLocalNode_l(node_id node) const {
return mIsLocalNode.indexOfKey(node) >= 0;
}
// static
bool MuxOMX::IsSoftwareComponent(const char *name) {
return !strncasecmp(name, "OMX.google.", 11);
}
const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
}
status_t MuxOMX::listNodes(List<ComponentInfo> *list) {
Mutex::Autolock autoLock(mLock);
if (mLocalOMX == NULL) {
mLocalOMX = new OMX;
}
return mLocalOMX->listNodes(list);
}
status_t MuxOMX::allocateNode(
const char *name, const sp<IOMXObserver> &observer,
node_id *node) {
Mutex::Autolock autoLock(mLock);
sp<IOMX> omx;
if (IsSoftwareComponent(name)) {
if (mLocalOMX == NULL) {
mLocalOMX = new OMX;
}
omx = mLocalOMX;
} else {
omx = mRemoteOMX;
}
status_t err = omx->allocateNode(name, observer, node);
if (err != OK) {
return err;
}
if (omx == mLocalOMX) {
mIsLocalNode.add(*node, true);
}
return OK;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNMGzT9c-1585192476143)(https://www.processon.com/chart_image/581c705ce4b0c6fe57196996.png)]
三 OMX 类
OMX 类负责真正的是解码 编码解码的服务总管。主要是通过OMXMaster 加载解码器;OMXNodeInstance 负责函数调用。
OMXMaster *mMaster;
OMX::OMX()
: mMaster(new OMXMaster),
mNodeCounter(0) {
}
1.OMXMaster
在OMX 的构造函数中初始化了mMaster, mMaster 为OMXMaster 类型,在头文件中定义了几个函数,主要用于加载解码器插件,原理是dlopen dlsym, 需要export 的API定义在OMX_Component.h。 addVendorPlugin 加载厂商的硬解码,封装在libstagefrighthw.so 中;addPlugin(new SoftOMXPlugin) 加载软解码。所有的解码插件保存在 List<OMXPluginBase *> mPlugins; 真正的操作封装在OMXNodeInstance类中。
struct OMXMaster : public OMXPluginBase {
private:
List<OMXPluginBase *> mPlugins;
KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
KeyedVector<OMX_COMPONENTTYPE *, OMXPluginBase *> mPluginByInstance;
void addVendorPlugin();
void addPlugin(const char *libname);
void addPlugin(OMXPluginBase *plugin);
void clearPlugins();
};
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
addVendorPlugin();
addPlugin(new SoftOMXPlugin);
}
void OMXMaster::addVendorPlugin() {
addPlugin("libstagefrighthw.so");
}
void OMXMaster::addPlugin(const char *libname) {
mVendorLibHandle = dlopen(libname, RTLD_NOW);
if (mVendorLibHandle == NULL) {
return;
}
typedef OMXPluginBase *(*CreateOMXPluginFunc)();
CreateOMXPluginFunc createOMXPlugin =
(CreateOMXPluginFunc)dlsym(
mVendorLibHandle, "createOMXPlugin");
if (!createOMXPlugin)
createOMXPlugin = (CreateOMXPluginFunc)dlsym(
mVendorLibHandle, "_ZN7android15createOMXPluginEv");
if (createOMXPlugin) {
addPlugin((*createOMXPlugin)());
}
}
void OMXMaster::addPlugin(OMXPluginBase *plugin) {
Mutex::Autolock autoLock(mLock);
mPlugins.push_back(plugin);
OMX_U32 index = 0;
......
}
2. OMXNodeInstance
OMXNodeInstance 是真正的API调用的地方。在OMX中通过 findInstance(node) 获取OMXNodeInstance实例。 在上面的分析中我们一共调用了
allocateNode emptyBuffer fillBuffer 这几个函数
看下这几个函数的实现.
allocateNote
OMXNodeInstance 实例化
在 allocateNote 中,首先new了OMXNodeInstance 实例,然后根据name 通过Master 在List中查找对应的插件,并实例化OMXNodeInstance中需要调用的定义在OMX_Component.h的函数操作。
status_t OMX::allocateNode(
const char *name, const sp<IOMXObserver> &observer, node_id *node) {
Mutex::Autolock autoLock(mLock);
*node = 0;
OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
OMX_COMPONENTTYPE *handle;
OMX_ERRORTYPE err = mMaster->makeComponentInstance(
name, &OMXNodeInstance::kCallbacks,
instance, &handle);
if (err != OMX_ErrorNone) {
ALOGV("FAILED to allocate omx component '%s'", name);
instance->onGetHandleFailed();
return UNKNOWN_ERROR;
}
*node = makeNodeID(instance);
mDispatchers.add(*node, new CallbackDispatcher(instance));
instance->setHandle(*node, handle);
mLiveNodes.add(observer->asBinder(), instance);
observer->asBinder()->linkToDeath(this);
return OK;
}
可以通过SoftOMXPlugin查看function实例化的调用流程为
OMXMaster::makeComponentInstance ->
SoftOMXPlugin::makeComponentInstance
OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
for (size_t i = 0; i < kNumComponents; ++i) {
if (strcmp(name, kComponents[i].mName)) {
continue;
}
AString libName = "libstagefright_soft_";
libName.append(kComponents[i].mLibNameSuffix);
libName.append(".so");
void *libHandle = dlopen(libName.c_str(), RTLD_NOW);
typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(
const char *, const OMX_CALLBACKTYPE *,
OMX_PTR, OMX_COMPONENTTYPE **);
CreateSoftOMXComponentFunc createSoftOMXComponent =
(CreateSoftOMXComponentFunc)dlsym(
libHandle,
"_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
"PvPP17OMX_COMPONENTTYPE");
sp<SoftOMXComponent> codec =
(*createSoftOMXComponent)(name, callbacks, appData, component);
......
}
return OMX_ErrorInvalidComponentName;
}
分配node_id
完成 实例化后调用makeNodeID 分配node_id; 分配node_id 类型为void *;其实是一个int 指针,指示对应的OMXNodeInstance 在mNodeIDToInstance 的位置。
typedef node_id void *
OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
// mLock is already held.
node_id node = (node_id)++mNodeCounter;
mNodeIDToInstance.add(node, instance);
return node;
}
emptyBuffer
OMX 的emptyBuffer 直接通过findInstance调用到了实例对应的OMXNodeInstance 的emptyBuffer.
status_t OMX::emptyBuffer(
node_id node,
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp) {
return findInstance(node)->emptyBuffer(
buffer, range_offset, range_length, flags, timestamp);
}
看下OMXNodeInstance 的emptyBuffer的实现:最终调用到so中的OMX_EmptyThisBuffer
status_t OMXNodeInstance::emptyBuffer(
OMX::buffer_id buffer,
OMX_U32 rangeOffset, OMX_U32 rangeLength,
OMX_U32 flags, OMX_TICKS timestamp) {
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
header->nFilledLen = rangeLength;
header->nOffset = rangeOffset;
header->nFlags = flags;
header->nTimeStamp = timestamp;
BufferMeta *buffer_meta =
static_cast<BufferMeta *>(header->pAppPrivate);
buffer_meta->CopyToOMX(header);
OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
return StatusFromOMXError(err);
}
fillBuffer
和emptyBuffer 类似:
status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
header->nFilledLen = 0;
header->nOffset = 0;
header->nFlags = 0;
OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
return StatusFromOMXError(err);
}