Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 1】

Android native MediaCodec编解码器模块化注册和创建处理流程
本系列文章分析的安卓源码版本:【Android 10.0 版本】

【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】章节分析中涉及到了MediaCodec编解码器创建处理流程,因此有必要此章节单独分析编解码器创建流程,主要会涉及到OpenMAX框架的实现和交互。

推荐涉及到的知识点:
Binder机制实现原理:Android C++底层Binder通信机制原理分析总结【通俗易懂】
ALooper机制实现原理:Android native层媒体通信架构AHandler/ALooper机制实现源码分析
Binder异常关闭监听:Android native层DeathRecipient对关联进程(如相关Service服务进程)异常关闭通知事件的监听实现源码分析

在start请求播放处理流程中有如下涉及代码:【省略其他代码】
有两种创建方式,format参数表示的是音频或视频track的媒体元数据信息(KV值)。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp]
void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
   
    CHECK(mCodec == NULL);

	// 获取音频或视频mime格式
    AString mime;
    CHECK(format->findString("mime", &mime));

    // 通过文件扩展格式mime判断
    mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
    // MEDIA_MIMETYPE_VIDEO_AVC:"video/avc"
    mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
	
	// 在该值后面添加decoder字符串
    mComponentName = mime;
    mComponentName.append(" decoder");
    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get());
    
    // 创建MediaCodec解码器对象
    
    // 第一种创建方式:根据文件扩展格式mime值
    // 见第1小节分析
    mCodec = MediaCodec::CreateByType(
            mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid, mUid);
   
   // 第二种创建方式:根据编码器组件名称
   // 见第2小节分析
            ALOGI("[%s] creating", mComponentName.c_str());
            mCodec = MediaCodec::CreateByComponentName(
                    mCodecLooper, mComponentName.c_str(), NULL /* err */, mPid, mUid);
}

1、MediaCodec::CreateByType() 实现分析:
方法声明

// [frameworks/av/media/libstagefright/include/media/stagefright/MediaCodec.h]

    static const pid_t kNoPid = -1;
    static const uid_t kNoUid = -1;

    static sp<MediaCodec> CreateByType(
            const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err = NULL,
            pid_t pid = kNoPid, uid_t uid = kNoUid);

方法实现

// [frameworks/av/media/libstagefright/MediaCodec.cpp]
// static
sp<MediaCodec> MediaCodec::CreateByType(
        const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
        uid_t uid) {
   
    Vector<AString> matchingCodecs;
	// 根据方法名可知,此处为查询匹配可处理指定mime类型格式数据的编/解码器组件名集合,缓存在[matchingCodecs]中返回
	// 见1.1小节分析
    MediaCodecList::findMatchingCodecs(
            mime.c_str(),
            encoder,
            0,
            &matchingCodecs);

	// err为调用端传入可用于接收错误码
    if (err != NULL) {
   
        *err = NAME_NOT_FOUND;
    }
    // 循环创建MediaCodec对象,并执行init来判断是否处理成功,
    // 成功则直接返回当前可处理该mime类型格式的编解码器MediaCodec编解码处理对象。
    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
   
    	// MediaCodec类声明和构造函数,见1.2小节分析
        sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
        AString componentName = matchingCodecs[i];
        // 初始化编解码器,检查是否初始化成功
        // 见1.3小节分析
        status_t ret = codec->init(componentName, true);
        if (err != NULL) {
   
            *err = ret;
        }
        // 成功则直接返回,否则循环尝试下一个组件
        if (ret == OK) {
   
            return codec;
        }
        ALOGD("Allocating component '%s' failed (%d), try next one.",
                componentName.c_str(), ret);
    }
    return NULL;
}

1.1、MediaCodecList::findMatchingCodecs() 实现分析:

// [frameworks/av/media/libstagefright/MediaCodecList.cpp]
//static
void MediaCodecList::findMatchingCodecs(
        const char *mime, bool encoder, uint32_t flags,
        Vector<AString> *matches) {
   
    matches->clear();

	// 先获取媒体编解码器列表操作对象【单列对象】
	// 见1.1.1小节分析
    const sp<IMediaCodecList> list = getInstance();
    if (list == nullptr) {
   
        return;
    }

    // 循环查询并匹配组件列表中支持当前mime类型格式的编解码器组件(插件)实例,
    // 因此可以知道,支持同一种mime媒体格式类型的编码器或解码器可能会有多个不同实现,如软/硬编解码器组件。
    size_t index = 0;
    for (;;) {
   
    	// 获取支持该mime类型格式的编解码器组件在组件列表中的匹配索引
    	// 见1.1.2小节分析
        ssize_t matchIndex =
            list->findCodecByType(mime, encoder, index);

        if (matchIndex < 0) {
   
        	// 若查询失败则表明列表中所有编解码器组件都不支持该mime类型数据的编解码
            break;
        }

        // 循环查找下一个组件的索引
        index = matchIndex + 1;

		// 获取对应组件列表索引的组件信息实例
		// 见1.1.3小节分析
        const sp<MediaCodecInfo> info = list->getCodecInfo(matchIndex);
        // 此次确保一定不能为空,否则报错
        CHECK(info != nullptr);
        // 获取当前匹配的组件名
        AString componentName = info->getCodecName
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值