古詩詞大全網 - 成語故事 - 怎麽用stagefright框架

怎麽用stagefright框架

1、 StageFright介紹

Android froyo版本多媒體引擎做了變動,新添加了stagefright框架,並且默認情況android選擇stagefright,並沒有完全拋棄opencore,主要是做了壹個OMX層,僅僅是對 opencore的omx-component部分做了引用。stagefright是在MediaPlayerService這壹層加入的,和opencore是並列的。Stagefright在 Android中是以shared library的形式存在(libstagefright.so),其中的module -- AwesomePlayer可用來播放video/audio。 AwesomePlayer提供許多API,可以讓上層的應用程序(Java/JNI)來調用。

2、 StageFright數據流封裝

2.1》由數據源DataSource生成MediaExtractor。通過MediaExtractor::Create(dataSource)來實現。Create方法通過兩步來生成相應的 MediaExtractor(MediaExtractor.cpp):

通過dataSource->sniff來探測數據類型

生成相應的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);

}

2.2》把音視頻軌道分離,生成mVideoTrack和mAudioTrack兩個MediaSource。代碼如下(AwesomePlayer.cpp):

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;

}

2.3》得到的這兩個MediaSource,只具有parser功能,沒有decode功能。還需要對這兩個MediaSource做進壹步的包裝,獲取了兩個MediaSource(具有parse和decode功能):

mVideoSource = OMXCodec::Create(

mClient.interface(), mVideoTrack->getFormat(),

false, // createEncoder

mVideoTrack,

NULL, flags);

mAudioSource = OMXCodec::Create(

mClient.interface(), mAudioTrack->getFormat(),

false, // createEncoder

mAudioTrack);

當調用MediaSource.start()方法後,它的內部就會開始從數據源獲取數據並解析,等到緩沖區滿後便停止。在AwesomePlayer裏就可以調用MediaSource的read方法讀取解碼後的數據。

對於mVideoSource來說,讀取的數據:mVideoSource->read(&mVideoBuffer, &options)交給顯示模塊進行渲染,mVideoRenderer->render(mVideoBuffer);

對mAudioSource來說,用mAudioPlayer對mAudioSource進行封裝,然後由mAudioPlayer負責讀取數據和播放控制。

3、 StageFright的Decode

經過“數據流的封裝”得到的兩個MediaSource,其實是兩個OMXCodec。AwesomePlayer和mAudioPlayer都是從MediaSource中得到數據進行播放。AwesomePlayer得到的是最終需要渲染的原始視頻數據,而mAudioPlayer讀取的是最終需要播放的原始音頻數據。也就是說,從OMXCodec中讀到的數據已經是原始數據了。

OMXCodec是怎麽把數據源經過parse、decode兩步以後轉化成原始數據的。從OMXCodec::Create這個構造方法開始,它的參數:

IOMX &omx指的是壹個OMXNodeInstance對象的實例。

MetaData &meta這個參數由MediaSource.getFormat獲取得到。這個對象的主要成員就是壹個KeyedVector<uint32_t, typed_data> mItems,裏面存放了壹些代表MediaSource格式信息的名值對。

bool createEncoder指明這個OMXCodec是編碼還是解碼。

MediaSource &source是壹個MediaExtractor。

char *matchComponentName指定壹種Codec用於生成這個OMXCodec。

先使用findMatchingCodecs尋找對應的Codec,找到以後為當前IOMX分配節點並註冊事件監聽器:omx->allocateNode(componentName, observer, &node)。最後,把IOMX封裝進壹個OMXCodec:

sp<OMXCodec> codec = new OMXCodec(

omx, node, quirks,

createEncoder, mime, componentName,

source);

這樣就得到了OMXCodec。

AwesomePlayer中得到這個OMXCodec後,首先調用mVideoSource->start()進行初始化。 OMXCodec初始化主要是做兩件事:

向OpenMAX發送開始命令。mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle)

調用allocateBuffers()分配兩個緩沖區,存放在Vector<BufferInfo> mPortBuffers[2]中,分別用於輸入和輸出。

AwesomePlayer開始播放後,通過mVideoSource->read(&mVideoBuffer, &options)讀取數據。mVideoSource->read(&mVideoBuffer, &options)具體是調用OMXCodec.read來讀取數據。而OMXCodec.read主要分兩步來實現數據的讀取:

通過調用drainInputBuffers()對mPortBuffers[kPortIndexInput]進行填充,這壹步完成 parse。由OpenMAX從數據源把demux後的數據讀取到輸入緩沖區,作為OpenMAX的輸入。

通過fillOutputBuffers()對mPortBuffers[kPortIndexOutput]進行填充,這壹步完成 decode。由OpenMAX對輸入緩沖區中的數據進行解碼,然後把解碼後可以顯示的視頻數據輸出到輸出緩沖區。

AwesomePlayer通過mVideoRenderer->render(mVideoBuffer)對經過parse和decode 處理的數據進行渲染。壹個mVideoRenderer其實就是壹個包裝了IOMXRenderer的AwesomeRemoteRenderer:

mVideoRenderer = new AwesomeRemoteRenderer(

mClient.interface()->createRenderer(

mISurface, component,

(OMX_COLOR_FORMATTYPE)format,

decodedWidth, decodedHeight,

mVideoWidth, mVideoHeight,

rotationDegrees));

4、 StageFright處理流程

Audioplayer 為AwesomePlayer的成員,audioplayer通過callback來驅動數據的獲取,awesomeplayer則是通過 videoevent來驅動。二者有個***性,就是數據的獲取都抽象成mSource->Read()來完成,且read內部把parser和dec 綁在壹起。Stagefright AV同步部分,audio完全是callback驅動數據流,video部分在onVideoEvent裏會獲取audio的時間戳,是傳統的AV時間戳做同步。

4.1》AwesomePlayer的Video主要有以下幾個成員:

mVideoSource(解碼視頻)

mVideoTrack(從多媒體文件中讀取視頻數據)

mVideoRenderer(對解碼好的視頻進行格式轉換,android使用的格式為RGB565)

mISurface(重繪圖層)

mQueue(event事件隊列)

4.2》stagefright運行時的Audio部分抽象流程如下:

設置mUri的路徑

啟動mQueue,創建壹個線程來運行 threadEntry(命名為TimedEventQueue,這個線程就是event調度器)

打開mUri所指定的文件的頭部,則會根據類型選擇不同的分離器(如MPEG4Extractor)

使用 MPEG4Extractor對MP4進行音視頻軌道的分離,並返回MPEG4Source類型的視頻軌道給mVideoTrack

根據 mVideoTrack中的編碼類型來選擇解碼器,avc的編碼類型會選擇AVCDecoder,並返回給mVideoSource,並設置mVideoSource中的mSource為mVideoTrack

插入onVideoEvent到Queue中,開始解碼播放

通過mVideoSource對象來讀取解析好的視頻buffer

如果解析好的buffer還沒到AV時間戳同步的時刻,則推遲到下壹輪操作

mVideoRenderer為空,則進行初始化(如果不使用 OMX會將mVideoRenderer設置為AwesomeLocalRenderer)

通過mVideoRenderer對象將解析好的視頻buffer轉換成RGB565格式,並發給display模塊進行圖像繪制

將onVideoEvent重新插入event調度器來循環

4.3》數據由源到最終解碼後的流程如下:

URI,FD

DataSource

MediaExtractor

|

mVideoTrack mAudioTrack//音視頻數據流

mVideoSource mAudioSource//音視頻解碼器

| |

mVideoBuffer mAudioPlayer

說明:

設置DataSource,數據源可以兩種URI和FD。URI可以.cooliris.media/.MovieView } from pid 327

I/RenderView( 327): OnPause RenderView com.cooliris.media.RenderView@4054a3b0

E/AwesomePlayer( 34): beginning AwesomePlayer... by jay remarked...

E/AwesomePlayer( 34): returning AwesomeEvent...by jay remarked...

E/AwesomePlayer( 34): returning AwesomeEvent...by jay remarked...

E/AwesomePlayer( 34): returning AwesomeEvent...by jay remarked...

E/AwesomePlayer( 34): returning AwesomeEvent...by jay remarked...

E/AwesomePlayer( 34): ending AwesomePlayer... by jay remarked...

E/AwesomePlayer( 34): setting video source now... by jay remarked...

E/AwesomePlayer( 34): setting Video Type... by jay remarked...

E/AwesomePlayer( 34): returning AwesomeEvent...by jay remarked...

E/AwesomePlayer( 34): beginning initVideoDecoder by jay remarked...

D/MediaPlayer( 327): getMetadata

I/ActivityManager( 61): Displayed com.cooliris.media/.MovieView: +1s761ms

E/AwesomePlayer( 34): beginning AwesomeLocalRenderer init ...by jay remarked...

E/AwesomePlayer( 34): returning open(libstagefrighthw.so) correctly by jay remarked...

E/MemoryHeapBase( 34): error opening /dev/pmem_adsp: No such file or directory

I/SoftwareRenderer( 34): Creating physical memory heap failed, reverting to regular heap.

E/AwesomePlayer( 34): ending AwesomeLocalRenderer init close ...by jay remarked...

E/AwesomePlayer( 34): returning AwesomeLocalRenderer...by jay remarked...

I/CacheService( 327): Starting CacheService