一、Media FrameWork背景
Media Framework (媒體函數(shù)庫(kù)):此函數(shù)庫(kù)讓Android 可以播放與錄制許多常見(jiàn)的音頻與視頻文件,支持的文件類型包括MPEG4、H.264、MP3、AAC、AMR、JPG 與PNG 等。 Surface Manager (外觀管理函數(shù)庫(kù)):管理圖形界面的操作與2D、3D 圖層的顯示。
二、Media Framework“路線圖”
我們可以看到用紅色框框圈起來(lái)的地方。一個(gè)是app應(yīng)用Gallery(也可以為第三方player);另外一個(gè)是Media Framework。對(duì),沒(méi)錯(cuò),講了這么多,我們的主角“Media Framework”登場(chǎng)了。讓我們來(lái)看看它的廬山真面目, 如圖所示:
接下來(lái),給大家簡(jiǎn)單介紹下它。看的順序是 (腫么都覺(jué)得是在打表情符號(hào):-D)
2.1 代理端
這一端做的事情只是將下面復(fù)雜的邏輯進(jìn)行封裝(java),然后透過(guò)jni調(diào)用底下的native層方法來(lái)實(shí)現(xiàn)具體功能。并且,這些個(gè)具體的功能是在服務(wù)端實(shí)現(xiàn)的,他們分屬不同的進(jìn)程,通過(guò)Binder來(lái)通信,最終通過(guò)調(diào)用服務(wù)端的方法實(shí)現(xiàn)具體的邏輯處理。(有童鞋問(wèn):Binder是個(gè)什么東東呢? 小弟有時(shí)間會(huì)講解的,現(xiàn)在就理解它是一個(gè)進(jìn)程間通信的一種方式就好,求甚解的朋友們可以百度下_)
2.2 服務(wù)端
這邊的主要任務(wù)就是在MediaPlayerFactory中,創(chuàng)建出NuplayerDriver(這個(gè)不是底層驅(qū)動(dòng)啦,我們理解為一個(gè)抽象出來(lái)的NuPlayer的基類就好啦)。 然后Nuplayer中,我們可以看到有三大模塊。
2.2.1 Source
這里是為咱們的播放器提供數(shù)據(jù)源的(解協(xié)議,解封裝在這里)。
2.2.2 Decoder
這里是解碼數(shù)據(jù)的地方(解碼在這里)
2.2.3 Renderer
這里是用來(lái)做Display的,里面涉及到A/V同步的問(wèn)題。
2.2.4 Foundation
這個(gè)部分是基礎(chǔ)類。在后面的分析當(dāng)中,我們會(huì)知道在NuPlayer中會(huì)啟動(dòng)相當(dāng)多的線程,這些線程如何異步/同步的通信,需要依靠AMessage/ALooper/AHandler來(lái)支持
之后, 通過(guò)接口類IOMX來(lái)通過(guò)Binder進(jìn)程間通信,遠(yuǎn)程調(diào)用具體的decoder來(lái)實(shí)現(xiàn)解碼。
2.3 OMX端
這一端就比較靠近底層了,里面會(huì)有各種各樣的插件注冊(cè)其中。它還鏈接這Codec Driver,這里面就是放的各種具體的解碼器啦。
2.4 Kernel端
最后, OMX的具體解碼器在啟動(dòng)Kernel層的A/V Codec Driver完成解碼操作。
三、media播放的流程
在framework中涉及media播放的流程頭文件如下:IMediaPlayer.h mediaplayer.h IMediaPlayerClient.h
其中IMediaPlayer.h 定義了binder通信相關(guān)的接口。 定義了:
class BnMediaPlayer: public BnInterface{public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);};
IMediaPlayer.cpp 是binder通信接口的實(shí)現(xiàn)。
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;}
服務(wù)端在MediaPlayerService中。在MediaPlayerService.h中如下定義:
class Client : public BnMediaPlayer 在MediaPlayerService.cpp中,create函數(shù)創(chuàng)建了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;}
再來(lái)看一下MediaPlayer這個(gè)類的定義:
class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier{} 很奇怪:在binder通信的客戶端又有了一個(gè)binder通信的服務(wù)端: BnMediaPlayerClient 在IMediaPlayerClient.h 中這個(gè)binder通信只有一個(gè)接口:
class IMediaPlayerClient: public IInterface{public: DECLARE_META_INTERFACE(MediaPlayerClient); virtual void notify(int msg, int ext1, int ext2) = 0;};
這個(gè)binder通信服務(wù)為誰(shuí)提供呢?在回來(lái)看一下MediaPlayerServer中的create函數(shù):
sp MediaPlayerService::create( pid_t pid, const sp& client, const char* url, const KeyedVector *headers)
客戶端就在這里。這個(gè)binder通信的實(shí)質(zhì)是一個(gè)消息回調(diào)函數(shù)。framework的media框架式一個(gè)雙向binder通信框架。
以seek接口為例分析一下:
在mediaplayer.cpp 中調(diào)用seek 接口:
MediaPlayer (seek)->IMediaPlayer.cpp(bpMediaPlayer.cpp )->IMediaPlayer.cpp(bnMediaPlayer.cpp ) 在這里其實(shí)已經(jīng)達(dá)到了MediaPlayerServer中的client類。當(dāng)?shù)讓拥膍edia 完成seek 以后會(huì)拋出來(lái)一消息,這個(gè)消息通過(guò) const sp& client 通知給MediaPlayer。
在media相關(guān)的頭文件中還有一個(gè)MediaPlayerInterface.h 。這個(gè)頭文件定義了底層播放器的接口。
四、Media FrameWork源碼分析
首先,針對(duì)android.media.MediaPlayer進(jìn)行分析。
里面有很多native代碼,我們找到native_setup這個(gè)jni調(diào)用,就可以找到整個(gè)框架的入口。
我們查看
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在這里實(shí)例化了一個(gè)變量mp:MediaPlayer。
并且為其設(shè)置了一個(gè)listener:JNIMediaPlayerListener
在后面我們會(huì)看到對(duì)mp的調(diào)用,現(xiàn)在讓我們先看看MediaPlayer是什么東東。
MediaPlayer@framworks/base/include/media/mediaplayer.h MediaPlayer@framworks/base/media/libmedia/mediaplayer.cpp
在這里我們終于找到了MediaPlayer:BnMediaPlayerClient:IMediaPlayerClient
原來(lái)他也是對(duì)Bind Native的一個(gè)封裝,而他本身提供了很多方法用于訪問(wèn),包括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;}
原來(lái)這里又調(diào)用了mPlayer:sp
從這里我們發(fā)現(xiàn)最終的服務(wù),還是由IMediaPlayer這個(gè)東西提供的,而IMediaPlayer@framworks/base/include/media/IMediaPlayer.h
實(shí)際上是如下定義的一個(gè)類,它繼承了IInterface@framworks/base/include/binder/IInterface.h這個(gè)類(注意雖然名字是Interface,但是它確實(shí)是個(gè)類!:-))
class IMediaPlayer: public IInterface{public: DECLARE_META_INTERFACE(MediaPlayer); virtual void disconnect() = 0; virtual status_t setVideoSurface(const sp& 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;};
為了弄清楚,在什么地方產(chǎn)生的mPlayer,我轉(zhuǎn)而分析MediaPlayerService@framworks/base/media/libmediaplayerservice/MediaPlayerService.h
其中有如下代碼
virtual sp createMediaRecorder(pid_t pid);void removeMediaRecorderClient(wp client);virtual sp createMetadataRetriever(pid_t pid); // House keeping for media player clientsvirtual sp create(pid_t pid, const sp& client, const char* url);virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length);
原來(lái)在這個(gè)地方會(huì)創(chuàng)建你sp對(duì)象。
五、文末
在本篇中,我們知道了Media Framework在整個(gè)Android框架中的位置, 也了解了Media Framework自己是個(gè)什么樣框架,以及它和各部分的聯(lián)系。 以及他的源碼分析。這也是音視頻學(xué)習(xí)的重要部分。音視頻進(jìn)階入門,請(qǐng)私信發(fā)送“核心筆記”或“手冊(cè)”,即可獲取音視頻資料!