Android的MediaPlayer架構(gòu)介紹關(guān)鍵字: android的mediaplayer架構(gòu)介紹轉(zhuǎn)載自hanchao3c Android開發(fā)者論壇原創(chuàng))
本文由中國(guó)的Androidin社區(qū)的hanchao3c原創(chuàng),主要介紹的是Android中很重要也最為復(fù)雜的媒體播放器(MediaPlayer)部分的架構(gòu)。對(duì)于Android這樣一個(gè)完整又相對(duì)復(fù)雜的系統(tǒng),一個(gè)MediaPlayer功能的實(shí)現(xiàn)不在其具體的功能,而是具體功能如何適應(yīng)Android系統(tǒng)Android MediaPlayer的主要具體實(shí)現(xiàn)在OpenCore的Player中,這部分不是本文的關(guān)注點(diǎn)。本文關(guān)注的是MediaPlayer系統(tǒng)的架構(gòu),其他的一些Android的應(yīng)用程序也使用類似的架構(gòu)。 對(duì)于開源事業(yè)在中國(guó)的發(fā)展,hanchao3c認(rèn)為應(yīng)該共享的不僅僅是代碼,文檔、設(shè)計(jì)思想、理念甚至對(duì)于技術(shù)的理解都應(yīng)該得到充分的共享。Android為中國(guó)人進(jìn)入大規(guī)模的開源項(xiàng)目提供了很好的機(jī)遇,對(duì)于走在技術(shù)前沿的人們,不應(yīng)將技術(shù)視為私有財(cái)產(chǎn),而應(yīng)該將自己理解更好地奉獻(xiàn)給大眾,提高大眾的學(xué)習(xí)速度,從中也可以得到反饋,從而促進(jìn)自己的進(jìn)步。僅以此文奉獻(xiàn)給所有關(guān)系技術(shù)的朋友,希望可以拋磚引玉,促進(jìn)我們共同的技術(shù)進(jìn)步! 第一部分 MediaPlayer概述 Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video兩個(gè)應(yīng)用程序都是調(diào)用MediaPlayer實(shí)現(xiàn)的。 MediaPlayer在底層是基于OpenCore(PacketVideo)的庫(kù)實(shí)現(xiàn)的,為了構(gòu)建一個(gè)MediaPlayer程序,上層還包含了進(jìn)程間通訊等內(nèi)容,這種進(jìn)程間通訊的基礎(chǔ)是Android基本庫(kù)中的Binder機(jī)制。 以開源的Android為例MediaPlayer的代碼主要在以下的目錄中: JAVA程序的路徑: packages/apps/Music/src/com/android/music/ JAVA本地調(diào)用部分(JNI): frameworks/base/media/jni/android_media_MediaPlayer.cpp 這部分內(nèi)容編譯成為目標(biāo)是libmedia_jni.so。 主要的頭文件在以下的目錄中: frameworks/base/include/media/ 多媒體底層庫(kù)在以下的目錄中: frameworks/base/media/libmedia/ 這部分的內(nèi)容被編譯成庫(kù)libmedia.so。 多媒體服務(wù)部分: frameworks/base/media/libmediaplayerservice/ 文件為mediaplayerservice.h和mediaplayerservice.cpp 這部分內(nèi)容被編譯成庫(kù)libmediaplayerservice.so。 基于OpenCore的多媒體播放器部分 external/opencore/ 這部分內(nèi)容被編譯成庫(kù)libopencoreplayer.so。 從程序規(guī)模上來(lái)看,libopencoreplayer.so是主要的實(shí)現(xiàn)部分,而其他的庫(kù)基本上都是在其上建立的封裝和為建立進(jìn)程間通訊的機(jī)制。 第二部分 MediaPlayer的接口與架構(gòu) (hanchao3c Android開發(fā)者論壇原創(chuàng),轉(zhuǎn)載請(qǐng)注明) 2.1 整體框架圖 MediaPlayer的各個(gè)庫(kù)之間的結(jié)構(gòu)比較復(fù)雜,可以用下圖的表示: 1.png (62.54 KB) 2008-11-22 00:11 在各個(gè)庫(kù)中,libmedia.so位于核心的位置,它對(duì)上層的提供的接口主要是MediaPlayer類,類libmedia_jni.so通過(guò)調(diào)用MediaPlayer類提供對(duì)JAVA的接口,并且實(shí)現(xiàn)了android.media.MediaPlayer類。 libmediaplayerservice.so是Media的服務(wù)器,它通過(guò)繼承l(wèi)ibmedia.so的類實(shí)現(xiàn)服務(wù)器的功能,而libmedia.so中的另外一部分內(nèi)容則通過(guò)進(jìn)程間通訊和libmediaplayerservice.so進(jìn)行通訊。libmediaplayerservice.so的真正功能通過(guò)調(diào)用OpenCore Player來(lái)完成。 MediaPlayer部分的頭文件在frameworks/base/include/media/目錄中,這個(gè)目錄是和libmedia.so庫(kù)源文件的目錄frameworks/base/media/libmedia/相對(duì)應(yīng)的。主要的頭文件有以下幾個(gè): IMediaPlayerClient.h mediaplayer.h IMediaPlayer.h IMediaPlayerService.h MediaPlayerInterface.h 在這些頭文件mediaplayer.h提供了對(duì)上層的接口,而其他的幾個(gè)頭文件都是提供一些接口類(即包含了純虛函數(shù)的類),這些接口類必須被實(shí)現(xiàn)類繼承才能夠使用。 整個(gè)MediaPlayer庫(kù)和調(diào)用的關(guān)系如下圖所示: 2.png (46.74 KB) 2008-11-22 00:11 整個(gè)MediaPlayer在運(yùn)行的時(shí)候,可以大致上分成Client和Server兩個(gè)部分,它們分別在兩個(gè)進(jìn)程中運(yùn)行,它們之間使用Binder機(jī)制實(shí)現(xiàn)IPC通訊。從框架結(jié)構(gòu)上來(lái)看,IMediaPlayerService.h、IMediaPlayerClient.h和MediaPlayer.h三個(gè)類定義了MeidaPlayer的接口和架構(gòu),MediaPlayerService.cpp和mediaplayer.coo兩個(gè)文件用于MeidaPlayer架構(gòu)的實(shí)現(xiàn),MeidaPlayer的具體功能在PVPlayer(庫(kù)libopencoreplayer.so)中的實(shí)現(xiàn)。 2.2 頭文件IMediaPlayerClient.h IMediaPlayerClient.h用于描述一個(gè)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); }; 在定義中,IMediaPlayerClient類繼承IInterface,并定義了一個(gè)MediaPlayer客戶端的接口,BnMediaPlayerClient繼承了BnInterface<IMediaPlayerClient>,這是為基于Android的基礎(chǔ)類Binder機(jī)制實(shí)現(xiàn)在進(jìn)程通訊而構(gòu)建的。事實(shí)上,根據(jù)BnInterface類模版的定義BnInterface<IMediaPlayerClient>類相當(dāng)于雙繼承了BnInterface和ImediaPlayerClient。這是Android一種常用的定義方式。 2.3 頭文件mediaplayer.h mediaplayer.h是對(duì)外的接口類,它最主要是定義了一個(gè)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); //…… } 從接口中可以看出MediaPlayer類剛好實(shí)現(xiàn)了一個(gè)MediaPlayer的基本操作,例如播放(start)、停止(stop)、暫停(pause)等。 另外的一個(gè)類DeathNotifier在MediaPlayer類中定義,它繼承了IBinder類中的DeathRecipient類: class DeathNotifier: public IBinder:: DeathRecipient { public: DeathNotifier() {} virtual ~DeathNotifier(); virtual void binderDied(const wp<IBinder>& who); }; 事實(shí)上,MediaPlayer類正是間接地繼承了IBinder,而MediaPlayer:: DeathNotifier類繼承了IBinder:: DeathRecipient,這都是為了實(shí)現(xiàn)進(jìn)程間通訊而構(gòu)建的。 2.4 頭文件IMediaPlayer.h IMediaPlayer.h主要的的內(nèi)容是一個(gè)實(shí)現(xiàn)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); }; 在IMediaPlayer類中,主要定義MediaPlayer的功能接口,這個(gè)類必須被繼承才能夠使用。值得注意的是,這些接口和MediaPlayer類的接口有些類似,但是它們并沒(méi)有直接的關(guān)系。事實(shí)上,在MediaPlayer類的各種實(shí)現(xiàn)中,一般都會(huì)通過(guò)調(diào)用IMediaPlayer類的實(shí)現(xiàn)類來(lái)完成。 2.5 頭文件IMediaPlayerService.h IMediaPlayerService.h用于描述一個(gè)MediaPlayer的服務(wù),定義方式如下所示: 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); }; 由于具有純虛函數(shù),IMediaPlayerService 以及BnMediaPlayerService必須被繼承實(shí)現(xiàn)才能夠使用,在IMediaPlayerService定義的create和decode等接口,事實(shí)上是必須被繼承者實(shí)現(xiàn)的內(nèi)容。注意,create的返回值的類型是sp<IMediaPlayer>,這個(gè)IMediaPlayer正是提供實(shí)現(xiàn)功能的接口。 第三部分 MediaPlayer的主要實(shí)現(xiàn)分析 (hanchao3c Android開發(fā)者論壇原創(chuàng),轉(zhuǎn)載請(qǐng)注明) 3.1 JAVA程序部分 在packages/apps/Music/src/com/android/music/目錄的MediaPlaybackService.java文件中,包含了對(duì)MediaPlayer的調(diào)用。 在MediaPlaybackService.java中包含對(duì)包的引用: import android.media.MediaPlayer; 在MediaPlaybackService類的內(nèi)部,定義了MultiPlayer類: private class MultiPlayer { private MediaPlayer mMediaPlayer = new MediaPlayer(); } MultiPlayer類中使用了MediaPlayer類,其中有一些對(duì)這個(gè)MediaPlayer的調(diào)用,調(diào)用的過(guò)程如下所示: mMediaPlayer.reset(); mMediaPlayer.setDataSource(path); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); reset、setDataSource和setAudioStreamType等接口就是通過(guò)JAVA本地調(diào)用(JNI)來(lái)實(shí)現(xiàn)的。 3.2 MediaPlayer的JAVA本地調(diào)用部分 MediaPlayer的JAVA本地調(diào)用部分在目錄frameworks/base/media/jni/的android_media_MediaPlayer.cpp中的文件中實(shí)現(xiàn)。 android_media_MediaPlayer.cpp之中定義了一個(gè)JNINativeMethod(JAVA本地調(diào)用方法)類型的數(shù)組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}, } JNINativeMethod的第一個(gè)成員是一個(gè)字符串,表示了JAVA本地調(diào)用方法的名稱,這個(gè)名稱是在JAVA程序中調(diào)用的名稱;第二個(gè)成員也是一個(gè)字符串,表示JAVA本地調(diào)用方法的參數(shù)和返回值;第三個(gè)成員是JAVA本地調(diào)用方法對(duì)應(yīng)的C語(yǔ)言函數(shù)。 其中android_media_MediaPlayer_reset函數(shù)的實(shí)現(xiàn)如下所示: 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 ); } 在android_media_MediaPlayer_reset的調(diào)用中,得到一個(gè)MediaPlayer指針,通過(guò)對(duì)它的調(diào)用實(shí)現(xiàn)實(shí)際的功能。 register_android_media_MediaPlayer用于將gMethods注冊(cè)為的類"android/media/MediaPlayer",其實(shí)現(xiàn)如下所示。 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)); } "android/media/MediaPlayer"對(duì)應(yīng)JAVA的類android.media.MediaPlayer。 (hanchao3c Android開發(fā)者論壇原創(chuàng),轉(zhuǎn)載請(qǐng)注明) 3.3 mediaplayer的核心庫(kù)libmedia.so libs/media/mediaplayer.cpp文件用于實(shí)現(xiàn)mediaplayer.h提供的接口,其中一個(gè)重要的片段如下所示: 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; } 其中最重要的一點(diǎn)是binder = sm->getService(String16("media.player"));這個(gè)調(diào)用用來(lái)得到一個(gè)名稱為"media.player"的服務(wù),這個(gè)調(diào)用返回值的類型為IBinder,根據(jù)實(shí)現(xiàn)將其轉(zhuǎn)換成類型IMediaPlayerService使用。 一個(gè)具體的函數(shù)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; } 在函數(shù)setDataSource函數(shù)中,調(diào)用getMediaPlayerService得到了一個(gè)IMediaPlayerService,又從IMediaPlayerService中得到了IMediaPlayer類型的指針,通過(guò)這個(gè)指針進(jìn)行著具體的操作。 其他一些函數(shù)的實(shí)現(xiàn)也與setDataSource類似。 libmedia.so中的其他一些文件與頭文件的名稱相同,它們是: libs/media/IMediaPlayerClient.cpp libs/media/IMediaPlayer.cpp libs/media/IMediaPlayerService.cpp 為了實(shí)現(xiàn)Binder的具體功能,在這些類中還需要實(shí)現(xiàn)一個(gè)BpXXX的類,例如IMediaPlayerClient.cpp的實(shí)現(xiàn)如下所示: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); } }; 還需要實(shí)現(xiàn)定義宏IMPLEMENT_META_INTERFACE,這個(gè)宏將被展開,生成幾個(gè)函數(shù): IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient"); 以上的實(shí)現(xiàn)都是基于Binder框架的實(shí)現(xiàn)方式,只需要按照模版實(shí)現(xiàn)即可。其中BpXXX的類為代理類(proxy),BnXXX的類為本地類(native)。代理類的transact函數(shù)和本地類的onTransact函數(shù)實(shí)現(xiàn)對(duì)應(yīng)的通訊。 3.4 media服務(wù)libmediaservice.so frameworks/base/media\libmediaplayerservice目錄中的MediaPlayerService.h和MediaPlayerService.cpp用于實(shí)現(xiàn)一個(gè) servers/media/的服務(wù),MediaPlayerService是繼承BnMediaPlayerService的實(shí)現(xiàn),在這個(gè)類的內(nèi)部又定義了類Client,MediaPlayerService::Client繼承了BnMediaPlayer。 class MediaPlayerService : public BnMediaPlayerService { class Client : public BnMediaPlayer } 在MediaPlayerService中具有如下一個(gè)靜態(tài)函數(shù)instantiate: void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService()); } 在instantiate函數(shù)中,調(diào)用IServiceManager的一個(gè)函數(shù)addService,向其中增加了一個(gè)名為"media.player"的服務(wù)。 這個(gè)名為"media.player"的服務(wù)和mediaplayer.cpp中調(diào)用getService中得到的使用一樣名稱。因此,在這里調(diào)用addService增加服務(wù)在mediaplayer.cpp中可以按照名稱"media.player"來(lái)使用。這就是使用Binder實(shí)現(xiàn)進(jìn)程間通訊的(IPC)的作用,事實(shí)上這個(gè)MediaPlayerService類是在服務(wù)中運(yùn)行的,而mediaplayer.cpp調(diào)用的功能在應(yīng)用中運(yùn)行,二者并不是一個(gè)進(jìn)程。但是在mediaplayer.cpp卻像一個(gè)進(jìn)程的調(diào)用一樣調(diào)用MediaPlayerService的功能。 在MediaPlayerService.cpp中的createPlayer函數(shù)如下所示: 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; } 在這里根據(jù)playerType的類型建立不同的播放器:對(duì)于大多數(shù)情況,類型將是PV_PLAYER,這時(shí)會(huì)調(diào)用了new PVPlayer()建立一個(gè)PVPlayer,然后將其指針轉(zhuǎn)換成MediaPlayerBase來(lái)使用;對(duì)于Mini文件的情況,類型為SONIVOX_PLAYER,將會(huì)建立一個(gè)MidiFile;對(duì)于Ogg Vorbis格式的情況,將會(huì)建立一個(gè)VorbisPlayer。 (OGG Vobis是一種音頻壓縮格式,與MP3等的音樂(lè)格式類似,它具有完全免費(fèi)、開放和沒(méi)有專利限制的特點(diǎn)。) 值得注意的是PVPlayer、MidiFile和VorbisPlayer三個(gè)類都是繼承MediaPlayerInterface得到的,而MediaPlayerInterface又是繼承MediaPlayerBase得到的,因此三者具有相同接口類型。只有建立的時(shí)候會(huì)調(diào)用各自的構(gòu)造函數(shù),在建立之后,將只通過(guò)MediaPlayerBase接口來(lái)MediaPlayerBase控制它們。 在frameworks/base/media/libmediaplayerservice目錄中,MidiFile.h和MidiFile.cpp的實(shí)現(xiàn)MidiFile,VorbisPlayer.h和VorbisPlayer.cpp實(shí)現(xiàn)一個(gè)VorbisPlayer。 3.5 OpenCorePlayer的實(shí)現(xiàn)libopencoreplayer.so OpenCore Player在external/opencore/中實(shí)現(xiàn),這個(gè)實(shí)現(xiàn)是一個(gè)基于OpenCore的Player的實(shí)現(xiàn)。具體實(shí)現(xiàn)的文件為playerdriver.cpp。其中實(shí)現(xiàn)了兩個(gè)類:PlayerDriver和PVPlayer。PVPlayer通過(guò)調(diào)用PlayerDriver的函數(shù)實(shí)現(xiàn)具體的功能。 |
|