Android音视频——OMX 中 Nodeinstance 列表的管理与节点的操作
Posted 程思扬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android音视频——OMX 中 Nodeinstance 列表的管理与节点的操作相关的知识,希望对你有一定的参考价值。
在我们创建Componentinstance (OMX组件实例)后,需要对它里面的Nodelnstance列表 进行管理。
- OMX对解码器组件Component的使用,是通过OMXNodelnstance来实现的。 OMXNodelnstance
自身的动作包括 Nodeinstance 的生成(allocateNode )和删除
(freeNode)o其实就是对niDispatchers和mNode】DToInstance进行添加和删除。 - mNodelDToInstance 就是一个 key 为 node id» value 为 Nodeinstance 的键/值对列表。而
niDispatchers 就是一个 key 为 node id, value 为 OMX::CallbackDispatcher
的键/值对列 表。并且,每个 Nodeinstance 都拥有一个 0MX::CalIbackDispatchero - CallbackDispatcher的主要作用是在解码器组件Component发出回调动作后,将message
分发给对应的OMXCodec客户端。
在我们了解到OMXNodelnstance列表管理后,每个OMXNodelnstance中都有Node节 点,若你需要给这些Node节点分配一些Buffer,下面看看对Node节点的操作过程。
在/frameworks/av/media/libstagefright/include/OMXNodeInstance.h 中:
struct OMXNodeInstance
OMXNodeInstance(
OMX *owner, const sp<IOMXObserver> &observer, const char *name);
void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
status_t prepareForAdaptivePlayback(
OMX_U32 portIndex, OMX_BOOL enable,
OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
status_t useBuffer(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer, OMX_U32 allottedSize);
//OMX: :Client通过此鹵数将已分配好的Buffer传给OMX服务器端组件,让其使用
status_t allocateBuffer(
OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
void **buffer_data);
//Client通过调用此函数让Component分配Buffer
status_t allocateBufferWithBackup(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer, OMX_U32 allottedSize);
status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
//Client通过调用此函数让Component释放allocateBuffer分配的Buffer
status_t fillBuffer(OMX::buffer_id buffer, int fenceFd);
//Client通过调用此函数传递空的Buffer给Component»让其将处理好的
//数据填入其中。此函数会调用OMX标准接口 OMX_FillThisBuffer
static OMX_ERRORTYPE OnEmptyBufferDone(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
//Buffer的读取后,调用此回调函数,向Client发送EmptyBufferDone消息
static OMX_ERRORTYPE OnFillBufferDone(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
//在Component莞成相应的处理操作并将输出数据填入输出Buffer后,调用此回调 //函数,向 Client 发送 FillBufferDone 消息
sp<GraphicBufferSource> getGraphicBufferSource();
void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
// 处理| msg 124;,并可以对其进行修改。返回true iff完全处理并
// |msg| does not need to be sent to the event listener.
bool handleMessage(omx_message &msg);
OMXNodeInstance(const OMXNodeInstance &);
OMXNodeInstance &operator=(const OMXNodeInstance &);
当执行这些函数时,都是先通过findinstance在mNodelDToInstance列表中找到对应的 Nodeinstance,然后调用Nodelnstance对应的方法。
OMXCodec对具体的component函数的操作,是通过OMXNodelnstance来实现的,如 filIBuffer> emptyBuffer> sendCommand等,它们都是通过OMX Core.h中的宏定义间接调用 OMX_Component.h 的 OMX_COMPONENTTYPE 中的相应函数指针来完成的。OMX_Core.h 和OMX_Compoiient.h都是OpenMAX标准头文件。
OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks =
&OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
;
它把3个OMXNodelnstance类的静态方法注册给了 kCallbacks。kCallbacks实际就是struct OMX COMPONENTTYPE和struct OMX_CALLBACKTYPE的具体实现,而这两者就是在 OMX Core.h 和 OMX_Component.h 中定义的。
在哪里使用kCallbacks呢?下面看看OMX.cpp中的allocateNode函数:
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, name);
OMX_COMPONENTTYPE *handle;
OMX_ERRORTYPE err = mMaster->makeComponentInstance(
name, &OMXNodeInstance::kCallbacks,
instance, &handle);
if (err != OMX_ErrorNone)
ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
instance->onGetHandleFailed();
return StatusFromOMXError(err);
*node = makeNodeID(instance);
mDispatchers.add(*node, new CallbackDispatcher(instance));
instance->setHandle(*node, handle);
mLiveNodes.add(IInterface::asBinder(observer), instance);
IInterface::asBinder(observer)->linkToDeath(this);
return OK;
事件处理函数传给了组件Componentinstance,也就是传给了具体芯片平台相关的OMX IL 层。
当组件有事件发生时,就会调用OMXNodelnstance中这几个注册过的事件处理函数:
OMX_ERRORTYPE OMXNodelnstance::OnEmptyBufferDone
OMX_ERRORTYPE OMXNodelnstance::OnFillBufferDone
OMX_ERRORTYPE OMXNodelnstance::OnEvent
而这几个函数又会调用OMX中对应的函数,也就是下面这3个函数:
OMX_ERRORTYPE OMX::OnEmptyBufferDone
OMX_ERRORTYPE OMX::OnFillBufferDone
OMX_ERRORTYPE OMX::OnEvent
总结一下,这儿个函数都采用相同的方式,即根据n odeid找到Cal I back Dispatcher,并把 事件信息传递出去,也就是findDispatcher(node)->post(msg)o
进一步地,需要了解CallbackDispatcher的实现机制。它内部开启了一个线程,使用了信 号量(signal)机制。
findDispatcher(node)->post(msg)是一个异步操作,只把消息传递过去,不会等待事件处理 完毕就返回。
问题来了,那么CallbackDispatcher是怎么处理接收到的消息的呢?查看以下代码:
bool OMX::CallbackDispatcher::loop()
for (;;)
std::list<omx_message> messages;
Mutex::Autolock autoLock(mLock);
while (!mDone && mQueue.empty())
mQueueChanged.wait(mLock);
if (mDone)
break;
messages.swap(mQueue);
dispatch(messages);
return false;
这样事件最终还是跨Binder传到OMXCodec里面,交给OMXCodecObserver 了« •旦有 关于回调的过程,再从OMX服务器端发送到OMX客户端。我们又知道AwesomePlayer类中 持有OMX客户端,所以这些从OMX组件通知上来的消息就可以到达AwesomePlayer中。这 样就完成了 AwesomePlayer和OMX组件之间的通信。
Android音视频——OpenMAX (OMX)框架
本文分为两个部分进行讲解
Codec 部分中的 AwesomePlayer 到 OMX 服务
前面介绍了NuPlayer最终解码都会到达OMX框架,也就是 OpenMAX框架,本文开始分析编解码部分中的AwesomePlayer到OMX服务过程,也就是开启OpenMAX准备相关内容。Android系统中用OpenMAX来做编解码,Android向上抽象了一 层OMXCodec,提供给上层播放器AwesomePlayer使用。同时有一个IOMX接口,在ACodec 中可以通过IOMX调用OpenMAX组件。播放器中音视频解码器mVideoSource、 mAudioSource 都是 OMXCodec 的实例。
OMXCodec::Create是解码器初始化的入口。OMXCodec通过IOMX依赖Binder机制获得 OMX服务,OMX服务才是OpenMAX在Android中的实现。
OpenMAX与StageFright框架层级的关系
StageFright框架通过OpenMAX与硬件层进行通信,图1是OpenMAX和StageFright的 层级关系图。
在图1中可以看到,StrageFright层共有两路到达OpenMAX框架° 一路是通过NuPlayer 到达ACodec类,然后直接调用OMX IL Core中的接口。另一路是通过StagefrightPlayer到 AwesomePlayer,再到达0MXCodec类,然后调用OMX组件接口进行数据传输。
在以前的AwesomePlayer中,音频和视频数据会到OMXCodec中寻找对应的解码器进行 解码,如图2所示:IOMX和OMX组件通过Binder通信,中间还涉及OMXClient。
OMX 中的OMXNodelnstance负责创建并维护不同的实例,这些实例是根据上面的需求创建的,以 Node作为唯…标识。这样播放器中的每一个OMXCodec在OMX服务器端都有了自己对应的 OMXNodelnstance实例。
OMXMaster维护底层软硬件解码库,根据OMXNodelnstance中想要 的解码器来创建解码实体组件。
OpenMAX和StageFright的层级关系图
AwesomePlayer 与 OMX 的关系
以上是关于Android音视频——OMX 中 Nodeinstance 列表的管理与节点的操作的主要内容,如果未能解决你的问题,请参考以下文章
Android音视频——OMX 中 Nodeinstance 列表的管理与节点的操作