一、引言:
本博客涉及的内容是mediacodec从create到config过程中native层的逻辑分析,mediacodec在应用层的逻辑时序图如下(create->start):
二、create的native层代码分析:
进入到native层之后,mediacodec会先去实例化本体对象,然后执行init操作,
init函数关键代码贴出如下:
MediaCodec.cpp
status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
...
/* 1.实例化ACodec */
mCodec = new ACodec;
...
/* 2.在MediaCodec中实例化一个ALooper,用于ACodec进行消息传送 */
if (needDedicatedLooper) {
if (mCodecLooper == NULL) {
mCodecLooper = new ALooper;
mCodecLooper->setName("CodecLooper");
mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
}
mCodecLooper->registerHandler(mCodec);
} else {
/* 3.将ACodec注册到MediaCodec创建的ALooper中 */
mLooper->registerHandler(mCodec);
}
/* 4.将MediaCodec注册到jni层创建的ALooper中 */
mLooper->registerHandler(this);
mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, id()));
/* 5.发送一个kWhatInit消息 */
sp<AMessage> msg = new AMessage(kWhatInit, id());
msg->setString("name", name);
msg->setInt32("nameIsType", nameIsType);
if (nameIsType) {
msg->setInt32("encoder", encoder);
}
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
以上代码我们重点分析注释一和注释五,首先,在init函数中,会先去实例化ACodec,而ACodec的构造函数会创建多个状态,用于AHierarchicalStateMachine进行维护,ACodec的构造函数最后会将当前的状态设置为mUninitializedState,贴一下部分代码:
ACodec.cpp
ACodec::ACodec()...{
...
changeState(mUninitializedState);
}
状态设置完成之后,我们回到MediaCodec的init函数,直接看注释五,此时,发送了一个kWhatInit的消息,我们直接跳转到MediaCodec的onMessageReceived函数:
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
...
case kWhatInit:
{
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState != UNINITIALIZED) {
PostReplyWithError(replyID, INVALID_OPERATION);
break;
}
mReplyID = replyID;
setState(INITIALIZING);
AString name;
CHECK(msg->findString("name", &name));
int32_t nameIsType;
int32_t encoder = false;
CHECK(msg->findInt32("nameIsType", &nameIsType));
if (nameIsType) {
CHECK(msg->findInt32("encoder", &encoder));
}
sp<AMessage> format = new AMessage;
if (nameIsType) {
format->setString("mime", name.c_str());
format->setInt32("encoder", encoder);
} else {
format->setString("componentName", name.c_str());
}
/* 1.跳转到ACodec中 */
mCodec->initiateAllocateComponent(format);
break;
}
...
}
这里的mCodc就是我们之前实例化的ACodec,所以直接进入initiateAllocateComponent进行分析:
void ACodec::initiateAllocateComponent(const sp<AMessage> &msg) {
msg->setWhat(kWhatAllocateComponent);
msg->setTarget(id());
msg->post();
}
继续跟进到ACodec中的onMessageReceived,因为在实例化的时候,我们当前的状态已经改为UninitializedState了,所以AHierarchicalStateMachine会将该条消息分配给UninitializedState来处理:
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
...
case ACodec::kWhatAllocateComponent:
{
onAllocateComponent(msg);
handled = true;
break;
}
...
}
进入到onAllocateComponent,这个函数很长,还是找重点分析:
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
...
OMXClient client;
/* 1.获取mediaplayerservice的服务 */
CHECK_EQ(client.connect(), (status_t)OK);
sp<IOMX> omx = client.interface();
sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec->id());
mDeathNotifier = new DeathNotifier(notify);
if (omx->asBinder()->linkToDeath(mDeathNotifier) != OK) {
// This was a local binder, if it dies so do we, we won't care
// about any notifications in the afterlife.
mDeathNotifier.clear();
}
Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
AString mime;
AString componentName;
uint32_t quirks = 0;
int32_t encoder = false;
/* 2-1:如果之前发送的消息包含componentName字符串 */
if (msg->findString("componentName", &componentName)) {
ssize_t index = matchingCodecs.add();
OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index);
entry->mName = String8(componentName.c_str());
if (!OMXCodec::findCodecQuirks(
componentName.c_str(), &entry->mQuirks)) {
entry->mQuirks = 0;
}
} else {
CHECK(msg->findString("mime", &mime));
if (!msg->findInt32("encoder", &encoder)) {
encoder = false;
}
/* 2-2:没有componentName字符串,就从mediacodec库中找 */
OMXCodec::findMatchingCodecs(
mime.c_str(),
encoder, // createEncoder
NULL, // matchComponentName
0, // flags
&matchingCodecs);
}
sp<CodecObserver> observer = new CodecObserver;
IOMX::node_id node = NULL;
for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
++matchIndex) {
componentName = matchingCodecs.itemAt(matchIndex).mName.string();
quirks = matchingCodecs.itemAt(matchIndex).mQuirks;
pid_t tid = androidGetTid();
int prevPriority = androidGetThreadPriority(tid);
androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
androidSetThreadPriority(tid, prevPriority);
if (err == OK) {
break;
} else {
ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
}
node = NULL;
}
if (node == NULL) {
if (!mime.empty()) {
ALOGE("Unable to instantiate a %scoder for type '%s'.",
encoder ? "en" : "de", mime.c_str());
} else {
ALOGE("Unable to instantiate codec '%s'.", componentName.c_str());
}
mCodec->signalError(OMX_ErrorComponentNotFound);
return false;
}
/* 3.发送kWhatOMXMessage消息 */
notify = new AMessage(kWhatOMXMessage, mCodec->id());
observer->setNotificationMessage(notify);
mCodec->mComponentName = componentName;
mCodec->mFlags = 0;
if (componentName.endsWith(".secure")) {
mCodec->mFlags |= kFlagIsSecure;
mCodec->mFlags |= kFlagIsGrallocUsageProtected;
mCodec->mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
if (mCodec->mSaveES) {
ALOGI("Unable to save ES streams for secure codec '%s'.", componentName.c_str());
mCodec->mSaveES = false;
}
}
mCodec->mQuirks = quirks;
mCodec->mOMX = omx;
mCodec->mNode = node;
{
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatComponentAllocated);
notify->setString("componentName", mCodec->mComponentName.c_str());
notify->post();
}
/* 4.调用ACodec的changeState(实际是调用父类AHierarchicalStateMachine)将状态切换 */
mCodec->changeState(mCodec->mLoadedState);
return true;
}
这个函数需要注意的点有两个,一个是omx使用了binder机制,我们需要先获取mediaplayerservice的服务,然后通过此服务获取Bn端的OMX对象,之后,就可以通过ACodec去调用OMX了,注释第四部也是我们需要注意的,在这里,将UninitializedState状态设置成为了LoadedState状态;这里,大家对这个mCodec可能会有点疑惑,不知道到底是哪个对象,我们在文章最前面说过,ACodec的构造函数中会去实例化多个状态的对象,这些状态有一个共同的特点是继承自BaseState基类,以UninitializedState为例:
struct ACodec::UninitializedState : public ACodec::BaseState {
UninitializedState(ACodec *codec);
而BaseState 其中就有一个成员变量为mCodec:
struct ACodec::BaseState : public AState {
...
ACodec *mCodec;
...
}
可以看到,mCodec的类型为ACodec 的指针,这里你就明白了,在各个状态实例化的时候,会去调用父类BaseState 的构造函数,通过参数列表初始化的方式赋值mCodec,而mCodec正是ACodec对象自己。
整个create过程就分析完了,我们知道,对于ACodec而言,其状态先是UninitializedState,然后变成了LoadedState。
三、configur的native层代码分析:
下面我们简要分析一下configue的时候看下native代码是不是紧跟当前状态走的:
直接到mediacodec.cpp中,这里会发送一个kWhatConfigure的消息,我们直接到onMessageReceived去找到实现:
case kWhatConfigure:
{
...
mCodec->initiateConfigureComponent(format);
break;
}
只看重点,会去调用ACodec中的initiateConfigureComponent:
void ACodec::initiateConfigureComponent(const sp<AMessage> &msg) {
msg->setWhat(kWhatConfigureComponent);
msg->setTarget(id());
msg->post();
}
这里又会发送一个kWhatConfigureComponent消息,因为现在的状态已经是LoadedState了,所以消息处理自然要由LoadedState来:
bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {
bool handled = false;
switch (msg->what()) {
case ACodec::kWhatConfigureComponent:
{
onConfigureComponent(msg);
handled = true;
break;
}
...
}
继续跟进:
bool ACodec::LoadedState::onConfigureComponent(
const sp<AMessage> &msg) {
...
/* 调用ACodec中的configureCodec */
status_t err = mCodec->configureCodec(mime.c_str(), msg);
if (err != OK) {
ALOGE("[%s] configureCodec returning error %d",
mCodec->mComponentName.c_str(), err);
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
return false;
}
...
}
前面已经说过,mCodec就是ACodec,所以我们只需要直接进入到ACodec中去找到对应的configureCodec函数就可以了。
三、总结:
用一张图简单概括一下:
①mediacodec通过函数直调到ACodec;
②ACodec通过消息机制下发给当前的状态处理;
③ACodec当前状态机是由父类AHierarchicalStateMachine来管理的;
④对应状态机处理还是通过回调到ACodec来完成的;