android stagefright框架(一)Video Playback的流程

stagefright框架(一)Video Playback的流程

在Android上,預設的多媒體框架(multimedia framework)是OpenCORE 。 OpenCORE的優點是兼顧了跨平台的移植性,而且已經過多方驗證,所以相對來說較為穩定;但是其缺點是過於龐大複雜,需要耗費相當多的時間去維護。從 Android 2.0開始,Google引進了架構稍為簡潔的Stagefright,並且有逐漸取代OpenCORE的趨勢 (註1)

[圖1] Stagefright在Android多媒體架構中的位置。

[圖2] Stagefright所涵蓋的模組 (註2)
以下我們就先來看看Stagefright是如何播放一個影片檔。

Stagefright
在Android中是以shared library的形式存在(libstagefright.so),其中的module -- AwesomePlayer可用來播放video/audio (註3) 。AwesomePlayer提供許多API,可以讓上層的應用程式(Java/JNI)來呼叫,我們以一個簡單的程式來說明video playback的流程。

在Java中,若要播放一個影片檔,我們會這樣寫:

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE); ...... (1)
mp.prepare(); ........................ (2) (3)
mp.start(); .......................... (4)

在Stagefright中,則會看到相對應的處理;

(1)
將檔案的絕對路徑指定給mUri

status_t AwesomePlayer: : setDataSource( const char * uri, . . . )
{
  return setDataSource_l( uri, . . . ) ;
}

status_t AwesomePlayer: : setDataSource_l( const char * uri, . . . )
{
  mUri = uri;
}


(2) 啟動mQueue,作為event handler

status_t AwesomePlayer: : prepare( )
{
  return prepare_l( ) ;
}

status_t AwesomePlayer: : prepare_l( )
{
  prepareAsync_l( ) ;

  while ( mFlags & PREPARING)
  {
    mPreparedCondition. wait( mLock) ;
  }
}

status_t AwesomePlayer: : prepareAsync_l( )
{
  mQueue. start( ) ;

  mFlags | = PREPARING;
  mAsyncPrepareEvent = new AwesomeEvent(
                             this
                             & AwesomePlayer: : onPrepareAsyncEvent) ;
  mQueue. postEvent( mAsyncPrepareEvent) ;
}


(3) onPrepare AsyncEvent被觸發

void AwesomePlayer: : onPrepareAsyncEvent( )
{
  finishSetDataSource_l( ) ;

  initVideoDecoder( ) ; . . . . . . ( 3. 3)
  initAudioDecoder( ) ;
}

status_t AwesomePlayer: : finishSetDataSource_l( )
{
  dataSource = DataSource: : CreateFromURI( mUri. string ( ) , . . . ) ;
  sp< MediaExtractor> extractor =
                     MediaExtractor: : Create( dataSource) ; . . . . . ( 3. 1)

  return setDataSource_l( extractor) ; . . . . . . . . . . . . . . . . . . . . . . . . . ( 3. 2)
}


(3.1) 解析mUri所指定的檔案,並且根據其header來選擇對應的extractor

sp< MediaExtractor> MediaExtractor: : Create( const sp< DataSource> & source, . . . )
{
  source- > sniff( & tmp, . . . ) ;
  mime = tmp. string ( ) ;

  if ( ! strcasecmp( mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
  {
    return new MPEG4Extractor( source) ;
  }
  else if ( ! strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_MPEG) )
  {
    return new MP3Extractor( source) ;
  }
  else if ( ! strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
  {
    return new AMRExtractor( source) ;
  }
}


(3.2) 使用extractor對檔案做A/V的分離 (mVideoTrack/mAudioTrack)

status_t AwesomePlayer: : setDataSource_l( const sp< MediaExtractor> & extractor)
{
  for ( size_t i = 0; i < extractor- > countTracks( ) ; + + i)
  {
    sp< MetaData> meta = extractor- > getTrackMetaData( i) ;

    CHECK( meta- > findCString( kKeyMIMEType, & mime) ) ;

    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 ;
    }
  }
}

void AwesomePlayer: : setVideoSource( sp< MediaSource> source)
{
  mVideoTrack = source;
}


(3.3) 根據mVideoTrack中的編碼類型來選擇video decoder (mVideoSource)

status_t AwesomePlayer: : initVideoDecoder( )
{
  mVideoSource = OMXCodec: : Create( mClient. interface( ) ,
                                  mVideoTrack- > getFormat( ) ,
                                  false ,
                                  mVideoTrack) ;
}


(4)
將mVideoEvent放入mQueue中,開始解碼播放,並交由mVideoRenderer來畫出

status_t AwesomePlayer: : play( )
{
  return play_l( ) ;
}

status_t AwesomePlayer: : play_l( )
{
  postVideoEvent_l( ) ;
}

void AwesomePlayer: : postVideoEvent_l( int64_t delayUs)
{
  mQueue. postEventWithDelay( mVideoEvent, delayUs) ;
}

void AwesomePlayer: : onVideoEvent( )
{
  mVideoSource- > read ( & mVideoBuffer, & options) ;
  [ Check Timestamp]
  mVideoRenderer- > render( mVideoBuffer) ;

  postVideoEvent_l( ) ;
}



(註1) 從Android2.3 (Gingerbread) 開始,預設的多媒體框架為 Stagefright。
(註2) Stagefright的架構尚不斷在演進中,本系列文章並未含括所有的模組。
(註3) Audio的播放是交由 AudioPlayer 來處理,請參考《
Stagefright (6) - Audio Playback的流程 》。

你可能感兴趣的:(android,框架,video,library,audio,playback)