您的位置:首页 > 移动开发 > Android开发

Android_ics openmax in stagefright 学习记录------1

2012-07-17 08:41 495 查看
这几篇文章是之前学习openmax的输出,记录在这里,希望不要误导菜鸟的同时又能得到牛牛们的指导。

android_ics openmax_in_stagefright 再次学习

/*
*在学习android源代码的工程中,一点要时刻牢记C/S架构
*任何时刻都要搞清除,这个时候的代码是运行在客户端,
*还是服务端,这个对象来之,客户端还是服务端的代理。
*/

<---以下的讨论,目的都在于弄清楚,stagefright框架内,OpenMaXIL和各个编解码的组件是如何通信的--->

At first:

OpenMax是事实上的标准,也是android上多媒体编解码框架未来的趋势。

分析的比较凌乱,后面在做整理。

/////////////////////////////////////////////
//1,OMX 从何开始?
////////////////////////////////////////////

看下awesomeplayer的构造函数

AwesomePlayer::AwesomePlayer()
: mQueueStarted(false),
...
mTextPlayer(NULL) {
/*mClient是一个OMXClient类型的成员变量*/
CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
...
mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
mVideoEventPending = false;
mCheckAudioStatusEvent = new AwesomeEvent(
this, &AwesomePlayer::onCheckAudioStatus);
...
}

/*connect函数的定义*/

status_t OMXClient::connect() {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);

CHECK(service.get() != NULL);

mOMX = service->getOMX();
CHECK(mOMX.get() != NULL);

return OK;
}

上面的函数,通过binder取请求MediaPlayerService的getOmx然后反回一个OMX实例,事实上这个时候在awesomePlayer
中的mOMX是一个来之服务端的实例。打通了一条Client->Service的通道。个人认为这就是OpenMax框架的入口。

/*OMX的构造函数如下,@OMX.cpp*/
OMX::OMX():mMaster(new OMXMaster),mNodeCounter(0) {
}

-------------------------以下是插曲,首次看请忽略--------------------------------------------------------->
/*下面完整的贴出OMX的结构,其中有些成员的作用,在后面的学习中,会慢慢的揭开其真面目*/
class OMX : public BnOMX,
public IBinder::DeathRecipient {
public:
OMX();

virtual bool livesLocally(pid_t pid);

virtual status_t listNodes(List<ComponentInfo> *list);

virtual status_t allocateNode(
const char *name, const sp<IOMXObserver> &observer, node_id *node);

virtual status_t freeNode(node_id node);

virtual status_t sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);

virtual status_t getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size);

virtual status_t setParameter(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size);

virtual status_t getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size);

virtual status_t setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size);

virtual status_t getState(
node_id node, OMX_STATETYPE* state);

virtual status_t enableGraphicBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable);

virtual status_t getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage);

virtual status_t storeMetaDataInBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable);

virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer);

virtual status_t useGraphicBuffer(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer);

virtual status_t allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data);

virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer);

virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer);

virtual status_t fillBuffer(node_id node, buffer_id buffer);

virtual status_t emptyBuffer(
node_id node,
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp);

virtual status_t getExtensionIndex(
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index);

virtual void binderDied(const wp<IBinder> &the_late_who);

OMX_ERRORTYPE OnEvent(
node_id node,
OMX_IN OMX_EVENTTYPE eEvent,
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData);

OMX_ERRORTYPE OnEmptyBufferDone(
node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);

OMX_ERRORTYPE OnFillBufferDone(
node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);

void invalidateNodeID(node_id node);

protected:
virtual ~OMX();

private:
struct CallbackDispatcherThread;  //关注下
struct CallbackDispatcher;		  //关注下

Mutex mLock;
OMXMaster *mMaster;
int32_t mNodeCounter;

KeyedVector<wp<IBinder>, OMXNodeInstance *> mLiveNodes;
KeyedVector<node_id, OMXNodeInstance *> mNodeIDToInstance;
KeyedVector<node_id, sp<CallbackDispatcher> > mDispatchers;

node_id makeNodeID(OMXNodeInstance *instance);
OMXNodeInstance *findInstance(node_id node);
sp<CallbackDispatcher> findDispatcher(node_id node);

void invalidateNodeID_l(node_id node);

OMX(const OMX &);
OMX &operator=(const OMX &);
};

}  // namespace android

#endif  // ANDROID_OMX_H_
<-------------------------以上是插曲,首次看请忽略---------------------------------------------------------

可以看到,在构造OMX的时候,会new一个OMXMaster给成员变量mMaster,这个mMaster是对OMXPluginBase(基类)
类型的插件的管理,其中各个插件在ICS的框架中就是软硬件编解码的插件。

#ifndef OMX_MASTER_H_

#define OMX_MASTER_H_

#include <media/stagefright/OMXPluginBase.h>

#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/String8.h>

namespace android {

struct OMXMaster : public OMXPluginBase {
OMXMaster();
virtual ~OMXMaster();

virtual OMX_ERRORTYPE makeComponentInstance(     //符合OpenMAX标准的接口
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component);

virtual OMX_ERRORTYPE destroyComponentInstance(  //符合OpenMAX标准的接口
OMX_COMPONENTTYPE *component);

virtual OMX_ERRORTYPE enumerateComponents(       //符合OpenMAX标准的接口
OMX_STRING name,
size_t size,
OMX_U32 index);

virtual OMX_ERRORTYPE getRolesOfComponent(		 //符合OpenMAX标准的接口
const char *name,
Vector<String8> *roles);

private:
Mutex mLock;
List<OMXPluginBase *> mPlugins;
KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
KeyedVector<OMX_COMPONENTTYPE *, OMXPluginBase *> mPluginByInstance;

void *mVendorLibHandle;

void addVendorPlugin();
void addPlugin(const char *libname);
void addPlugin(OMXPluginBase *plugin);
void clearPlugins();

OMXMaster(const OMXMaster &);
OMXMaster &operator=(const OMXMaster &);
};

}  // namespace android

#endif  // OMX_MASTER_H_

-----到目前为止,android2.3和ICS在该部分没有明显区别-----

在OMXMaster的构造函数中,就开始不同了。

////2.3////
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
addVendorPlugin();

#ifndef NO_OPENCORE
addPlugin(new OMXPVCodecsPlugin);
#endif
}
2.3中,硬解部分还是使用原来OMX的标准来进行即addVendorPlugin(),然后软件部分的话,在这里没有说明,
事实上软件部分,2.3之间返回了XXXDecoder

////4.0////
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
addVendorPlugin();
addPlugin(new SoftOMXPlugin);
}

4.0上对于软硬编解码,都使用OMX标准,挂载plugins的方式来进行。软解部分使用addPlugin(new SoftOMXPlugin)。


/////////////////////////////////////////////
//2,一个重要的类OMXCodecObserver
/////////////////////////////////////////////

OMXCodecObserver是一个OMXCodec的内部类,它在OMXCodec的Create函数中会实例化一个,并且使用observer->setCodec(codec)
接口,对一个OMXCodec进行管理。OMXCodecObserver还有一个接口onMessage,其作用是对由observer管理的codec进行消息处理,
这个位于OMXCodecObserver的onMessage函数是一个统一的入口,具体的消息处理,由被observer管理的codec自己实现。

/////////////////////////////////////////////
//3,在OMXCodec的create中还做了些什么
/////////////////////////////////////////////
现在看看相关的代码片段

sp<MediaSource> OMXCodec::Create(
const sp<IOMX> &omx,
const sp<MetaData> &meta, bool createEncoder,
const sp<MediaSource> &source,
const char *matchComponentName,
uint32_t flags,
const sp<ANativeWindow> &nativeWindow) {
int32_t requiresSecureBuffers;
if (source->getFormat()->findInt32(
kKeyRequiresSecureBuffers,
&requiresSecureBuffers)
&& requiresSecureBuffers) {
flags |= kIgnoreCodecSpecificData;
flags |= kUseSecureInputBuffers;
flags |= kEnableGrallocUsageProtected;
}
else
{
flags &= ~kEnableGrallocUsageProtected;
}

const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
CHECK(success);

Vector<String8> matchingCodecs;
findMatchingCodecs(
mime, createEncoder, matchComponentName, flags, &matchingCodecs);
if (matchingCodecs.isEmpty()) {
return NULL;
}
sp<OMXCodecObserver> observer = new OMXCodecObserver;
IOMX::node_id node = 0;

for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const char *componentNameBase = matchingCodecs[i].string();
const char *componentName = componentNameBase;

AString tmp;
if (flags & kUseSecureInputBuffers) {
tmp = componentNameBase;
tmp.append(".secure");

componentName = tmp.c_str();
}
...

status_t err = omx->allocateNode(componentName, observer, &node);

...

sp<OMXCodec> codec = new OMXCodec(
omx, node, quirks, flags,
createEncoder, mime, componentName,
source, nativeWindow);

observer->setCodec(codec);

err = codec->configureCodec(meta);

if (err == OK) {
if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
}

return codec;
...

return NULL;
}

从OMXCodec::Create的代码中可以看到,这个Create函数主要做了一下几件事:

//这里,根据mime的类型,先找到对应的容器格式,然后把这个ComponentName放到matchingCodecs中。如果有指定的容器话,作为实参传递给matchComponentName。

1,findMatchingCodecs(mime, createEncoder, matchComponentName, flags, &matchingCodecs);

//实例化一个OMXCodecObserver,作用上面有提到,然后给即将创建的node分配一个node_id,id号被初始化为0
2,sp<OMXCodecObserver> observer = new OMXCodecObserver;
IOMX::node_id node = 0;

//allocateNode函数会通过binder调用到服务端的OMX::allocateNode,函数的具体实现如下
3,status_t err = omx->allocateNode(componentName, observer, &node);

status_t OMX::allocateNode(
const char *name, const sp<IOMXObserver> &observer, node_id *node) {
Mutex::Autolock autoLock(mLock);

*node = 0;
//OMXNodeInstance,与node_id一一对应,指的是OMX标准下node的实例,这个OMXNodeInstance内部封装了一下对不同实例的操作,以及回调。
OMXNodeInstance *instance = new OMXNodeInstance(this, observer);

OMX_COMPONENTTYPE *handle;

//这里会一直调用具体的OMXPlugins的的的makeComponentInstance函数,假设这里的具体OMX plugin是SoftOMXPlugin,那么
//SoftOMXPlugin的makeComponentInstance函数会根据容器名来动态的打开一个名为llibstagefright_soft_XXX.so的的动态库
//然后使用ddlopen和dlsym来来调用这个so中的函数。这个操作完成之后,会在底层对应一个具体的编解码组件,例如SoftMPEG4,并对
//这个编解码组件进行初始化,例如initPorts(),initDecoder()......
OMX_ERRORTYPE err = mMaster->makeComponentInstance(
name, &OMXNodeInstance::kCallbacks,
instance, &handle);

if (err != OMX_ErrorNone) {
LOGV("FAILED to allocate omx component '%s'", name);

instance->onGetHandleFailed();

return UNKNOWN_ERROR;
}

*node = makeNodeID(instance);
//首先由node_id来区分不同的node,然后给各个不同的node实例化一个CallbackDispatcher来与之对应,这个CallbackDispatcher
//靠OMXNodeInstance instance来区分。CallbackDispatcher在实例化之后,内部会开启一个线程,这个线程循环的监听List<omx_message> mQueue;
//看看是否有新的omx_message被分派过来。如果有就dispatch(msg)。
mDispatchers.add(*node, new CallbackDispatcher(instance));

//给这个OMXNodeInstance绑定一个node_id,和handler,这个handler是上面mMaster->makeComponentInstance传出的。
instance->setHandle(*node, handle);

mLiveNodes.add(observer->asBinder(), instance);
observer->asBinder()->linkToDeath(this);

return OK;
}

//在框架层实例化一个OOMXCodec
4,sp<OMXCodec> codec = new OMXCodec(
omx, node, quirks, flags,
createEncoder, mime, componentName,
source, nativeWindow);
//将前面的codec拉入observer的管理
observer->setCodec(codec);
//根据媒体流的format对codec进行一些配置
err = codec->configureCodec(meta);

下面来看张图:

从上面的时序图看一看出omx在stagefright框架中的条用关系,
1,在awesomeplayer中,有一个OMXClient成员变量mClient,作用与服务端OMX交互的代理。
2,stagefright框架通过OMXCodec进入到OMX(即OMX的服务端)
3,通过服务端的OMX去和具体的OMXNodeInstance还有编解码Components打交道。
4,回调机制可以从图中看出来,是通过CallbackDispatcher分派消息,然后一层一层的往上调用onMessage().


节约篇幅再开一篇
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息