Android 9.0 multimedia框架解析(五)ACodec配置解码器过程

概述

先来回顾下上篇文章所讲的MediaPlayerService的start过程。MediaPlayerService的start通过层层调用会调用到NuPlayer::onStart,onStart会先启动GenericSource,然后通过异步的方式调用到NuPlayer::instantiateDecoder。在instantiateDecoder中,会创建NuPlayer::Decoder(这个Decoder跟我标题里面的decoder是不一样的,标题里面的decoder指的是实际的解码器,而这里的NuPlayer::Decoder经过层层调用会调用到实际的解码器),然后会进行初始化和配置。从时序图中可以看出Decoder的配置过程会先去查找对应的解码器,然后为为解码器创建ACodec。上一节我们分析到了创建ACodec这里,没有分析ACodec的配置过程。这里我以自己集成的ffmpeg播放视频为场景,分析ACodec配置解码器的过程。

时序图

在这里插入图片描述

configureCodec

从时序图可以看出配置过程会调用到ACodec::configureCodec,这个configureCodec是配置过程的核心函数。
来看看配置的第一步SetComponentRole。

status_t ACodec::configureCodec(
        const char *mime, const sp<AMessage> &msg) {
   
	    if (!msg->findInt32("encoder", &encoder)) {
   		//从AMessage中取出encoder对应的值,如果不存在就认为是要初始化解码器。
	        encoder = false;
	    }
    	......
	    status_t err = setComponentRole(encoder /* isEncoder */, mime);
}
status_t ACodec::setComponentRole(
        bool isEncoder, const char *mime) {
   
    const char *role = GetComponentRole(isEncoder, mime);//根据mime找到组件的ComponentRole
    ......
    status_t err = SetComponentRole(mOMXNode, role);//把ComponentRole传递给解码器
    ......
}
status_t SetComponentRole(const sp<IOMXNode> &omxNode, const char *role) {
   
    OMX_PARAM_COMPONENTROLETYPE roleParams;
    InitOMXParams(&roleParams);
    strncpy((char *)roleParams.cRole,role, OMX_MAX_STRINGNAME_SIZE - 1);
    roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
    return omxNode->setParameter(OMX_IndexParamStandardComponentRole,&roleParams, sizeof(roleParams));//传给解码器
}

omxNode->setParameter就是调用到OMXNodeInstance::setParameter,然后OMXNodeInstance::setParameter会去调用到真正的解码器。来看看我解码器中对于OMX_IndexParamStandardComponentRole会做什么。

OMX_ERRORTYPE SoftFFmpegVideoDec::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params)
{
   
	switch (index){
   
		case OMX_IndexParamStandardComponentRole:{
   
			const OMX_PARAM_COMPONENTROLETYPE *roleParams = (const OMX_PARAM_COMPONENTROLETYPE *)params;
			if (strncmp((const char *)roleParams->cRole,"video_decoder.ffmpeg",OMX_MAX_STRINGNAME_SIZE - 1)){
   
				ALOGE("OMX_ErrorUndefined");
				return OMX_ErrorUndefined;
			}
			return OMX_ErrorNone;
		}
}

可以看出,我会识别roleParams->cRole是否是等于video_decoder.ffmpeg,如果是则返回OMX_ErrorNone,让配置过程继续。
来看看第二步setPortMode。一般来说一个解码器有两个port,一个是input,一个是output。input用于输入数据,output用于存放解码完的数据。我一般只分析output。

status_t ACodec::configureCodec(
        const char *mime, const sp<AMessage> &msg) {
   
        if (haveNativeWindow) {
   	//如果使用nativewindow
        	......
        	err = setPortMode(kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer);//设置output的端口模式为DynamicANWBuffer
        }
}
status_t ACodec::setPortMode(int32_t portIndex, IOMX::PortMode mode) {
   	
    status_t err = mOMXNode->setPortMode(portIndex, mode);	//调用OMXNodeInstance::setPortMode
	......
    mPortMode[portIndex] = mode;
    return OK;
}
status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
   
    switch (mode) {
   
    case IOMX::kPortModeDynamicANWBuffer:
    {
   
        if (portIndex == kPortIndexOutput) {
   	//由于是配置output,所以会先走这里
        	.....
            status_t err = enableNativeBuffers_l(
                    portIndex, OMX_TRUE /*graphic*/, OMX_TRUE);
        }
        (void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
        return storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL);
    }
}
status_t OMXNodeInstance::enableNativeBuffers_l(....){
   
	OMX_STRING name = const_cast<OMX_STRING>(
            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"	//graphic为true
                    : "OMX.google.android.index.allocateNativeHandle");
    OMX_INDEXTYPE index;
    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);	//获取自定义的的index(或许是为了兼容把)
    if (err == OMX_ErrorNone) {
   
    	err = OMX_SetParameter(mHandle, index, &params);	//设置参数
    }
}

来看一下我的解码器是怎么实现OMX_GetExtensionIndex对应的函数接口的

OMX_ERRORTYPE SoftFFmpegVideoDec::getExtensionIndex( const char *name, OMX_INDEXTYPE *index) {
   
    if(strcmp(name, SPRD_INDEX_PARAM_ENABLE_ANB) == 0) {
   
        ALOGI("getExtensionIndex:%s",SPRD_INDEX_PARAM_ENABLE_ANB);
        *index = (OMX_INDEXTYPE) OMX_IndexParamEnableAndroidBuffers;	
        return OMX_ErrorNone;
    } else......
    return OMX_ErrorNotImplemented;
}

可以看出我调用OMX_GetExtensionIndex将获取到index为OMX_IndexParamEnableAndroidBuffers的值。再来看看解码器是怎么实现OMX_SetParameter对应的函数接口的。

OMX_ERRORTYPE SoftFFmpegVideoDec::internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params){
   
		case OMX_IndexParamEnableAndroidBuffers:
		{
   
			EnableAndroidNativeBuffersParams *peanbp = (EnableAndroidNativeBuffersParams *)params;
			PortInfo *pOutPort = editPortInfo(kOutputPortIndex);
			if (peanbp->enable == OMX_FALSE) {
   
				pOutPort->mDef.format
  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值