我在MediaCodec中看到一段代码,感觉很蒙蔽
if (mIsVideo) {
if (mCodecLooper == NULL) {
mCodecLooper = new ALooper;
mCodecLooper->setName("CodecLooper");
mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
}
mCodecLooper->registerHandler(mCodec);
}
在MediaCodec.h中定义了
sp<ALooper> mCodecLooper;
这是一个ALooper对象,然后在MediaCodec这个类里就再也搜索不到mCodecLooper的使用了。所以就很奇怪,总不能这段代码写出来没什么用吧? 对了,mCodecLooper是一个ALooper,start调用完之后,完全不像不作为的样子啊
status_t ALooper::start(
bool runOnCallingThread, bool canCallJava, int32_t priority) {
...
Mutex::Autolock autoLock(mLock);
...
mThread = new LooperThread(this, canCallJava);
status_t err = mThread->run(
mName.empty() ? "ALooper" : mName.c_str(), priority);
if (err != OK) {
mThread.clear();
}
return err;
}
很明显,这个线程被启动了,并且有事儿干。 此时,我的目光被这个调用吸引了
mCodecLooper->registerHandler(mCodec);
ALooper调用了registerHandler方法,传递了一个ACodec对象。而ACodec使用了很多AMessage来发消息,进行异步调用。那我们先列举一下这几个类的关系 暂时无法在文档外展示此内容 接着看看registerHandler方法
ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
return gLooperRoster.registerHandler(this, handler);
}
函数就执行了,ALooper中的gLooperRoster调用registerHandler方法。在ALooper中没有发现gLooperRoster的使用,它是一个全局变量。 在frameworks/av/media/libstagefright目录搜索发现,除了ALooper,AMessage中也有这个全局变量的身影
foundation/AMessage.cpp:39:extern ALooperRoster gLooperRoster;
除此之外就没有线索了。所以再次在frameworks/av底下就行搜索
media/libmediaplayer2/mediaplayer2.cpp:49:extern ALooperRoster gLooperRoster;
media/libmediaplayer2/mediaplayer2.cpp:352: gLooperRoster.dump(fd, args);
media/libstagefright/foundation/AMessage.cpp:39:extern ALooperRoster gLooperRoster;
media/libstagefright/foundation/ALooper.cpp:34:ALooperRoster gLooperRoster;
media/libstagefright/foundation/ALooper.cpp:76: gLooperRoster.unregisterStaleHandlers();
media/libstagefright/foundation/ALooper.cpp:89: return gLooperRoster.registerHandler(this, handler);
media/libstagefright/foundation/ALooper.cpp:93: gLooperRoster.unregisterHandler(handlerID);
media/libmediaplayerservice/MediaPlayerService.cpp:260:extern ALooperRoster gLooperRoster;
media/libmediaplayerservice/MediaPlayerService.cpp:551: gLooperRoster.dump(fd, args);
就可以发现这个变量在mediaplayer被用到了,不过,也只是用来调用dump方法。而这个变量名起名是 g(global)Looper + Roster(名册)。难道这是一个用来做media全局记录所有ALooper的一个名册? 还是继续看看ALooperRoster先吧
ALooper::handler_id ALooperRoster::registerHandler(
const sp<ALooper> &looper, const sp<AHandler> &handler) {
Mutex::Autolock autoLock(mLock);
if (handler->id() != 0) {
CHECK(!"A handler must only be registered once.");
return INVALID_OPERATION;
}
HandlerInfo info;
info.mLooper = looper;
info.mHandler = handler;
ALooper::handler_id handlerID = mNextHandlerID++;
mHandlers.add(handlerID, info);
handler->setID(handlerID, looper);
return handlerID;
}
到setID的时候,发现ACodec并没有实现setID方法。实现在这里: struct AHandler
inline void setID(ALooper::handler_id id, const wp<ALooper> &looper) {
mID = id;
mLooper = looper;
}
也就是说ACodec调用完setID方法之后,首先它获得了一个唯一生成的id,其次ACodec的mLooper对象被赋值为mCodecLooper。 终于把联系都串起来,然而!当我去搜索mLooper对象的时候,ACodec中并没有。 别着急!经验告诉我们,那就是他的父类AHandler已经把这个变量替他用好了,他没必要再重新造轮子了。果不其然
struct AHandler
sp<ALooper> looper() const {
return mLooper.promote();
}
wp<ALooper> getLooper() const {
return mLooper;
}
当然,这里也有可能只是为了不想让用户不直接访问mLooper对象,所以封装成函数 搜索发现,下面这段代码,高度疑似
void AMessage::setTarget(const sp<const AHandler> &handler) {
if (handler == NULL) {
mTarget = 0;
mHandler.clear();
mLooper.clear();
} else {
mTarget = handler->id();
mHandler = handler->getHandler();
mLooper = handler->getLooper();
}
}
再来看看ACodec中是怎么使用的吧:
void ACodec::initiateAllocateComponent(const sp<AMessage> &msg) {
msg->setWhat(kWhatAllocateComponent);
msg->setTarget(this);
msg->post();
}
这个函数是从MediaCodec调用过来的,msg传入的时候,携带了codecinfo和componentName信息。 进入函数之后
- 调用了一个setWhat,把AMessage的mWhat进行赋值。
- setTarget将ACodec对象送入上面我们提到的方法,那这个消息的mTarget就获得了当前ACodec对象的id。前面分析中,registerHandler中生成的那一个。
- mHandler赋值为handler->getHandler(),这个方法我们之前没有提过,返回的就是ACodec本身。
- mLooper赋值为handler->getLooper(),就是我们前面追踪的方法,还记得这里返回的mLooper是谁吗?就是mCodecLooper,那个名字叫做CodecLooper的线程。
- 接着setTarget方法执行完之后,就执行了AMessage的post的方法。
status_t AMessage::post(int64_t delayUs) {
sp<ALooper> looper = mLooper.promote();
if (looper == NULL) {
ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
return -ENOENT;
}
looper->post(this, delayUs);
return OK;
}
此时,mLooper是谁呢?就是名字叫做CodecLooper的线程。 它的promote又是谁呢?由于ALooper继承自RefBase,所以,这里可以理解为,就是mLooper这个wp封装的指针指向的对象。简单来说,这里就还是名字叫做CodecLooper的线程。 然后就看看post方法
void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
Mutex::Autolock autoLock(mLock);
int64_t whenUs;
if (delayUs > 0) {
whenUs = GetNowUs() + delayUs;
} else {
whenUs = GetNowUs();
}
List<Event>::iterator it = mEventQueue.begin();
while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
++it;
}
Event event;
event.mWhenUs = whenUs;
event.mMessage = msg;
if (it == mEventQueue.begin()) {
mQueueChangedCondition.signal();
}
mEventQueue.insert(it, event);
}
刚才那一条mWhat为kWhatAllocateComponent的消息被post去了哪里? mEventQueue中,再一搜索mEventQueue,整个流程就明白了
bool ALooper::loop() {
Event event;
{
Mutex::Autolock autoLock(mLock);
if (mThread == NULL && !mRunningLocally) {
return false;
}
if (mEventQueue.empty()) {
mQueueChangedCondition.wait(mLock);
return true;
}
int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
int64_t nowUs = GetNowUs();
if (whenUs > nowUs) {
int64_t delayUs = whenUs - nowUs;
mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
return true;
}
event = *mEventQueue.begin();
mEventQueue.erase(mEventQueue.begin());
}
event.mMessage->deliver();
return true;
}
这个loop即是名字叫做CodecLooper的线程的loop。会不断被所属LooperThread的threadLoop不断触发(前提是得返回true,返回false就停掉了)。
- 名字叫做CodecLooper的线程是一个ALooper,它有一个mEventQueue。
- mEventQueue为空的时候,他就等着。
- 一旦有AMessage被post,就会触发event.mMessage->deliver();
void AMessage::deliver() {
sp<AHandler> handler = mHandler.promote();
...
handler->deliverMessage(this);
}
再次回到mHandler,我们前面说了,就是ACodec本身,实现在它父类AHandler里。
void AHandler::deliverMessage(const sp<AMessage> &msg) {
onMessageReceived(msg);
...
}
重点就是调用了onMessageReceived,这个父类并没有实现,所以还是要回到ACodec自己来处理了。而ACodec自己的处理过程也很精妙,且听我细细道来。 ACodec::onMessageReceived实现如下:
virtual void onMessageReceived(const sp<AMessage> &msg) {
handleMessage(msg);
}
注释中也写明白了,AHierarchicalStateMachine实现消息处理,因为AHierarchicalStateMachine是ACodec的父类,所以子类没实现的方法,就调用父类的
void AHierarchicalStateMachine::handleMessage(const sp<AMessage> &msg) {
...
sp<AState> cur = mState;
...
cur->onMessageReceived(msg)
...
}
而这个mState是在AHierarchicalStateMachine::changeState中设置的。在ACodec的构造函数中就调用了这个
ACodec::ACodec() {
...
changeState(mUninitializedState);
}
这样的话,很巧妙的,每次调用完changeState,发出去的消息就会发给不同的类了!
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
case ACodec::kWhatAllocateComponent:
{
onAllocateComponent(msg);
...
}
比如说当前是mState被赋值为mUninitializedState,所以处理消息的就是UninitializedState了,这里想继续操作ACodec怎么办?再看ACodec构造函数
ACodec::ACodec() {
...
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
mIdleToExecutingState = new IdleToExecutingState(this);
mExecutingState = new ExecutingState(this);
mOutputPortSettingsChangedState =
new OutputPortSettingsChangedState(this);
mExecutingToIdleState = new ExecutingToIdleState(this);
mIdleToLoadedState = new IdleToLoadedState(this);
mFlushingState = new FlushingState(this);
}
所有状态机函数都传递了一个this指针做参数 然后
ACodec::UninitializedState::UninitializedState(ACodec *codec)
: BaseState(codec) {
}
ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
: AState(parentState),
mCodec(codec) {
}
也就是说BaseState所定义的mCodec即前面我们一直在使用的ACodec对象,所以这里就可以随便操作了。可以理解为这些状态机管理着ACodec的行为。
到这里,可以总结发现,MediaCodec变量mCodecLooper作用主要是
创建一个线程,供ACodec来使用。可以在线程上执行所有的异步流程。
|