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

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

【此章节小节编号就接着上一章节排列】
1、setComponentRole(encoder /* isEncoder */, mime)实现分析:
设置组件角色信息

// [frameworks/av/media/libstagefright/ACodec.cpp]
status_t ACodec::setComponentRole(
        bool isEncoder, const char *mime) {
    // 由前面很早章节分析过AVUtils该类实现方式,因此此处我们直接分析默认实现
    // 见1.1小节分析    
    const char *role = AVUtils::get()->getComponentRole(isEncoder, mime);
    if (role == NULL) {
        return BAD_VALUE;
    }
    // 设置组建角色信息,mOMXNode为此前【allocateNode】流程中创建的OMX组件节点接口对象
    // 见1.2小节分析
    status_t err = SetComponentRole(mOMXNode, role);
    if (err != OK) {
        ALOGW("[%s] Failed to set standard component role '%s'.",
             mComponentName.c_str(), role);
    }
    return err;
}

1.1、AVUtils::get()->getComponentRole(isEncoder, mime)实现分析:
由前面很早章节分析过AVUtils该类实现方式,因此此处我们直接分析默认实现

// [frameworks/av/media/libavextensions/stagefright/ACodec.cpp]
const char *AVUtils::getComponentRole(bool isEncoder, const char *mime) {
    return GetComponentRole(isEncoder,mime);
}

// [frameworks/av/media/libstagefright/omx/OMXUtils.cpp]
const char *GetComponentRole(bool isEncoder, const char *mime) {
	// 定义方法内结构,mime信息和编解码器角色信息映射
    struct MimeToRole {
        const char *mime;
        const char *decoderRole;
        const char *encoderRole;
    };

    // 定义该结构静态数组【所有mime信息的映射】
    static const MimeToRole kMimeToRole[] = {
#ifdef __ANDROID_VNDK_EXT__
// 默认该值在【libstagefright/foundation/Android.bp】和【libstagefright/omx/Android.bp】编译文件中已定义,因此将执行此处
        { MEDIA_MIMETYPE_AUDIO_EVRC,
          "audio_decoder.evrchw", "audio_encoder.evrc" },
        { MEDIA_MIMETYPE_AUDIO_QCELP,
          "audio_decoder.qcelp13Hw", "audio_encoder.qcelp13" },
        { MEDIA_MIMETYPE_VIDEO_DIVX,
          "video_decoder.divx", NULL },
        { MEDIA_MIMETYPE_VIDEO_DIVX4,
          "video_decoder.divx4", NULL },
        { MEDIA_MIMETYPE_VIDEO_DIVX311,
          "video_decoder.divx311", NULL },
        { MEDIA_MIMETYPE_VIDEO_WMV,
          "video_decoder.vc1",  NULL },
        { MEDIA_MIMETYPE_VIDEO_WMV_VC1,
          "video_decoder.vc1",  NULL },
        { MEDIA_MIMETYPE_AUDIO_AC3,
          "audio_decoder.ac3", NULL },
        { MEDIA_MIMETYPE_AUDIO_WMA,
          "audio_decoder.wma", NULL },
        { MEDIA_MIMETYPE_AUDIO_ALAC,
          "audio_decoder.alac", NULL },
        { MEDIA_MIMETYPE_AUDIO_APE,
          "audio_decoder.ape", NULL },
        { MEDIA_MIMETYPE_VIDEO_HEVC,
          "video_decoder.hevc", "video_encoder.hevc" },
        { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
            "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" },
        { MEDIA_MIMETYPE_AUDIO_EVRC,
            "audio_decoder.evrchw", "audio_encoder.evrc" },
        { MEDIA_MIMETYPE_AUDIO_QCELP,
            "audio_decoder.qcelp13Hw", "audio_encoder.qcelp13" },
        { MEDIA_MIMETYPE_VIDEO_MPEG4_DP,
            "video_decoder.mpeg4", NULL },
        { MEDIA_MIMETYPE_VIDEO_TME,
          NULL, "video_encoder.tme" },
        { MEDIA_MIMETYPE_AUDIO_MHAS,
            "audio_decoder.mpegh", "audio_encoder.mpegh" },
#endif
        { MEDIA_MIMETYPE_AUDIO_MPEG,
            "audio_decoder.mp3", "audio_encoder.mp3" },
        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
            "audio_decoder.mp1", "audio_encoder.mp1" },
        { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
            "audio_decoder.mp2", "audio_encoder.mp2" },
        { MEDIA_MIMETYPE_AUDIO_AMR_NB,
            "audio_decoder.amrnb", "audio_encoder.amrnb" },
        { MEDIA_MIMETYPE_AUDIO_AMR_WB,
            "audio_decoder.amrwb", "audio_encoder.amrwb" },
        { MEDIA_MIMETYPE_AUDIO_AAC,
            "audio_decoder.aac", "audio_encoder.aac" },
        { MEDIA_MIMETYPE_AUDIO_VORBIS,
            "audio_decoder.vorbis", "audio_encoder.vorbis" },
        { MEDIA_MIMETYPE_AUDIO_OPUS,
            "audio_decoder.opus", "audio_encoder.opus" },
        { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
            "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
        { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
            "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
        { MEDIA_MIMETYPE_VIDEO_AVC,
            "video_decoder.avc", "video_encoder.avc" },
        { MEDIA_MIMETYPE_VIDEO_HEVC,
            "video_decoder.hevc", "video_encoder.hevc" },
        { MEDIA_MIMETYPE_VIDEO_MPEG4,
            "video_decoder.mpeg4", "video_encoder.mpeg4" },
        { MEDIA_MIMETYPE_VIDEO_H263,
            "video_decoder.h263", "video_encoder.h263" },
        { MEDIA_MIMETYPE_VIDEO_VP8,
            "video_decoder.vp8", "video_encoder.vp8" },
        { MEDIA_MIMETYPE_VIDEO_VP9,
            "video_decoder.vp9", "video_encoder.vp9" },
        { MEDIA_MIMETYPE_VIDEO_AV1,
            "video_decoder.av1", "video_encoder.av1" },
        { MEDIA_MIMETYPE_AUDIO_RAW,
            "audio_decoder.raw", "audio_encoder.raw" },
        { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
            "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
#ifdef QTI_FLAC_DECODER
// QTI_FLAC_DECODER 默认在ACodec.cpp中定义了
#ifdef __ANDROID_VNDK_EXT__
// 执行此处
        { MEDIA_MIMETYPE_AUDIO_FLAC,
            "audio_decoder.flac", NULL },
#endif
#else
        { MEDIA_MIMETYPE_AUDIO_FLAC,
            "audio_decoder.flac", "audio_encoder.flac" },
#endif
#ifdef __ANDROID_VNDK_EXT__
        { MEDIA_MIMETYPE_AUDIO_DSD,
            "audio_decoder.dsd", NULL },
#endif
        { MEDIA_MIMETYPE_AUDIO_MSGSM,
            "audio_decoder.gsm", "audio_encoder.gsm" },
        { MEDIA_MIMETYPE_VIDEO_MPEG2,
            "video_decoder.mpeg2", "video_encoder.mpeg2" },
        { MEDIA_MIMETYPE_AUDIO_AC3,
            "audio_decoder.ac3", "audio_encoder.ac3" },
        { MEDIA_MIMETYPE_AUDIO_EAC3,
            "audio_decoder.eac3", "audio_encoder.eac3" },
        { MEDIA_MIMETYPE_AUDIO_EAC3_JOC,
            "audio_decoder.eac3_joc", "audio_encoder.eac3_joc" },
        { MEDIA_MIMETYPE_AUDIO_AC4,
            "audio_decoder.ac4", "audio_encoder.ac4" },
        { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
            "image_decoder.heic", "image_encoder.heic" },
    };

	// 从上面的分析中,可知,同一个mime格式可能有多个编解码器配置(实现)
	
    // 静态变量,计算该数组大小
    static const size_t kNumMimeToRole =
        sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);

	// 循环找到第一个mime匹配上的映射结构索引
    size_t i;
    for (i = 0; i < kNumMimeToRole; ++i) {
        if (!strcasecmp(mime, kMimeToRole[i].mime)) {
            break;
        }
    }

    // 未找到返回null
    if (i == kNumMimeToRole) {
        return NULL;
    }

    // 找到返回对应编码或解码器角色信息
    return isEncoder ? kMimeToRole[i].encoderRole
                  : kMimeToRole[i].decoderRole;
}

1.2、SetComponentRole(mOMXNode, role)实现分析:
设置组建角色信息,mOMXNode为此前流程中创建的OMX组件节点接口对象

// [frameworks/av/media/libstagefright/omx/OMXUtils.cpp]
status_t SetComponentRole(const sp<IOMXNode> &omxNode, const char *role) {
	// OMX组件角色类型参数对象,即用于OMX接口层的数据类型交互
	// 见1.2.1小节分析
    OMX_PARAM_COMPONENTROLETYPE roleParams;
	// 初始化OMX参数对象
    // 见1.2.2小节分析
    InitOMXParams(&roleParams);

    // 将传入的标准编解码器角色信息存入该角色参数中
    // OMX_MAX_STRINGNAME_SIZE值为128,即限制了组件名和角色名最大为128个字符包括结尾空字符
    strncpy((char *)roleParams.cRole,
            role, OMX_MAX_STRINGNAME_SIZE - 1);
	
	// 字符串结尾空字符
    roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';

	// 请求OMX框架层OMX节点接口对象设置参数方法
	// OMX_IndexParamStandardComponentRole:为OMX(参数)索引类型OMX_INDEXTYPE枚举
    // 见1.2.3小节分析
    return omxNode->setParameter(
            OMX_IndexParamStandardComponentRole,
            &roleParams, sizeof(roleParams));
}

1.2.1、OMX_PARAM_COMPONENTROLETYPE结构体声明:
OMX组件角色类型参数对象,即用于OMX接口层的数据类型交互

// [frameworks/native/headers/media_plugin/media/openmax/OMX_Core.h]
/** @ingroup comp */
typedef struct OMX_PARAM_COMPONENTROLETYPE {
	// 当前结构体数据大小(字节单位)
	// typedef uint32_t OMX_U32;
    OMX_U32 nSize;              /**< size of the structure in bytes */
    // OMX版本类型
    // 见下面声明
    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
    // 角色参数,char数组即字符串
    OMX_U8 cRole[OMX_MAX_STRINGNAME_SIZE];  /**< name of standard component which defines component role */
} OMX_PARAM_COMPONENTROLETYPE;

OMX_VERSIONTYPE 联合体 声明:

// [frameworks/native/headers/media_plugin/media/openmax/OMX_Core.h]

/** The OMX_VERSIONTYPE union is used to specify the version for
    a structure or component.  For a component, the version is entirely
    specified by the component vendor.  Components doing the same function
    from different vendors may or may not have the same version.  For
    structures, the version shall be set by the entity that allocates the
    structure.  For structures specified in the OMX 1.1 specification, the
    value of the version shall be set to 1.1.0.0 in all cases.  Access to the
    OMX_VERSIONTYPE can be by a single 32 bit access (e.g. by nVersion) or
    by accessing one of the structure elements to, for example, check only
    the Major revision.
 */
typedef union OMX_VERSIONTYPE
{
    struct
    {
    	// typedef unsigned char OMX_U8;
        OMX_U8 nVersionMajor;   /**< Major version accessor element */
        OMX_U8 nVersionMinor;   /**< Minor version accessor element */
        OMX_U8 nRevision;       /**< Revision version accessor element */
        OMX_U8 nStep;           /**< Step version accessor element */
    } s;
    OMX_U32 nVersion;           /**< 32 bit value to make accessing the
                                    version easily done in a single word
                                    size copy/compare operation */
} OMX_VERSIONTYPE;

1.2.2、InitOMXParams(&roleParams)实现分析:
初始化OMX参数对象,其实就是将其内存分配为0,再初始化字段值

// [frameworks/av/media/libstagefright/omx/innclude/media/stagefright/omx/OMXUtils.h]
template<class T>
static void InitOMXParams(T *params) {
    memset(params, 0, sizeof(T));
    params->nSize = sizeof(T);
    params->nVersion.s.nVersionMajor = 1;
    params->nVersion.s.nVersionMinor = 0;
    params->nVersion.s.nRevision = 0;
    params->nVersion.s.nStep = 0;
}

1.2.3、omxNode->setParameter(OMX_IndexParamStandardComponentRole,&roleParams, sizeof(roleParams))实现分析:
请求OMX框架层OMX节点接口对象设置参数方法
OMX_IndexParamStandardComponentRole:为OMX(参数)索引类型OMX_INDEXTYPE枚举
由前面【MediaCodec的allocateNode()】流程【omxNode】参数对象的创建流程可知,其最终实现类为OMXNodeInstance,中间有大量数据类转换进行Binder调用的代理类实现将不再分析,直接定位实现处:

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::setParameter(
        OMX_INDEXTYPE index, const void *params, size_t size) {
    Mutex::Autolock autoLock(mLock);
    // 具体编解码器so库中OMX组件类型结构【OMX_COMPONENTTYPE】对象访问句柄指针(void *)
    // 该值见此前MediaCodec创建章节分析
    if (mHandle == NULL) {
        return DEAD_OBJECT;
    }

    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
    CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);

    if (extIndex == OMX_IndexParamMaxFrameDurationForBitrateControl) {
    	// OMX参数类型为:码率控制的最大帧时长时
    	// 见下面的分析 
        return setMaxPtsGapUs(params, size);
    }

    // 检查OMX参数类型是否为有效类型枚举,若返回true表示非法禁止则不处理
    // 见下面的分析
    if (isProhibitedIndex_l(index)) {
        android_errorWriteLog(0x534e4554, "29422020");
        return BAD_INDEX;
    }

    // 向底层具体编解码器实现组件设置参数,该方法也是一个宏定义
    // 见下面的分析
    OMX_ERRORTYPE err = OMX_SetParameter(
            mHandle, index, const_cast<void *>(params));
    CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
    return StatusFromOMXError(err);
}

setMaxPtsGapUs(params, size)实现分析:
OMX参数类型为:码率控制的最大帧时长时。即设置最大PTS间隔时长

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
status_t OMXNodeInstance::setMaxPtsGapUs(const void *params, size_t size) {
	// 检查参数有效性,大小检查即是否为相同类型结构体
    if (params == NULL || size != sizeof(OMX_PARAM_U32TYPE)) {
        CLOG_ERROR(setMaxPtsGapUs, BAD_VALUE, "invalid params (%p,%zu)", params, size);
        return BAD_VALUE;
    }

    // 强制转换参数对象的字段值缓存
    // The incoming number is an int32_t contained in OMX_U32.
    // Cast to int32_t first then int64_t.
    mMaxTimestampGapUs = (int32_t)((OMX_PARAM_U32TYPE*)params)->nU32;

    return OK;
}

isProhibitedIndex_l(index)实现分析:
检查OMX参数类型是否为有效类型枚举,若返回true表示非法禁止则不处理,若为false则有效

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
	// 如注释:该严格扩展字符串数组只能该类内部使用,外部调用端禁止直接使用
    // these extensions can only be used from OMXNodeInstance, not by clients directly.
    static const char *restricted_extensions[] = {
        "OMX.google.android.index.storeMetaDataInBuffers",
        "OMX.google.android.index.storeANWBufferInMetadata",
        "OMX.google.android.index.prepareForAdaptivePlayback",
        "OMX.google.android.index.configureVideoTunnelMode",
        "OMX.google.android.index.useAndroidNativeBuffer2",
        "OMX.google.android.index.useAndroidNativeBuffer",
        "OMX.google.android.index.enableAndroidNativeBuffers",
        "OMX.google.android.index.allocateNativeHandle",
        "OMX.google.android.index.getAndroidNativeBufferUsage",
    };

    // 检查OMX参数类型是否有效
    // 备注:其实就是该枚举类型中每种特定枚举的开始和结尾区间内则有效
    if ((index > OMX_IndexComponentStartUnused && index < OMX_IndexComponentEndUnused)
            || (index > OMX_IndexPortStartUnused && index < OMX_IndexPortEndUnused)
            || (index > OMX_IndexAudioStartUnused && index < OMX_IndexAudioEndUnused)
            || (index > OMX_IndexVideoStartUnused && index < OMX_IndexVideoEndUnused)
            || (index > OMX_IndexCommonStartUnused && index < OMX_IndexCommonEndUnused)
            || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
                    && index < (OMX_INDEXTYPE)OMX_IndexExtAudioEndUnused)
            || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
                    && index < (OMX_INDEXTYPE)OMX_IndexExtVideoEndUnused)
            || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
                    && index < (OMX_INDEXTYPE)OMX_IndexExtOtherEndUnused)) {
        return false;
    }

	// 质疑的禁止扩展参数类型标记:默认为false
	// 备注:其实该参数只会设置一次true,后续将不会被设置为false,也就是该if处理只会进入一次。
    if (!mQueriedProhibitedExtensions) {
    	// 此处处理其实很简单,就是将上面严格扩展参数类型循环处理,
    	// 循环从mHandle即从编解码器组件so实现的OMX组件类型【OMX_COMPONENTTYPE】结构实现类功能,
    	// 获取该字符串对应的so库内部支持的【OMX_INDEXTYPE】参数索引类型值,然后存入全局排序集合中。
        for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
            OMX_INDEXTYPE ext;
            // 获取具体编解码器组件so库支持的OMX参数类型索引值,该方法为宏定义
            // 见下面的分析
            if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
        		// 添加具体编解码器组件so库支持的类型值到已排序列表数据中
        		// SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;    
                mProhibitedExtensions.add(ext);
            }
        }
        mQueriedProhibitedExtensions = true;
    }

	// 然后判断当前index是否在so库支持的私有index索引中存在,存在则返回true即表示被禁止设置的参数类型
    return mProhibitedExtensions.indexOf(index) >= 0;
}

OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) 实现分析:
获取具体编解码器组件so库支持的OMX参数类型索引值,该方法为宏定义

// [frameworks/native/headers/media_plugin/media/openmax/OMX_Core.h]

/** The OMX_GetExtensionIndex macro will invoke a component to translate
    a vendor specific configuration or parameter string into an OMX
    structure index.  There is no requirement for the vendor to support
    this command for the indexes already found in the OMX_INDEXTYPE
    enumeration (this is done to save space in small components).  The
    component shall support all vendor supplied extension indexes not found
    in the master OMX_INDEXTYPE enumeration.  This is a blocking call.

    The component should return from this call within 5 msec.

    @param [in] hComponent
        Handle of the component to be accessed.  This is the component
        handle returned by the call to the GetHandle function.
    @param [in] cParameterName
        OMX_STRING that shall be less than 128 characters long including
        the trailing null byte.  This is the string that will get
        translated by the component into a configuration index.
    @param [out] pIndexType
        a pointer to a OMX_INDEXTYPE to receive the index value.
    @return OMX_ERRORTYPE
        If the command successfully executes, the return code will be
        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
    @ingroup comp
 */
#define OMX_GetExtensionIndex(                              \
        hComponent,                                         \
        cParameterName,                                     \
        pIndexType)                                         \
        // 实际调用了so库实现的【OMX_COMPONENTTYPE】结构对象的该方法实现
    ((OMX_COMPONENTTYPE*)(hComponent))->GetExtensionIndex(  \
        hComponent,                                         \
        cParameterName,                                     \
        pIndexType)                     /* Macro End */

关于具体编解码器组件so库实现的【OMX_COMPONENTTYPE】结构对象,目前暂不分析。
因此此处只是简单将以h264解码器组件的处理类阐述其大致实现原理。
【后续将在h264/h265编解码器分析系列章节单独分析】
此处实现其实很简单,就是SoftAVCDec的父类实现,目前只支持上面的"OMX.google.android.index.prepareForAdaptivePlayback"对应返回kPrepareForAdaptivePlaybackIndex。

OMX_SetParameter(mHandle, index, const_cast<void *>(params)实现分析:
向底层具体编解码器实现组件设置参数,该方法也是一个宏定义。params参数强转为无类型指针参数。

// [frameworks/native/headers/media_plugin/media/openmax/OMX_Core.h]

/** The OMX_SetParameter macro will send an initialization parameter
    structure to a component.  Each structure shall be sent one at a time,
    in a separate invocation of the macro.  This macro can only be
    invoked when the component is in the OMX_StateLoaded state, or the
    port is disabled (when the parameter applies to a port). The
    nParamIndex parameter is used to indicate which structure is being
    passed to the component.  The application shall allocate the
    correct structure and shall fill in the structure size and version
    information (as well as the actual data) before invoking this macro.
    The application is free to dispose of this structure after the call
    as the component is required to copy any data it shall retain.  This
    is a blocking call.

    The component should return from this call within 20 msec.

    @param [in] hComponent
        Handle of the component to be accessed.  This is the component
        handle returned by the call to the OMX_GetHandle function.
    @param [in] nIndex
        Index of the structure to be sent.  This value is from the
        OMX_INDEXTYPE enumeration.
    @param [in] pComponentParameterStructure
        pointer to application allocated structure to be used for
        initialization by the component.
    @return OMX_ERRORTYPE
        If the command successfully executes, the return code will be
        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
    @ingroup comp
 */
#define OMX_SetParameter(                                   \
        hComponent,                                         \
        nParamIndex,                                        \
        pComponentParameterStructure)                       \
        // 和上一个方法类似处理,将会执行具体组件so实现的该方法指针执行的方法
    ((OMX_COMPONENTTYPE*)(hComponent))->SetParameter(       \
        hComponent,                                         \
        nParamIndex,                                        \
        pComponentParameterStructure)    /* Macro End */

简述底层工作原理:也是父类检查index是否有效,有效则获取该值并缓存在【mComponentRole】全局变量中。

2、findVideoBitrateControlInfo(msg, &bitrateMode, &bitrate, &quality)实现分析:
视频或图片编码器时,查找视频码率控制信息,默认为可变码率模式

// [frameworks/av/media/libstagefright/ACodec.cpp]
static bool findVideoBitrateControlInfo(const sp<AMessage> &msg,
        OMX_VIDEO_CONTROLRATETYPE *mode, int32_t *bitrate, int32_t *quality) {
    // 获取视频码率模式
    *mode = getVideoBitrateMode(msg);
    // 是否为恒定质量码率模式
    bool isCQ = (*mode == OMX_Video_ControlRateConstantQuality);
    // false则获取码率,true获取质量
    return (!isCQ && msg->findInt32("bitrate", bitrate))
         || (isCQ && msg->findInt32("quality", quality));
}

getVideoBitrateMode(msg)实现分析:
获取原输入格式码率模式信息,其实际就是模式类型转换,转换成OMX框架交互使用的类型,对应恒定码率、可变码率、恒定码率质量等模式。当前还有其他不常见模式暂不介绍。

// [frameworks/av/media/libstagefright/ACodec.cpp]
static OMX_VIDEO_CONTROLRATETYPE getVideoBitrateMode(const sp<AMessage> &msg) {
    int32_t tmp;
    // 获取原输入格式码率模式参数信息
    if (msg->findInt32("bitrate-mode", &tmp)) {
    	// 获取成功时
        // explicitly translate from MediaCodecInfo.EncoderCapabilities.
        // BITRATE_MODE_* into OMX bitrate mode.
        switch (tmp) {
            //BITRATE_MODE_CQ
            case 0: return OMX_Video_ControlRateConstantQuality;
            //BITRATE_MODE_VBR
            case 1: return OMX_Video_ControlRateVariable;
            //BITRATE_MODE_CBR
            case 2: return OMX_Video_ControlRateConstant;
            default: break;
        }
    }
    // 默认为可变码率模式
    return OMX_Video_ControlRateVariable;
}

3、setPortMode(kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer)实现分析:
设置输出缓冲区buffer端口模式为 kPortModeDynamicANWBuffer 即会使用动态ANativeWindowBuffer来传递已解码输出数据。
由于本章节接下来分析内容篇幅较长,因此见下一章节分析,请查看:
【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 6】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值