MediaCodec的简单测试sample及部分代码摘要

一、引言:
mediacodec在framework层的代码逻辑确实比较复杂,因为对整个通路还不是很熟悉,所以这里摘要一些代码的查看心得,并在网上找了一个demo来了解一下mediacodec是怎么工作的。

二、测试demo:
测试代码摘录自何俊林,demo主要演示了如何渲染一个视频流文件到显示设备上:
MediaCodec测试demo

三、代码心得:
1.mediacodec与omx的调用逻辑:
在这里插入图片描述
这个图不是严格意义上的逻辑时序图,举例了mediacodec和stagefright框架在调用omx进行解码时的逻辑:
①Acodec和omxcodec分别被上层的mediacodec和awesomeplayer调用;
②Omx使用的是binder机制,acodec和omxcodec都是通过mediaplayerservice提供的服务获取到Bn端的omx对象,然后通过OMXNodeInstance去调入到omx的组件中去;
③OMX_Core.h和OMX_Component.h是标准的OMX接口,前者是上层调用的接口,后者是下层组件实现的接口,两个文件串联起了OMX上层和下层;

2.omx如何配置解码器的:
ACodec通过onAllocateComponent函数去获取了omx对象,通过configureCodec函数去配置解码器,omx解码器的配置主要通过不停地调用omx标准接口getParameter和setParameter去实现,视频和音频是分开设置的,音频是按照不同类型去设置的,在这里可以扩展对应的解码类型;

3.mediacodec是通过不停填充输入输出buffer实现的解码,那么buffer是在什么时候申请的:
答案:buffer的申请是在切换到LoadedToIdleState时申请的。
a.我们知道,ACodec中维护了多个状态对象,不同的消息会在对应的状态去处理,每当状态改变时,就会调用changeState函数,先看一下ACodec的继承关系:

struct ACodec : public AHierarchicalStateMachine, public CodecBase{
	...
}

ACodec继承自AHierarchicalStateMachine,看一下changeState函数实现:

void AHierarchicalStateMachine::changeState(const sp<AState> &state) {
    if (state == mState) {
        // Quick exit for the easy case.
        return;
    }
	
	/* state A记录的是对象中当前保存的状态 */
    Vector<sp<AState> > A;
    sp<AState> cur = mState;
    for (;;) {
        A.push(cur);
        if (cur == NULL) {
            break;
        }
        cur = cur->parentState();
    }
	
	/* state B记录的是即将切换的状态 */
    Vector<sp<AState> > B;
    cur = state;
    for (;;) {
        B.push(cur);
        if (cur == NULL) {
            break;
        }
        cur = cur->parentState();
    }

    // Remove the common tail.
    while (A.size() > 0 && B.size() > 0 && A.top() == B.top()) {
        A.pop();
        B.pop();
    }

    mState = state;
	/* 调用状态中的stateExited()函数 */
    for (size_t i = 0; i < A.size(); ++i) {
        A.editItemAt(i)->stateExited();
    }
	
	/* 调用状态中的stateEntered()函数 */
    for (size_t i = B.size(); i-- > 0;) {
        B.editItemAt(i)->stateEntered();
    }
}

changeState实际上做的事就是记录即将切换的状态,并且适时地调用stateExited()和stateEntered()函数。

b.知道了changeState函数的实现之后,我们再回顾一下启用解码器过程中,上层调用与ACodec是如何控制状态的:
①上层调用createDecoderByType时,对于ACodec中的状态变化是UninitializedState->LoadedState;
②上层调用configure时,对于ACodec中状态没有改变,维持LoadedState;
③上层调用start时,对于ACodec中状态变化是LoadedState->LoadedToIdleState;
具体我们看一下ACodec中切换时的源码:

void ACodec::LoadedState::onStart() {
    ALOGV("onStart");
	
	/* 调用omx的sendCommand函数 */
    CHECK_EQ(mCodec->mOMX->sendCommand(
                mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle),
             (status_t)OK);
	
	/* 调用changeState函数,传入的状态为LoadedToIdleState */
    mCodec->changeState(mCodec->mLoadedToIdleState);
}

因为有了前面changeState的分析做铺垫,我们直接去看LoadedToIdleState对应的stateEntered函数实现:

void ACodec::LoadedToIdleState::stateEntered() {
    ALOGV("[%s] Now Loaded->Idle", mCodec->mComponentName.c_str());

    status_t err;
    /* 1.调用allocateBuffers去申请input和output的buffer */
    if ((err = allocateBuffers()) != OK) {
        ALOGE("Failed to allocate buffers after transitioning to IDLE state "
             "(error 0x%08x)",
             err);

        mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
		
		/* 2.如果申请失败,回退状态 */
        mCodec->changeState(mCodec->mLoadedState);
    
}

这里就会去申请buffer,如果buffer申请失败了,那么就会回退状态。

3.上层如何驱动codec进行解码:
应用中,不停地去调用dequeueInputBuffer和queueInputBuffer让code往输入buffer中填充数据,然后调用dequeueOutputBuffer查询输出buffer中是否获取到了解码完后的原始数据,之后调用releaseOutputBuffer去进行渲染,具体流程可参看demo。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值