ACodec从UninitializedState状态到LoadedState状态分析

一、引言:
本博客涉及的内容是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来完成的;

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值