Android4.2.2多媒体架构MediaPlay的创建过程分析(二):解析器的创建
本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。
欢迎和大家交流。qq:1037701636 email: gzzaigcn2012@gmail.com
在上一文中,我们分析到setDataSource_pre()函数最终实际返回的是StagefrightPlayer类(class StagefrightPlayer : public MediaPlayerInterface).
1 .继续分析setDataSource 函数:
// now set data source setDataSource_post(p, p->setDataSource(fd, offset, length));
实际是多态下的StagefrightPlayer的setDataSource 函数的实现:
status_t StagefrightPlayer::setDataSource( const char *url, const KeyedVector<String8, String8> *headers) { return mPlayer->setDataSource(url, headers); }
mPlayer这个成员函数是new AwesomePlayer出来的对象,故最终是进入了stagefright中去做进一步的处理:
status_t AwesomePlayer::setDataSource( int fd, int64_t offset, int64_t length) { Mutex::Autolock autoLock(mLock); ... ..... return setDataSource_l(dataSource); }
status_t AwesomePlayer::setDataSource_l( const sp<DataSource> &dataSource) { sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);//创建一个解析器MPEG4Extractor,mime = NULL if (extractor == NULL) { return UNKNOWN_ERROR; } if (extractor->getDrmFlag()) { checkDrmStatus(dataSource); } return setDataSource_l(extractor); }
MediaExtractor类,可以理解为音视频数据源的解析器,我们来看其创建过程,传入是默认参数mime= NULL:
sp<MediaExtractor> MediaExtractor::Create( const sp<DataSource> &source, const char *mime) { sp<AMessage> meta; String8 tmp; if (mime == NULL) { float confidence; if (!source->sniff(&tmp, &confidence, &meta)) {//提取mime数值 ALOGV("FAILED to autodetect media content."); return NULL; } mime = tmp.string();//获取mime值 ALOGV("Autodetected media content as ‘%s‘ with confidence %.2f", mime, confidence); } //根据对文件解析的不同格式创建一个Extractor解析器 MediaExtractor *ret = NULL; if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")) { int fragmented = 0; if (meta != NULL && meta->findInt32("fragmented", &fragmented) && fragmented) { ret = new FragmentedMP4Extractor(source); } else { ret = new MPEG4Extractor(source); } ................. return ret; }
在这里穿插解释下MIME类型的概念,谷歌来的,应该是表示各种视频格式的一个字符段:
video/x-ms-asf asf video/mpeg mpeg mpg video/x-msvideo avi application/vnd.rn-realmedia rm audio/x-pn-realaudio ram ra audio/x-aiff aif aiff aifc audio/mpeg mpga mp3 audio/midi mid midi audio/wav wav audio/x-ms-wma wma video/x-ms-wmv wmv
2. 这里和大家简单分析source->sniff的实现过程,其目的很清楚就是获取当前视频源的MIME类型。
bool DataSource::sniff( String8 *mimeType, float *confidence, sp<AMessage> *meta) { *mimeType = ""; *confidence = 0.0f; meta->clear(); Mutex::Autolock autoLock(gSnifferMutex); for (List<SnifferFunc>::iterator it = gSniffers.begin(); it != gSniffers.end(); ++it) { String8 newMimeType; float newConfidence; sp<AMessage> newMeta; if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) { if (newConfidence > *confidence) { *mimeType = newMimeType; *confidence = newConfidence; *meta = newMeta; } } } return *confidence > 0.0; }
该函数中一个gSnifers的全局变量中查找注册的函数it,函数指针类型为SnifferFunc。那么这些函数是如何注册的呢,我们回到AwesomePlay的构造函数中去:
DataSource::RegisterDefaultSniffers();
void DataSource::RegisterDefaultSniffers() { RegisterSniffer(SniffMPEG4); RegisterSniffer(SniffFragmentedMP4); .......... char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { RegisterSniffer(SniffDRM); } }
我们看到其注册了多个函数指针,而这都是针对不同的格式进行的注册,将他维护在这个gSniffers迭代器中:
void DataSource::RegisterSniffer(SnifferFunc func) { Mutex::Autolock autoLock(gSnifferMutex); for (List<SnifferFunc>::iterator it = gSniffers.begin(); it != gSniffers.end(); ++it) { if (*it == func) { return; } } gSniffers.push_back(func);//保存函数指针 }
最终都回调到这个函数指针之中去:
bool SniffMPEG4( const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) { if (BetterSniffMPEG4(source, mimeType, confidence, meta)) { return true; } if (LegacySniffMPEG4(source, mimeType, confidence)) { ALOGW("Identified supported mpeg4 through LegacySniffMPEG4."); return true; } return false; }
这里的BetterSniffMPEG4()函数逻辑比较复杂,但总体思想是读取出source的一些头信息,如果好当前的MPEG4格式所需具备的信息一样则返回。
最终返回一个属于该source的MIEM类型,如这里假设的是MEDIA_MIMETYPE_CONTAINER_MPEG4的格式。
3.解析器的创建
经历过上述的过程,继续回到sp<MediaExtractor> MediaExtractor::Create()函数中去,根据提取到的MEME的类型,做如下操作。
ret = new MPEG4Extractor(source);
创建好上述的解析器后,我们回到AwesomePlayer::setDataSource_l()中,继续执行setDataSource_l(extractor),对新建的这个解析器做处理,其实质是显示音视频A/V的分离。
setVideoSource(extractor->getTrack(i));//设置视频源mVideoTrack ;
setAudioSource(extractor->getTrack(i));//设置音频源mAudioTrack;
mVideoTrack和mAudioTrack的做为创建的AwesomePlay的成员函数,其类型为MPEG4Source,继承了MediaSource。
sp<MediaSource> MPEG4Extractor::getTrack(size_t index) { status_t err; if ((err = readMetaData()) != OK) { return NULL; } Track *track = mFirstTrack; while (index > 0) { if (track == NULL) { return NULL; } track = track->next; --index; } if (track == NULL) { return NULL; } return new MPEG4Source( track->meta, mDataSource, track->timescale, track->sampleTable); }
到此为止就是讲视频源进行了A\V的分离,其过程是通过Stagefrightplay多媒体框架——>Awesomeplay——>MPEG4Extractor——>MPEG4Source.这几个过程。
4. 准备好解码器
在完成APP侧的setDataSource后,就进入prepare操作。在MPS侧由如下函数来实现:
status_t MediaPlayerService::Client::prepareAsync() { ALOGV("[%d] prepareAsync", mConnId); sp<MediaPlayerBase> p = getPlayer();//stragefrightplay类 if (p == 0) return UNKNOWN_ERROR; status_t ret; ret = p->prepareAsync(); #if CALLBACK_ANTAGONIZER ALOGD("start Antagonizer"); if (ret == NO_ERROR) mAntagonizer->start(); #endif return ret; }
getPlayer获取之前创建的播放器StagefrightPlayer这个对象,继续执行:
status_t StagefrightPlayer::prepareAsync() { return mPlayer->prepareAsync(); }
mPlayer即为Awesomeplayer,实际的实现如下:
status_t AwesomePlayer::prepareAsync_l() { if (mFlags & PREPARING) { return UNKNOWN_ERROR; // async prepare already pending } if (!mQueueStarted) { mQueue.start(); mQueueStarted = true; } modifyFlags(PREPARING, SET); mAsyncPrepareEvent = new AwesomeEvent( this, &AwesomePlayer::onPrepareAsyncEvent);//onPrepareAsyncEvent回调函数,事件处理 mQueue.postEvent(mAsyncPrepareEvent);//传入类对象AwesomeEvent,mAsyncPrepareEvent return OK; }
在这里将回答在(一)中提到的事件注册与处理的这个过程。
4.1 AwesomePlayer中的Event处理机制。
a. 首先这里需要来看mQueue,他是TimedEventQueue类的对象,称为时间事件队列。首次调用是,需要进行start。
void TimedEventQueue::start() { if (mRunning) { return; } mStopped = false; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_create(&mThread, &attr, ThreadWrapper, this);//创建一个进程 pthread_attr_destroy(&attr); mRunning = true; }
显而易见的是,这个e事件处理机制脱离了Awesomeplayer,独立创建了一个线程ThradWrapper,其内部调用thredEntry来处理
void TimedEventQueue::threadEntry() { prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0); for (;;) { int64_t now_us = 0; sp<Event> event; while (mQueue.empty()) { mQueueNotEmptyCondition.wait(mLock); } ....... }
该函数就是在不断等待着有事件需要处理,类似于一个Queue里面非空则一直阻塞,等待signal唤醒。
b.我们来看AwesomeEvent类继承了TimedEventQueue的Event内部类。其构造函数表明,将一个函数指针作为一个参数维护在mMethod。可以猜测到这个函数将会作为事件发生时的处理函数。那么这个过程如何触发呢?
struct AwesomeEvent : public TimedEventQueue::Event { AwesomeEvent( AwesomePlayer *player, void (AwesomePlayer::*method)()) : mPlayer(player), mMethod(method) { } protected: virtual ~AwesomeEvent() {} virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { (mPlayer->*mMethod)();//调用最终的注册的处理函数 } private: AwesomePlayer *mPlayer; void (AwesomePlayer::*mMethod)(); AwesomeEvent(const AwesomeEvent &); AwesomeEvent &operator=(const AwesomeEvent &); };
c. mQueue.postEvent(mAsyncPrepareEvent);//传入类对象AwesomeEvent,mAsyncPrepareEvent来实现事件的唤醒与处理
TimedEventQueue::event_id TimedEventQueue::postTimedEvent( const sp<Event> &event, int64_t realtime_us) { Mutex::Autolock autoLock(mLock); event->setEventID(mNextEventID++); List<QueueItem>::iterator it = mQueue.begin(); while (it != mQueue.end() && realtime_us >= (*it).realtime_us) { ++it; } QueueItem item; item.event = event; item.realtime_us = realtime_us; if (it == mQueue.begin()) { mQueueHeadChangedCondition.signal(); } mQueue.insert(it, item);//在mQueue中插入event mQueueNotEmptyCondition.signal();//发出信号触发事件 return event->eventID(); }
将当前的Event对象插入打Awesomeplayer的mQueue队列中,然后发出signal,唤醒threadEntry线程,让线程去处理当前的事件。
5.真正进入解码器创建的世界
void AwesomePlayer::onPrepareAsyncEvent() { //基于队列和事件机制调用 Mutex::Autolock autoLock(mLock); if (mFlags & PREPARE_CANCELLED) { ALOGI("prepare was cancelled before doing anything"); abortPrepare(UNKNOWN_ERROR); return; } if (mUri.size() > 0) { status_t err = finishSetDataSource_l(); if (err != OK) { abortPrepare(err); return; } } if (mVideoTrack != NULL && mVideoSource == NULL) { status_t err = initVideoDecoder();//初始化视频解码器 if (err != OK) { abortPrepare(err); return; } } if (mAudioTrack != NULL && mAudioSource == NULL) { status_t err = initAudioDecoder();//初始化饮品解码器 if (err != OK) { abortPrepare(err); return; } } modifyFlags(PREPARING_CONNECTED, SET); if (isStreamingHTTP()) { postBufferingEvent_l(); } else { finishAsyncPrepare_l();//完成异步的prepare } }
对于音视频解码器的创建和调用这里不在做分析,考虑到他是一块独特的模块,将在另一文中进行分析,自己也有很多内容需要进一步消化。