Android PVPlayer介紹

來源:互聯網
上載者:User
 (hanchao3c Android開發人員論壇原創,轉載請註明)

本文是《Android的多媒體架構OpenCore(PacketVideo)介紹 》的後續內容,前文請參考:
http://www.androidin.com/bbs/viewthread.php?tid=2585&extra=page%3D1

5.1 Player的組成

    OpenCore的Player的編譯檔案是pvplayer/Android.mk,
將產生動態庫檔案libopencoreplayer.so。這個庫包含了兩方面的內容:一方是Player的engine(引擎),一方面是為
Android構件的Player,這實際上是一個適配器(adapter)。engine的路徑是engine/player;adapter的路徑是
android。



5.2 Player Engine部分

    OpenCore的Player Engine具有清晰明確的介面。在這個介面之上,不同的系統可一個根據自己的情況實現不同Player。目錄engines中的檔案結構如下所示:

    OpenCore的Player Engine具有清晰明確的介面。在這個介面之上,不同的系統可一個根據自己的情況實現不同Player。目錄engines中的檔案結構如下所示:
engines/player/
|-- Android.mk
|-- build
|   |-- linux_nj
|   |-- make
|   `-- makefile.conf
|-- config
|   `-- linux_nj
|-- include
|   |-- pv_player_datasink.h
|   |-- pv_player_datasinkfilename.h
|   |-- pv_player_datasinkpvmfnode.h
|   |-- pv_player_datasource.h
|   |-- pv_player_datasourcepvmfnode.h
|   |-- pv_player_datasourceurl.h
|   |-- pv_player_events.h
|   |-- pv_player_factory.h
|   |-- pv_player_interface.h
|   |-- pv_player_license_acquisition_interface.h
|   |-- pv_player_registry_interface.h
|   |-- pv_player_track_selection_interface.h
|   `-- pv_player_types.h
|-- sample_app
|   |-- Android.mk
|   |-- build
|   |-- sample_player_app_release.txt
|   `-- src
|-- src
|   |-- pv_player_datapath.cpp
|   |-- pv_player_datapath.h
|   |-- pv_player_engine.cpp
|   |-- pv_player_engine.h
|   |-- pv_player_factory.cpp
|   |-- pv_player_node_registry.h
|   `-- pv_player_sdkinfo.h
`-- test
    |-- Android.mk
    |-- build
    |-- config
    `-- src
     其中,engines/player/include目錄中是介面標頭檔,engines/player/src目錄源檔案和私人標頭檔,主要標頭檔的功能如下所示:
pv_player_types.h:定義一些資料結構和枚舉值
pv_player_events.h:定義UUID和一些錯誤值。
pv_player_datasink.h:datasink是媒體資料的輸出,定義類PVPlayerDataSink,這是媒體資料輸出的基類,作為介面使用
pv_player_datasinkfilename.h:定義類PVPlayerDataSinkFilename繼承PVPlayerDataSink。
pv_player_datasinkpvmfnode.h:定義類PVPlayerDataSinkPVMFNode繼承PVPlayerDataSink。
pv_player_datasource.h:datasource是媒體資料的輸入,定義類PVPlayerDataSource,這是媒體資料輸入的基類,作為介面使用。
pv_player_datasourcepvmfnode.h:定義類PVPlayerDataSourcePVMFNode繼承PVPlayerDataSource。
pv_player_datasourceurl.h:定義類PVPlayerDataSourceURL繼承PVPlayerDataSource。
pv_player_interface.h:定義Player的介面PVPlayerInterface,這是一個介面類。
pv_player_factory.h:主要定義工廠類PVPlayerFactory,用於建立和銷毀PVPlayerInterface。
    事實上,在engines/player/src目錄中,主要實作類別為pv_player_engine.cpp,其中定義了類PVPlayerEngine,PVPlayerEngine繼承了PVPlayerInterface,這是一個實作類別,在PVPlayerFactory建立PVPlayerInterface介面的時候,實際建立的是PVPlayerEngine。

       在Player Engine的實現中,包含了編解碼和流量控制等功能,而輸出的介質需要從外部設定近來。PVPlayerInterface定義的介面基本是按照操作順序的,主要的介面如下所示:
    在Player Engine的實現中,包含了編解碼和流量控制等功能,而輸出的介質需要從外部設定近來。PVPlayerInterface定義的介面基本是按照操作順序的,主要的介面如下所示:
PVCommandId AddDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData = NULL);
PVCommandId Init(const OsclAny* aContextData = NULL);
PVCommandId AddDataSink(PVPlayerDataSink& aDataSink, const OsclAny* aContextData = NULL);
PVCommandId Prepare(const OsclAny* aContextData = NULL);
PVCommandId Start(const OsclAny* aContextData = NULL);
PVCommandId Pause(const OsclAny* aContextData = NULL);
PVCommandId Resume(const OsclAny* aContextData = NULL);
PVCommandId Stop(const OsclAny* aContextData = NULL);
PVCommandId RemoveDataSink(PVPlayerDataSink& aDataSink, const OsclAny* aContextData = NULL);
PVCommandId Reset(const OsclAny* aContextData = NULL);
PVCommandId RemoveDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData = NULL);
   這裡面的DataSink可能包含Video的輸出和Audio的輸出兩者部分。在pv_player_types.h檔案中,定義了Player的狀態機器,以PVP_STATE_為開頭,如下所示:
typedef enum
{
    PVP_STATE_IDLE        = 1,
    PVP_STATE_INITIALIZED = 2,
    PVP_STATE_PREPARED    = 3,
    PVP_STATE_STARTED     = 4,
    PVP_STATE_PAUSED      = 5,
    PVP_STATE_ERROR       = 6
} PVPlayerState;
 
 PVPlayerInterface中的各個操作如果成功,可以更改Player的狀態機器:初始化的時候Player是PVP_STATE_IDLE狀
態,調用Init後,進入PVP_STATE_INITIALIZED狀態;調用AddDataSink,進入PVP_STATE_PREPARED狀
態;調用Prepare後,進入PVP_STATE_PREPARED狀態;調用start後進入PVP_STATE_STARTED狀態,之後可以調用
pause進入PVP_STATE_PAUSED狀態。
   PVP_STATE_STARTED和PVP_STATE_PAUSED狀態是播放情況下的狀態,可以使用start和pause函數在這兩個狀態中切換。
   在播放過程中,調用stop可以返回PVP_STATE_INITIALIZED狀態,在調用RemoveDataSource返回PVP_STATE_IDLE狀態。

5.3 Android Player Adapter
在android目錄中定義為Player的適配器,這個目錄主要包含的檔案如下所示:
android
|-- Android.mk
|-- android_audio_mio.cpp
|-- android_audio_mio.h
|-- android_audio_output.cpp
|-- android_audio_output.h
|-- android_audio_output_threadsafe_callbacks.cpp
|-- android_audio_output_threadsafe_callbacks.h
|-- android_audio_stream.cpp
|-- android_audio_stream.h
|-- android_log_appender.h
|-- android_surface_output.cpp
|-- android_surface_output.h
|-- mediascanner.cpp
|-- metadatadriver.cpp
|-- metadatadriver.h
|-- playerdriver.cpp
|-- playerdriver.h
`-- thread_init.cpp
      這個Android的Player的“適配器”需要調用OpenCore的Player
Engine的介面,實現Android的媒體播放器的服務所需要介面,即最終實現一個PVPlayer,而PVPlayer實際上是繼承了
MediaPlayerInterface。
在實現過程中,首先實現了一個PlayerDriver,然後再使用PVPlayer,PVPlayer通過調用PlayerDriver來完成具體的功能。整個實現的結構圖:
  
      對PVPlayerDriver的各種操作使用各種命令來完成,這些命令在playerdriver.h中進行的定義。
enum player_command_type {
    PLAYER_QUIT                     = 1,
    PLAYER_SETUP                    = 2,
    PLAYER_SET_DATA_SOURCE          = 3,
    PLAYER_SET_VIDEO_SURFACE        = 4,
    PLAYER_SET_AUDIO_SINK           = 5,
    PLAYER_INIT                     = 6,
    PLAYER_PREPARE                  = 7,
    PLAYER_START                    = 8,
    PLAYER_STOP                     = 9,
    PLAYER_PAUSE                    = 10,
    PLAYER_RESET                    = 11,
    PLAYER_SET_LOOP                 = 12,
    PLAYER_SEEK                     = 13,
    PLAYER_GET_POSITION             = 14,
    PLAYER_GET_DURATION             = 15,
    PLAYER_GET_STATUS               = 16,
    PLAYER_REMOVE_DATA_SOURCE       = 17,
    PLAYER_CANCEL_ALL_COMMANDS      = 18,
};
      這些命令一般實現的是PVPlayerInterface各個介面的簡單封裝,例如對於較為簡單的暫停播放這個操作,整個系統執行的過程如下所示:
1.在PVPlayer中的pause函數(在playerdriver.cpp檔案中)
status_t PVPlayer::pause()
{
    LOGV("pause");
    return mPlayerDriver->enqueueCommand(new PlayerPause(0,0));
}
這時調用其成員mPlayerDriver(PlayerDriver類型)的函數,將一個PlayerPause命令加入了命令序列,具體的各種命令功能在playerdriver.h檔案中。
2.PlayerDriver類的enqueueCommand將間接調用各個以handle為開頭的函數,對於PlayerPause命令,調用的函數是handlePause
void PlayerDriver::handlePause(PlayerPause* ec)
{
    LOGV("call pause");
    mPlayer->Pause(0);
    FinishSyncCommand(ec);
}
       這裡的mPlayer是一個PVPlayerInterface類型的指標,使用這個指標調用到了OpenCore的 Player Engine中的PVPlayerEngine類。
 
   在這個播放器適配器的實現中,一個主要的工作是將Android架構中定義的媒體的輸出(包括Audio的輸出和Video的輸出)轉換
成,OpenCore的 Player
Engine需要的形式。在這裡兩個重要的類是android_surface_output.cpp實現的
AndroidSurfaceOutput,android_audio_output.cpp實現的AndroidAudioOutput。
對於Video輸出的設定過程,在類PlayerDriver中定義了3個成員:
    PVPlayerDataSink        *mVideoSink;
    PVMFNodeInterface       *mVideoNode;
    PvmiMIOControl          *mVideoOutputMIO;
      這裡的mVideoSink 的類型為PVPlayerDataSink,這是Player
Engine中定義的類介面,mVideoNode的類型為VMFNodeInterface,在pvmi/pvmf/include的
pvmf_node_interface.h中定義,這是所有的PVMF的NODE都需要繼承的統一介面,mVideoOutputMIO的類型為
PvmiMIOControl也在pvmi/pvmf/include中定義,這是媒圖輸出控制的介面類。
1.在PVPlayer的setVideoSurface用以設定一個Video輸出的介面,這裡使用的參數的類型是ISurface指標:
status_t PVPlayer::setVideoSurface(const sp<ISurface>& surface)
{
    LOGV("setVideoSurface(%p)", surface.get());
    mSurface = surface;
    return OK;
}
     setVideoSurface函數設定的是PVPlayer中的一個成員mSurface,真正設定Video輸出的介面的功能在run_set_video_surface()函數中實現:
void PVPlayer::run_set_video_surface(status_t s, void *cookie)
{
    LOGV("run_set_video_surface s=%d", s);
    if (s == NO_ERROR) {
        PVPlayer *p = (PVPlayer*)cookie;
        if (p->mSurface == NULL) {
            run_set_audio_output(s, cookie);
        } else {
            p->mPlayerDriver->enqueueCommand(new PlayerSetVideoSurface(p->mSurface, run_set_audio_output, cookie));
        }
    }
}
     這時使用的命令是PlayerSetVideoSurface,最終將調用到PlayerDriver中的handleSetVideoSurface函數。
2.handleSetVideoSurface函數的實現如下所示:
void PlayerDriver::handleSetVideoSurface(PlayerSetVideoSurface* ec)
{
    int error = 0;
    mVideoOutputMIO = new AndroidSurfaceOutput(ec->surface());
    mVideoNode = PVMediaOutputNodeFactory::CreateMediaOutputNode(mVideoOutputMIO);
    mVideoSink = new PVPlayerDataSinkPVMFNode;
    ((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkNode(mVideoNode);
    ((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkFormatType(PVMF_YUV420);
    OSCL_TRY(error, mPlayer->AddDataSink(*mVideoSink, ec));
    OSCL_FIRST_CATCH_ANY(error, commandFailed(ec));
}
    
 在這裡首先建立的建立成員mVideoOutputMIO(類型為PvmiMIOControl),這時建立的類是類
AndroidSurfaceOutput,這個類繼承了PvmiMIOControl,所以可以作為PvmiMIOControl使用。然後調用
PVMediaOutputNodeFactory::CreateMediaOutputNode建立了PVMFNodeInterface
類型的mVideoNode。隨後建立PVPlayerDataSinkPVMFNode類型的
mVideoSink,PVPlayerDataSinkPVMFNode本身繼承了PVPlayerDataSink,因此可以作為
PVPlayerDataSink使用。調用SetDataSinkNode函數將mVideoNode設定為mVideoSink的資料輸出節點。

      
事實上,對於Video的輸出,基本的功能都是在類AndroidSurfaceOutput中完成的,在這個類當中,主要的工作是將Android的
ISurface輸出作為Player
Engine的輸出。最後調用了AddDataSink將mVideoSink增加為了PVPlayerInterface的輸出。
    
 在android_surface_output.cpp檔案中實現了類AndroidSurfaceOutput,這個類相當於一個OpenCore
Player
Engine的Video輸出和Android輸出的“適配器”。AndroidSurfaceOutput類本身繼承了類
PvmiMIOControl,而其建構函式又以ISurface類型為參數。這個類的實現是使用ISurface實現PvmiMIOControl的各
個介面。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.