Android音視頻開(kāi)發(fā)Media FrameWork框架源碼解析
一、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)單介紹下它??吹捻樞蚴?rarr; ↓ ← ↓ →(腫么都覺(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<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;
};
為了弄清楚,在什么地方產(chǎn)生的mPlayer,我轉(zhuǎn)而分析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);
原來(lái)在這個(gè)地方會(huì)創(chuàng)建你sp對(duì)象。
以上就是Android音視頻開(kāi)發(fā)Media FrameWork框架源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Android音視頻Media FrameWork的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
flutter日期選擇器 flutter時(shí)間選擇器
這篇文章主要為大家詳細(xì)介紹了flutter日期選擇器,flutter時(shí)間選擇器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
android仿華為手機(jī)懸浮窗設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了android仿華為手機(jī)懸浮窗設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
android:layout_gravity和android:gravity的區(qū)別
本篇文章主要介紹了android中g(shù)iavity和layout_gravity的區(qū)別。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04
談?wù)凙ndroid開(kāi)發(fā)之RecyclerView的使用全解
這篇文章主要介紹了談?wù)凙ndroid開(kāi)發(fā)之RecyclerView的使用全解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2016-12-12
Android 實(shí)現(xiàn)仿網(wǎng)絡(luò)直播彈幕功能詳解及實(shí)例
這篇文章主要介紹了Android 實(shí)現(xiàn)仿網(wǎng)絡(luò)直播彈幕功能詳解的相關(guān)資料,并附實(shí)例代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11

