\
MediaPlayer for Android includes Audio and video playback. Both Music and Video applications are implemented by calling MediaPlayer. In the bottom layer, MediaPlayer is based on OpenCore(PacketVideo) library. In order to build a MediaPlayer program, the upper layer also includes interprocess communication, which is based on the Binder mechanism in Android basic library. Open-source Android, for example the MediaPlayer code mainly in the following directory: the path of the JAVA program: packages/apps/Music/SRC/com/Android/Music/JAVA class path: Frameworks/base/media/Java/android/media/MediaPlayer. Java Java local call part (JNI) : Frameworks/base/media/jni/android_media_MediaPlayer CPP this part of contents is compiling targeted libmedia_jni. So. The main header files in the following directory: frameworks/base/include/media/multimedia underlying library in the following directory: frameworks/base/media/libmedia/this part of the contents is compiled into library libmedia. So. Multimedia Services: Frameworks/base/media/libmediaplayerservice/file for mediaplayerservice. H and mediaplayerservice. CPP This is compiled into the library libMediaplayerservice.so. External/OpenCore/is compiled into libOpenCorePlayer.so. In terms of program size, libOpenCorePlayer. so is the main implementation, while the other libraries are basically built on top of it for encapsulation and interprocess communication.
The second part of MediaPlayer interface and architecture
2.1 Overall Framework Diagram The structure of MediaPlayer libraries is quite complex, which can be shown in the following figure
Libmedia_jni. so provides an interface to JAVA by calling the MediaPlayer class. And implement the android. Media. MediaPlayer class.
Libmediaplayerservice. So is the MediaThe server, which is implemented by inheriting classes from libmedia.soThe serverThe other part of libmedia. So communicates with libmediaplayerservice.so via interprocess communication. The real functionality of libmediaplayerservice.so is accomplished by calling OpenCore Player.
MediaPlayer section of the header file inframeworks/base/include/media/This directory is the directory for the libmedia.so library source filesframeworks/base/media/libmedia/Corresponding to. The main header files are as follows:
IMediaPlayerClient.h
mediaplayer.h
IMediaPlayer.h
IMediaPlayerService.h
MediaPlayerInterface.h
In these headers mediaPlayer. h provides interfaces to the upper layer, while the other headers provide interface classes (classes containing pure virtual functions) that must be used by implementing class inheritance.
The relationship between the MediaPlayer library and the call is shown below:
The entire MediaPlayer can be roughly divided into two parts, Client and Server, which run separately in two processes using Binder mechanism for IPC communication. H, iMediaPlayerClient. h, and mediaPlayer. h classes define the interface and architecture of MeidaPlayer. CPP and mediaPlayer. coo are used to implement MeidaPlayer architecture. The specific functions of MeidaPlayer are implemented in PVPlayer (libopenCorePlayer.so).
2.2 Header File iMediaPlayerClient. h IMediaPlayerClient.h Describes the interface of a MediaPlayer client. Class IMediaPlayerClient: public IInterface { public: DECLARE_META_INTERFACE(MediaPlayerClient); virtual void notify(int msg, int ext1, int ext2) = 0; }; class BnMediaPlayerClient: public BnInterface
{ public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; In the definition, the IMediaPlayerClient class inherits IInterface and defines an interface for the MediaPlayer client. BnMediaPlayerClient inherits BnInterface
. It was built for the Android base Binder mechanism for in-process communication. In fact, the BnInterface
class inherits both BnInterface and IMediaPlayerClient according to the BnInterface class template. This is a common way to define Android. Mediaplayer. h mediaplayer.h is an external interface class. It defines a mediaplayer class: 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); status_t setListener(const sp
& 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
decode(const char* url, uint32_t *pSampleRate, int* pNumChannels); static sp
decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels); / /… } The MediaPlayer class implements the basic operations of MediaPlayer, such as start, stop, and pause. Another class, DeathNotifier, is defined in the MediaPlayer class, which extends from the IBinder class DeathRecipient: class DeathNotifier: public IBinder:: DeathRecipient { public: DeathNotifier() {} virtual ~DeathNotifier(); virtual void binderDied(const wp
& who); }; In fact, the MediaPlayer class indirectly inherits from IBinder, and the MediaPlayer:: DeathNotifier class inherits from IBinder:: DeathRecipient, both built for interprocess communication. Imediaplayer. h The main content of iMediaPlayer. h is an interface to implement the MediaPlayer function, which is defined as follows: 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 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
{ public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; In the IMediaPlayer class, which defines MediaPlayer’s functional interface, this class must be inherited before it can be used. It is important to note that these interfaces are similar to those of the MediaPlayer class, but they are not directly related. In fact, in various implementations of the MediaPlayer class, this is usually done by calling the implementation class of the IMediaPlayer class. ** iMediaPlayerService. h ** iMediaPlayerService. h Describes a MediaPlayer service. Class IMediaPlayerService: public IInterface { public: DECLARE_META_INTERFACE(MediaPlayerService); virtual sp
create(pid_t pid, const sp
& client, const char* url) = 0; virtual sp
create(pid_t pid, const sp
& client, int fd, int64_t offset, int64_t length) = 0; virtual sp
decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0; virtual sp
decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0; }; class BnMediaPlayerService: public BnInterface
{ public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; Because of pure virtual functions, IMediaPlayerService and BnMediaPlayerService must be inherited to be used. Interfaces such as Create and decode defined by IMediaPlayerService must be implemented by inheritors
The third part of the main analysis of MediaPlayer 3.1 JAVA program is part of the * * * * in the packages/apps/Music/SRC/com/android/Music/directory MediaPlaybackService. JAVA file, Contains calls to MediaPlayer. In MediaPlaybackService. Java contains a reference to the pack: import android. Media. The MediaPlayer; Inside the MediaPlaybackService class, we define the MultiPlayer class: private class MultiPlayer { private MediaPlayer mMediaPlayer = new MediaPlayer(); } the MultiPlayer class has the MediaPlayer class and there are several calls to the MediaPlayer as follows: mmediaplayer.reset (); mMediaPlayer.setDataSource(path); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); The reset, setDataSource, and setAudioStreamType interfaces are implemented through JAVA native calls (JNI). 3.2 MediaPlayer JAVA JAVA local call part of the local call part MediaPlayer frameworks in the directory/base/media/jni/android_media_MediaPlayer. CPP file in implementation. Android_media_mediaplayer. CPP defines an array of gMethods of type JNINativeMethod, as shown below: 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”, Android_media_MediaPlayer_native_finalize},} The first member of JNINativeMethod is a string representing the name of the JAVA local call method, which is the name of the call in the JAVA program; The second member is also a string representing the arguments and return values of the JAVA locally called method; The third member is the C function corresponding to the JAVA native call method. The android_media_MediaPlayer_reset function is implemented as follows: static void android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) { sp
mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, “java/lang/IllegalStateException”, NULL); return; } process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); } in the call to android_media_MediaPlayer_reset, you get a pointer to the MediaPlayer that does the actual function by calling it. Register_android_media_MediaPlayer used to gMethods to register for classes “android/media/MediaPlayer”, its implementation as shown below. 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” corresponding JAVA classes android. Media. The MediaPlayer.
3.3 mediaplayer core library libmedia. So libs/media/mediaplayer CPP file is used to realize the mediaplayer. H provided interfaces, one of the important segments as shown below: const sp
& MediaPlayer::getMediaPlayerService() { Mutex::Autolock _l(mServiceLock); if (mMediaPlayerService.get() == 0) { sp
sm = defaultServiceManager(); sp
binder; do { binder = sm->getService(String16(“media.player”)); if (binder ! = 0) break; LOGW(“MediaPlayerService not published, waiting…” ); usleep(500000); // 0.5s} while(true); if (mDeathNotifier == NULL) { mDeathNotifier = new DeathNotifier(); } binder->linkToDeath(mDeathNotifier); mMediaPlayerService = interface_cast
(binder); } LOGE_IF(mMediaPlayerService==0, “no MediaPlayerService! ?” ); return mMediaPlayerService; } Binder = sm->getService(String16(“media.player”)); This call is used to get a service named “media.player”. The call returns a value of type IBinder, which is converted to type IMediaPlayerService depending on the implementation. A specific setDataSource () function as follows: status_t MediaPlayer: : setDataSource (const char * url) {LOGV (” setDataSource (% s) “, url); status_t err = UNKNOWN_ERROR; if (url ! = NULL) { const sp
& service(getMediaPlayerService()); if (service ! = 0) { sp
player(service->create(getpid(), this, url)); err = setDataSource(player); } } return err; }} In the setDataSource function, getMediaPlayerService gets an IMediaPlayerService, and IMediaPlayerService gets a pointer of type IMediaPlayer, This pointer is used to perform specific operations. Some other functions are implemented similarly to setDataSource. Some other files in libmedia.so have the same name as the header file: Libs/media/IMediaPlayerClient CPP libs/media/IMediaPlayer CPP libs/media/IMediaPlayerService CPP in order to achieve the specific function of Binder, In these classes, we also need to implement a BpXXX class, such as iMediaPlayerClient. CPP implementation as follows: public BpInterface
{ public: BpMediaPlayerClient(const sp
& impl) : BpInterface
(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); }}; The macro IMPLEMENT_META_INTERFACE will be expanded to generate several functions: IMPLEMENT_META_INTERFACE(MediaPlayerClient, “android.hardware.IMediaPlayerClient”); All the above implementations are based on the Binder framework and only need to be implemented according to the template. BpXXX class is proxy class, BnXXX class is native class. The transact function of the proxy class communicates with the onTransact function of the local class.
3.4 Media Service libMediaservice. So Mediaplayerservice. h and mediaplayerservice. CPP in frameworks/base/media/libMediaplayerService are used to implement a Servers /media/ service. MediaPlayerService is inherited BnMediaPlayerService implementation, on the inside of the class and defines the type of Client, MediaPlayerService: : Client inherited BnMediaPlayer. class MediaPlayerService : public BnMediaPlayerService { class Client : Public BnMediaPlayer} has the following static function instantiate in MediaPlayerService: void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16(“media.player”), new MediaPlayerService()); } from instantiate, call IServiceManager’s addService and add a service named “media.player” to it. The service named “media.player” uses the same name as the call to getService in mediaPlayer.cpp. So, calling addService here to add the service in mediaplayer. CPP can be used with the name “media.player”. This is where interprocess communication (IPC) with Binder comes in. The MediaPlayerService class actually runs in the service, while mediaPlayer. CPP calls in the application, not the same process. But mediaplayer. CPP calls MediaPlayerService like a process call. The createPlayer function in mediaplayerservice. CPP looks like this: static sp
createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc) { sp
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; } Here we create different players according to the type of playerType: for most cases, the type will be PV_PLAYER, which calls new PVPlayer() to create a PVPlayer, and then converts its pointer to MediaPlayerBase to use; In the case of a Mini file of type SONIVOX_PLAYER, a MidiFile will be created; In the case of Ogg Vorbis format, a VorbisPlayer will be created. (OGG Vobis is an audio compression format, similar to music formats such as MP3, which is completely free, open and patent free.) Note that PVPlayer, MidiFile, and VorbisPlayer all inherit from MediaPlayerInterface, which in turn inherits from MediaPlayerBase. Therefore, all three have the same interface type. The respective constructors are called only when they are created, and after they are created, they are controlled by MediaPlayerBase only through the MediaPlayerBase interface. In the frameworks/base/media/libmediaplayerservice directory, MidiFile. H and MidiFile. The realization of the CPP MidiFile, Vorbisplayer. h and vorbisplayer. CPP implement a VorbisPlayer. Libopencoreplayer. so OpenCorePlayer is implemented in external/ OpenCore /. This implementation is an implementation based on OpenCorePlayer. The implementation file is playerdriver.cpp. Two classes are implemented: PlayerDriver and PVPlayer. PVPlayer implements specific functions by calling PlayerDriver functions.