MediaPlayer的start过程会调用到MediaPlayerService::Client的start函数,再调用Nuplayer对Decoder和MediaCodec进行初始化,然后找到解码器开始进行解码的工作。
1.Nuplayer::Decoder:解码模块。在播放的时候会调用MediaCodec去获取编解码列表,选择合适解码库。
2.MediaCodec:Decoder的代工。根据Decoder的要求,去MediaCodecList中查找解码器信息,然后选择合适的解码库。负责跟ACodec进行数据交互。
3…ACodec:主要负责解码相关工作。通过IOMXNode去控制解码器:设置参数,获取参数等。将从ACodecBufferChannel获取的解析之后的文件数据送给解析器。
下图的橙色边框内的时序就是start过程相关的。
start过程可以分为下面几个流程:
1.启动解析器,启动GenericSource的start过程,从MP3Source中读取解析后的数据。
2.创建Nuplayer::Decoder,初始化Decoder。
3.根据mine类型查找并创建解码器。
MediaPlayerService::Client的start函数经过层层调用会调用到NuPlayer::onStart,这个过程从时序图就可以看出来了,比较简单。NuPlayer::onStart函数一进来就对mSourceStarted进行判断,如果还没有启动则调用GenericSource::start。下面是相关代码。
void NuPlayer::onStart(int64_t startPositionUs, MediaPlayerSeekMode mode) {
if (!mSourceStarted) {
mSourceStarted = true;
mSource->start();
}
......
}
void NuPlayer::GenericSource::start() {
if (mAudioTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
}
......
}
咦,postReadBuffer不就是prepare流程会调用到的函数吗,它会发送kWhatReadBuffer给自己的消息处理函数,然后启动onReadBuffer的操作,从解析器的source,比如MP3Source中读取64帧的buffer。这个过程上一节已经分析过了,这里就不分析了。
Decoder是Nuplayer的一个内部类,它在start流程中的instantiateDecoder被初始化。start流程是如何调用到instantiateDecoder,可以直接看时序图。
status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange){
sp<AMessage> format = mSource->getFormat(audio); //从解析器获取格式信息
if (audio) {
if (mOffloadAudio){
}else{ //我这里不是mOffloadAudio,所以走这里
*decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer); //创建decoder
}
}
(*decoder)->init();
(*decoder)->configure(format); //把格式信息传递给decoder
}
先来看看mSource->getFormat是如何获取到格式信息的。mSource是Nuplayer::Source类型的,前面已经知道了mSource保存的是Nuplayer::Source的子类Nuplayer::GenericSource对象。由于GenericSource没有实现getFormat,所以这里先调用了Source::getFormat。
接着调用了子类GenericSource的getFormatMeta,getFormatMeta再去调用到getFormatMeta_l。
sp<AMessage> NuPlayer::Source::getFormat(bool audio) {
sp<MetaData> meta = getFormatMeta(audio);
sp<AMessage> msg = new AMessage;
convertMetaDataToMessage(meta, &msg) == OK;
}
sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
return source->getFormat();
}
我们上一节已经知道了mAudioTrack.mSource就是MP3Source wrapper的binder调用。所以这里source->getFormat()最终调用的是 MP3Source::getFormat。这个函数会返回MetaDataBase mMeta,这个是一个存储类,用于保存文件的详细信息,比如采样率,比特流,通道数量等等。
status_t MP3Source::getFormat(MetaDataBase &meta) {
meta = mMeta;
return OK;
}
MP3Extractor::MP3Extractor(...){
......
mMeta.setInt32(kKeySampleRate, sample_rate);
mMeta.setInt32(kKeyBitRate, bitrate * 1000);
mMeta.setInt32(kKeyChannelCount, num_channels);
......
}
这里我们知道了原来获取格式就是去获取MetaData,但是在返回调用的时候又调用了convertMetaDataToMessage。顾名思义,这个函数的作用就是把MetaData转换成AMessage,AMessage也是信息存储的一个类。
获得格式信息之后,会调用一个比较重要的函数NuPlayer::Decoder::onConfigure,我们来看看这个函数做了什么。
struct NuPlayer::Decoder : public DecoderBase {
sp<MediaCodec> mCodec;
}
void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid, mUid);
.......
}
可以看出函数onConfigure会先去创建MediaCodec,来看看CreateByType会去做什么操作
sp<MediaCodec> MediaCodec::CreateByType(...const AString &mime...){
Vector<AString> matchingCodecs;
MediaCodecList::findMatchingCodecs(mime.c_str(),encoder, 0,&matchingCodecs);
for (size_t i = 0; i < matchingCodecs.size(); ++i) { //我这里是音频,所以只有一个
sp<MediaCodec> codec = new MediaCodec(looper, pid, uid); //创建MediaCodec
AString componentName = matchingCodecs[i];
status_t ret = codec->init(componentName); //把解码器名字传递给MediaCodec
}
}
MediaCodecList::findMatchingCodecs的过程有点绕,直接来看时序图。
从时序图可以看出这个过程会去通过MediaPlayerService获取server端的MediaCodecList。如果没有已存在的解码器列表,会去重新获取,从omxStore中去获取列表。omxStore是一个驻留在Main_codecservice中的服务,它会在开机的时候使用MediaCodecsXmlParser去解析xml文件 ,获取到编解码器列表。omx相关的东西后续会开一节来讲解。
来看看codec->init(componentName)操作。componentName是一个形如OMX.google.vorbis.decoder的AString。
struct MediaCodec : public AHandler {
sp<CodecBase> mCodec; //struct ACodec : public AHierarchicalStateMachine, public CodecBase
}
status_t MediaCodec::init(const AString &name) {
mCodec = GetCodecBase(name);
}
sp<CodecBase> MediaCodec::GetCodecBase(const AString &name) {
if (name.startsWithIgnoreCase("c2.")) {
return CreateCCodec();
} else if (name.startsWithIgnoreCase("omx.")) { //我这边都是omx的,所以都是new ACodec
return new ACodec;
} else if......
}
到了这里ACodec已经创建完毕了,并且已经保存在MediaCodec的成员mCodec中了,往后就是通过MediaCodec来控制ACodec,继而控制解码器了。来梳理一下decoder初始化流程:
1.NuPlayer创建Decoder,保存在NuPlayer的sp
2.在创建MediaCodec之前会去查找编解码列表,找到匹配的omx组件。
3.创建MediaCodec,保存在Decoder的sp
4.在MediaCodec::init中创建ACodec,保存在MediaCodec的sp
接下来就是ACodec从ACodecBufferChannel获取解析后的数据流,然后传给真正的解码器去解码了。这个过程后面整理好相关逻辑再来讲…