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其它相關文章!
推薦閱讀:
- Android 圖文詳解Binder進程通信底層原理
- Android中關於Binder常見面試問題小結
- Android系統服務概覽
- Android實現音樂視頻播放
- android系統按鍵音framework流程源碼詳細解析