Android音視頻開發Media FrameWork框架源碼解析

一、Media FrameWork背景

Media Framework (媒體函數庫):此函數庫讓Android 可以播放與錄制許多常見的音頻與視頻文件,支持的文件類型包括MPEG4、H.264、MP3、AAC、AMR、JPG 與PNG 等。 Surface Manager (外觀管理函數庫):管理圖形界面的操作與2D、3D 圖層的顯示。

二、Media Framework“路線圖”

我們可以看到用紅色框框圈起來的地方。一個是app應用Gallery(也可以為第三方player);另外一個是Media Framework。對,沒錯,講瞭這麼多,我們的主角“Media Framework”登場瞭。讓我們來看看它的廬山真面目, 如圖所示:

接下來,給大傢簡單介紹下它。看的順序是→ ↓ ← ↓ →(腫麼都覺得是在打表情符號:-D)

2.1 代理端

這一端做的事情隻是將下面復雜的邏輯進行封裝(java),然後透過jni調用底下的native層方法來實現具體功能。並且,這些個具體的功能是在服務端實現的,他們分屬不同的進程,通過Binder來通信,最終通過調用服務端的方法實現具體的邏輯處理。(有童鞋問:Binder是個什麼東東呢? 小弟有時間會講解的,現在就理解它是一個進程間通信的一種方式就好,求甚解的朋友們可以百度下_)

2.2 服務端

這邊的主要任務就是在MediaPlayerFactory中,創建出NuplayerDriver(這個不是底層驅動啦,我們理解為一個抽象出來的NuPlayer的基類就好啦)。 然後Nuplayer中,我們可以看到有三大模塊。

2.2.1 Source

這裡是為咱們的播放器提供數據源的(解協議,解封裝在這裡)。

2.2.2 Decoder

這裡是解碼數據的地方(解碼在這裡)

2.2.3 Renderer

這裡是用來做Display的,裡面涉及到A/V同步的問題。

2.2.4 Foundation

這個部分是基礎類。在後面的分析當中,我們會知道在NuPlayer中會啟動相當多的線程,這些線程如何異步/同步的通信,需要依靠AMessage/ALooper/AHandler來支持

之後, 通過接口類IOMX來通過Binder進程間通信,遠程調用具體的decoder來實現解碼。

2.3 OMX端

這一端就比較靠近底層瞭,裡面會有各種各樣的插件註冊其中。它還鏈接這Codec Driver,這裡面就是放的各種具體的解碼器啦。

2.4 Kernel端

最後, OMX的具體解碼器在啟動Kernel層的A/V Codec Driver完成解碼操作。

三、media播放的流程

在framework中涉及media播放的流程頭文件如下:IMediaPlayer.h mediaplayer.h IMediaPlayerClient.h

其中IMediaPlayer.h 定義瞭binder通信相關的接口。 定義瞭:

class BnMediaPlayer: public BnInterface
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};
​

IMediaPlayer.cpp 是binder通信接口的實現。

class BpMediaPlayer: public BpInterface; status_t BnMediaPlayer::onTransact();

mediaplayer.h 是定義binder通信的客戶端。在mediaplayer.cpp中如下代碼獲取BpMediaPlayer:

status_t MediaPlayer::setDataSource(
        const char *url, const KeyedVector *headers)
{
    LOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        const sp& service(getMediaPlayerService());
        if (service != 0) {
            sp player(
                    service->create(getpid(), this, url, headers));
            err = setDataSource(player);
        }
    }
    return err;
}
​

服務端在MediaPlayerService中。在MediaPlayerService.h中如下定義:

class Client : public BnMediaPlayer 在MediaPlayerService.cpp中,create函數創建瞭BnMediaPlayer:

sp MediaPlayerService::create(
​
        pid_t pid, const sp& client, const char* url,
        const KeyedVector *headers)
{
    int32_t connId = android_atomic_inc(&mNextConnId);
    sp c = new Client(this, pid, connId, client);
    LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);
    if (NO_ERROR != c->setDataSource(url, headers))
    {
        c.clear();
        return c;
    }
    wp w = c;
    Mutex::Autolock lock(mLock);
    mClients.add(w);
    return c;
}

再來看一下MediaPlayer這個類的定義:

class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier{}

很奇怪:在binder通信的客戶端又有瞭一個binder通信的服務端: BnMediaPlayerClient 在IMediaPlayerClient.h 中這個binder通信隻有一個接口:

class IMediaPlayerClient: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayerClient);​
    virtual void notify(int msg, int ext1, int ext2) = 0;
};

這個binder通信服務為誰提供呢?在回來看一下MediaPlayerServer中的create函數:

sp MediaPlayerService::create( pid_t pid, const sp& client, const char* url, const KeyedVector *headers)

客戶端就在這裡。這個binder通信的實質是一個消息回調函數。framework的media框架式一個雙向binder通信框架。

以seek接口為例分析一下:

在mediaplayer.cpp 中調用seek 接口:

MediaPlayer (seek)->IMediaPlayer.cpp(bpMediaPlayer.cpp )->IMediaPlayer.cpp(bnMediaPlayer.cpp )

在這裡其實已經達到瞭MediaPlayerServer中的client類。當底層的media 完成seek 以後會拋出來一消息,這個消息通過 const sp& client 通知給MediaPlayer。

在media相關的頭文件中還有一個MediaPlayerInterface.h 。這個頭文件定義瞭底層播放器的接口。

四、Media FrameWork源碼分析

首先,針對android.media.MediaPlayer進行分析。

裡面有很多native代碼,我們找到native_setup這個jni調用,就可以找到整個框架的入口。

我們查看

android_media_MediaPlayer_native_setup@framworks/base/media/jni/android_media_MediaPlayer.cpp

`static` `void` `android_media_MediaPlayer_native_setup(
    JNIEnv *env, jobject thiz, jobject weak_this
    )``
    {
        ``  ``
    LOGV(``"native_setup"``);
        ``  ``sp mp = ``new` `MediaPlayer();
        ``  ``
        if` `(mp == NULL) {
        ``    ``
        jniThrowException(
            env, ``"java/lang/RuntimeException"``, 
            ``"Out of memory"``);
            ``    
            ``return``;
            ``  ``
            
        }
            ` `  ``
            // create new listener and give it to MediaPlayer
            ``  ``
            sp listener = ``new` `JNIMediaPlayerListener(
                env, thiz, weak_this);
                ``  ``
                mp->setListener(listener);
                ` `  ``
                // Stow our new C++ MediaPlayer in an opaque field in the Java object.
                ``  ``
                setMediaPlayer(env, thiz, mp);
                ``
        
    }
        `

從這裡的這段代碼我們可以看到,android在這裡實例化瞭一個變量mp:MediaPlayer。

並且為其設置瞭一個listener:JNIMediaPlayerListener

在後面我們會看到對mp的調用,現在讓我們先看看MediaPlayer是什麼東東。

MediaPlayer@framworks/base/include/media/mediaplayer.h MediaPlayer@framworks/base/media/libmedia/mediaplayer.cpp

在這裡我們終於找到瞭MediaPlayer:BnMediaPlayerClient:IMediaPlayerClient

原來他也是對Bind Native的一個封裝,而他本身提供瞭很多方法用於訪問,包括start等。下面是start的cpp代碼:

status_t MediaPlayer::start()
{
    LOGV("start");
    Mutex::Autolock _l(mLock);
    if (mCurrentState & MEDIA_PLAYER_STARTED)
        return NO_ERROR;
    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
        mPlayer->setLooping(mLoop);
        mPlayer->setVolume(mLeftVolume, mRightVolume);
        mCurrentState = MEDIA_PLAYER_STARTED;
        status_t ret = mPlayer->start();
        if (ret != NO_ERROR) {
            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
        } else {
            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
                LOGV("playback completed immediately following start()");
            }
        }
        return ret;
    }
    LOGE("start called in state %d", mCurrentState);
    return INVALID_OPERATION;
}

原來這裡又調用瞭mPlayer:sp

從這裡我們發現最終的服務,還是由IMediaPlayer這個東西提供的,而IMediaPlayer@framworks/base/include/media/IMediaPlayer.h

實際上是如下定義的一個類,它繼承瞭IInterface@framworks/base/include/binder/IInterface.h這個類(註意雖然名字是Interface,但是它確實是個類!:-))

class IMediaPlayer: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayer);
    virtual void            disconnect() = 0;
    virtual status_t        setVideoSurface(const sp<ISurface>& surface) = 0;
    virtual status_t        prepareAsync() = 0;
    virtual status_t        start() = 0;
    virtual status_t        stop() = 0;
    virtual status_t        pause() = 0;
    virtual status_t        isPlaying(bool* state) = 0;
    virtual status_t        seekTo(int msec) = 0;
    virtual status_t        getCurrentPosition(int* msec) = 0;
    virtual status_t        getDuration(int* msec) = 0;
    virtual status_t        reset() = 0;
    virtual status_t        setAudioStreamType(int type) = 0;
    virtual status_t        setLooping(int loop) = 0;
    virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;
    virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;
    virtual status_t        setMetadataFilter(const Parcel& filter) = 0;
    virtual status_t        getMetadata(bool update_only,
                                        bool apply_filter,
                                        Parcel *metadata) = 0;
};

為瞭弄清楚,在什麼地方產生的mPlayer,我轉而分析MediaPlayerService@framworks/base/media/libmediaplayerservice/MediaPlayerService.h

其中有如下代碼

virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid);
void    removeMediaRecorderClient(wp<MediaRecorderClient> client);
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
// House keeping for media player clients
virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url);
virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);

原來在這個地方會創建你sp對象。

以上就是Android音視頻開發Media FrameWork框架源碼解析的詳細內容,更多關於Android音視頻Media FrameWork的資料請關註WalkonNet其它相關文章!

推薦閱讀: