博客
关于我
ACodec从UninitializedState状态到LoadedState状态分析
阅读量:380 次
发布时间:2019-03-05

本文共 9130 字,大约阅读时间需要 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/

你可能感兴趣的文章
MySQL5.7.37windows解压版的安装使用
查看>>
mysql5.7免费下载地址
查看>>
mysql5.7命令总结
查看>>
mysql5.7安装
查看>>
mysql5.7性能调优my.ini
查看>>
MySQL5.7新增Performance Schema表
查看>>
Mysql5.7深入学习 1.MySQL 5.7 中的新增功能
查看>>
Webpack 之 basic chunk graph
查看>>
Mysql5.7版本单机版my.cnf配置文件
查看>>
mysql5.7的安装和Navicat的安装
查看>>
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>