Android-StageFright之資料流的封裝和AwesomePlayer流程

jackie_gnu發表於2011-11-16

 http://disanji.net/2011/03/06/android-stagefright-datastream-awesomeplayer/

 

資料流的封裝
一、

由資料來源DataSource生成MediaExtractor。

通過MediaExtractor::Create(dataSource)來實現。Create方法通過兩步來生成相應的MediaExtractor:

1、通過dataSource->sniff來探測資料型別

2、生成相應的Extractor:

 
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
 
            || !strcasecmp(mime, "audio/mp4")) {
 
        return new MPEG4Extractor(source);
 
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
 
        return new MP3Extractor(source, meta);
 
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
 
            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
 
        return new AMRExtractor(source);
 
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
 
        return new WAVExtractor(source);
 
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
 
        return new OggExtractor(source);
 
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
 
        return new MatroskaExtractor(source);
 
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
 
        return new MPEG2TSExtractor(source);

二、

接下來,通過以下程式碼把音視訊軌道分離:

if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
 
        setVideoSource(extractor->getTrack(i));
 
        haveVideo = true;
 
   } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
 
        setAudioSource(extractor->getTrack(i));
 
        haveAudio = true;

生成mVideoTrack和mAudioTrack兩個MediaSource。

三、

到目前為止我們得到的這兩個MediaSource只具有parser功能,沒有decode功能。還需要對這兩個MediaSource做進一步的包裝:

mVideoSource = OMXCodec::Create(
 
            mClient.interface(), mVideoTrack->getFormat(),
 
            false, // createEncoder
 
            mVideoTrack,
 
            NULL, flags);
 
mAudioSource = OMXCodec::Create(
 
                mClient.interface(), mAudioTrack->getFormat(),
 
                false, // createEncoder
 
                mAudioTrack);

這回又獲取了兩個MediaSource。它們具有parse和decode功能。當呼叫MediaSource.start()方法後,它的內部就會開始從資料來源獲取資料並解析,等到緩衝區滿後便停止。在AwesomePlayer裡就可以呼叫MediaSource的read方法讀取解碼後的資料。

對於mVideoSource來說:

讀取的資料。

1
mVideoSource->read(&mVideoBuffer, &options)

交給顯示模組進行渲染。

1
mVideoRenderer->render(mVideoBuffer);

對mAudioSource來說:

用mAudioPlayer對mAudioSource進行封裝,然後由mAudioPlayer負責讀取資料和播放控制。

AwesomePlayer流程
URI,FD

DataSource

MediaExtractor

|

mVideoTrack mAudioTrack//音視訊資料流

mVideoSource mAudioSource//音視訊解碼器

| |

mVideoBuffer mAudioPlayer

上面示意了資料由源到最終解碼後的流程。

1、設定DataSource,資料來源可以兩種URI和FD。URI可以http://,rtsp://等。FD是一個本地檔案描述符,能過FD,可以找到對應的檔案。

2、由DataSource生成MediaExtractor。通過sp extractor = MediaExtractor::Create(dataSource);來實現。 MediaExtractor::Create(dataSource)會根據不同的資料內容建立不同的資料讀取物件。

3、通過呼叫setVideoSource由MediaExtractor分解生成音訊資料流(mAudioTrack)和視訊資料流(mVideoTrack)。

4、 onPrepareAsyncEvent()

如果DataSource是URL的話,根據地址獲取資料,並開始緩衝,直到獲取到mVideoTrack和mAudioTrack。

mVideoTrack和mAudioTrack通過呼叫initVideoDecoder()和initAudioDecoder()來生成mVideoSource和mAudioSource這兩個音視訊解碼器。

然後呼叫postBufferingEvent_l()提交事件開啟緩衝。資料緩衝的執行函式是onBufferingUpdate()。

緩衝區有足夠的資料可以播放時,呼叫play_l()開始播放。play_l()中關鍵是呼叫了postVideoEvent_l(),提交了 mVideoEvent。這個事件執行時會呼叫函式onVideoEvent()。這個函式通過呼叫 mVideoSource->read(&mVideoBuffer, &options)進行視訊解碼。音訊解碼通過mAudioPlayer實現。

視訊解碼器解碼後通過mVideoSource->read讀取一幀幀的資料,放到mVideoBuffer中,最後通過mVideoRenderer->render(mVideoBuffer)把視訊資料傳送到顯示模組。

當需要暫停或停止時,呼叫cancelPlayerEvents來提交事件用來停止解碼,還可以選擇是否繼續緩衝資料。

相關文章