承接上一章节分析:【六】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)