第一部分 MediaPlayer概述
Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video兩個應用程序都是調用MediaPlayer實現的。
MediaPlayer在底層是基於OpenCore(PacketVideo)的庫實現的,爲了構建一個MediaPlayer程序,上層還包含了進程間通訊等內容,這種進程間通訊的基礎是Android基本庫中的Binder機制。
以開源的Android爲例,MediaPlayer的代碼主要在以下的目錄中:
JAVA程序的路徑:
packages/apps/Music/src/com/android/music/
JAVA類的路徑:
frameworks/base/media/java/android/media/MediaPlayer.java
JAVA本地調用部分(JNI):
frameworks/base/media/jni/android_media_MediaPlayer.cpp
這部分內容編譯成爲目標是libmedia_jni.so。
主要的頭文件在以下的目錄中:
frameworks/base/include/media/
多媒體底層庫在以下的目錄中:
frameworks/base/media/libmedia/
這部分的內容被編譯成庫libmedia.so。
多媒體服務部分:
frameworks/base/media/libmediaplayerservice/
文件爲mediaplayerservice.h和mediaplayerservice.cpp
這部分內容被編譯成庫libmediaplayerservice.so。
基於OpenCore的多媒體播放器部分
external/opencore/
這部分內容被編譯成庫libopencoreplayer.so。
從程序規模上來看,libopencoreplayer.so是主要的實現部分,而其他的庫基本上都是在其上建立的封裝和爲建立進程間通訊的機制。
第二部分 MediaPlayer的接口與架構
2.1 整體框架圖
MediaPlayer的各個庫之間的結構比較複雜,可以用下圖的表示
在各個庫中,libmedia.so位於核心的位置,它對上層的提供的接口主要是MediaPlayer類,類libmedia_jni.so通過調用MediaPlayer類提供對JAVA的接口,並且實現了android.media.MediaPlayer類。
libmediaplayerservice.so是Media的服務器,它通過繼承libmedia.so的類實現服務器的功能,而libmedia.so中的另外一部分內容則通過進程間通訊和libmediaplayerservice.so進行通訊。libmediaplayerservice.so的真正功能通過調用OpenCore Player來完成。
MediaPlayer部分的頭文件在frameworks/base/include/media/目錄中,這個目錄是和libmedia.so庫源文件的目錄frameworks/base/media/libmedia/相對應的。主要的頭文件有以下幾個:
IMediaPlayerClient.h
mediaplayer.h
IMediaPlayer.h
IMediaPlayerService.h
MediaPlayerInterface.h
在這些頭文件mediaplayer.h提供了對上層的接口,而其他的幾個頭文件都是提供一些接口類(即包含了純虛函數的類),這些接口類必須被實現類繼承才能夠使用。
整個MediaPlayer庫和調用的關係如下圖所示:
整個MediaPlayer在運行的時候,可以大致上分成Client和Server兩個部分,它們分別在兩個進程中運行,它們之間使用Binder機制實現IPC通訊。從框架結構上來看,IMediaPlayerService.h、IMediaPlayerClient.h和MediaPlayer.h三個類定義了MeidaPlayer的接口和架構,MediaPlayerService.cpp和mediaplayer.coo兩個文件用於MeidaPlayer架構的實現,MeidaPlayer的具體功能在PVPlayer(庫libopencoreplayer.so)中的實現。
2.2 頭文件IMediaPlayerClient.h
IMediaPlayerClient.h用於描述一個MediaPlayer客戶端的接口,描述如下所示:
- class IMediaPlayerClient: public IInterface
- {
- public:
- DECLARE_META_INTERFACE(MediaPlayerClient);
- virtual void notify(int msg, int ext1, int ext2) = 0;
- };
- class BnMediaPlayerClient: public BnInterface<IMediaPlayerClient>
- {
- public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
- };
2.3 頭文件mediaplayer.h
mediaplayer.h是對外的接口類,它最主要是定義了一個MediaPlayer類:
- class MediaPlayer : public BnMediaPlayerClient
- {
- public:
- MediaPlayer();
- ~MediaPlayer();
- void onFirstRef();
- void disconnect();
- status_t setDataSource(const char *url);
- status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setVideoSurface(const sp<Surface>& surface);
- status_t setListener(const sp<MediaPlayerListener>& listener);
- status_t prepare();
- status_t prepareAsync();
- status_t start();
- status_t stop();
- status_t pause();
- bool isPlaying();
- status_t getVideoWidth(int *w);
- status_t getVideoHeight(int *h);
- status_t seekTo(int msec);
- status_t getCurrentPosition(int *msec);
- status_t getDuration(int *msec);
- status_t reset();
- status_t setAudioStreamType(int type);
- status_t setLooping(int loop);
- status_t setVolume(float leftVolume, float rightVolume);
- void notify(int msg, int ext1, int ext2);
- static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);
- static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels);
- //……
- }
另外的一個類DeathNotifier在MediaPlayer類中定義,它繼承了IBinder類中的DeathRecipient類:
- class DeathNotifier: public IBinder:: DeathRecipient
- {
- public:
- DeathNotifier() {}
- virtual ~DeathNotifier();
- virtual void binderDied(const wp<IBinder>& who);
- };
2.4 頭文件IMediaPlayer.h
IMediaPlayer.h主要的的內容是一個實現MediaPlayer功能的接口,它的主要定義如下所示:
- 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 getVideoSize(int* w, int* h) = 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;
- };
- class BnMediaPlayer: public BnInterface<IMediaPlayer>
- {
- public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
- };
2.5 頭文件IMediaPlayerService.h
IMediaPlayerService.h用於描述一個MediaPlayer的服務,定義方式如下所示:
- class IMediaPlayerService: public IInterface
- {
- public:
- DECLARE_META_INTERFACE(MediaPlayerService);
- virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
- virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
- virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0;
- virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0;
- };
- class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
- {
- public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
- };
第三部分 MediaPlayer的主要實現分析
3.1 JAVA程序部分
在packages/apps/Music/src/com/android/music/目錄的MediaPlaybackService.java文件中,包含了對MediaPlayer的調用。在MediaPlaybackService.java中包含對包的引用:
import android.media.MediaPlayer;
在MediaPlaybackService類的內部,定義了MultiPlayer類:
- private class MultiPlayer {
- private MediaPlayer mMediaPlayer = new MediaPlayer();
- }
- mMediaPlayer.reset();
- mMediaPlayer.setDataSource(path);
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
3.2 MediaPlayer的JAVA本地調用部分
MediaPlayer的JAVA本地調用部分在目錄frameworks/base/media/jni/的android_media_MediaPlayer.cpp中的文件中實現。
android_media_MediaPlayer.cpp之中定義了一個JNINativeMethod(JAVA本地調用方法)類型的數組gMethods,如下所示:
- static JNINativeMethod gMethods[] = {
- {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},
- {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
- {"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
- {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
- {"_start", "()V", (void *)android_media_MediaPlayer_start},
- {"_stop", "()V", (void *)android_media_MediaPlayer_stop},
- {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
- {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
- {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
- {"_pause", "()V", (void *)android_media_MediaPlayer_pause},
- {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
- {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
- {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
- {"_release", "()V", (void *)android_media_MediaPlayer_release},
- {"_reset", "()V", (void *)android_media_MediaPlayer_reset},
- {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
- {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
- {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
- {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
- {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
- {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
- }
其中android_media_MediaPlayer_reset函數的實現如下所示:
- static void android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
- {
- sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return;
- }
- process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
- }
register_android_media_MediaPlayer用於將gMethods註冊爲的類"android/media/MediaPlayer",其實現如下所示。
- static int register_android_media_MediaPlayer(JNIEnv *env)
- {
- jclass clazz;
- clazz = env->FindClass("android/media/MediaPlayer");
- // ......
- return AndroidRuntime::registerNativeMethods(env, "android/media/MediaPlayer", gMethods, NELEM(gMethods));
- }
3.3 mediaplayer的核心庫libmedia.so
libs/media/mediaplayer.cpp文件用於實現mediaplayer.h提供的接口,其中一個重要的片段如下所示:
- const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
- {
- Mutex::Autolock _l(mServiceLock);
- if (mMediaPlayerService.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.player"));
- if (binder != 0)
- break;
- LOGW("MediaPlayerService not published, waiting...");
- usleep(500000); // 0.5 s
- } while(true);
- if (mDeathNotifier == NULL) {
- mDeathNotifier = new DeathNotifier();
- }
- binder->linkToDeath(mDeathNotifier);
- mMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
- }
- LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?");
- return mMediaPlayerService;
- }
一個具體的函數setDataSource如下所示:
- status_t MediaPlayer::setDataSource(const char *url)
- {
- LOGV("setDataSource(%s)", url);
- status_t err = UNKNOWN_ERROR;
- if (url != NULL) {
- const sp<IMediaPlayerService>& service(getMediaPlayerService());
- if (service != 0) {
- sp<IMediaPlayer> player(service->create(getpid(), this, url));
- err = setDataSource(player);
- }
- }
- return err;
- }
其他一些函數的實現也與setDataSource類似。
libmedia.so中的其他一些文件與頭文件的名稱相同,它們是:
libs/media/IMediaPlayerClient.cpp
libs/media/IMediaPlayer.cpp
libs/media/IMediaPlayerService.cpp
爲了實現Binder的具體功能,在這些類中還需要實現一個BpXXX的類,例如IMediaPlayerClient.cpp的實現如下所示:l
- class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
- {
- public:
- BpMediaPlayerClient(const sp<IBinder>& impl)
- : BpInterface<IMediaPlayerClient>(impl){}
- virtual void notify(int msg, int ext1, int ext2)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
- data.writeInt32(msg);
- data.writeInt32(ext1);
- data.writeInt32(ext2);
- remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
- }
- };
IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
以上的實現都是基於Binder框架的實現方式,只需要按照模版實現即可。其中BpXXX的類爲代理類(proxy),BnXXX的類爲本地類(native)。代理類的transact函數和本地類的onTransact函數實現對應的通訊。
3.4 media服務libmediaservice.so
frameworks/base/media\libmediaplayerservice目錄中的MediaPlayerService.h和MediaPlayerService.cpp用於實現一個
servers/media/的服務,MediaPlayerService是繼承BnMediaPlayerService的實現,在這個類的內部又定義了類Client,MediaPlayerService::Client繼承了BnMediaPlayer。
- class MediaPlayerService : public BnMediaPlayerService
- {
- class Client : public BnMediaPlayer
- }
- void MediaPlayerService::instantiate() {
- defaultServiceManager()->addService(
- String16("media.player"), new MediaPlayerService());
- }
這個名爲"media.player"的服務和mediaplayer.cpp中調用getService中得到的使用一樣名稱。因此,在這裏調用addService增加服務在mediaplayer.cpp中可以按照名稱"media.player"來使用。這就是使用Binder實現進程間通訊的(IPC)的作用,事實上這個MediaPlayerService類是在服務中運行的,而mediaplayer.cpp調用的功能在應用中運行,二者並不是一個進程。但是在mediaplayer.cpp卻像一個進程的調用一樣調用MediaPlayerService的功能。
在MediaPlayerService.cpp中的createPlayer函數如下所示:
- static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc)
- {
- sp<MediaPlayerBase> p;
- switch (playerType) {
- case PV_PLAYER:
- LOGV(" create PVPlayer");
- p = new PVPlayer();
- break;
- case SONIVOX_PLAYER:
- LOGV(" create MidiFile");
- p = new MidiFile();
- break;
- case VORBIS_PLAYER:
- LOGV(" create VorbisPlayer");
- p = new VorbisPlayer();
- break;
- }
- //……
- return p;
- }
(OGG Vobis是一種音頻壓縮格式,與MP3等的音樂格式類似,它具有完全免費、開放和沒有專利限制的特點。)
值得注意的是PVPlayer、MidiFile和VorbisPlayer三個類都是繼承MediaPlayerInterface得到的,而MediaPlayerInterface又是繼承MediaPlayerBase得到的,因此三者具有相同接口類型。只有建立的時候會調用各自的構造函數,在建立之後,將只通過MediaPlayerBase接口來MediaPlayerBase控制它們。
在frameworks/base/media/libmediaplayerservice目錄中,MidiFile.h和MidiFile.cpp的實現MidiFile,VorbisPlayer.h和VorbisPlayer.cpp實現一個VorbisPlayer。
3.5 OpenCorePlayer的實現libopencoreplayer.so
OpenCore Player在external/opencore/中實現,這個實現是一個基於OpenCore的Player的實現。具體實現的文件爲playerdriver.cpp。其中實現了兩個類:PlayerDriver和PVPlayer。PVPlayer通過調用PlayerDriver的函數實現具體的功能。