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

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

【此章节小节编号将重新排序】
(*decoder)->configure(format)实现分析:
解码器配置工作。该方法也是在父类中声明和实现的,如下
注意:此方法执行完毕后,第10.1小节NuPlayer的执行将会和此处后续流程是异步同时执行的!因为它们已经属于两个不同的消息循环线程中执行了。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp]
void NuPlayer::DecoderBase::configure(const sp<AMessage> &format) {
   
   
	// 也就是给自己的消息循环线程发送【kWhatConfigure】事件消息接收处理
    sp<AMessage> msg = new AMessage(kWhatConfigure, this);
    msg->setMessage("format", format);
    msg->post();
}

【kWhatConfigure】事件消息接收处理:

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp]
void NuPlayer::DecoderBase::onMessageReceived(const sp<AMessage> &msg) {
   
   
    switch (msg->what()) {
   
   
        case kWhatConfigure:
        {
   
   
            sp<AMessage> format;
            CHECK(msg->findMessage("format", &format));
            // 见下面的分析
            onConfigure(format);
            break;
        }
	}
}

onConfigure(format)实现分析:
解码器配置工作,创建MediaCodec处理流程。
关于下面分析的【MediaCodec::CreateByType】和【MediaCodec::CreateByComponentName】两种方式创建MediaCodec的处理流程请查看如下系列章节分析:【该流程处理是非常复杂的,需耐心掌握】
Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】

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

    mFormatChangePending = false;
    mTimeChangePending = false;

    // 缓冲Buffer操作代数值加1
    ++mBufferGeneration;

    // 获取当前音频或视频track的编码格式
    AString mime;
    CHECK(format->findString("mime", &mime));

    // 是否为音频
    mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
    // 是否为AVC即h264编码的视频格式
    // MEDIA_MIMETYPE_VIDEO_AVC:"video/avc"
    mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());

    mComponentName = mime;
    // mime格式字符串后面添加 " decoder" 字符串
    mComponentName.append(" decoder");
    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get());

    // 此处我们默认为空实现,关于AVUtils的实现原理此前章节中已有分析过,不再阐述,就是厂商可自定义编解码器so库实现
    mCodec = AVUtils::get()->createCustomComponentByName(mCodecLooper, mime.c_str(), false /* encoder */, format);
    if (mCodec == NULL) {
   
   
    // 创建MediaCodec,见上面推荐章节分析
    mCodec = MediaCodec::CreateByType(
            mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid, mUid);
    }
    // 此次处理安全编解码器流程,【CreateByComponentName】见相关章节分析
    int32_t secure = 0;
    if (format->findInt32("secure", &secure) && secure != 0) {
   
   
        if (mCodec != NULL) {
   
   
            mCodec->getName(&mComponentName);
            mComponentName.append(".secure");
            mCodec->release();
            ALOGI("[%s] creating", mComponentName.c_str());
            mCodec = MediaCodec::CreateByComponentName(
                    mCodecLooper, mComponentName.c_str(), NULL /* err */, mPid, mUid);
        }
    }
    if (mCodec == NULL) {
   
   
        ALOGE("Failed to create %s%s decoder",
                (secure ? "secure " : ""), mime.c_str());
        // 编解码器创建失败,发送未知错误码
        // 见第1小节分析
        handleError(UNKNOWN_ERROR);
        return;
    }
    mIsSecure = secure;
	
	// 获取(插件编解码器)组件名
	// 见第2小节分析
    mCodec->getName(&mComponentName);

    status_t err;
    if (mSurface != NULL) {
   
   
        // disconnect from surface as MediaCodec will reconnect
        // 如英文注释:断开native window,后续MediaCodec将会重连接
        // 该方法分析见前面第四章节中的分析
        err = nativeWindowDisconnect(mSurface.get(), "onConfigure");
        // We treat this as a warning, as this is a preparatory step.
        // Codec will try to connect to the surface, which is where
        // any error signaling will occur.
        ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
    }

    // 通常非加密源, pCrypto 为null
    // Modular DRM
    void *pCrypto;
    if (!format->findPointer("crypto", &pCrypto)) {
   
   
        pCrypto = NULL;
    }
    sp<ICrypto> crypto = (ICrypto*)pCrypto;
    // non-encrypted source won't have a crypto
    mIsEncrypted = (crypto != NULL);
    // configure is called once; still using OR in case the behavior changes.
    mIsEncryptedObservedEarlier = mIsEncryptedObservedEarlier || mIsEncrypted;
    ALOGV("onConfigure mCrypto: %p (%d)  mIsSecure: %d",
            crypto.get(), (crypto != NULL ? crypto->getStrongCount() : 0), mIsSecure);
	
	// 配置工作
	// 见第3小节分析
    err = mCodec->configure(
            format, mSurface, crypto, 0 /* flags */);

    if (err != OK) {
   
   
    	// 失败将会执行底层Codec的释放清除工作,并上报上层APP该错误事件。
    	// 备注:目前暂不分析错误处理流程的实现。TODO
        ALOGE("Failed to configure [%s] decoder (err=%d)", mComponentName.c_str(), err);
        mCodec->release();
        mCodec.clear();
        handleError(err)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值