2015年8月18日 星期二

android media player 簡介

在這裡我們只簡介 MediaPlayer 的模型,
從一般的 player 模型開始簡介;
然後介紹 media player 的 state machine,
state machine 是 media application 必須遵守否則無法播放;
接著簡介 media framework 的各個子模組;
最後才是介紹 nuplayer, nuplayer 從 android 5.0 開始已經是 media framework 的預設 player, 他也是整個 media framework 的核心.

1. MEDIAPLAYER 一般模型
無論是使用 vlc, gstreamer, 或是其他的 media,
其實他還是使用以下的模型,就只是程式撰寫技巧和t程式組織上的差異而已.

一個 Media framework 可以分成以下四大類組件
  • Source:資料進來的 stream, 這裡只是一個很抽象的概念,可以是一個很簡單的 file source, 也可以是複雜一點的 http source, 或是更複雜的 rtsp, HLS或是 drm stream
  • Demux: 當一個 data stream 進來時, 他其實只是一個被包裝過的 container, decoder 無法直接讀取裡面的資訊, 因此 Demux 的功用主要是把這個 container 解開並且把裡面的 audio stream, video stream, 或是其他的 data 導引到對的位置
  • Decoder: 一般的 media file 如果未壓縮則會浪費掉大量的空間, 因此所有的 media file 都是壓縮過的, 然而 Video driver 和 audio driver 他們只能接受 raw data, 因此要把資料餵給他們前, 必須先經過 decoder 把資料先 decode 成 raw data 再餵給 driver, 然而因為在 arm 上 cpu 的能力較弱, 因此一般的晶片廠都還會再包一顆 dsp 來執行 decoder 的功用
  • Output:  把 decoder 解出來的 raw data 顯示出來, 如果是 video data 就交給 display driver 如果是 audio data 就交給 speaker 把 audio 播出來

2. Media application在介紹 Media framework 前先從 Media application 談起,  要寫 Media application 時先要了解 Media Player 的 state machine, Media application 所有的操作都必須遵循這個 state machine, 否則 Media  framework 就會跟你抱怨操作有問題, 並且 throw exception 讓你的 application crash.



3. Media framework
一般的 Media framework 分成以下四個部分


  • Media player java side: 會有這一層是因為所有的 application 都是用 java 寫成的,但是 media player 都是由 c++, 因此必須透過這一層再透過 java 的 jni 跟 native 的 code 溝通,另外這一層是 google open 出來的 api 介面, 因此盡量不要修改這一層, 以免造成 application 的執行錯誤
  • Media player native side: 這一層工作是透過 binder 跟 MediaPlayerService 溝通
  • Mediaplayer service: Media Player Service 有點類似大總管的角色, 就以 playback 的觀點來看media player service, 他主要的工作是選擇對的 player 和提供 audio sink, 把 application 提供的 View 交給 player
  • StagefrightPlayer/NuPlayer: StagefrightPlayer 是android 2.2至4.4.4時所用的 media player engine他主要負責撥放 local file 和 http streaming, 然而從 android 5.0 開始 google 已經捨棄不用了, NuPlayer 是 google 從4.0 開始引進的 player engine, 原本只負責 rtsp 和 HLS, 但是到了 android 5.0 開始他負責所有的播放.

4. NuPlayer
底下以 HLS 來解釋 NuPlayer, 對主要依靠著 Looper 和 Handler 來構成他的基礎


  • Looper/Handler:所有 application 層發出的 command 都是一個 Handler, 並且他會送到 ALooper 裡,再由 ALopper 把 Handler 拿出來執行;當底層有訊息要通知 application 時, 也是發出一個 Handler再把這個 Handler 取出來送給 Application.
  • Stream:再 NuPlayer 中引入了 Stream 的概念, 再 NuPlayer 中所講的 Stream 就很像我們最上面那張圖所講的 Source另外必須 NuPlayer 的 stream 只是抽象的概念, 他隱藏了各個 Streaming 的細節, 因此以 NuPlayer 的角度來講做 HLS 和 RTSP, local file, http 都是一樣的, 就是 read 檔案而已, 然而怎麼跟 server side 溝通的細節就隱藏在各自的子模組中, NuPlayer 不在意怎麼跟 Server 溝通, 只要各自的子模組都遵守 interface 就可以了
  • NuPlayer 實做了 render, 主要是用來將資料送給  Audio, display driver
  • NuPlayer 實做了 codec, 主要是定義一組介面好連接 HW codec 或是 software code, 並且將解碼出來的資料送給 render
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // get 需要的 UI 元件的 instance
        mPlayButton = (Button) findViewById(R.id.playbutton);
        mPauseButton = (Button) findViewById(R.id.pausebutton);
        mSkipButton = (Button) findViewById(R.id.skipbutton);
        mRewindButton = (Button) findViewById(R.id.rewindbutton);
        mStopButton = (Button) findViewById(R.id.stopbutton);
        mEjectButton = (Button) findViewById(R.id.ejectbutton);

        // 註冊相對應的 callback function, 當事件發生時, 由 framework 執行相對應的 callback function
        mPlayButton.setOnClickListener(this);
        mPauseButton.setOnClickListener(this);
        mSkipButton.setOnClickListener(this);
        mRewindButton.setOnClickListener(this);
        mStopButton.setOnClickListener(this);
        mEjectButton.setOnClickListener(this);
    }


沒有留言:

張貼留言