【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】【01】

承接上一章节分析:【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 5】
本系列文章分析的安卓源码版本:【Android 10.0 版本】

【此章节小节编号就接着上一章节排列】
3、setPortMode(kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer)实现分析:
设置输出缓冲区buffer端口模式为 kPortModeDynamicANWBuffer 即会使用动态ANativeWindowBuffer来传递已解码输出数据。

// [frameworks/av/media/libstagefright/ACodec.cpp]
status_t ACodec::setPortMode(int32_t portIndex, IOMX::PortMode mode) {
	// 调用底层具体实现者OMXNodeInstance对象的该方式
	// 见下面的分析
    status_t err = mOMXNode->setPortMode(portIndex, mode);
    if (err != OK) {
        ALOGE("[%s] setPortMode on %s to %s failed w/ err %d",
                mComponentName.c_str(),
                portIndex == kPortIndexInput ? "input" : "output",
                asString(mode),
                err);
        return err;
    }

    // 缓存对应索引缓冲区buffer端口模式
    mPortMode[portIndex] = mode;
    return OK;
}

mOMXNode->setPortMode(portIndex, mode)实现分析:
调用底层具体实现者OMXNodeInstance对象的该方式

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
    Mutex::Autolock autoLock(mLock);
    if (mHandle == NULL) {
        return DEAD_OBJECT;
    }

    // 检查输入输出buffer端口模式索引不能大于当前支持的模式索引最大值
    // NELEM:宏定义计算数组大小
    // #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
    if (portIndex >= NELEM(mPortMode)) {
        ALOGE("b/31385713, portIndex(%u)", portIndex);
        android_errorWriteLog(0x534e4554, "31385713");
        return BAD_VALUE;
    }

	// mSailed:配置已设置(没有更多的元模式更改),即表示正在改变组件状态中时为true
	// mNumPortBuffers[portIndex]:表示当前端口模式的buffer数量
	// 若为true并且buffer已分配则返回失败
    if (mSailed || mNumPortBuffers[portIndex] > 0) {
        android_errorWriteLog(0x534e4554, "29422020");
        return INVALID_OPERATION;
    }

    CLOG_CONFIG(setPortMode, "%s(%d), port %d", asString(mode), mode, portIndex);

    status_t err = OK;
    switch (mode) {
    // 该模式IOMX::PortMode枚举声明
    // 见3.1小节分析
    case IOMX::kPortModeDynamicANWBuffer:
    {
        if (portIndex == kPortIndexOutput) {
        	// 输出buffer端口索引时
        	// 该标识根据此前相关章节分析可知,该值默认为false,是个实验性功能开关,打开则直接返回不支持状态码
            if (mLegacyAdaptiveExperiment) {
                CLOG_INTERNAL(setPortMode, "Legacy adaptive experiment: "
                        "not setting port mode to %s(%d) on output",
                        asString(mode), mode);
                err = StatusFromOMXError(OMX_ErrorUnsupportedIndex);
                break;
            }

            // 启用native buffer
            // 见3.2小节分析
            err = enableNativeBuffers_l(
                    portIndex, OMX_TRUE /*graphic*/, OMX_TRUE);
            if (err != OK) {
            	// 如3.2分析可知,若是SoftAVCDec组件实现的话,那么将会执行此处,即不支持该buffer类型的输出数据
                break;
            }
        }
        // 此处将再次执行3.2小节流程,只是参数不同,最后两个都为false,
        // 其实际预期处理结果:mSecureBufferType[portIndex] 为 kSecureBufferTypeOpaque 即 不透明安全buffer类型
        (void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
        // 存储元数据buffer类型模式设置
        // 见3.3小节分析
        err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL);
        break;
    }

    case IOMX::kPortModeDynamicNativeHandle:
    {
        if (portIndex != kPortIndexInput) {
            CLOG_ERROR(setPortMode, BAD_VALUE,
                    "%s(%d) mode is only supported on input port", asString(mode), mode);
            err = BAD_VALUE;
            break;
        }
        (void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
        (void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);

        MetadataBufferType metaType = kMetadataBufferTypeNativeHandleSource;
        err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, &metaType);
        break;
    }

    case IOMX::kPortModePresetSecureBuffer:
    {
        // Allow on both input and output.
        (void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
        (void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
        err = enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_TRUE);
        break;
    }

    case IOMX::kPortModePresetANWBuffer:
    {
        if (portIndex != kPortIndexOutput) {
            CLOG_ERROR(setPortMode, BAD_VALUE,
                    "%s(%d) mode is only supported on output port", asString(mode), mode);
            err = BAD_VALUE;
            break;
        }

        // Check if we're simulating legacy mode with metadata mode,
        // if so, enable metadata mode.
        if (mLegacyAdaptiveExperiment) {
            if (storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL) == OK) {
                CLOG_INTERNAL(setPortMode, "Legacy adaptive experiment: "
                        "metdata mode enabled successfully");
                break;
            }

            CLOG_INTERNAL(setPortMode, "Legacy adaptive experiment: "
                    "unable to enable metadata mode on output");

            mLegacyAdaptiveExperiment = false;
        }

        // Disable secure buffer and enable graphic buffer
        (void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
        err = enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_TRUE);
        if (err != OK) {
            break;
        }

        // Not running experiment, or metadata is not supported.
        // Disable metadata mode and use legacy mode.
        (void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
        break;
    }

	// 输入输出buffer预设模式为字节buffer时
    case IOMX::kPortModePresetByteBuffer:
    {
        // 由前面的分析,此处处理最终大致功能为:禁止使用这三种buffer数据类型模式
        // Disable secure buffer, native buffer and metadata.
        (void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
        (void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
        (void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
        // 注意:此处执行完毕之后 err 状态默认为OK,因此会执行下面的缓存对应索引buffer端口模式
        break;
    }

    default:
        CLOG_ERROR(setPortMode, BAD_VALUE, "invalid port mode %d", mode);
        err = BAD_VALUE;
        break;
    }

    if (err == OK) {
    	// 缓存对应索引buffer端口模式
        mPortMode[portIndex] = mode;
    }
    return err;
}

3.1、该模式IOMX::PortMode枚举声明
也就是定了几种不同缓冲区buffer端口模式,将会采用不同的buffer来承载传递编解码数据

// [frameworks/av/media/libmedia/include/media/IOMX.h]
class IOMX : public RefBase {
    enum PortMode {
        kPortModePresetStart = 0,
        kPortModePresetByteBuffer,
        kPortModePresetANWBuffer,
        kPortModePresetSecureBuffer,
        kPortModePresetEnd,

        kPortModeDynamicStart = 100,
        kPortModeDynamicANWBuffer,      // uses metadata mode kMetadataBufferTypeANWBuffer
                                        // or kMetadataBufferTypeGrallocSource
        kPortModeDynamicNativeHandle,   // uses metadata mode kMetadataBufferTypeNativeHandleSource
        kPortModeDynamicEnd,
    };
}

3.2、enableNativeBuffers_l(portIndex, OMX_TRUE /graphic/, OMX_TRUE)实现分析:
启用native buffer

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::enableNativeBuffers_l(
        OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
    // 安全buffer类型枚举,见3.2.1小节声明
    // 判断不能大于该buffer类型数组最大索引值
    if (portIndex >= NELEM(mSecureBufferType)) {
        ALOGE("b/31385713, portIndex(%u)", portIndex);
        android_errorWriteLog(0x534e4554, "31385713");
        return BAD_VALUE;
    }
    // 由参数可知,graphic和enable这两个值为true

    CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
                graphic ? ", graphic" : "", enable);
    // graphic为true时启用android native buffer传递解码数据,否则为分配native句柄访问
    // 此处为强转为OMX框架层的扩展参数数据类型
    // 备注:举例SotfAVCDec即安卓原生h264解码器对这两个buffer参数类型(扩展参数类型)支持情况,都不支持。
    OMX_STRING name = const_cast<OMX_STRING>(
            graphic ? "OMX.google.android.index.enableAndroidNativeBuffers"
                    : "OMX.google.android.index.allocateNativeHandle");

    // 获取该扩展参数类型索引,该方法见前面已有分析
    OMX_INDEXTYPE index;
    // 备注:举例SoftAVCDec都不支持,因此都会返回不支持错误码。然后进入失败流程走默认的buffer参数类型模式
    // 也就是说:在SoftAVCDec中,graphic为true时返回错误,graphic为false时将会采用 mSecureBufferType[portIndex] = kSecureBufferTypeOpaque
    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);

    if (err == OMX_ErrorNone) {
    	// 若支持该buffer分配数据模式时
    	// 创建OMX该参数
    	// 见3.2.2小节声明
        EnableAndroidNativeBuffersParams params;
        // 初始化该参数对象,见前面的分析
        InitOMXParams(&params);
        // 赋值
        params.nPortIndex = portIndex;
        params.enable = enable;

        // 设置参数,此为宏定义即如前面流程分析的将会执行具体组件的实现方法
        // 目前只举例简单阐述SoftAVCDec解码器其大致处理原理:
        // TODO 待分析
        err = OMX_SetParameter(mHandle, index, &params);
        CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
                      portString(portIndex), portIndex, enable);
        if (!graphic) {
        	// 图形标记为false时
            if (err == OMX_ErrorNone) {
            	// 底层处理成功时,根据enable来选择对应安全buffer类型类传递解码数据	
                mSecureBufferType[portIndex] =
                    enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
            	// 失败时,默认采用不透明数据模式
                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
            }
        } else {
        	// 图形标记为true时,表示根据enable来判断启用图形buffer类型
            if (err == OMX_ErrorNone) {
            	// 底层处理成功时,赋值
                mGraphicBufferEnabled[portIndex] = enable;
            } else if (enable) {
            	// 若要求启用图形buffer但又失败了即底层不支持,则直接该为false不启用该类型。
                mGraphicBufferEnabled[portIndex] = false;
            }
        }
    } else {
    	// 若上面获取要求的扩展参数类型索引失败时即底层不支持该buffer参数类型时
        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
        if (!graphic) {
        	// graphic为false即不采用图形buffer时
        	// 如注释:底层解码器不支持该buffer扩展参数类型时,因此将检查是否有设置系统属性来手动覆盖,
        	// 这只是个临时应变方案,直到底层实现组件支持这个OMX扩展数据类型。该属性默认未设置
            // Extension not supported, check for manual override with system property
            // This is a temporary workaround until partners support the OMX extension
            if (property_get_bool("media.mediadrmservice.enable", false)) {
                CLOG_CONFIG(enableNativeBuffers, "system property override: using native-handles");
                // 若设置为true即将会使用native buffer句柄访问
                mSecureBufferType[portIndex] = kSecureBufferTypeNativeHandle;
            } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
            	// 若未设置,则默认采用不透明数据模式
                mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
            }
            // 修正为成功
            err = OMX_ErrorNone;
        }
    }
	// OMX状态类型转换为native状态类型
	// 见3.2.3小节分析
    return StatusFromOMXError(err);
}

3.2.1、mSecureBufferType数据类型即SecureBufferType安全buffer类型枚举声明:

// [frameworks/av/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h]
    enum SecureBufferType {
        kSecureBufferTypeUnknown,
        // 不透明的安全数据类型
        kSecureBufferTypeOpaque,
        // native句柄的安全数据类型
        kSecureBufferTypeNativeHandle,
    };
    // 枚举数组
    SecureBufferType mSecureBufferType[2];

3.2.2、EnableAndroidNativeBuffersParams该OMX该参数声明:
【英文注释太多,因此去掉了,可以自行在android源码在线官网查看说明】
其实就是个简单的结构声明,有几个参数

// [frameworks/native/headers/media_plugin/media/hardware/HardwareAPI.h]
struct EnableAndroidNativeBuffersParams {
	// 该结构的数据大小
    OMX_U32 nSize;
    // 版本
    OMX_VERSIONTYPE nVersion;
    // 端口模式索引
    OMX_U32 nPortIndex;
    // 是否启用
    OMX_BOOL enable;
};

3.2.3、StatusFromOMXError(err)实现分析:
OMX状态类型转换为native状态类型

// [frameworks/av/media/libstagefright/omx/OMXUtils.cpp]
status_t StatusFromOMXError(OMX_ERRORTYPE err) {
    switch (err) {
    	// 成功
        case OMX_ErrorNone:
            return OK;
        // 数据不足    
        case OMX_ErrorNoMore:
            return NOT_ENOUGH_DATA;
        // 不支持    
        case OMX_ErrorUnsupportedSetting:
        case OMX_ErrorUnsupportedIndex:
            return ERROR_UNSUPPORTED; // this is a media specific error
        // 参数有误    
        case OMX_ErrorBadParameter:
            return BAD_VALUE;
        // 资源不足即内存不足    
        case OMX_ErrorInsufficientResources:
            return NO_MEMORY;
        // 无效组件名或组件未找到,转换为组件名未找到    
        case OMX_ErrorInvalidComponentName:
        case OMX_ErrorComponentNotFound:
            return NAME_NOT_FOUND;
        // 未知错误    
        default:
            return UNKNOWN_ERROR;
    }
}

3.3、storeMetaDataInBuffers_l(portIndex, OMX_TRUE, NULL)实现分析:
存储元数据buffer类型模式设置

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::storeMetaDataInBuffers_l(
        OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
    if (mSailed) {
        android_errorWriteLog(0x534e4554, "29422020");
        return INVALID_OPERATION;
    }
    if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
        android_errorWriteLog(0x534e4554, "26324358");
        if (type != NULL) {
            *type = kMetadataBufferTypeInvalid;
        }
        return BAD_VALUE;
    }
    
	// 通过举例SoftAVCDec模块实现可知,该组件不支持这两种buffer模式。

    OMX_INDEXTYPE index;
    OMX_STRING name = const_cast<OMX_STRING>(
            "OMX.google.android.index.storeMetaDataInBuffers");

    OMX_STRING nativeBufferName = const_cast<OMX_STRING>(
            "OMX.google.android.index.storeANWBufferInMetadata");
    MetadataBufferType negotiatedType;
    MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer;

    StoreMetaDataInBuffersParams params;
    InitOMXParams(&params);
    params.nPortIndex = portIndex;
    params.bStoreMetaData = enable;

    OMX_ERRORTYPE err =
        requestedType == kMetadataBufferTypeANWBuffer
                ? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index)
                : OMX_ErrorUnsupportedIndex;
    OMX_ERRORTYPE xerr = err;
    if (err == OMX_ErrorNone) {
        err = OMX_SetParameter(mHandle, index, &params);
        if (err == OMX_ErrorNone) {
            name = nativeBufferName; // set name for debugging
            negotiatedType = requestedType;
        }
    }
    if (err != OMX_ErrorNone) {
    	// 因此对于SoftAVCDec组件将执行此处,但也不支持
        err = OMX_GetExtensionIndex(mHandle, name, &index);
        xerr = err;
        if (err == OMX_ErrorNone) {
            negotiatedType =
                requestedType == kMetadataBufferTypeANWBuffer
                        ? kMetadataBufferTypeGrallocSource : requestedType;
            err = OMX_SetParameter(mHandle, index, &params);
        }
        if (err == OMX_ErrorBadParameter) {
        	// 因此对于SoftAVCDec组件将执行此处
            err = OMX_ErrorUnsupportedIndex;
        }
    }

    // don't log loud error if component does not support metadata mode on the output
    if (err != OMX_ErrorNone) {
        if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
        	// 若底层不支持,则上层会采用回退方式处理
            CLOGW("component does not support metadata mode; using fallback");
        } else if (xerr != OMX_ErrorNone) {
            CLOG_ERROR(getExtensionIndex, xerr, "%s", name);
        } else {
            CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index,
                    portString(portIndex), portIndex, enable, negotiatedType);
        }
        negotiatedType = mMetadataType[portIndex];
    } else {
        if (!enable) {
            negotiatedType = kMetadataBufferTypeInvalid;
        }
        mMetadataType[portIndex] = negotiatedType;
    }
    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u %srequested %s:%d negotiated %s:%d",
            portString(portIndex), portIndex, enable ? "" : "UN",
            asString(requestedType), requestedType, asString(negotiatedType), negotiatedType);

    if (type != NULL) {
        *type = negotiatedType;
    }
	
	// 注意:上面处理可能对于不同编/解码器会不支持而失败,但是看到这些错误log时其实也不会影响功能正常编解码

    return StatusFromOMXError(err);
}

4、mOMXNode->prepareForAdaptivePlayback(kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight)实现分析:
自适应播放准备请求

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::prepareForAdaptivePlayback(
        OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
        OMX_U32 maxFrameHeight) {
    Mutex::Autolock autolock(mLock);
    if (mHandle == NULL) {
        return DEAD_OBJECT;
    }

    if (mSailed) {
        android_errorWriteLog(0x534e4554, "29422020");
        return INVALID_OPERATION;
    }
    CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);

    if (mLegacyAdaptiveExperiment) {
        CLOG_INTERNAL(prepareForAdaptivePlayback,
                "Legacy adaptive experiment: reporting success");
        return OK;
    }
    // 前面三个判断见此前相关分析

    OMX_INDEXTYPE index;
    // 备注:该buffer扩展OMX参数类型在SoftAVCDec组件中支持
    OMX_STRING name = const_cast<OMX_STRING>(
            "OMX.google.android.index.prepareForAdaptivePlayback");
	
	// 备注:SoftAVCDec组件中支持返回成功,并返回index = kPrepareForAdaptivePlaybackIndex;
    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
    if (err != OMX_ErrorNone) {
        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
        return StatusFromOMXError(err);
    }

    // 创建该参数对象,其声明见下面的分析
    PrepareForAdaptivePlaybackParams params;
    // 初始化,见此前流程中分析
    InitOMXParams(&params);
    // 赋值
    params.nPortIndex = portIndex;
    params.bEnable = enable;
    params.nMaxFrameWidth = maxFrameWidth;
    params.nMaxFrameHeight = maxFrameHeight;

    // 再次请求具体实现组件的设置参数方法
    // 备注:按照此前国际惯例具体组件暂不分析,只简单阐述其大致工作:
    // 注意此时的index = kPrepareForAdaptivePlaybackIndex,
    // 解析参数,并记录支持自适应播放模式,缓存视频最大宽高及其默认宽高值。
    // 并更新输入输出buffer端口配置信息(最初在构造函数中初始化的)例如帧宽高、步幅、色彩空间模式、buffer大小等
    err = OMX_SetParameter(mHandle, index, &params);
    CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index,
            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
    // 最后正常情况下返回成功状态。        
    return StatusFromOMXError(err);
}

PrepareForAdaptivePlaybackParams 结构声明:

// [frameworks/native/headers/media_plugin/media/hardware/HardwareAPI.h]
struct PrepareForAdaptivePlaybackParams {
    OMX_U32 nSize;
    OMX_VERSIONTYPE nVersion;
    OMX_U32 nPortIndex;
    OMX_BOOL bEnable;
    OMX_U32 nMaxFrameWidth;
    OMX_U32 nMaxFrameHeight;
};

5、setupVideoDecoder(mime, msg, haveNativeWindow, usingSwRenderer, outputFormat)实现分析:
视频解码器初始化
备注:通过前面分析可知,在安卓原生SoftAVCDec软解码器组件时,haveNativeWindow值为false,usingSwRenderer为true。

// [frameworks/av/media/libstagefright/ACodec.cpp]
status_t ACodec::setupVideoDecoder(
        const char *mime, const sp<AMessage> &msg, bool haveNativeWindow,
        bool usingSwRenderer, sp<AMessage> &outputFormat) {
    int32_t width, height;
    // 获取原始输入格式的宽高
    if (!msg->findInt32("width", &width)
            || !msg->findInt32("height", &height)) {
        return INVALID_OPERATION;
    }

	// 根据mime格式获取对应的OMX支持的视频编码类型枚举
    OMX_VIDEO_CODINGTYPE compressionFormat;
    // 见5.1小节分析
    status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);

    if (err != OK) {
        return err;
    }

    if (compressionFormat == OMX_VIDEO_CodingHEVC) {
    	// 判断压缩格式即视频编码格式为HEVC即H265时
        int32_t profile;
        // 获取编码档次级别,并且判断该档次级别是否被当前解码器组件支持,不支持则直接fail
        // 备注:目前只举例分析AVC即h264解码器处理原理,因此暂不展开此处理分析
        if (msg->findInt32("profile", &profile)) {
            // verify if Main10 profile is supported at all, and fail
            // immediately if it's not supported.
            if (profile == OMX_VIDEO_HEVCProfileMain10 ||
                profile == OMX_VIDEO_HEVCProfileMain10HDR10) {
                err = verifySupportForProfileAndLevel(
                        kPortIndexInput, profile, 0);
                if (err != OK) {
                    return err;
                }
            }
        }
    }

	// 备注:目前只举例分析AVC即h264解码器处理原理,因此暂不展开此处理分析
    if (compressionFormat == OMX_VIDEO_CodingVP9) {
        OMX_VIDEO_PARAM_PROFILELEVELTYPE params;
        InitOMXParams(&params);
        params.nPortIndex = kPortIndexInput;
        // Check if VP9 decoder advertises supported profiles.
        params.nProfileIndex = 0;
        status_t err = mOMXNode->getParameter(
                OMX_IndexParamVideoProfileLevelQuerySupported,
                &params, sizeof(params));
        mIsLegacyVP9Decoder = err != OK;
    }

    // 设置视频输入buffer端口格式类型信息
    // 见5.2小节分析
    err = setVideoPortFormatType(
            kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);

    if (err != OK) {
        return err;
    }

    int32_t tmp;
    // 获取色彩空间类型
    if (msg->findInt32("color-format", &tmp)) {
        OMX_COLOR_FORMATTYPE colorFormat =
            static_cast<OMX_COLOR_FORMATTYPE>(tmp);
        // 再次执行该方法不同参数,如上该方法处理分析可知,举例SoftAVCDec组件时此处将会返回失败    
        err = setVideoPortFormatType(
                kPortIndexOutput, OMX_VIDEO_CodingUnused, colorFormat, haveNativeWindow);
        if (err != OK) {
        	// 是否设置了缩略图模式
            int32_t thumbnailMode = 0;
            if (msg->findInt32("thumbnail-mode", &thumbnailMode) &&
                thumbnailMode) {
                // 如上该方法处理分析可知,举例SoftAVCDec组件时此处将会返回失败
                err = setVideoPortFormatType(
                kPortIndexOutput, OMX_VIDEO_CodingUnused,
                OMX_COLOR_FormatYUV420Planar, haveNativeWindow);
            }
            if (err != OK) {
            	// 此处将会在log中打印该不支持的色彩空间格式,但没关系,下面马上来处理默认加载可替代灵活格式
                ALOGW("[%s] does not support color format %d",
                      mComponentName.c_str(), colorFormat);
                // 可替代灵活格式处理流程
                // 见5.3小节分析
                // 备注:如下分析可知,举例SoftAVCDec时将会返回true
                err = setSupportedOutputFormat(!haveNativeWindow /* getLegacyFlexibleFormat */);
            }
        }
    } else {
        // 可替代灵活格式处理流程
        // 见5.3小节分析
        err = setSupportedOutputFormat(!haveNativeWindow /* getLegacyFlexibleFormat */);
    }

    if (err != OK) {
        return err;
    }

    // Set the component input buffer number to be |tmp|. If succeed,
    // component will set input port buffer number to be |tmp|. If fail,
    // component will keep the same buffer number as before.
    // 根据注释:此处为设置组件输入缓冲区buffer数量(大小),未设置该字段时则为默认输入端口buffer数量
    // 备注:也就是说我们可以(修改)指定底层缓冲区对应的缓冲区大小。
    // 一般情况下不需要设置,使用默认值即可,因此暂不分析。【举例SoftAVCDec组件支持该设置】
    if (msg->findInt32("android._num-input-buffers", &tmp)) {
        err = setPortBufferNum(kPortIndexInput, tmp);
        if (err != OK)
            return err;
    }

    // Set the component output buffer number to be |tmp|. If succeed,
    // component will set output port buffer number to be |tmp|. If fail,
    // component will keep the same buffer number as before.
    // 同上,此处设置输出buffer缓冲区大小
    if (msg->findInt32("android._num-output-buffers", &tmp)) {
        err = setPortBufferNum(kPortIndexOutput, tmp);
        if (err != OK)
            return err;
    }

    // 获取原始输入格式的帧率信息【此处通过获取两种不同类型数据来兼容处理】,未设置则为-1,正常情况都已设置
    int32_t frameRateInt;
    float frameRateFloat;
    if (!msg->findFloat("frame-rate", &frameRateFloat)) {
        if (!msg->findInt32("frame-rate", &frameRateInt)) {
            frameRateInt = -1;
        }
        frameRateFloat = (float)frameRateInt;
    }

	// 设置缓冲区(输入)端口buffer视频格式
	// 见5.4小节分析
    err = setVideoFormatOnPort(
            kPortIndexInput, width, height, compressionFormat, frameRateFloat);

    if (err != OK) {
        return err;
    }
	
	// 同上,设置缓冲区(输出)端口buffer视频格式
	// 见5.4小节分析
    err = setVideoFormatOnPort(
            kPortIndexOutput, width, height, OMX_VIDEO_CodingUnused);

    if (err != OK) {
        return err;
    }

    // 设置色彩空间配置信息如色彩矩阵转换系数类型等
    // 见5.5小节分析
    err = setColorAspectsForVideoDecoder(
            width, height, haveNativeWindow | usingSwRenderer, msg, outputFormat);
    // 该支持情况是可选的,因此不支持时处理为正确        
    if (err == ERROR_UNSUPPORTED) { // support is optional
        err = OK;
    }

    if (err != OK) {
        return err;
    }
	
	// 百度百科信息:
	// 高动态范围图像(High-Dynamic Range,简称HDR),相比普通的图像,可以提供更多的动态范围和图像细节,
	// 根据不同的曝光时间的LDR(Low-Dynamic Range,低动态范围图像),并利用每个曝光时间相对应最佳细节的LDR图像来合成最终HDR图像。
	// 它能够更好地反映出真实环境中的视觉效果。
    // 向底层组件设置HDR静态信息
    // 见5.6小节分析
    err = setHDRStaticInfoForVideoCodec(kPortIndexOutput, msg, outputFormat);
    // 由5.6分析可知,举例SoftAVCDec组件不支持该属性,但该属性为可选,因此允许修改为OK
    if (err == ERROR_UNSUPPORTED) { // support is optional
        err = OK;
    }
    return err;
}

5.1、GetVideoCodingTypeFromMime(mime, &compressionFormat)实现分析:
根据mime格式获取对应的OMX支持的视频编码类型枚举
由于本章节接下来内容篇幅过长,因此必须放入另一章节分析,请查看:
TODO 【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】【02】

上一篇:oracle表分区详解


下一篇:Java经典面试题详解:java面向对象程序设计耿祥义pdf