Android MediaPlayer(2)

来源:互联网 发布:淘宝厚底鞋 编辑:程序博客网 时间:2024/05/22 06:39

Android StagefrightPlayer调用流程

Android 2.3开始,Android MediaPlayer采用Stagefright框架。Based on Android 4.0.1.

StagefrightPlayer创建函数如下:(MediaPlayerService.cpp,详细过程见文章:Android Audio 数据流详解

[html] view plaincopyprint?
  1. static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,  
  2.         notify_callback_f notifyFunc)  
  3. {  
  4.     sp<MediaPlayerBase> p;  
  5.     switch (playerType) {  
  6.         case SONIVOX_PLAYER:  
  7.             LOGV(" create MidiFile");  
  8.             p = new MidiFile();  
  9.             break;  
  10.         case STAGEFRIGHT_PLAYER:  
  11.             LOGV(" create StagefrightPlayer");  
  12.             p = new StagefrightPlayer;  
  13.             break;  
  14.         case NU_PLAYER:  
  15.             LOGV(" create NuPlayer");  
  16.             p = new NuPlayerDriver;  
  17.             break;  
  18.         case TEST_PLAYER:  
  19.             LOGV("Create Test Player stub");  
  20.             p = new TestPlayerStub();  
  21.             break;  
  22.         default:  
  23.             LOGE("Unknown player type: %d", playerType);  
  24.             return NULL;  
  25.     }  
  26.     if (p != NULL) {  
  27.         if (p->initCheck() == NO_ERROR) {  
  28.             p->setNotifyCallback(cookie, notifyFunc);  
  29.         } else {  
  30.             p.clear();  
  31.         }  
  32.     }  
  33.     if (p == NULL) {  
  34.         LOGE("Failed to create player object");  
  35.     }  
  36.     return p;  
  37. }  

首先了解下系统本身的调用流程,StagefrightPlayer使用的AwesomePlayer来实现的,首先是Demuxer的实现,对于系统本身不支持的格式是没有分离器的,具体查看代码(本文以本地文件播放为例).

1. Demuxer的实现
Awesomeplayer.cpp的setDataSource_l(
  const sp<DataSource> &dataSource) {
  sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);

这个就是创建Demux的地方,查看代码MediaExtractor.cpp的create函数,datasource的sniff函数就是自动检测媒体格式容器的类型的,如果需要新增原系统无法识别的媒体格式,必然无法得到有效的分离器,所以这里需要自己创建自己Demuxer,每一种格式的XXXXExtractor.cpp函数中有个SniffXXXX函数,在Awesomeplayer的构造函数中的这一句DataSource::RegisterDefaultSniffers()就是注册好所有的sniff函数,写一个自己的XXXExtractor类,照样写个XXXXsinff函数,在RegisterDefaultSniffers中加入自己的函数。然后自已实现一个需要的Demuxer.通过Demuxer分离出音视频流后,就是进入解码阶段了。

 

2. AV Decoder

status_t AwesomePlayer::initVideoDecoder() {
  mVideoSource = OMXCodec::Create(
  mClient.interface(), mVideoTrack->getFormat(),
  false, 
  mVideoTrack);
这个就是创建的解码器了,create的最后一个参数就是分离出来的独立的视频流,具备的接口最重要的就是read接口,是分离器中实现的,这个track是XXXXExtractor中的getTrack获取的。


解码器的逻辑主要集中在OMXCodec.cpp中,在OMXCodec::Create中主要负责寻找匹配的codec并创建codec.

寻找匹配的codec:

[html] view plaincopyprint?
  1. Vector<String8> matchingCodecs;  
  2. findMatchingCodecs(  
  3.         mime, createEncoder, matchComponentName, flags, &matchingCodecs);  
  4.   
  5. if (matchingCodecs.isEmpty()) {  
  6.     return NULL;  
  7. }  

创建codec:

[html] view plaincopyprint?
  1. status_t err = omx->allocateNode(componentName, observer, &node);  
  2. if (err == OK) {  
  3.     LOGV("Successfully allocated OMX node '%s'", componentName);  
  4.   
  5.     sp<OMXCodec> codec = new OMXCodec(  
  6.             omx, node, quirks, flags,  
  7.             createEncoder, mime, componentName,  
  8.             source, nativeWindow);  
  9.   
  10.     observer->setCodec(codec);  
  11.   
  12.     err = codec->configureCodec(meta);  
  13.   
  14.     if (err == OK) {  
  15.         if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {  
  16.             codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;  
  17.         }  
  18.   
  19.         return codec;  
  20.     }  
  21.   
  22.     LOGV("Failed to configure codec '%s'", componentName);  
  23. }  


findMatchingCodecs这个函数就是查找解码器的,它在kDecoderInfo数组中寻找需要的解码器。

 

[html] view plaincopyprint?
  1. void OMXCodec::findMatchingCodecs(  
  2.         const char *mime,  
  3.         bool createEncoder, const char *matchComponentName,  
  4.         uint32_t flags,  
  5.         Vector<String8> *matchingCodecs) {  
  6.     matchingCodecs->clear();  
  7.   
  8.     for (int index = 0;; ++index) {  
  9.         const char *componentName;  
  10.   
  11.         if (createEncoder) {  
  12.             componentName = GetCodec(  
  13.                     kEncoderInfo,  
  14.                     sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),  
  15.                     mime, index);  
  16.         } else {  
  17.             componentName = GetCodec(  
  18.                     kDecoderInfo,  
  19.                     sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),  
  20.                     mime, index);  
  21.         }  
  22.   
  23.         if (!componentName) {  
  24.             break;  
  25.         }  
  26.   
  27.         // If a specific codec is requested, skip the non-matching ones.  
  28.         if (matchComponentName && strcmp(componentName, matchComponentName)) {  
  29.             continue;  
  30.         }  
  31.   
  32.         // When requesting software-only codecs, only push software codecs  
  33.         // When requesting hardware-only codecs, only push hardware codecs  
  34.         // When there is request neither for software-only nor for  
  35.         // hardware-only codecs, push all codecs  
  36.         if (((flags & kSoftwareCodecsOnly) &&   IsSoftwareCodec(componentName)) ||  
  37.             ((flags & kHardwareCodecsOnly) &&  !IsSoftwareCodec(componentName)) ||  
  38.             (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {  
  39.   
  40.             matchingCodecs->push(String8(componentName));  
  41.         }  
  42.     }  
  43.   
  44.     if (flags & kPreferSoftwareCodecs) {  
  45.         matchingCodecs->sort(CompareSoftwareCodecsFirst);  
  46.     }  
  47. }  

 

差不多流程是这样把,关于显示部分就不用管了,解码器对接render部分,应该自己会弄好,解码器最重要的对外接口也就是read接口的,返回的一帧帧的解码后的数据,
http://blog.csdn.net/myarrow/article/details/7043494

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Android Audio 数据流详解

 Android Audio Architecture 图如下所示

详细调用路径如下

1. 音频播放
示例代码
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();

1.1 MediaPlayer mp = new MediaPlayer()

实现流程如下表:

函数名文件名MediaPlayer:: MediaPlayerMediaPlayer.JavaMediaPlayer::native_setupMediaPlayer.Javaandroid_media_MediaPlayer_native_setupandroid_media_MediaPlayer.cppMediaPlayer::MediaPlayerMediaPlayer.cpp

1.2 mp.setDataSource(PATH_TO_FILE);

实现流程如下:

函数名文件名MediaPlayer::setDataSourceMediaPlayer.Javaandroid_media_MediaPlayer_setDataSourceandroid_media_MediaPlayer.cppMediaPlayer::setDataSource

MediaPlayer.cpp

   -MediaPlayer::getMediaPlayerServiceMediaPlayer.cpp   -IMediaPlayerServiceIMediaPlayerService.h   -IMediaPlayerService::createMediaPlayer.cpp       --MediaPlayerService::createMediaPlayerService.cpp   -IMediaPlayer::setDataSourceMediaPlayer.cpp      --BpMediaPlayer::setDataSourceIMediaPlayer.cpp          --MediaPlayerService::Client::setDataSource(真正执行操作)MediaPlayerService.cpp             --android::createPlayerMediaPlayerService.cpp                    -- new StagefrightPlayerMediaPlayerService.cpp            --new AudioOutputMediaPlayerService.cpp           --StagefrightPlayer::setDataSourceStagefrightPlayer.cpp              --AwesomePlayer::setDataSourceAwesomePlayer.cpp                  --AwesomePlayer::setDataSource_lAwesomePlayer.cpp

1.3 mp.prepare() 

函数名文件名MediaPlayer:: prepareMediaPlayer.Java android_media_MediaPlayer_prepareandroid_media_MediaPlayer.cppMediaPlayer:: prepareMediaPlayer.cpp    MidiFile:: prepareMidiFile.cpp    VorbisPlayer:: prepare VorbisPlayer.cpp          VorbisPlayer::createOutputTrackVorbisPlayer.cpp               AudioOutput::openMediaPlayerService.cpp                  AudioTrack::AudioTrackAudioTrack.cpp                       AudioSystem::get_audio_flingerAudioSystem.cpp                       AudioFlinger::createTrackAudioFlinger.cpp    

1.4 mp.start()

函数名文件名MediaPlayer:: startMediaPlayer.Javaandroid_media_MediaPlayer_startandroid_media_MediaPlayer.cppMediaPlayer::startMediaPlayer.cpp   PVPlayer:: startPVPlayer.h   MidiFile:: startMidiFile.cpp   VorbisPlayer:: startVorbisPlayer.cpp       AudioTrack::startAudioTrack.cpp

MediaPlayerService:: MediaPlayerService(MediaPlayerService.cpp)由systemserver进程创建,在文件system_init.cpp里的函数system_init()调用MediaPlayerService::instantiate创建

getPlayerType(MediaPlayerService.cpp)返回3种player:
1) PV_PLAYER:播放mp3
2) SONIVOX_PLAYER:播放midi
3) VORBIS_PLAYER:播放ogg,

简单说来,播放流程如下:
Java端发起调用,MediaPlayer会转至MediaPlayerService,然后会调用相应的解码工具解码后创建AudioTrack,所有待输出的AudioTrack在AudioFlinger::AudioMixer里合成,然后通过AudioHAL(AudioHardwareInterface的实际实现者)传至实际的硬件来实现播放

 http://blog.csdn.net/myarrow/article/details/7036955

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 AwesomePlayer的启动工作

继前一篇文章AwesomePlayer的准备工作,本文主要描述当Java调用mp.start();时,AwesomePlayer做了些什么...

1. AwesomePlayer::play_l

  其调用流程如下:

    StagefrightPlayer::start->

       AwesomePlayer::play->

         AwesomePlayer::play_l

    AwesomePlayer::play_l主要代码如下:

 

[cpp] view plaincopyprint?
  1. status_t AwesomePlayer::play_l() {  
  2.     modifyFlags(SEEK_PREVIEW, CLEAR);  
  3.   
  4.     modifyFlags(PLAYING, SET);  
  5.     modifyFlags(FIRST_FRAME, SET);  
  6.       
  7.     // 创建AudioPlayer  
  8.     if (mAudioSource != NULL) {  
  9.         if (mAudioPlayer == NULL) {  
  10.             if (mAudioSink != NULL) {  
  11.                 mAudioPlayer = new AudioPlayer(mAudioSink, this);  
  12.                 mAudioPlayer->setSource(mAudioSource);  
  13.   
  14.                 mTimeSource = mAudioPlayer;  
  15.   
  16.                 // If there was a seek request before we ever started,  
  17.                 // honor the request now.  
  18.                 // Make sure to do this before starting the audio player  
  19.                 // to avoid a race condition.  
  20.                 seekAudioIfNecessary_l();  
  21.             }  
  22.         }  
  23.   
  24.         CHECK(!(mFlags & AUDIO_RUNNING));  
  25.           
  26.         //如果只播放音频,则启动AudioPlayer  
  27.         if (mVideoSource == NULL) {  
  28.             // We don't want to post an error notification at this point,  
  29.             // the error returned from MediaPlayer::start() will suffice.  
  30.   
  31.             status_t err = startAudioPlayer_l(  
  32.                     false /* sendErrorNotification */);  
  33.   
  34.             if (err != OK) {  
  35.                 delete mAudioPlayer;  
  36.                 mAudioPlayer = NULL;  
  37.   
  38.                 modifyFlags((PLAYING | FIRST_FRAME), CLEAR);  
  39.   
  40.                 if (mDecryptHandle != NULL) {  
  41.                     mDrmManagerClient->setPlaybackStatus(  
  42.                             mDecryptHandle, Playback::STOP, 0);  
  43.                 }  
  44.   
  45.                 return err;  
  46.             }  
  47.         }  
  48.     }  
  49.   
  50.     if (mTimeSource == NULL && mAudioPlayer == NULL) {  
  51.         mTimeSource = &mSystemTimeSource;  
  52.     }  
  53.   
  54.     // 启动视频回放  
  55.     if (mVideoSource != NULL) {  
  56.         // Kick off video playback  
  57.         postVideoEvent_l();  
  58.   
  59.         if (mAudioSource != NULL && mVideoSource != NULL) {  
  60.             postVideoLagEvent_l();  
  61.         }  
  62.     }  
  63.   
  64.     ...  
  65.   
  66.     return OK;  
  67. }  

 


1.1 创建AudioPlayer

      创建AudioPlayer,创建之后,如果只播放音频,则调用AwesomePlayer::startAudioPlayer_l启动音频播放,在启动音频播放时,主要调用以下启动工作:

     AudioPlayer::start->

          mSource->start

          mSource->read

          mAudioSink->open

          mAudioSink->start

1.2 启动视频回放

      调用AwesomePlayer::postVideoEvent_l启动视频回放。此函数代码如下:

 

[cpp] view plaincopyprint?
  1. void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {  
  2.     if (mVideoEventPending) {  
  3.         return;  
  4.     }  
  5.   
  6.     mVideoEventPending = true;  
  7.     mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);  
  8. }  

 


    前面已经讲过, mQueue.postEventWithDelay发送一个事件到队列中,最终执行事件的fire函数。这些事件的初始化在AwesomePlayer::AwesomePlayer中进行。

 

[cpp] view plaincopyprint?
  1. AwesomePlayer::AwesomePlayer()  
  2.     : mQueueStarted(false),  
  3.       mUIDValid(false),  
  4.       mTimeSource(NULL),  
  5.       mVideoRendererIsPreview(false),  
  6.       mAudioPlayer(NULL),  
  7.       mDisplayWidth(0),  
  8.       mDisplayHeight(0),  
  9.       mFlags(0),  
  10.       mExtractorFlags(0),  
  11.       mVideoBuffer(NULL),  
  12.       mDecryptHandle(NULL),  
  13.       mLastVideoTimeUs(-1),  
  14.       mTextPlayer(NULL) {  
  15.     CHECK_EQ(mClient.connect(), (status_t)OK);  
  16.   
  17.     DataSource::RegisterDefaultSniffers();  
  18.   
  19.     mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);  
  20.     mVideoEventPending = false;  
  21.     mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);  
  22.     mStreamDoneEventPending = false;  
  23.     mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);  
  24.     mBufferingEventPending = false;  
  25.     mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);  
  26.     mVideoEventPending = false;  
  27.   
  28.     mCheckAudioStatusEvent = new AwesomeEvent(  
  29.             this, &AwesomePlayer::onCheckAudioStatus);  
  30.   
  31.     mAudioStatusEventPending = false;  
  32.   
  33.     reset();  
  34. }  

 


      现在明白了,对于mVideoEnent,最终将执行函数AwesomePlayer::onVideoEvent,一层套一层,再继续向下看看... 

1.2.1 AwesomePlayer::onVideoEvent

相关简化代码如下:

 

[cpp] view plaincopyprint?
  1. <span style="font-size: 10px;">void AwesomePlayer::postVideoEvent_l(int64_t delayUs)  
  2. {  
  3.   mQueue.postEventWithDelay(mVideoEvent, delayUs);  
  4. }  
  5.   
  6. void AwesomePlayer::onVideoEvent()  
  7. {  
  8.   mVideoSource->read(&mVideoBuffer,&options);  //获取解码后的YUV数据  
  9.   [Check Timestamp]                        //进行AV同步  
  10.   mVideoRenderer->render(mVideoBuffer);   //显示解码后的YUV数据  
  11.   
  12.   postVideoEvent_l();    //进行下一帧的显示  
  13. }  
  14. </span>  

 

 

1)调用OMXCodec::read创建mVideoBuffer

2)调用AwesomePlayer::initRenderer_l初始化mVideoRender

 

[cpp] view plaincopyprint?
  1. if (USE_SURFACE_ALLOC  //硬件解码  
  2.         && !strncmp(component, "OMX.", 4)  
  3.         && strncmp(component, "OMX.google.", 11)) {  
  4.     // Hardware decoders avoid the CPU color conversion by decoding  
  5.     // directly to ANativeBuffers, so we must use a renderer that  
  6.     // just pushes those buffers to the ANativeWindow.  
  7.     mVideoRenderer =  
  8.         new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);  
  9. else {  //软件解码  
  10.     // Other decoders are instantiated locally and as a consequence  
  11.     // allocate their buffers in local address space.  This renderer  
  12.     // then performs a color conversion and copy to get the data  
  13.     // into the ANativeBuffer.  
  14.     mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);  
  15. }  

 


3)调用AwesomePlayer::startAudioPlayer_l启动音频播放

4)然后再循环调用postVideoEvent_l来post mVideoEvent事件,以循环工作。

 其主要对象及关系如下图所示:

 

 

 2. AwesomePlayer数据流

 

 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

AwesomePlayer的准备工作

1. 前提条件

本文以播放本地文件为例,且setDataSource时传入的是文件的url地址。

在Java中,若要播放一个本地文件,其代码如下:

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE); ...... (1)
mp.prepareAsync(); ........................ (2)、(3)
当收到视频准备完毕,收到OnPreparedListener时
mp.start(); .......................... (4)

在AwesomePlayer中,则会看到相应的处理;

 

2. AwesomePlayer::setDataSource

为了能播放本地文件,需要通过AwesomePlayer::setDataSource来告诉AwesomePlayer播放url地址,AwesomePlayer也只是简单地把此url地址存入mUri和mStats.mURI中以备在prepare时使用。

 

3. AwesomePlayer::prepareAsync或AwesomePlayer::prepare

3.1 mQueue.start();

      表面看是启动一个队例,实质上是创建了一个线程,此程入口函数为:TimedEventQueue::ThreadWrapper。真正的线程处理函数为:TimedEventQueue::threadEntry, 从TimedEventQueue::mQueue队列中读取事件,然后调用event->fire处理此事件。TimedEventQueue中的每一个事件都带有触发此事件的绝对时间,到时间之后才执行此事件的fire.

     TimedEventQueue::Event的fire是一个纯虚函数,其实现由其派生类来实现,如在AwesomePlayer::prepareAsync_l中,创建了一个AwesomeEvent,然后通过mQueue.postEvent把事件发送到mQueue中,此时,fire函数为AwesomePlayer::onPrepareAsyncEvent.

3.2 AwesomePlayer::onPrepareAsyncEvent被执行

     根据上面的描述,把事件发送到队列之后,队列线程将读取此线程的事件,然后执行event的fire. 3.1中事件的fire函数为AwesomePlayer::onPrepareAsyncEvent,其代码为: 

[cpp] view plaincopyprint?
  1. void AwesomePlayer::onPrepareAsyncEvent() {  
  2.     Mutex::Autolock autoLock(mLock);  
  3.     ....  
  4.     if (mUri.size() > 0) { //获取mAudioTrack和mVideoTrack  
  5.         status_t err = finishSetDataSource_l();    ---3.2.1   
  6.         ...  
  7.     }  
  8.     if (mVideoTrack != NULL && mVideoSource == NULL) { //获取mVideoSource  
  9.         status_t err = initVideoDecoder();             ---3.2.2  
  10.         ...  
  11.     }  
  12.     if (mAudioTrack != NULL && mAudioSource == NULL) { //获取mAudioSource  
  13.         status_t err = initAudioDecoder();              ---3.2.3  
  14.         ...  
  15.     }  
  16.     modifyFlags(PREPARING_CONNECTED, SET);  
  17.     if (isStreamingHTTP() || mRTSPController != NULL) {  
  18.         postBufferingEvent_l();  
  19.     } else {  
  20.         finishAsyncPrepare_l();  
  21.     }  
  22. }  

 


 3.2.1 finishSetDataSource_l

 

[cpp] view plaincopyprint?
  1. {  
  2.   dataSource = DataSource::CreateFromURI(mUri.string(), ...); (3.2.1.1)  
  3.   sp<MediaExtractor> extractor =  
  4.                      MediaExtractor::Create(dataSource); ..... (3.2.1.2)  
  5.   
  6.   return setDataSource_l(extractor); ......................... (3.2.1.3)  
  7. }  

 

3.2.1.1 创建dataSource

a. 对于本地文件(http://,https://,rtsp://实现方式不一样)的实现方式如下:

dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);

根据url创建dataSource,它实际上new了一个FileSource。当new FileSource时,它打开此文件:

mFd = open(filename, O_LARGEFILE | O_RDONLY);

b. 对于http://和https://,则new一个ChromiumHTTPDataSource,

这些类之间的派生关系如下图所示:

3.2.1.2 创建一个MediaExtractor

       创建MediaExtractor::Create中创建真正的MediaExtractor,以下以MPEG2TSExtractor为例,它解析TS流,它也是一个空架子,它有传入的mDataSource给它读数据,并创建了一个mParser(ATSParser)来真正的数据解析。在此过程中产生的对象即拥有关系为:

       MPEG2TSExtractor->ATSParser->ATSParser::Program->ATSParser::Stream->AnotherPacketSource

 

       extractor = MediaExtractor::Create(dataSource);它解析source所指定的文件,并且根据其header来选择extractor(解析器)。其代码如下:

[cpp] view plaincopyprint?
  1. sp<MediaExtractor> MediaExtractor::Create(  
  2.         const sp<DataSource> &source, const char *mime) {  
  3.     sp<AMessage> meta;  
  4.     String8 tmp;  
  5.     if (mime == NULL) {  
  6.         float confidence;  
  7.         if (!source->sniff(&tmp, &confidence, &meta)) {  
  8.             return NULL;  
  9.         }  
  10.   
  11.         mime = tmp.string();  
  12.     }  
  13.     ...  
  14.     MediaExtractor *ret = NULL;  
  15.     if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)  
  16.             || !strcasecmp(mime, "audio/mp4")) {  
  17.         ret = new MPEG4Extractor(source);  
  18.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {  
  19.         ret = new MP3Extractor(source, meta);  
  20.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)  
  21.             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {  
  22.         ret = new AMRExtractor(source);  
  23.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {  
  24.         ret = new FLACExtractor(source);  
  25.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {  
  26.         ret = new WAVExtractor(source);  
  27.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {  
  28.         ret = new OggExtractor(source);  
  29.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {  
  30.         ret = new MatroskaExtractor(source);  
  31.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {  
  32.         ret = new MPEG2TSExtractor(source);  
  33.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)) {  
  34.         ret = new AVIExtractor(source);  
  35.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {  
  36.         ret = new WVMExtractor(source);  
  37.     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {  
  38.         ret = new AACExtractor(source);  
  39.     }  
  40.     if (ret != NULL) {  
  41.        if (isDrm) {  
  42.            ret->setDrmFlag(true);  
  43.        } else {  
  44.            ret->setDrmFlag(false);  
  45.        }  
  46.     }  
  47.     ...  
  48.     return ret;  
  49. }  

 

       当然对于TS流,它将创建一个MPEG2TSExtractor并返回。

       当执行new MPEG2TSExtractor(source)时:

       1) 把传入的FileSource对象保存在MEPG2TSExtractor的mDataSource成没变量中

       2) 创建一个ATSParser并保存在mParser中,它负责TS文件的解析,

       3) 在feedMore中,通过mDataSource->readAt从文件读取数据,把读取的数据作为mParser->feedTSPacket的参数,它将分析PAT表(ATSParser::parseProgramAssociationTable)而找到并创建对应的Program,并把Program存入ATSParser::mPrograms中。每个Program有一个唯一的program_number和programMapPID.

         扫盲一下,PAT中包含有所有PMT的PID,一个Program有一个对应的PMT,PMT中包含有Audio PID和Video PID.  

         ATSParser::Program::parseProgramMap中,它分析PMT表,并分别根据Audio和Video的PID,为他们分别创建一个Stream。然后把新创建的Stream保存在ATSParser::Program的mStreams成员变量中。

       ATSParser::Stream::Stream构造函数中,它根据媒体类型,创建一个类型为ElementaryStreamQueue的对象mQueue;并创建一个类型为ABuffer的对象mBuffer(mBuffer = new ABuffer(192 * 1024);)用于保存数据 。

       注:ATSParser::Stream::mSource<AnotherPacketSource>创建流程为:

MediaExtractor::Create->

  MPEG2TSExtractor::MPEG2TSExtractor->

    MPEG2TSExtractor::init->

     MPEG2TSExtractor::feedMore->

       ATSParser::feedTSPacket->

         ATSParser::parseTS->

           ATSParser::parsePID->

             ATSParser::parseProgramAssociationTable

             ATSParser::Program::parsePID->

               ATSParser::Program::parseProgramMap

               ATSParser::Stream::parse->

                 ATSParser::Stream::flush->

                   ATSParser::Stream::parsePES->

                     ATSParser::Stream::onPayloadData

 

       以上source->sniff函数在DataSource::sniff中实现,这些sniff函数是通过DataSource::RegisterSniffer来进行注册的,如MEPG2TS的sniff函数为:SniffMPEG2TS,其代码如下:
 

[cpp] view plaincopyprint?
  1. bool SniffMPEG2TS(  
  2.         const sp<DataSource> &source, String8 *mimeType, float *confidence,  
  3.         sp<AMessage> *) {  
  4.     for (int i = 0; i < 5; ++i) {  
  5.         char header;  
  6.         if (source->readAt(kTSPacketSize * i, &header, 1) != 1  
  7.                 || header != 0x47) {  
  8.             return false;  
  9.         }  
  10.     }  
  11.   
  12.     *confidence = 0.1f;  
  13.     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);  
  14.   
  15.     return true;  
  16. }  

 

        由此可见,这些sniff是根据文件开始的内容来识别各种file container. 比如wav文件通过其头中的RIFF或WAVE字符串来识别。注:在创建player时,是根据url中的相关信息来判断的,而不是文件的内容来判断

 

 3.2.1.3 AwesomePlayer::setDataSource_l(extractor)

       主要逻辑代码如下(当然此extractor实质为MPEG2TSExtractor对象):

[cpp] view plaincopyprint?
  1. status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor)   
  2. {  
  3.    for (size_t i = 0; i < extractor->countTracks(); ++i) {  
  4.    ...  
  5.    if (!haveVideo && !strncasecmp(mime, "video/", 6))  
  6.       setVideoSource(extractor->getTrack(i));  
  7.    ...  
  8.    if(!haveAudio && !strncasecmp(mime, "audio/", 6))  
  9.       setAudioSource(extractor->getTrack(i));  
  10.    ...  
  11.    }  
  12. }  

 

    先看看extractor->getTrack做了些什么?

    它以MPEG2TSExtractor和AnotherPacketSource做为参数创建了一个MPEG2TSSource对象返回,然后AwesomePlayer把它保存在mVideoTrack或mAudioTrack中。

 3.2.2 initVideoDecoder

    主要代码如下:

[cpp] view plaincopyprint?
  1. status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {  
  2.   
  3.     if (mDecryptHandle != NULL) {  
  4.         flags |= OMXCodec::kEnableGrallocUsageProtected;  
  5.     }  
  6.   
  7.     mVideoSource = OMXCodec::Create(                     //3.2.2.1  
  8.             mClient.interface(), mVideoTrack->getFormat(),  
  9.             false// createEncoder  
  10.             mVideoTrack,  
  11.             NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);  
  12.   
  13.     if (mVideoSource != NULL) {  
  14.         int64_t durationUs;  
  15.         if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {  
  16.             Mutex::Autolock autoLock(mMiscStateLock);  
  17.             if (mDurationUs < 0 || durationUs > mDurationUs) {  
  18.                 mDurationUs = durationUs;  
  19.             }  
  20.         }  
  21.   
  22.         status_t err = mVideoSource->start();     //3.2.2.2  
  23.   
  24.         if (err != OK) {  
  25.             mVideoSource.clear();  
  26.             return err;  
  27.         }  
  28.     }  
  29.   
  30.     return mVideoSource != NULL ? OK : UNKNOWN_ERROR;  
  31. }  

 

      它主要做了两件事,1)创建一个OMXCodec对象,2)调用OMXCodec的start方法。注mClient.interface()返回为一个OMX对象。其创建流程如下:

AwesomePlayer::AwesomePlayer->

   mClient.connect->

     OMXClient::connect(获取OMX对象,并保存在mOMX)->

       BpMediaPlayerService::getOMX->

         BnMediaPlayerService::onTransact(GET_OMX)->

            MediaPlayerService::getOMX


3.2.2.1 创建OMXCodec对象

      从上面的代码中可以看出,其mVideoTrack参数为一个MPEG2TSSource对象。

      1)从MPEG2TSSource的metadata中获取mime类型

      2)调用OMXCodec::findMatchingCodecs从kDecoderInfo中寻找可以解此mime媒体类型的codec名,并放在matchingCodecs变量中

      3)创建一个OMXCodecObserver对象

      4)调用OMX::allocateNode函数,以codec名和OMXCodecObserver对象为参数,创建一个OMXNodeInstance对象,并把其makeNodeID的返回值保存在node(node_id)中。

      5)以node,codec名,mime媒体类型,MPEG2TSSource对象为参数,创建一个OMXCodec对象,并把此OMXCodec对象保存在OMXCodecObserver::mTarget中

 

[cpp] view plaincopyprint?
  1. OMXCodec::OMXCodec(  
  2.         const sp<IOMX> &omx, IOMX::node_id node,  
  3.         uint32_t quirks, uint32_t flags,  
  4.         bool isEncoder,  
  5.         const char *mime,  
  6.         const char *componentName,  
  7.         const sp<MediaSource> &source,  
  8.         const sp<ANativeWindow> &nativeWindow)  

 


      6)调用OMXCodec::configureCodec并以MEPG2TSSource的MetaData为参数,对此Codec进行配置。

 

 

3.2.2.2 调用OMXCodec::start方法

      1)它调用mSource->start,即调用MPEG2TSSource::start函数。

      2)它又调用Impl->start,即AnotherPacketSource::start,真遗憾,这其中什么都没有做。只是return OK;就完事了。

 

 

 3.2.3 initAudioDecoder

           其流程基本上与initVideoDecoder类似。创建一个OMXCodec保存在mAudioSource中。

     至此,AwesomePlayer的准备工作已经完成。其架构如下图所示:

 http://blog.csdn.net/myarrow/article/details/7067574

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Android4.0.1中各个Player的功能

1. Android4.0.1中默认定义了4个真正的Player,具体情况如下:

[cpp] view plaincopyprint?
  1. static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,  
  2.         notify_callback_f notifyFunc)  
  3. {  
  4.     sp<MediaPlayerBase> p;  
  5.     switch (playerType) {  
  6.         case SONIVOX_PLAYER:  
  7.             LOGV(" create MidiFile");  
  8.             p = new MidiFile();  
  9.             break;  
  10.         case STAGEFRIGHT_PLAYER:  
  11.             LOGV(" create StagefrightPlayer");  
  12.             p = new StagefrightPlayer;  
  13.             break;  
  14.         case NU_PLAYER:  
  15.             LOGV(" create NuPlayer");  
  16.             p = new NuPlayerDriver;  
  17.             break;  
  18.         case TEST_PLAYER:  
  19.             LOGV("Create Test Player stub");  
  20.             p = new TestPlayerStub();  
  21.             break;  
  22.         default:  
  23.             LOGE("Unknown player type: %d", playerType);  
  24.             return NULL;  
  25.     }  
  26.     if (p != NULL) {  
  27.         if (p->initCheck() == NO_ERROR) {  
  28.             p->setNotifyCallback(cookie, notifyFunc);  
  29.         } else {  
  30.             p.clear();  
  31.         }  
  32.     }  
  33.     if (p == NULL) {  
  34.         LOGE("Failed to create player object");  
  35.     }  
  36.     return p;  
  37. }  

 


2. 每个Player的专长是什么呢?

 

Player TypeFeature DescriptionTEST_PLAYERurl以test:开始的。如test:xxxNU_PLAYERurl以http://或https://开始的,且url以.m3u8结束或url中包含有m3u8字符串SONIVOX_PLAYER处理url中扩展名为:.mid,.midi,.smf,.xmf,.imy,.rtttl,.rtx,.ota的媒体文件STAGEFRIGHT_PLAYER它是一个大好人,前面三位不能处理的都交给它来处理,不知能力是否有如此强大

 

以上言论以代码为证,获取player type的代码如下:

[cpp] view plaincopyprint?
  1. player_type getPlayerType(const char* url)  
  2. {  
  3.     if (TestPlayerStub::canBeUsed(url)) {  
  4.         return TEST_PLAYER;  
  5.     }  
  6.   
  7.     if (!strncasecmp("http://", url, 7)  
  8.             || !strncasecmp("https://", url, 8)) {  
  9.         size_t len = strlen(url);  
  10.         if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {  
  11.             return NU_PLAYER;  
  12.         }  
  13.   
  14.         if (strstr(url,"m3u8")) {  
  15.             return NU_PLAYER;  
  16.         }  
  17.     }  
  18.   
  19.     // use MidiFile for MIDI extensions  
  20.     int lenURL = strlen(url);  
  21.     for (int i = 0; i < NELEM(FILE_EXTS); ++i) {  
  22.         int len = strlen(FILE_EXTS[i].extension);  
  23.         int start = lenURL - len;  
  24.         if (start > 0) {  
  25.             if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) {  
  26.                 return FILE_EXTS[i].playertype;  
  27.             }  
  28.         }  
  29.     }  
  30.   
  31.     return getDefaultPlayerType();  
  32. }  

 

如果你想增加自己的player,以上两个函数都需要修改。

现在对整个媒体系统基本上有一个清晰的框架了,就突发奇想,到底在StagefrightPlayer如何增加自己的硬件解码呢? 很好奇,想一探究竟...

 http://blog.csdn.net/myarrow/article/details/7055786

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MediaPlayer-MediaPlayerService-MediaPlayerService::Client的三角关系

1. MediaPlayer是客户端

2. MediaPlayerService和MediaPlayerService::Client是服务器端。

2.1 MediaPlayerService实现IMediaPlayerService定义的业务逻辑,其主要功能是根据MediaPlayer::setDataSource输入的URL调用create函数创建对应的Player.

2.2 MediaPlayerService::Client实现IMediaPlayer定义的业务逻辑,其主要功能包括start, stop, pause, resume...,其实现方法是调用MediaPlayerService create的Player中的对应方法来实现具体功能。

2.3 它们的三角恋如下图所示:

 3. IXX是什么东东?

在一个BnXXX或BpXXX都派生于两个类,具体情况如下:

class BpXXX : public IXXX, public BpRefBase

class BnXXX : public IXXX, public BBinder

3.1 看到了吧,BpXXX和BnXXX都派生于IXXX,哪IXXX又是做什么的呢? 明确地告诉你,定义业务逻辑,但在BpXXX与BnXXX中的实现方式不同:

1) 在BpXXX中,把对应的binder_transaction_data打包之后通过BpRefBase中的mRemote(BpBinder)发送出去,并等待结果

2) 在BnXXX中,实现对应的业务逻辑,通过调用BnXXX派生类中的方法来实现,如MediaPlayerService::Client

懂了吧, IXXX定义业务逻辑

3.2 哪另外一个做什么呢?

从上图可以看出,是用来进行进程间通信用的。

BpRefBase中有一个mRemote(BpBinder)用来与Binder驱动交互用的。

BBinder是用来从Binder驱动中接收相关请求,并进行相关处理的。

 

4. 不得不说的MediaPlayerService

class MediaPlayerService : public BnMediaPlayerService

它本身用来实现IMediaPlayerService中定义的业务逻辑,可以看看IMediaPlayerService到底定义了些什么东东?

[cpp] view plaincopyprint?
  1. class IMediaPlayerService: public IInterface  
  2. {  
  3. public:  
  4.     DECLARE_META_INTERFACE(MediaPlayerService);  
  5.   
  6.     virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;  
  7.     virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;  
  8.     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, const KeyedVector<String8, String8> *headers = NULL) = 0;  
  9.     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;  
  10.     virtual sp<IMediaConfig>    createMediaConfig(pid_t pid ) = 0;  
  11.     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;  
  12.     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;  
  13.     virtual sp<IOMX>            getOMX() = 0;  
  14.   
  15.     // Take a peek at currently playing audio, for visualization purposes.  
  16.     // This returns a buffer of 16 bit mono PCM data, or NULL if no visualization buffer is currently available.  
  17.     virtual sp<IMemory>         snoop() = 0;  
  18. };  

 


从上面可以看出,还说自己是一个MediaPlayerService,而且还向大内总管ServiceManager进行了注册,就这么个create和decode,能做什么呢? 我们最熟悉的start ,stop, pause, resume...怎么不见呢?没有这些东东,MediaPlayer需要的功能如何实现呢?

 带着这么多疑问,我们先看看MediaPlayerService是如何实现上述功能的,它到底做了些什么?

还是让代码自己说话吧:

[cpp] view plaincopyprint?
  1. sp<IMediaPlayer> MediaPlayerService::create(  
  2.         pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,  
  3.         const KeyedVector<String8, String8> *headers)  
  4. {  
  5.     int32_t connId = android_atomic_inc(&mNextConnId);  
  6.     sp<Client> c = new Client(this, pid, connId, client);  
  7.     LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);  
  8.     if (NO_ERROR != c->setDataSource(url, headers))  
  9.     {  
  10.         c.clear();  
  11.         return c;  
  12.     }  
  13.     wp<Client> w = c;  
  14.     Mutex::Autolock lock(mLock);  
  15.     mClients.add(w);  
  16.     return c;  
  17. }  

 

原来如此,它负责创建MediaPlayer需要的对应功能,创建了Client(MediaPlayerService),MediaPlayerService::Client的定义如下:

class Client : public BnMediaPlayer, 它实现了IMediaPlayer定义的业务逻辑,哪就看看IMediaPlayer定义了些什么:

[cpp] view plaincopyprint?
  1. class IMediaPlayer: public IInterface  
  2. {  
  3. public:  
  4.     DECLARE_META_INTERFACE(MediaPlayer);  
  5.   
  6.     virtual void            disconnect() = 0;  
  7.   
  8.     virtual status_t        setVideoSurface(const sp<ISurface>& surface) = 0;  
  9.     virtual status_t        setSurfaceXY(int x,int y) = 0;  /*add by h00186041   add interface for surface left-up position*/  
  10.     virtual status_t        setSurfaceWH(int w,int h) = 0;  /*add by h00186041  add interface for surface size*/  
  11.     virtual status_t        prepareAsync() = 0;  
  12.     virtual status_t        start() = 0;  
  13.     virtual status_t        stop() = 0;  
  14.     virtual status_t        pause() = 0;  
  15.     virtual status_t        isPlaying(bool* state) = 0;  
  16.     virtual status_t        seekTo(int msec) = 0;  
  17.     virtual status_t        getCurrentPosition(int* msec) = 0;  
  18.     virtual status_t        getDuration(int* msec) = 0;  
  19.     virtual status_t        reset() = 0;  
  20.     virtual status_t        setAudioStreamType(int type) = 0;  
  21.     virtual status_t        setLooping(int loop) = 0;  
  22.     virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;  
  23.     virtual status_t        suspend() = 0;  
  24.     virtual status_t        resume() = 0;  
  25.   
  26.     // Invoke a generic method on the player by using opaque parcels  
  27.     // for the request and reply.  
  28.     // @param request Parcel that must start with the media player  
  29.     // interface token.  
  30.     // @param[out] reply Parcel to hold the reply data. Cannot be null.  
  31.     // @return OK if the invocation was made successfully.  
  32.     virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;  
  33.   
  34.     // Set a new metadata filter.  
  35.     // @param filter A set of allow and drop rules serialized in a Parcel.  
  36.     // @return OK if the invocation was made successfully.  
  37.     virtual status_t        setMetadataFilter(const Parcel& filter) = 0;  
  38.   
  39.     // Retrieve a set of metadata.  
  40.     // @param update_only Include only the metadata that have changed  
  41.     //                    since the last invocation of getMetadata.  
  42.     //                    The set is built using the unfiltered  
  43.     //                    notifications the native player sent to the  
  44.     //                    MediaPlayerService during that period of  
  45.     //                    time. If false, all the metadatas are considered.  
  46.     // @param apply_filter If true, once the metadata set has been built based  
  47.     //                     on the value update_only, the current filter is  
  48.     //                     applied.  
  49.     // @param[out] metadata On exit contains a set (possibly empty) of metadata.  
  50.     //                      Valid only if the call returned OK.  
  51.     // @return OK if the invocation was made successfully.  
  52.     virtual status_t        getMetadata(bool update_only,  
  53.                                         bool apply_filter,  
  54.                                         Parcel *metadata) = 0;  
  55. }  

 


终于找到了思念已久的start, stop, pause, resume...

所以MediaPlayer::setDataSource返回时,会创建一个与MediaPlayerService::Client对应的BpMediaPlayer,用于获取MediaPlayerService::Client的各项功能。

4. 1 MediaPlayer又是如何找到MediaPlayerService::Client的呢? 只有MediaPlayerService才向ServiceManager进行了注册,所以MediaPlayer必须先获取BpMediaPlayerService,然后通过BpMediaService的管理功能create,来创建一个MediaPlayerService::Client.

4.2 为什么不直接定义一个MediaPlayer向ServiceManager注册呢?

也许是为了系统简化吧,MediaPlayerService包含的功能不只是Client, 还有AudioOutput,AudioCache,MediaConfigClient功能。现在明白了吧,MediaPlayerService就是一个媒体服务的接口,它先把客人接回来,再根据客人的需求,安排不同的员工去做,就这么简单。

http://blog.csdn.net/myarrow/article/details/7054936

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Android中真正的Player

1.  在前面的介绍中,从Java到MediaPlayer---Binder---MediaPlayerService::Client已经讲清楚了。可是,在MediaPlayerService::Client <MediaPlayerService::create-> new Client / MediaPlayerService::Client::setDataSource->getPlayerType/createPlayer->android::createPlayer>中调用android::createPlayer之后,并把新创建的真正的Player保存到MediaPlayerService::Client中的mPlayer之后就没有下文了。

 

2. 真正的Player到底是什么样的?

根据本人的了解,有PVPlayer, StagefrightPlayer,MidiFile,VorbisPlayer,每个Player处理不同的媒体类型,他们通过getPlayerType(const char* url)的返回值进行分工完成。每个Player都有自己的特长,并做自己善于做的事情。详细分工情况见代码:sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
        notify_callback_f notifyFunc)
函数。

3. 如果要在自己的芯片上实现硬件Demux和硬件Decoder(如对于机顶盒中的TS流),怎么办呢?

据本人了解,有两种办法:

1)基于MediaPlayerInterface接口,实现其中所有的接口函数,自已创建一个XXPlayer,并增加到android::createPlayer中。每个接口函数的具体实现就与以前在Linux环境下实现的方式一样,简单吧,以前的成果都可以用上了。

2)在现在的Player(如StagefrightPlayer)中写Extractor和Decoder插件。

为了实现第二种方案,需要先了解StagefrightPlayer的架构。为什么两种方案都需要了解呢,因为怎么做,取决于你的首席架构师或CTO等。

http://blog.csdn.net/myarrow/article/details/7054631

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Android媒体播放器框架--图

1. 由于小弟用的平台的AV播放一直不稳定,为研究其原由,不得不把MediaPlayer这个东东搞个明白。

2. 媒体播放器本地部分对上层的接口是MediaPlayer,对下层的接口是媒体播放器对硬件的抽象层,StagefrightPlayer是其中的一个实现,你也可以自己基于硬件驱动实现一个MyPlayer,然后添加到MediaPlayerService.cpp中的createPlayer中,同时需要修改本文件中的getPlayerType以指定哪些类型由你的MyPlayer来处理。CreatePlayer中是根据URL的player_type来创建对应的播放器,并把它保存在MediaPlayerService::Client的mPlayer成员变量中,以供BnMediaPlayer的onTransact调用。

3. 媒体播放器的框架如下图所示:

http://blog.csdn.net/myarrow/article/details/7053622

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

原创粉丝点击