一直躺在草稿箱里:
要掌握的内容:
1. ACodec中omx组件的创建过程
2. buffer的操作
3. 和OMXCodec的区别
组件的创建基本上和OMXCodec的相同。
1. 在ACodec::ExecutingState::resume()中,有:
void ACodec::ExecutingState::resume() {
....
submitOutputBuffers();
...
postFillThisBuffer(info);
}
大概分别相当于OMXCode的fillOutputBuffer和drainInputBuffer。
在onOMXEmptyBufferDone()中,又调用 postFillThisBuffer
在getMoreInputDataIfPossible()中,又调用 postFillThisBuffer
在ACodec::OutputPortSettingsChangedState::onOMXEvent中,也调用submitOutputBuffers()
2. 应该分析ACode::resume()的调用过程
调用resume()的地方有两处,
一处在:
ACodec::IdleToExecutingState::onOMXEvent()中 OMX_EventCmdComplete中
当sendCommand(mCode->mNode, OMXCommandStateSet, OMXStateIdle)之后,
会在onOMXEvent()中调用 sendCommand(mCode->mNode, OMXCommandStateSet, OMXStateExcuting)
在设置OMXStateExcuting成功之后,会调用 mCodec->mExecutingState->resume()。
所以,在start()时会出发resume()的调用
void ACodec::LoadedState::onStart() {
ALOGV("onStart");
CHECK_EQ(mCodec->mOMX->sendCommand(
mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle),
(status_t)OK);
mCodec->changeState(mCodec->mLoadedToIdleState);
}
另一处在:
ACodec::ExecutingState::onMessageReceived()中 kWhatResum kWhatFlushCompleted --- > send kWhatResume msg
3. 分析msg的传递
BufferInfo中有一个AMessage mNotify的成员,在MediaCodec中enqueneInputBuffer()触发 mNotify->post()从而触
发 mOMX->emptyBuffer()
从postInputBuffer()开始分析;
在resume()中,会选取input buffers中第一个进行post
resume() {
....
// Post the first input buffer.
CHECK_GT(mCodec->mBuffers[kPortIndexInput].size(), 0u);
BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(0);
....
}
void ACodec::BaseState::postFillThisBuffer(BufferInfo *info) {
....
notify->setInt32("what", ACodec::kWhatFillThisBuffer);
....
sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec->id());//这个reply会在MediaCodec时被调用
notify->setMessage("reply", reply);
notify->post();
}
接下来在MediaCodec中接收到 kWhatFillThisBuffer消息,将该buffer push到可用buffer中:
mAvailPortBuffers[portIndex].push_back(i);
上层通过 dequeueInputBuffer()来获取该buffer的index进行操作
操作完毕后,调用该buffer的mNotify->post(),出发 mOMX->emptyBuffer()
OMXCodec::create()流程:
主要工作为:
1. findMatchingCodecs(mime, createEncoder, matchComponentName, flags, &matchingCodecs);
2. observer = new OMXCodecObserver;
3. omx->allocateNode(componentName, observer, &node);
4. sp<OMXCodec> codec = new OMXCodec()
5. observer->setCodec(codec);
OMX:allocateNode()流程:
原型: virtual status_t allocateNode(
const char *name, const sp<IOMXObserver> &observer, node_id *node);
参数: name, 组件名称
observer, OMXCodecObserver,传递给组件,用来调用callback函数
node, 用来返回的组件节点,代表一个组件
主要工作:
1. OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
//注意此处的this对象即 OMX 对象。此时已经和相关的 libstagefreighthw.so联系上了。
//即在此之前,已经进行过 OMXMaster的addVendorPlugin()了
2. mMaster->makeComponentInstance(
name, &OMXNodeInstance::kCallbacks,
instance, &handle);
//这里根据name去厂家提供的库里面查找组件。
//和某个组件关联的对象时:instance
3. *node = makeNodeID(instance);
//返回这个node后,则可以根据这个node查找到相关的instance
4. mDispatchers.add(*node, new CallbackDispatcher(instance));
OMX的工作都是通过OMXNodeInstance来完成,比如 sendCommand的操作:
1. 在OMXCodec中:err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
2. 在OMX中, findInstance(node)->sendCommand(cmd, param);
findInstance(node)即找到相关的 OMXNodeInstance 对象,调用其sendCommand
3. OMXNodeInstance调用 OMX_SendCommand,成功发送组件到command
OMX_SendCommand的定义在 omx_core.h中
callback的调用流程:
例如从 emptyBuffer怎么调用到 OnEmptyBufferDone():
OMX::emytpBuffer --> OMXNodeInstance::emptyBuffer --> OMX_EmptyThisBuffer
OMX_EmptyThisBuffer 宏定义在omx_core.h中:
#define OMX_EmptyThisBuffer( \
hComponent, \
pBuffer) \
((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer( \
hComponent, \
pBuffer) /* Macro End */
可知:会调用相关组件的EmptyThisBuffer(比OMXNodeInstance还要往深层次的组件,即厂家组件或软解码组件)
在SoftAAC2::onQueueFilled()中,调用 SoftOMXComponent::notifyEmptyBufferDone(header);
SoftOMXComponent::notifyEmptyBufferDone调用到 上面注册的callbacks
在这个组件中,会返回来调用OMXNodeInstance的OnEmptyBufferDone().????咋调用到的?....可以从软解码中看到
OMXNodeInstance中调用到OMX的OnEmptyBufferDone()
OMX的OnEmptyBufferDone中,调用 findDispatcher(node)->post(msg); 使用CallbackDispatcher
CallbackDispatcher中再调用OMXNodeInstance的onMessage()
OMXNodeInstance的onMessage中调用 OMXCodeObserver的onMessage()
OMXCodeObserver的onMessage中调用OMXCodec的onMessage
至此成功调用omMessage,完成EmptyBufferDone的调用
介绍ALooper,AMessage,AHandler
new ALooper();
ALooper.start()
ALooper.registerHandler();//绑定AHandler和Looper
new AMessage(what, id()); //id()决定由哪个handler来处理该message的消息
//ACodec和AMediaCode都继承自AHandler
msg->postAndAwaitResponse(response);//发送消息
MediaCodec 和 ACodec流程:
(一) MediaCodec::createByType
主要工作:
1. sp<MediaCodec> codec = new MediaCode(lopper)
2. codec->init(mime, nameIsType, encoder);
MediaCodec::init(){
主要工作:
mLooper->registerHandler(this);
mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, id()));
sp<AMessage> msg = new AMessage(kWhatInit, id());
PostAndAwaitResponse(msg, &response);
onMessageReceived:
case: kWaitInit
主要工作:
setState(INITIALIZING);
sp<AMessage> format = new AMessage;
mCodec->initiateAllocateComponent(format);
OMX的创建:
OMXClient client;
client.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();//omx服务端在mediaplayer service中创建
}
sp<IOMX> MediaPlayerService::getOMX() {
Mutex::Autolock autoLock(mLock);
if (mOMX.get() == NULL) {
mOMX = new OMX;
}
return mOMX;
}
ACodec::initiateAllocateComponent()
主要工作:发送 kWhatAllocateComponent,最终调用到onAllocateComponent
onAllocateComponent(const sp<AMessage> &msg):
主要工作://和OMXCodec流程基本一样
1. 获取omx
2. 获取matchingCodecs和matchingCodecQuirks。即符合要求的所有的解码组件
3. observer = new CodecObserver;
4. omx->allocateNode(componentName.c_str(), observer, &node);//从符合要求的组件中选取一个allocate
5. observer->setNotificationMessage(notify);
6. mCodec->mQuirks = quirks;
mCodec->mOMX = omx;
mCodec->mNode = node;
。。。
ACodec中和具体解码器相关的地方:
1. GetVideoCodingTypeFromMime()
在configureCodec()时调用setupVideoDecoder(),会调用到 GetVideoCodingTypeFromMime
主要工作是根据mime返回 coding type
2. setComponentRole() configureCodec()中调用
主要工作:
1. 根据mime,得到 decoder role
2. 确定是哪个decoder role后, 调用InitOMXParams(&roleParams);
3. mOMX->setParameter()
configureCodec()分析:
从MediaConfig::configure()中调用过来
主要工作是设置codec的一些参数
1. status_t err = setComponentRole(encoder /* isEncoder */, mime);
2. setupVideoDecoder(mime, width, height)