博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ACodec从UninitializedState状态到LoadedState状态分析
阅读量:376 次
发布时间:2019-03-05

本文共 9169 字,大约阅读时间需要 30 分钟。

一、引言:

本博客涉及的内容是mediacodec从create到config过程中native层的逻辑分析,mediacodec在应用层的逻辑时序图如下(create->start):
在这里插入图片描述
二、create的native层代码分析:
进入到native层之后,mediacodec会先去实例化本体对象,然后执行init操作,
init函数关键代码贴出如下:

MediaCodec.cppstatus_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
msg = new AMessage(kWhatInit, id()); msg->setString("name", name); msg->setInt32("nameIsType", nameIsType); if (nameIsType) {
msg->setInt32("encoder", encoder); } sp
response; return PostAndAwaitResponse(msg, &response);}

以上代码我们重点分析注释一和注释五,首先,在init函数中,会先去实例化ACodec,而ACodec的构造函数会创建多个状态,用于AHierarchicalStateMachine进行维护,ACodec的构造函数最后会将当前的状态设置为mUninitializedState,贴一下部分代码:

ACodec.cppACodec::ACodec()...{
... changeState(mUninitializedState);}

状态设置完成之后,我们回到MediaCodec的init函数,直接看注释五,此时,发送了一个kWhatInit的消息,我们直接跳转到MediaCodec的onMessageReceived函数:

void MediaCodec::onMessageReceived(const sp
&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
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
&msg) {
msg->setWhat(kWhatAllocateComponent); msg->setTarget(id()); msg->post();}

继续跟进到ACodec中的onMessageReceived,因为在实例化的时候,我们当前的状态已经改为UninitializedState了,所以AHierarchicalStateMachine会将该条消息分配给UninitializedState来处理:

bool ACodec::UninitializedState::onMessageReceived(const sp
&msg) {
... case ACodec::kWhatAllocateComponent: {
onAllocateComponent(msg); handled = true; break; } ...}

进入到onAllocateComponent,这个函数很长,还是找重点分析:

bool ACodec::UninitializedState::onAllocateComponent(const sp
&msg) {
... OMXClient client; /* 1.获取mediaplayerservice的服务 */ CHECK_EQ(client.connect(), (status_t)OK); sp
omx = client.interface(); sp
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
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
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
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
&msg) {
msg->setWhat(kWhatConfigureComponent); msg->setTarget(id()); msg->post();}

这里又会发送一个kWhatConfigureComponent消息,因为现在的状态已经是LoadedState了,所以消息处理自然要由LoadedState来:

bool ACodec::LoadedState::onMessageReceived(const sp
&msg) {
bool handled = false; switch (msg->what()) {
case ACodec::kWhatConfigureComponent: {
onConfigureComponent(msg); handled = true; break; } ...}

继续跟进:

bool ACodec::LoadedState::onConfigureComponent(        const sp
&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来完成的;

转载地址:http://gfwwz.baihongyu.com/

你可能感兴趣的文章