Android4.2.2多媒体架构MediaPlay的创建过程分析(二):解析器的创建

来源:互联网 发布:数据共享管理办法 编辑:程序博客网 时间:2024/06/05 11:29

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。

欢迎和大家交流。qq:1037701636 email: gzzaigcn2012@gmail.com

 

 

在上一文中,我们分析到setDataSource_pre()函数最终实际返回的是StagefrightPlayer类(class StagefrightPlayer : public MediaPlayerInterface).

1 .继续分析setDataSource 函数:

[html] view plain copy
  1. // now set data source  
  2. setDataSource_post(p, p->setDataSource(fd, offset, length));  

实际是多态下的StagefrightPlayer的setDataSource 函数的实现:

[html] view plain copy
  1. status_t StagefrightPlayer::setDataSource(  
  2.         const char *url, const KeyedVector<String8, String8> *headers) {  
  3.     return mPlayer->setDataSource(url, headers);  
  4. }  

mPlayer这个成员函数是new AwesomePlayer出来的对象,故最终是进入了stagefright中去做进一步的处理:

[cpp] view plain copy
  1. status_t AwesomePlayer::setDataSource(  
  2.         int fd, int64_t offset, int64_t length) {  
  3.     Mutex::Autolock autoLock(mLock);                                                                                                         ...                             .....                                                                                        return setDataSource_l(dataSource);  
  4. }  
[html] view plain copy
  1. status_t AwesomePlayer::setDataSource_l(  
  2.         const sp<DataSource> &dataSource) {  
  3.     sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);//创建一个解析器MPEG4Extractor,mime = NULL  
  4.   
  5.     if (extractor == NULL) {  
  6.         return UNKNOWN_ERROR;  
  7.     }  
  8.   
  9.     if (extractor->getDrmFlag()) {  
  10.         checkDrmStatus(dataSource);  
  11.     }  
  12.   
  13.     return setDataSource_l(extractor);  
  14. }  

MediaExtractor类,可以理解为音视频数据源的解析器,我们来看其创建过程,传入是默认参数mime= NULL:

[html] view plain copy
  1. sp<MediaExtractor> MediaExtractor::Create(  
  2.         const sp<DataSource> &source, const char *mime) {  
  3.     sp<AMessage> meta;  
  4.   
  5.     String8 tmp;  
  6.     if (mime == NULL) {  
  7.         float confidence;  
  8.         if (!source->sniff(&tmp, &confidence, &meta)) {//提取mime数值  
  9.             ALOGV("FAILED to autodetect media content.");  
  10.   
  11.             return NULL;  
  12.         }  
  13.   
  14.         mime = tmp.string();//获取mime值  
  15.         ALOGV("Autodetected media content as '%s' with confidence %.2f",  
  16.              mime, confidence);  
  17.     }  
  18.   
  19. //根据对文件解析的不同格式创建一个Extractor解析器  
  20.     MediaExtractor *ret = NULL;  
  21.     if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)  
  22.             || !strcasecmp(mime, "audio/mp4")) {  
  23.         int fragmented = 0;  
  24.         if (meta != NULL && meta->findInt32("fragmented", &fragmented) && fragmented) {  
  25.             ret = new FragmentedMP4Extractor(source);  
  26.         } else {  
  27.             ret = new MPEG4Extractor(source);  
  28.         }  
  29. .................  
  30.     return ret;  
  31. }  

在这里穿插解释下MIME类型的概念,谷歌来的,应该是表示各种视频格式的一个字符段:

[cpp] view plain copy
  1. video/x-ms-asf asf  
  2. video/mpeg mpeg mpg  
  3. video/x-msvideo avi  
  4. application/vnd.rn-realmedia rm  
  5. audio/x-pn-realaudio ram ra  
  6. audio/x-aiff aif aiff aifc  
  7. audio/mpeg mpga mp3  
  8. audio/midi mid midi  
  9. audio/wav wav  
  10. audio/x-ms-wma wma  
  11. video/x-ms-wmv wmv  

 

2. 这里和大家简单分析source->sniff的实现过程,其目的很清楚就是获取当前视频源的MIME类型。

[cpp] view plain copy
  1. bool DataSource::sniff(  
  2.         String8 *mimeType, float *confidence, sp<AMessage> *meta) {  
  3.     *mimeType = "";  
  4.     *confidence = 0.0f;  
  5.     meta->clear();  
  6.   
  7.     Mutex::Autolock autoLock(gSnifferMutex);  
  8.     for (List<SnifferFunc>::iterator it = gSniffers.begin();  
  9.          it != gSniffers.end(); ++it) {  
  10.         String8 newMimeType;  
  11.         float newConfidence;  
  12.         sp<AMessage> newMeta;  
  13.         if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {  
  14.             if (newConfidence > *confidence) {  
  15.                 *mimeType = newMimeType;  
  16.                 *confidence = newConfidence;  
  17.                 *meta = newMeta;  
  18.             }  
  19.         }  
  20.     }  
  21.   
  22.     return *confidence > 0.0;  
  23. }  

该函数中一个gSnifers的全局变量中查找注册的函数it,函数指针类型为SnifferFunc。那么这些函数是如何注册的呢,我们回到AwesomePlay的构造函数中去:

[html] view plain copy
  1. DataSource::RegisterDefaultSniffers();  
[html] view plain copy
  1. void DataSource::RegisterDefaultSniffers() {  
  2.     RegisterSniffer(SniffMPEG4);  
  3.     RegisterSniffer(SniffFragmentedMP4);  
  4. ..........  
  5.   
  6.     char value[PROPERTY_VALUE_MAX];  
  7.     if (property_get("drm.service.enabled", value, NULL)  
  8.             && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {  
  9.         RegisterSniffer(SniffDRM);  
  10.     }  
  11. }  

我们看到其注册了多个函数指针,而这都是针对不同的格式进行的注册,将他维护在这个gSniffers迭代器中:

[cpp] view plain copy
  1. void DataSource::RegisterSniffer(SnifferFunc func) {  
  2.     Mutex::Autolock autoLock(gSnifferMutex);  
  3.   
  4.     for (List<SnifferFunc>::iterator it = gSniffers.begin();  
  5.          it != gSniffers.end(); ++it) {  
  6.         if (*it == func) {  
  7.             return;  
  8.         }  
  9.     }  
  10.   
  11.     gSniffers.push_back(func);//保存函数指针  
  12. }  


最终都回调到这个函数指针之中去:

[cpp] view plain copy
  1. bool SniffMPEG4(  
  2.         const sp<DataSource> &source, String8 *mimeType, float *confidence,  
  3.         sp<AMessage> *meta) {  
  4.     if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {  
  5.         return true;  
  6.     }  
  7.   
  8.     if (LegacySniffMPEG4(source, mimeType, confidence)) {  
  9.         ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");  
  10.         return true;  
  11.     }  
  12.   
  13.     return false;  
  14. }  

这里的BetterSniffMPEG4()函数逻辑比较复杂,但总体思想是读取出source的一些头信息,如果好当前的MPEG4格式所需具备的信息一样则返回。

最终返回一个属于该source的MIEM类型,如这里假设的是MEDIA_MIMETYPE_CONTAINER_MPEG4的格式。

 

3.解析器的创建

经历过上述的过程,继续回到sp<MediaExtractor> MediaExtractor::Create()函数中去,根据提取到的MEME的类型,做如下操作。

[cpp] view plain copy
  1. 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。

[cpp] view plain copy
  1. sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {  
  2.     status_t err;  
  3.     if ((err = readMetaData()) != OK) {  
  4.         return NULL;  
  5.     }  
  6.   
  7.     Track *track = mFirstTrack;  
  8.     while (index > 0) {  
  9.         if (track == NULL) {  
  10.             return NULL;  
  11.         }  
  12.   
  13.         track = track->next;  
  14.         --index;  
  15.     }  
  16.   
  17.     if (track == NULL) {  
  18.         return NULL;  
  19.     }  
  20.   
  21.     return new MPEG4Source(  
  22.             track->meta, mDataSource, track->timescale, track->sampleTable);  
  23. }  

到此为止就是讲视频源进行了A\V的分离,其过程是通过Stagefrightplay多媒体框架——>Awesomeplay——>MPEG4Extractor——>MPEG4Source.这几个过程。

 

4. 准备好解码器

在完成APP侧的setDataSource后,就进入prepare操作。在MPS侧由如下函数来实现:

[cpp] view plain copy
  1. status_t MediaPlayerService::Client::prepareAsync()  
  2. {  
  3.     ALOGV("[%d] prepareAsync", mConnId);  
  4.     sp<MediaPlayerBase> p = getPlayer();//stragefrightplay类  
  5.     if (p == 0) return UNKNOWN_ERROR;  
  6.     status_t ret;   
  7.   
  8.     ret = p->prepareAsync();  
  9.       
  10. #if CALLBACK_ANTAGONIZER  
  11.     ALOGD("start Antagonizer");  
  12.     if (ret == NO_ERROR) mAntagonizer->start();  
  13. #endif  
  14.     return ret;  
  15. }  

getPlayer获取之前创建的播放器StagefrightPlayer这个对象,继续执行:

[cpp] view plain copy
  1. status_t StagefrightPlayer::prepareAsync() {  
  2.     return mPlayer->prepareAsync();  
  3. }  

mPlayer即为Awesomeplayer,实际的实现如下:

[cpp] view plain copy
  1. status_t AwesomePlayer::prepareAsync_l() {  
  2.     if (mFlags & PREPARING) {  
  3.         return UNKNOWN_ERROR;  // async prepare already pending  
  4.     }  
  5.   
  6.     if (!mQueueStarted) {  
  7.         mQueue.start();启动mQueue:TimeEventQueue首次启动  
  8.         mQueueStarted = true;  
  9.     }  
  10.   
  11.     modifyFlags(PREPARING, SET);  
  12.     mAsyncPrepareEvent = new AwesomeEvent(  
  13.             this, &AwesomePlayer::onPrepareAsyncEvent);//onPrepareAsyncEvent回调函数,事件处理  
  14.   
  15.     mQueue.postEvent(mAsyncPrepareEvent);//传入类对象AwesomeEvent,mAsyncPrepareEvent  
  16.   
  17.     return OK;  
  18. }  

在这里将回答在(一)中提到的事件注册与处理的这个过程。

 

4.1 AwesomePlayer中的Event处理机制。

a. 首先这里需要来看mQueue,他是TimedEventQueue类的对象,称为时间事件队列。首次调用是,需要进行start。

[cpp] view plain copy
  1. void TimedEventQueue::start() {  
  2.     if (mRunning) {  
  3.         return;  
  4.     }  
  5.   
  6.     mStopped = false;  
  7.   
  8.     pthread_attr_t attr;  
  9.     pthread_attr_init(&attr);  
  10.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);  
  11.   
  12.     pthread_create(&mThread, &attr, ThreadWrapper, this);//创建一个进程  
  13.   
  14.     pthread_attr_destroy(&attr);  
  15.   
  16.     mRunning = true;  
  17. }  

显而易见的是,这个Event事件处理机制脱离了Awesomeplayer,独立创建了一个线程ThradWrapper,其内部调用thredEntry来处理

[cpp] view plain copy
  1. void TimedEventQueue::threadEntry() {  
  2.     prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);  
  3.   
  4.     for (;;) {  
  5.         int64_t now_us = 0;  
  6.         sp<Event> event;  
  7.             while (mQueue.empty()) {  
  8.                 mQueueNotEmptyCondition.wait(mLock);  
  9.             }  
  10. .......  
  11. }  

该函数就是在不断等待着有事件需要处理,类似于一个Queue里面非空则一直阻塞,等待signal唤醒。

 

b.我们来看AwesomeEvent类继承了TimedEventQueue的Event内部类。其构造函数表明,将一个函数指针作为一个参数维护在mMethod。可以猜测到这个函数将会作为事件发生时的处理函数。那么这个过程如何触发呢?

[cpp] view plain copy
  1. struct AwesomeEvent : public TimedEventQueue::Event {  
  2.     AwesomeEvent(  
  3.             AwesomePlayer *player,  
  4.             void (AwesomePlayer::*method)())  
  5.         : mPlayer(player),  
  6.           mMethod(method) {  
  7.     }  
  8.   
  9. protected:  
  10.     virtual ~AwesomeEvent() {}  
  11.   
  12.     virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {  
  13.         (mPlayer->*mMethod)();//调用最终的注册的处理函数  
  14.     }  
  15.   
  16. private:  
  17.     AwesomePlayer *mPlayer;  
  18.     void (AwesomePlayer::*mMethod)();  
  19.   
  20.     AwesomeEvent(const AwesomeEvent &);  
  21.     AwesomeEvent &operator=(const AwesomeEvent &);  
  22. };  

 

c.  mQueue.postEvent(mAsyncPrepareEvent);//传入类对象AwesomeEvent,mAsyncPrepareEvent来实现事件的唤醒与处理

[cpp] view plain copy
  1. TimedEventQueue::event_id TimedEventQueue::postTimedEvent(  
  2.         const sp<Event> &event, int64_t realtime_us) {  
  3.     Mutex::Autolock autoLock(mLock);  
  4.   
  5.     event->setEventID(mNextEventID++);  
  6.   
  7.     List<QueueItem>::iterator it = mQueue.begin();  
  8.     while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {  
  9.         ++it;  
  10.     }  
  11.   
  12.     QueueItem item;  
  13.     item.event = event;  
  14.     item.realtime_us = realtime_us;  
  15.   
  16.     if (it == mQueue.begin()) {  
  17.         mQueueHeadChangedCondition.signal();  
  18.     }  
  19.   
  20.     mQueue.insert(it, item);//在mQueue中插入event  
  21.   
  22.     mQueueNotEmptyCondition.signal();//发出信号触发事件  
  23.   
  24.     return event->eventID();  
  25. }  

将当前的Event对象插入打Awesomeplayer的mQueue队列中,然后发出signal,唤醒threadEntry线程,让线程去处理当前的事件。

 

5.真正进入解码器创建的世界

[cpp] view plain copy
  1. void AwesomePlayer::onPrepareAsyncEvent() { //基于队列和事件机制调用  
  2.     Mutex::Autolock autoLock(mLock);  
  3.   
  4.     if (mFlags & PREPARE_CANCELLED) {  
  5.         ALOGI("prepare was cancelled before doing anything");  
  6.         abortPrepare(UNKNOWN_ERROR);  
  7.         return;  
  8.     }  
  9.   
  10.     if (mUri.size() > 0) {  
  11.         status_t err = finishSetDataSource_l();  
  12.   
  13.         if (err != OK) {  
  14.             abortPrepare(err);  
  15.             return;  
  16.         }  
  17.     }  
  18.   
  19.     if (mVideoTrack != NULL && mVideoSource == NULL) {  
  20.         status_t err = initVideoDecoder();//初始化视频解码器  
  21.   
  22.         if (err != OK) {  
  23.             abortPrepare(err);  
  24.             return;  
  25.         }  
  26.     }  
  27.   
  28.     if (mAudioTrack != NULL && mAudioSource == NULL) {  
  29.         status_t err = initAudioDecoder();//初始化饮品解码器  
  30.   
  31.         if (err != OK) {  
  32.             abortPrepare(err);  
  33.             return;  
  34.         }  
  35.     }  
  36.   
  37.     modifyFlags(PREPARING_CONNECTED, SET);  
  38.   
  39.     if (isStreamingHTTP()) {  
  40.         postBufferingEvent_l();  
  41.     } else {  
  42.         finishAsyncPrepare_l();//完成异步的prepare  
  43.     }  
  44. }  

对于音视频解码器的创建和调用这里不在做分析,考虑到他是一块独特的模块,将在另一文中进行分析,自己也有很多内容需要进一步消化。

附件:MediaPlayer的创建过程以及A/V的分离简易流程图:


 

 

阅读全文
0 0
原创粉丝点击